The controller asks no build of anybody (ADR 0501 §5, ADR 0525 clause 6, ADR 0503 §3). Every module of a walk is taken from the builder's done key; a key not done yet waits, named in the plan, and never fails it. - C2b/C2c: internal/builder and cmd/mesh-controller's asks go (askABuild, onlyTheBuildersOwn, buildOneAsked, takeIn from an outcome, buildAgentsOwn, the builder's say and its fallback, the daemon hearing an outcome). The server follows the retired seats' built subjects only to let go of them, because the installer's carried user list names them. - C2d: replay, queue, cancel, clear, kill, pause, resume, delivery-check, check-here and merge-gate are refused by name. - C3: the check queues (CHECKS_READY, CHECKS_OTHER) and their workers, the checks-running and plans-building buckets and their grants, the build queue and its hold (plans_building.go, queue.go, link/holds.go, builds_nats.go, checks_nats.go). - C4: merge_gate*.go, the pull request's repo-check path, the Checked event and its layers; a pull request asks the controller nothing but to tell mesh-config what its head declares. - C5: the builds bucket is written only by key_takein. - C10 (help and refusals): the terminal's help lists only what is served. Integration tests of the plan's tiers, sends, stops and retries now run on a stand-in builder with a done key for every module (walk_keys_scaffold_integration_test.go); the tests of the asks, the queue, the merge gate and the replays are deleted.
78 lines
3.0 KiB
Go
78 lines
3.0 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// **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 < 6 && (asking.Modules["notes"] == nil || asking.Modules["notes"].Build == "" || asking.Modules["notes"].State == "asked"); 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)
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|