From a31bd7d4a56c2da1dc8824f2c5ad32350c481152 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 23 Oct 2026 22:57:05 +0200 Subject: [PATCH 1/3] Give the assigner test's candidate the SDK's fingerprint set, which the SDK refuses without (issue 1927) --- .../cmd/mesh-delivery-assigner/integration_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go index 6a79f7c..f04d60c 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go @@ -181,8 +181,10 @@ func TestAChangeIsComposedOnTheBus(t *testing.T) { b.putJSON(t, provider.AssignmentsBucket, "ace.other", []byte(`{"node":"ace","module":"other","build":"build-2"}`)) heads := []delivery.Head{{Repository: "novox/web", Number: 7, Head: strings.Repeat("2", 40)}} hash, _ := delivery.HeadsHash(heads) - cand, err := delivery.EncodeCandidate(delivery.Candidate{Group: "feat/x", HeadsHash: hash, Pulls: []delivery.CandidatePull{{Head: heads[0], - Modules: []string{"web"}, Fps: map[string]delivery.CandidateModule{"web": {FP2: delivery.SourcePrefix2 + strings.Repeat("b", 64), Manifest: changed}}}}}) + // 1927/AC1: the candidate carries the fingerprint set the SDK computes, as the indexer writes it. + pulls := []delivery.CandidatePull{{Head: heads[0], + Modules: []string{"web"}, Fps: map[string]delivery.CandidateModule{"web": {FP2: delivery.SourcePrefix2 + strings.Repeat("b", 64), Manifest: changed}}}} + cand, err := delivery.EncodeCandidate(delivery.Candidate{Group: "feat/x", HeadsHash: hash, Pulls: pulls, FPSet: delivery.FingerprintSet(pulls)}) if err != nil { t.Fatal(err) } -- 2.54.0 From b303e32a4135ab916cbed19674cfe65d46233434 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 23 Oct 2026 23:03:38 +0200 Subject: [PATCH 2/3] Close the builder test's nodes from the bed's start, so no pull in hand takes the first ask (issue 1928) --- .../mesh-delivery-builder/integration_test.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go index 51580bf..5a37fc5 100644 --- a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go +++ b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go @@ -179,7 +179,11 @@ type bed struct { // startBed starts the bus, the buckets the controller makes from the builder's and the build modules' manifests, the // build modules' streams and the builder's durable consumers on them, two nodes' toolchains, the indexer's manifests, and // the fake build modules. It runs no builder. -func startBed(t *testing.T) *bed { +func startBed(t *testing.T) *bed { return startBedWith(t, false) } + +// startBedWith is startBed with the nodes' capacity 0 from the start when closed: a puller that reads its capacity before a +// test could close the nodes may be in a pull already and takes the first ask put (issue 1928). +func startBedWith(t *testing.T, closed bool) *bed { dir, err := os.MkdirTemp(os.Getenv("TMPDIR"), "b") if err != nil { t.Fatal(err) @@ -243,6 +247,7 @@ func startBed(t *testing.T) *bed { b.builds = mk(delivery.BuilderBuildsBucket, delivery.BuilderBuildsHistory) b.instances = mk(instancesBucket, 1) b.fake = &fakeBuildModules{js: js, ctx: ctx, calls: map[string]int{}} + b.fake.closed.Store(closed) b.fake.serve(t, "mesh-build-go", "n1", "n2") b.fake.serve(t, "mesh-build-node", "n1", "n2") b.fake.serve(t, "mesh-build-image", "n1") // the image build module runs on n1 only @@ -781,8 +786,7 @@ func (b *bed) asksPut(t *testing.T, nc *nats.Conn) func() []delivery.StepAsk { // 1887/AC3: a builder that started again while its asks waited in the streams (no node had a free slot) puts no second // ask: it waits for the asks its building key names, and the key is done once a node took them. func TestARestartedBuilderPutsNoSecondAsk(t *testing.T) { - b := startBed(t) - b.fake.closed.Store(true) + b := startBedWith(t, true) // 1928/AC1: no node can take an ask from the start, so no pull in hand takes the first one b.module(t, "netcheck", "catalogue-a67f0196-netcheck.module.json", "modules/netcheck") sub, err := nats.Connect(b.srvURL, nats.UserInfo("ctl", "pw")) if err != nil { @@ -792,11 +796,13 @@ func TestARestartedBuilderPutsNoSecondAsk(t *testing.T) { asked := b.asksPut(t, sub) b.start(t, "n1", nil) v := b.await(t, "netcheck", func(v delivery.BuilderBuild) bool { return v.State == delivery.BuildBuilding && len(v.Asks) == 2 }) - for deadline := time.Now().Add(5 * time.Second); len(asked()) < 2 && time.Now().Before(deadline); time.Sleep(20 * time.Millisecond) { + for deadline := time.Now().Add(20 * time.Second); len(asked()) < 2; time.Sleep(20 * time.Millisecond) { + if time.Now().After(deadline) { + t.Fatalf("asks put = %+v within 20 s, want the two the key names", asked()) + } } b.stop() b.start(t, "n1", nil) // the same builder, started again, while both asks wait - time.Sleep(500 * time.Millisecond) b.fake.open() done := b.await(t, "netcheck", isState(delivery.BuildDone)) if got := asked(); len(got) != 2 { -- 2.54.0 From cd3e55e056051093fce863883c1d91bbdf47d313 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 23 Oct 2026 23:18:11 +0200 Subject: [PATCH 3/3] Bring the checker's integration tests to what R4g decided: Go-only repository, echoed beside, readable kept (issue 1929) --- .../mesh-delivery-checker/integration_test.go | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/integration_test.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/integration_test.go index b7611e1..9e96ad9 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/integration_test.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/integration_test.go @@ -10,6 +10,7 @@ import ( "io" "os" "path/filepath" + "sort" "strings" "sync" "sync/atomic" @@ -81,6 +82,9 @@ type fakeBuildModules struct { mu sync.Mutex calls map[string]int // by `.` testTool *testing.T + // beside is, by workspace, the siblings the fetch placed in it as ` `, sorted: a digest echoes them + // (1929/AC2; mesh-sdk buildstep.besideOf), or the level runs whole and keeps nothing. + beside map[string][]string } func (f *fakeBuildModules) count(tool string) int { @@ -100,10 +104,30 @@ func (f *fakeBuildModules) result(t *testing.T, tool string, args map[string]any } fetched := readCaptured(t, name) fetched["commit"], fetched["base"] = args["commit"], args["base"] + var refs []struct { + Repository string `json:"repository"` + Commit string `json:"commit"` + } + raw, _ := json.Marshal(args["beside"]) + _ = json.Unmarshal(raw, &refs) + var lines []string + for _, r := range refs { + lines = append(lines, r.Repository+" "+r.Commit) + } + sort.Strings(lines) + f.mu.Lock() + if f.beside == nil { + f.beside = map[string][]string{} + } + f.beside[fmt.Sprint(fetched["workspace"])] = lines + f.mu.Unlock() v = fetched case strings.HasSuffix(tool, "_digest"): d := map[string]string{"unit": digU, "integration": digI}[level] - v = map[string]any{"level": level, "packages": map[string]string{"fixture/slow": d}} + f.mu.Lock() + beside := f.beside[fmt.Sprint(args["workspace"])] + f.mu.Unlock() + v = map[string]any{"level": level, "packages": map[string]string{"fixture/slow": d}, "beside": beside} case strings.HasSuffix(tool, "_test"): r := readCaptured(t, "go-test-slow") r["level"] = level @@ -288,6 +312,15 @@ func startBed(t *testing.T) *bed { } b.buckets[name] = kv } + // 1929/AC1: the indexer's value of the repository's module, with no TypeScript manifest, so the Go build module alone + // judges the repository (an unknown repository is judged by both, issue 1887 A12). + known, err := delivery.EncodeModule(delivery.Module{Repository: repo, Commit: trunk, Path: "modules/m", None2: "the fingerprint is computed with its chain"}) + if err != nil { + t.Fatal(err) + } + if _, err := b.buckets[delivery.ModulesBucket].Put(ctx, "m", known); err != nil { + t.Fatal(err) + } b.setOnline(t, "n1", true) for _, module := range []string{"mesh-build-go", "mesh-build-node"} { b.setHealth(t, "n1", module) @@ -436,7 +469,7 @@ func (b *bed) owed(t *testing.T, number int, head, state string) delivery.Owed { // TestCheckerJudgesACandidateAndOwesItsStatus: a candidate the indexer wrote, one pull request of mesh-delivery, is fetched // merged onto the trunk the gate names, digested and tested at both levels on the node, kept, previewed; the verdict passes // with the counts of both levels and the composition not run, and the status mesh/check is owed on the head as success. -func TestCheckerJudgesACandidateAndOwesItsStatus(t *testing.T) { // N6/AC5, 1300/AC5, 1445/AC1 +func TestCheckerJudgesACandidateAndOwesItsStatus(t *testing.T) { // N6/AC5, 1300/AC5, 1445/AC1, 1929/AC1 b := startBed(t) key := b.candidate(t, "feat/x", pull(repo, 7, head1)) b.start(t, nil) @@ -476,7 +509,7 @@ func TestCheckerJudgesACandidateAndOwesItsStatus(t *testing.T) { // N6/AC5, 1300 // TestACheckOfEqualInputsRunsNothing: a second candidate (another head, the same digests) is checked with every package // taken from the first's kept verdicts: no test step runs and no second kept key appears. -func TestACheckOfEqualInputsRunsNothing(t *testing.T) { // 1287/AC5, 1288/AC6 +func TestACheckOfEqualInputsRunsNothing(t *testing.T) { // 1287/AC5, 1288/AC6, 1929/AC2 b := startBed(t) first := b.candidate(t, "feat/x", pull(repo, 7, head1)) b.start(t, nil) @@ -574,7 +607,7 @@ func TestACheckLeftRunningIsTakenOverWhenTheCheckerStarts(t *testing.T) { // N6/ // TestAMemberNamingAMeshSDKCommitOffTheTrunkFailsNamingTheCommit: the go.mod the forge answers names a commit that main does not // hold; the verdict fails naming the member and the commit and no test runs (ADR 0484 clause 9). -func TestAMemberNamingAMeshSDKCommitOffTheTrunkFailsNamingTheCommit(t *testing.T) { // 1624/AC2 +func TestAMemberNamingAMeshSDKCommitOffTheTrunkFailsNamingTheCommit(t *testing.T) { // 1624/AC2, 1929/AC3 b := startBed(t) b.stalePin.Store(true) key := b.candidate(t, "feat/x", pull(repo, 7, head1)) @@ -583,9 +616,7 @@ func TestAMemberNamingAMeshSDKCommitOffTheTrunkFailsNamingTheCommit(t *testing.T if v.State != delivery.VerdictFail || !strings.Contains(v.Failed.Words, "9aaa5c80ac5c") || !strings.Contains(v.Failed.Words, repo+"#7") { t.Fatalf("verdict = %+v", v) } - if n := b.fake.count("mesh-build-go.build_go_test"); n != 0 { - t.Errorf("%d test steps ran after a stale pin", n) - } + // 1929/AC3: no assertion that no test ran: one ask runs fetch, digest and tests (ADR 0525 ยง3). } // triesStore is the tries bucket as the tools write it. @@ -671,7 +702,7 @@ func TestTheCheckerSaysOwedReadableOnTheBus(t *testing.T) { // R2-1 break } if said.Module != "mesh-delivery-checker" || said.Node != "n1" || !said.Keeps("owed") || !said.Readable("owed") || - !said.Readable("previews") || !said.Readable("verdicts") || said.Readable("kept") || said.Readable("tries") || len(said.States) != 5 { - t.Fatalf("the checker said %+v, want its five states with owed, previews and verdicts readable", said) + !said.Readable("previews") || !said.Readable("verdicts") || !said.Readable("kept") || said.Readable("tries") || len(said.States) != 5 { + t.Fatalf("the checker said %+v, want its five states with kept, owed, previews and verdicts readable (1929/AC4; 1887 A5b)", said) } } -- 2.54.0