test(release): pin the trash marker's key path and wire shape
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+27
−0
internal/release/trash_test.go+27 −0
diff --git a/internal/release/trash_test.go b/internal/release/trash_test.go| index 7cd2dceaf..104017c04 100644 |
| --- a/internal/release/trash_test.go |
| +++ b/internal/release/trash_test.go |
| @@ -11,6 +11,12 @@ func TestTrashAppRoundTrip(t *testing.T) { |
| s := NewDirStore(t.TempDir()) |
| now := time.Date(2026, 8, 4, 16, 0, 0, 0, time.UTC) |
| + // The key path is a wire contract: later tasks (route hiding, the purge |
| + // pass) string-match "deleted.json" independently of this package. |
| + if got, want := AppTombstoneKey("bab", "derp"), "apps/bab/derp/deleted.json"; got != want { |
| + t.Fatalf("AppTombstoneKey(bab, derp) = %q, want %q", got, want) |
| + } |
| + |
| // Absent: (nil, nil), not an error. |
| if tomb, err := ReadAppTombstone(ctx, s, "bab", "derp"); err != nil || tomb != nil { |
| t.Fatalf("absent marker: got %v, %v; want nil, nil", tomb, err) |
| @@ -45,6 +51,27 @@ func TestTrashAppRoundTrip(t *testing.T) { |
| } |
| } |
| +// TestReadAppTombstoneParsesWireShape pins the JSON tags against the spec's |
| +// exact example body — a struct-tag typo would still fail the negative |
| +// tests above (any parse error refuses), so only a positive round-trip on |
| +// literal bytes catches it. |
| +func TestReadAppTombstoneParsesWireShape(t *testing.T) { |
| + ctx := context.Background() |
| + s := NewDirStore(t.TempDir()) |
| + body := []byte(`{"schema":1,"account":"bab","app":"derp","deleted_at":"2026-08-04T16:00:00Z","actor":"paul@keymail.dev"}`) |
| + if _, err := s.Put(ctx, AppTombstoneKey("bab", "derp"), body, ""); err != nil { |
| + t.Fatal(err) |
| + } |
| + tomb, err := ReadAppTombstone(ctx, s, "bab", "derp") |
| + if err != nil || tomb == nil { |
| + t.Fatalf("ReadAppTombstone: got %v, %v", tomb, err) |
| + } |
| + want := time.Date(2026, 8, 4, 16, 0, 0, 0, time.UTC) |
| + if tomb.Account != "bab" || tomb.App != "derp" || tomb.Actor != "paul@keymail.dev" || !tomb.DeletedAt.Equal(want) { |
| + t.Fatalf("tombstone fields: %+v", tomb) |
| + } |
| +} |
| + |
| func TestReadAppTombstoneRefusesDisagreement(t *testing.T) { |
| ctx := context.Background() |
| s := NewDirStore(t.TempDir()) |