package console import ( "errors" "testing" "github.com/carlosframework/platform/internal/hostops" "github.com/carlosframework/platform/internal/mail" "github.com/carlosframework/platform/internal/release" ) // Rev 5 P2 (C6): the enabled purge's mail readiness uses strict, complete // inventories. Any claim or domain record it cannot read, parse or match to // its own key stops the purge. The original used ListDomainClaims and // ListDomains, which log and skip such objects, so an unreadable orphan claim // let the purge complete (nil error here) with its SES identity standing. func TestClaimPurgeMailReadyRefusesIncompleteInventory(t *testing.T) { const orphan = "email/domain-claims/orphan.example.com.json" cases := []struct { name string key string body string }{ {"malformed claim", orphan, "{not json"}, {"newer schema claim", orphan, `{"schema":2,"domain":"orphan.example.com","account":"bab","app":"web"}`}, {"claim body for another domain", orphan, `{"schema":1,"domain":"other.example.com","account":"bab","app":"web"}`}, {"claim with an invalid account", orphan, `{"schema":1,"domain":"orphan.example.com","account":"","app":"web"}`}, {"stray object under the claim prefix", "email/domain-claims/notes.txt", "x"}, {"malformed domain record", mail.DomainKey("bab", "broken.example.com"), "{not json"}, {"domain record under the wrong key", mail.DomainKey("bab", "wrong.example.com"), `{"schema":1,"domain":"right.example.com","apps":["web"]}`}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { raw := release.NewDirStore(t.TempDir()) p := &ClaimPurgeCoordinator{Server: &Server{}, Controller: hostops.Controller{Store: raw}} // Control: a clean store is ready (the app has no mail estate). if err := p.mailReady(t.Context(), "bab", "web"); err != nil { t.Fatalf("clean store: %v", err) } if _, err := raw.Put(t.Context(), tc.key, []byte(tc.body), ""); err != nil { t.Fatal(err) } if err := p.mailReady(t.Context(), "bab", "web"); !errors.Is(err, mail.ErrDomainInventory) { t.Fatalf("mailReady with %s: err=%v, want ErrDomainInventory", tc.name, err) } }) } } // A complete inventory of valid claims, other accounts' included, is ready. func TestClaimPurgeMailReadyAcceptsCompleteInventory(t *testing.T) { raw := release.NewDirStore(t.TempDir()) putMailClaim(t, raw, mail.DomainClaim{Domain: "a.example.com", Account: "zed", App: "other"}) putMailJSON(t, raw, mail.DomainKey("bab", "b.example.com"), mail.DomainRecord{Schema: 1, Domain: "b.example.com", Apps: []string{"sibling"}}) p := &ClaimPurgeCoordinator{Server: &Server{}, Controller: hostops.Controller{Store: raw}} if err := p.mailReady(t.Context(), "bab", "web"); err != nil { t.Fatalf("complete inventory: %v", err) } // Its own orphan claim is an estate, and with no provisioner that is the // contract refusal, not an inventory one. putMailClaim(t, raw, mail.DomainClaim{Domain: "mine.example.com", Account: "bab", App: "web"}) if err := p.mailReady(t.Context(), "bab", "web"); !errors.Is(err, hostops.ErrContract) { t.Fatalf("own claim without a provisioner: %v", err) } }