domainclaim: add JSON schema validation test; soften ListForApp doc
Add assertion to TestGetRoundTripsAndKeyShape that validates the on-disk JSON keys to catch struct tag typos. Update ListForApp doc comment to accurately reflect that ANY Get error (not just parse errors) skips claims.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 files changed,
+37
−2
internal/domainclaim/domainclaim.go+3 −2internal/domainclaim/domainclaim_test.go+34 −0
diff --git a/internal/domainclaim/domainclaim.go b/internal/domainclaim/domainclaim.go| index b0987ad13..6127510f4 100644 |
| --- a/internal/domainclaim/domainclaim.go |
| +++ b/internal/domainclaim/domainclaim.go |
| @@ -70,8 +70,9 @@ func Delete(ctx context.Context, s release.Store, host string) error { |
| } |
| // ListForApp returns the claims held by one account+app pair. Claims that |
| -// fail to parse are skipped: a malformed claim is #151's reconciler's |
| -// problem to surface, not a reason to blank an app's Settings list. |
| +// cannot be read or parsed are skipped: a malformed or unreachable claim is |
| +// #151's reconciler's problem to surface, not a reason to blank an app's |
| +// Settings list. |
| func ListForApp(ctx context.Context, s release.Store, account, app string) ([]Claim, error) { |
| keys, err := s.List(ctx, prefix) |
| if err != nil { |
diff --git a/internal/domainclaim/domainclaim_test.go b/internal/domainclaim/domainclaim_test.go| index ca890d286..37f404cbe 100644 |
| --- a/internal/domainclaim/domainclaim_test.go |
| +++ b/internal/domainclaim/domainclaim_test.go |
| @@ -3,7 +3,9 @@ package domainclaim |
| import ( |
| "context" |
| + "encoding/json" |
| "errors" |
| + "sort" |
| "testing" |
| "time" |
| @@ -40,6 +42,38 @@ func TestGetRoundTripsAndKeyShape(t *testing.T) { |
| if out != in { |
| t.Fatalf("round trip: got %+v want %+v", out, in) |
| } |
| + |
| + // Verify JSON schema: assert that the on-disk bytes have exactly the expected keys |
| + // to catch typos in struct tags (e.g. "account" → "accnt"). |
| + rawBody, _, err := s.Get(ctx, Key("example.com")) |
| + if err != nil { |
| + t.Fatalf("raw Get: %v", err) |
| + } |
| + var m map[string]any |
| + if err := json.Unmarshal(rawBody, &m); err != nil { |
| + t.Fatalf("unmarshal: %v", err) |
| + } |
| + gotKeys := make([]string, 0, len(m)) |
| + for k := range m { |
| + gotKeys = append(gotKeys, k) |
| + } |
| + sort.Strings(gotKeys) |
| + wantKeys := []string{"account", "app", "created_at", "host", "route", "schema"} |
| + if !equal(gotKeys, wantKeys) { |
| + t.Fatalf("JSON keys: got %v, want %v", gotKeys, wantKeys) |
| + } |
| +} |
| + |
| +func equal(a, b []string) bool { |
| + if len(a) != len(b) { |
| + return false |
| + } |
| + for i := range a { |
| + if a[i] != b[i] { |
| + return false |
| + } |
| + } |
| + return true |
| } |
| func TestListForAppFiltersOtherOwners(t *testing.T) { |