| index 86c6d1402..dbb5c3114 100644 |
| --- a/internal/console/lifetimes_purge_test.go |
| +++ b/internal/console/lifetimes_purge_test.go |
| @@ -9,6 +9,7 @@ import ( |
| "testing" |
| "time" |
| |
| + "github.com/carlosframework/platform/internal/mail" |
| "github.com/carlosframework/platform/internal/provision" |
| "github.com/carlosframework/platform/internal/release" |
| ) |
| @@ -96,27 +97,57 @@ func TestConsolePurgeRetiresEveryLifetime(t *testing.T) { |
| } |
| requirePurged(t, l, true) |
| }) |
| - t.Run("the hourly store sweep of an app with no console row", func(t *testing.T) { |
| - l := newLtOn(t) |
| - l.mustCreate(t, ltOne) |
| - old := time.Now().Add(-31 * 24 * time.Hour) |
| - if err := release.TrashApp(ctx, l.fx.rel, "bab", ltApp, "paul@keymail.dev", old); err != nil { |
| - t.Fatal(err) |
| - } |
| - if err := l.fx.st.TrashAppRow(OpsAccountID, ltApp, old); err != nil { |
| - t.Fatal(err) |
| - } |
| - if err := l.fx.st.PurgeAppRow(OpsAccountID, ltApp); err != nil { |
| - t.Fatal(err) |
| - } |
| - if !l.fx.srv.lifetimesIteration(ctx, "expiry pass", true, false, func(ctx context.Context) { l.fx.srv.expiryPass(ctx, time.Now()) }) { |
| - t.Fatal("the expiry pass did not run") |
| - } |
| - requireRetired(t, l.fx.rel, ltApp, ltOne, 1) |
| - if keys := appKeys(t, l.fx, ltApp); len(keys) != 0 { |
| - t.Fatalf("the bucket still holds %v", keys) |
| - } |
| - }) |
| + for _, estate := range []string{"none", "email", "unreadable"} { |
| + t.Run("the hourly store sweep of an app with no console row, email estate "+estate, func(t *testing.T) { |
| + l := newLtOn(t) |
| + l.mustCreate(t, ltOne) |
| + old := time.Now().Add(-31 * 24 * time.Hour) |
| + if err := release.TrashApp(ctx, l.fx.rel, "bab", ltApp, "paul@keymail.dev", old); err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := l.fx.st.TrashAppRow(OpsAccountID, ltApp, old); err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := l.fx.st.PurgeAppRow(OpsAccountID, ltApp); err != nil { |
| + t.Fatal(err) |
| + } |
| + switch estate { |
| + case "email": |
| + now := time.Now() |
| + putMailRecord(t, l.fx, ltApp, &mail.Record{ |
| + Declared: &mail.Declared{EnvPrefix: "CARLOS_SMTP", From: "hi@example.com", At: now}, |
| + Provisioned: &mail.Provisioned{KeyID: "AKIA1", Active: true, At: now}, |
| + }) |
| + case "unreadable": |
| + l.bucket.setHook(failNth("get", mail.SenderKey("bab", ltApp, mail.SenderAppID), 1, true)) |
| + } |
| + if !l.fx.srv.lifetimesIteration(ctx, "expiry pass", true, false, func(ctx context.Context) { l.fx.srv.expiryPass(ctx, time.Now()) }) { |
| + t.Fatal("the expiry pass did not run") |
| + } |
| + l.bucket.setHook(nil) |
| + if estate == "none" { |
| + requireRetired(t, l.fx.rel, ltApp, ltOne, 1) |
| + if keys := appKeys(t, l.fx, ltApp); len(keys) != 0 { |
| + t.Fatalf("the bucket still holds %v", keys) |
| + } |
| + return |
| + } |
| + // Refused before any purge step: the marker, the record and its |
| + // live slot all stand, and no retirement was begun. |
| + if tomb, err := release.ReadAppTombstone(ctx, l.fx.rel, "bab", ltApp); err != nil || tomb == nil { |
| + t.Fatalf("marker = %+v %v, want it untouched", tomb, err) |
| + } |
| + if raw, _ := rawOf(t, l.fx.rel, ltApp, ltOne); raw == nil { |
| + t.Fatal("the sweep removed a record of an app it must refuse") |
| + } |
| + if slot, _ := slotOf(t, l.fx.rel, ltOne); slot == nil || slot.State != provision.SlotLive { |
| + t.Fatalf("slot = %+v, want it live", slot) |
| + } |
| + if rows := retireRows(t, l.fx.st, ltOne); len(rows) != 0 { |
| + t.Fatalf("retirements = %+v, want none", rows) |
| + } |
| + }) |
| + } |
| t.Run("the guards run first and a refused purge retires nothing", func(t *testing.T) { |
| l := newLtOn(t) |
| purgeWorld(t, l) |