109 lines
4.5 KiB
Go
109 lines
4.5 KiB
Go
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"
|
|
)
|
|
|
|
func TestRetiringLocksMarksAndDropsNothing(t *testing.T) {
|
|
f, c := newFake(admin)
|
|
f.answer(`shobj_description\(oid`, []string{"c"}, []string{`{"mesh":"consumer","node":"ace"}`})
|
|
f.answer(`SELECT 1 FROM pg_roles`, []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 mesh stopped asking for it", at); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sql := f.statements()
|
|
if !has(sql, `ALTER ROLE "mesh_ace_letta" NOLOGIN`) || !has(sql, `pg_terminate_backend.*usename = 'mesh_ace_letta'`) ||
|
|
!has(sql, `COMMENT ON ROLE "mesh_ace_letta" IS '\{"mesh":"consumer","node":"ace","retired":"2026-10-06T12:00:00Z","why":"the mesh stopped asking for it"\}'`) {
|
|
t.Fatal(strings.Join(sql, "\n"))
|
|
}
|
|
noDrop(t, sql)
|
|
if has(sql, `REVOKE|ALLOW_CONNECTIONS|RENAME`) {
|
|
t.Fatal("retiring touched the database:", strings.Join(sql, "\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`) {
|
|
t.Fatal(f.statements(), err)
|
|
}
|
|
}
|
|
|
|
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", ""},
|
|
)
|
|
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) != 3 {
|
|
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.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 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())
|
|
}
|
|
}
|