//go:build integration package main import ( "strings" "testing" "time" "github.com/novox/mesh-controller/internal/link" ) // **Acceptance 12 of design 47: no table in the controller's store holds builds, rollouts or assignments** (novox/hq ADR // 0408, issue 1111). A delivery is driven through the live trigger — a merge heard, its batch cut into a plan, the plan's // build asked and answered, the assignment made — until a build, a rollout and an assignment exist; they are read from the // chain, and then the store's own catalog is read: none of the tables of the chain is in it, nor the function that raised the generation from the assignment table; the table that stays, stays. func TestNoTableOfTheControllersStoreHoldsBuildsRolloutsOrAssignments(t *testing.T) { open := windowed(t) everyHeadWaits(t) asked := asksRecorded(t) ctx := t.Context() inv := open.inventory if _, err := assign(ctx, open, "anchor", "notes"); err != nil { t.Fatal(err) } hear(t, open, catalogueMerge("c-notes", "notes", t0), t0.Add(time.Second)) cutAt(t, open, t0.Add(91*time.Second)) ws, _ := walks(t, open) if len(ws) != 1 { t.Fatalf("%d walk(s) after the cut", len(ws)) } rollout := ws[0].ID asking, err := inv.PlanByID(ctx, rollout) if err != nil { t.Fatal(err) } for try := 0; try < 3 && (asking.Modules["notes"] == nil || asking.Modules["notes"].Build == ""); try++ { advancePlans(ctx, open) if asking, err = inv.PlanByID(ctx, rollout); err != nil { t.Fatal(err) } } buildID := asking.Modules["notes"].Build if buildID == "" || len(*asked) != 1 { t.Fatalf("the walk asked %v, and notes' build is %q", *asked, buildID) } digest := "sha256:" + strings.Repeat("b", 64) result := outcome(buildID, "modules/notes", "c-notes", "notes", "") result.Made = []link.MadeArtifact{{Name: "notes", Kind: "image", Reference: "artifact-store://notes/notes@" + digest}} if err := (builds{inv: inv, open: open}).Built(ctx, result); err != nil { t.Fatal(err) } // What the live path made is in the chain. if built, found, err := inv.BuildByID(ctx, buildID); err != nil || !found || built.Commit != "c-notes" { t.Fatalf("the build is not read from the chain: %+v %v %v", built, found, err) } if p, err := inv.PlanByID(ctx, rollout); err != nil || p.ID != rollout { t.Fatalf("the rollout is not read from the chain: %+v %v", p, err) } if on, err := inv.AssignmentsOn(ctx, "anchor"); err != nil { t.Fatal(err) } else if _, ok := assignmentOf(on, "notes"); !ok { t.Fatalf("the assignment is not read from the chain: %+v", on) } // And the catalog of the store holds none of them. have := map[string]bool{} for _, row := range inv.QueryForTest(t, `select table_name::text from information_schema.tables where table_schema = 'public'`) { have[strings.Trim(row[0], `"`)] = true } for _, table := range []string{"build", "build_request", "release_plan", "batched_merge", "assignment", "pending_assignment", "chain_moved"} { if have[table] { t.Errorf("the table %s is in the controller's store", table) } } for _, table := range []string{"build_gate", "assignment_generation"} { if !have[table] { t.Errorf("the table %s, which stays, is gone", table) } } if rows := inv.QueryForTest(t, `select count(*) from pg_proc where proname = 'raise_assignment_generation'`); rows[0][0] != "0" { t.Errorf("the function raise_assignment_generation is in the store: %v", rows) } }