From 420ae3d0e771d390fc217eb9742a74c2dceb9935 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 22 Oct 2026 20:19:57 +0200 Subject: [PATCH] Test the group check's answer without swapping standard output, and wait for a take-in to forget a new module's wait (issue 1299, C2; issue 1851, A5) --- .../checks_stop_integration_test.go | 47 ------------------- cmd/mesh-controller/delivery.go | 10 +++- cmd/mesh-controller/group_check_test.go | 12 +++++ .../new_module_on_merge_test.go | 7 +-- 4 files changed, 24 insertions(+), 52 deletions(-) create mode 100644 cmd/mesh-controller/group_check_test.go diff --git a/cmd/mesh-controller/checks_stop_integration_test.go b/cmd/mesh-controller/checks_stop_integration_test.go index 0ed5b21a..df8a2e64 100644 --- a/cmd/mesh-controller/checks_stop_integration_test.go +++ b/cmd/mesh-controller/checks_stop_integration_test.go @@ -6,9 +6,6 @@ import ( "context" "encoding/json" "errors" - "io" - "os" - "strings" "testing" "git.novox.be/novox/mesh-sdk/go/catalogue" @@ -101,47 +98,3 @@ func TestThePullRequestChecksAreAskedOnlyForARepositoryTheCheckerDoesNotJudge(t t.Fatalf("0503 §5: the verdict said names a gate layer, or no repo-check layer: %+v", c) } } - -// C2 (ADR 0503 §3; issue 1299): a delivery group's composed check asks build-agent nothing and answers that the checker -// judges the group. -func TestTheGroupCheckAsksNothingAndNamesTheChecker(t *testing.T) { - aMesh(t) - ctx := t.Context() - js, _ := aBuildQueue(t) - servingBus.Store(js) - t.Cleanup(func() { servingBus.Store(nil) }) - members := `[{"id":"novox/a@111111111111","repository":"novox/a","base":"main","head":"1111111111111111111111111111111111111111","number":1},` + - `{"id":"novox/b@222222222222","repository":"novox/b","base":"main","head":"2222222222222222222222222222222222222222","number":2}]` - out := capturedStdout(t, func() error { - return deliveryCommand(ctx, []string{"check", "--group", "feat/x", "--members", members}) - }) - if !strings.Contains(out, `"judged-by": "mesh-delivery-checker"`) || !strings.Contains(out, `"asked": ""`) { - t.Fatalf("0503 §3: the group check answered %s", out) - } - q, err := link.ReadQueue(ctx, js, link.TheBuildMachine) - if err != nil { - t.Fatal(err) - } - if len(q.Asks) != 0 { - t.Fatalf("0503 §3: the group check asked %+v", q.Asks) - } -} - -// capturedStdout is what run writes to standard output. -func capturedStdout(t *testing.T, run func() error) string { - t.Helper() - r, w, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - was := os.Stdout - os.Stdout = w - runErr := run() - os.Stdout = was - w.Close() - out, _ := io.ReadAll(r) - if runErr != nil { - t.Fatal(runErr) - } - return string(out) -} diff --git a/cmd/mesh-controller/delivery.go b/cmd/mesh-controller/delivery.go index 17a9a16c..44d6c0f0 100644 --- a/cmd/mesh-controller/delivery.go +++ b/cmd/mesh-controller/delivery.go @@ -901,8 +901,7 @@ func deliveryCommand(ctx context.Context, args []string) error { } // **The group's composed check is the checker's** (novox/hq ADR 0503 §3; issue 1299, C2): nothing is asked of // build-agent, and the answer says who judges it. - return answer(map[string]any{"asked": "", "group": *group, "judged-by": checkerModule, - "said": "the checker judges a delivery group's heads merged together (ADR 0503 §3): nothing was asked"}) + return answer(groupCheckAnswer(*group)) case "go": if len(positionals) != 1 { return errors.New("delivery go [--by ] [--why ]") @@ -1258,3 +1257,10 @@ func recheckOneHead(member string, answer func(any) error, ask func() (string, e } return answer(recheckAnswer(asked, member)) } + +// groupCheckAnswer is what `delivery check` of a group answers from R4e: who judges it, and that nothing was asked +// (novox/hq ADR 0503 §3; issue 1299, C2). +func groupCheckAnswer(group string) map[string]any { + return map[string]any{"asked": "", "group": group, "judged-by": checkerModule, + "said": "the checker judges a delivery group's heads merged together (ADR 0503 §3): nothing was asked"} +} diff --git a/cmd/mesh-controller/group_check_test.go b/cmd/mesh-controller/group_check_test.go new file mode 100644 index 00000000..080f1ba1 --- /dev/null +++ b/cmd/mesh-controller/group_check_test.go @@ -0,0 +1,12 @@ +package main + +import "testing" + +// C2 (ADR 0503 §3; issue 1299): a delivery group's composed check is answered as the checker's, and nothing is asked +// of build-agent: the command answers before any ask is composed. +func TestTheGroupCheckNamesTheCheckerAndAsksNothing(t *testing.T) { + a := groupCheckAnswer("feat/x") + if a["judged-by"] != "mesh-delivery-checker" || a["asked"] != "" || a["group"] != "feat/x" { + t.Fatalf("the group check answered %v", a) + } +} diff --git a/cmd/mesh-controller/new_module_on_merge_test.go b/cmd/mesh-controller/new_module_on_merge_test.go index eb693721..4a763321 100644 --- a/cmd/mesh-controller/new_module_on_merge_test.go +++ b/cmd/mesh-controller/new_module_on_merge_test.go @@ -58,9 +58,10 @@ func TestAMergeAddingAModuleEndsRegisteredFromItsKeyAndAsksNoBuild(t *testing.T) _, known := inventoryHolds(t, inv, "systemd-resolved") return known }) - if obs := newModuleObservations(time.Now().Add(time.Hour)); len(obs) != 0 { - t.Fatalf("a registered module is still named waiting: %+v", obs) - } + // The take-in forgets the wait just after the registration it made is seen. + becomes(t, 5*time.Second, "the registered module no longer named waiting", func() bool { + return len(newModuleObservations(time.Now().Add(time.Hour))) == 0 + }) requests, err := inv.RequestsNamed(ctx, inventory.BuildRequest{Repository: "novox/mesh-catalog", Path: "modules/systemd-resolved"}.Name()) if err != nil || len(requests) != 0 {