package main // What retired means in postgres, held against the statements sent (retire_pg.go); the server's side // of it — the login refused, the data kept, a deletion dropping only its own — is live_test.go's. import ( "git.novox.be/novox/mesh-sdk/go/provider/harness" "strings" "testing" "time" ) // ADR 0570 clause 5, on the operator's yes: the login's database and objects go to its keeper, marked; its sessions // end; the login is dropped; the database is not. func TestRetiringHandsTheDatabaseToAKeeperAndRemovesTheLogin(t *testing.T) { f, c := newFake(admin) f.answer(`shobj_description\(oid`, []string{"c"}, []string{`{"mesh":"consumer","node":"ace"}`}) f.answer(`pg_roles WHERE rolname = 'mesh_ace_letta'$`, []string{"?column?"}, []string{"1"}) f.answer(`pg_database WHERE datname = 'mesh_ace_letta'$`, []string{"?column?"}, []string{"1"}) at := time.Date(2026, 10, 6, 12, 0, 0, 0, time.UTC) if err := c.RetireRole(ctx, "mesh_ace_letta", "the operator approved its retirement", at); err != nil { t.Fatal(err) } var order []string for _, call := range f.calls { switch { case strings.HasPrefix(call.SQL, "SELECT"): case strings.HasPrefix(call.SQL, "REASSIGN"), strings.HasPrefix(call.SQL, "DROP OWNED"): order = append(order, call.Database+": "+call.SQL) default: order = append(order, call.SQL) } } if !has(f.statements(), `pg_terminate_backend.*usename = 'mesh_ace_letta'`) { t.Fatal(strings.Join(f.statements(), "\n")) } want := []string{ `CREATE ROLE "mesh_ace_letta~retired" NOLOGIN`, `COMMENT ON ROLE "mesh_ace_letta~retired" IS '{"mesh":"consumer","node":"ace","retired":"2026-10-06T12:00:00Z","why":"the operator approved its retirement","login":"mesh_ace_letta"}'`, `ALTER ROLE "mesh_ace_letta" NOLOGIN`, `mesh_ace_letta: REASSIGN OWNED BY "mesh_ace_letta" TO "mesh_ace_letta~retired"`, `mesh_ace_letta: DROP OWNED BY "mesh_ace_letta"`, `DROP ROLE "mesh_ace_letta"`, } if strings.Join(order, "\n") != strings.Join(want, "\n") { t.Fatalf("sent:\n%s\nwant:\n%s", strings.Join(order, "\n"), strings.Join(want, "\n")) } if has(f.statements(), `DROP DATABASE|REVOKE|ALLOW_CONNECTIONS|RENAME`) { t.Fatal("retiring touched the database:", strings.Join(f.statements(), "\n")) } // No such role: nothing to retire, nothing done. f, c = newFake(admin) if err := c.RetireRole(ctx, "gone", "x", at); err != nil || has(f.statements(), `ALTER|COMMENT|CREATE|DROP`) { t.Fatal(f.statements(), err) } } // A login made again takes back what its keeper kept, and the keeper goes; with no keeper, nothing is sent. func TestALoginMadeAgainReclaimsWhatItsKeeperKept(t *testing.T) { f, c := newFake(admin) if err := c.Reclaim(ctx, "mesh_ace_letta", "mesh_ace_letta"); err != nil || has(f.statements(), `REASSIGN|DROP`) { t.Fatal(f.statements(), err) } f, c = newFake(admin) f.answer(`pg_roles WHERE rolname = 'mesh_ace_letta~retired'$`, []string{"?column?"}, []string{"1"}) if err := c.Reclaim(ctx, "mesh_ace_letta", "mesh_ace_letta"); err != nil { t.Fatal(err) } var got []string for _, call := range f.calls[1:] { got = append(got, call.Database+": "+call.SQL) } want := `mesh_ace_letta: REASSIGN OWNED BY "mesh_ace_letta~retired" TO "mesh_ace_letta"` + "\n" + `mesh_ace_letta: DROP OWNED BY "mesh_ace_letta~retired"` + "\n" + `postgres: DROP ROLE "mesh_ace_letta~retired"` if strings.Join(got, "\n") != want { t.Fatal(strings.Join(got, "\n")) } } func TestTheInventoryIsWhatTheMeshMadeByMarkOrShape(t *testing.T) { f, c := newFake(admin) f.answer(`FROM pg_roles r`, []string{"rolname", "rolcanlogin", "mark", "mesh_shaped", "size"}, []string{"active_marked", "t", `{"mesh":"consumer","node":"ace"}`, "f", "100"}, []string{"active_shaped", "t", "", "t", "200"}, []string{"retired_marked", "f", `{"mesh":"consumer","node":"ace","retired":"2026-10-06T12:00:00Z","why":"gone"}`, "t", "300"}, []string{"locked_before", "f", "", "t", "400"}, []string{"hal_registry", "t", "", "f", "500"}, []string{"jochens", "t", "", "t", ""}, []string{"mesh_ace_umami~retired", "f", `{"mesh":"consumer","node":"ace","retired":"2026-10-29T12:00:00Z","why":"approved","login":"mesh_ace_umami"}`, "f", "600"}, ) f.answer(`_deleted_`, []string{"datname", "size"}, []string{"mesh_novox_gitea_deleted_20261005", "7771827"}) inv, err := c.Inventory(ctx) if err != nil { t.Fatal(err) } if strings.Join(inv.Active, ",") != "active_marked,active_shaped" { t.Fatalf("active: %v", inv.Active) } if len(inv.Retired) != 4 { t.Fatalf("%+v", inv.Retired) } r := inv.Retired[0] if r.Consumer != "retired_marked" || r.Node != "ace" || r.Why != "gone" || r.SizeBytes != 300 || r.RetiredAt.Format(time.RFC3339) != "2026-10-06T12:00:00Z" { t.Fatalf("%+v", r) } if r := inv.Retired[1]; r.Consumer != "locked_before" || !r.RetiredAt.IsZero() || r.Kind != harness.KindConsumer { t.Fatalf("found locked without a mark: %+v", r) } if r := inv.Retired[2]; r.Consumer != "mesh_ace_umami" || r.SizeBytes != 600 || r.Why != "approved" { t.Fatalf("a keeper is listed under the login it keeps for: %+v", r) } if r := inv.Retired[3]; r.Kind != KindSetAside || r.RetiredAt.Format("20060102") != "20261005" || r.SizeBytes != 7771827 { t.Fatalf("set aside: %+v", r) } } func TestDeletingRefusesALoginThatCanConnect(t *testing.T) { f, c := newFake(admin) f.answer(`SELECT rolcanlogin`, []string{"rolcanlogin"}, []string{"t"}) if _, err := c.DeleteRetired(ctx, harness.Retired{Consumer: "mesh_ace_baserow", Kind: harness.KindConsumer}); err == nil { t.Fatal("deleted an active consumer") } noDrop(t, f.statements()) f, c = newFake(admin) if _, err := c.DeleteRetired(ctx, harness.Retired{Consumer: "mesh_ace_baserow", Kind: KindSetAside}); err == nil { t.Fatal("dropped a database not set aside") } noDrop(t, f.statements()) } func TestDeletingDropsTheDatabaseThenTheRole(t *testing.T) { f, c := newFake(admin) f.answer(`SELECT rolcanlogin`, []string{"rolcanlogin"}, []string{"f"}) f.answer(`SELECT pg_database_size`, []string{"size"}, []string{"9000"}) freed, err := c.DeleteRetired(ctx, harness.Retired{Consumer: "mesh_ace_letta", Kind: harness.KindConsumer}) if err != nil || freed != 9000 { t.Fatal(freed, err) } sql := strings.Join(f.statements(), "\n") db, role := strings.Index(sql, `DROP DATABASE "mesh_ace_letta"`), strings.Index(sql, `DROP ROLE "mesh_ace_letta"`) if db < 0 || role < db { t.Fatal(sql) } // A login removed on retiring: the database, then its keeper. f, c = newFake(admin) f.answer(`SELECT pg_database_size`, []string{"size"}, []string{"9000"}) f.answer(`pg_roles WHERE rolname = 'mesh_ace_umami~retired'$`, []string{"?column?"}, []string{"1"}) if _, err := c.DeleteRetired(ctx, harness.Retired{Consumer: "mesh_ace_umami", Kind: harness.KindConsumer}); err != nil { t.Fatal(err) } sql = strings.Join(f.statements(), "\n") db, keeper := strings.Index(sql, `DROP DATABASE "mesh_ace_umami"`), strings.Index(sql, `DROP ROLE "mesh_ace_umami~retired"`) if db < 0 || keeper < db { t.Fatal(sql) } // A role still owning a set-aside database is kept, and said. f, c = newFake(admin) f.answer(`SELECT rolcanlogin`, []string{"rolcanlogin"}, []string{"f"}) f.answer(`SELECT datname FROM pg_database WHERE datdba`, []string{"datname"}, []string{"mesh_ace_letta_deleted_20261005"}) if _, err := c.DeleteRetired(ctx, harness.Retired{Consumer: "mesh_ace_letta", Kind: harness.KindConsumer}); err == nil || !strings.Contains(err.Error(), "still owns") || has(f.statements(), `DROP ROLE`) { t.Fatal(err, f.statements()) } }