From dec3b83e66b4e591b51e4cbdff523addfeb1344f Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 23 Oct 2026 16:11:07 +0200 Subject: [PATCH] Test that the builder, a build module and the controller are taken from the builder's keys and nothing reaches node-build-agent (issue 1851, C2 criterion) --- .../walk_from_keys_integration_test.go | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/cmd/mesh-controller/walk_from_keys_integration_test.go b/cmd/mesh-controller/walk_from_keys_integration_test.go index bc8960c1..3705da9d 100644 --- a/cmd/mesh-controller/walk_from_keys_integration_test.go +++ b/cmd/mesh-controller/walk_from_keys_integration_test.go @@ -3,6 +3,7 @@ package main import ( + "github.com/nats-io/nats.go" "reflect" "strings" "testing" @@ -102,3 +103,55 @@ func TestAFailedKeyFailsTheWalkInTheBuildersWords(t *testing.T) { t.Fatalf("A7: a failed walk sent %v", tm.sent) } } + +// C2's criterion (issue 1851, R4g): a merge whose walk moves the builder, a build module and the controller takes every one +// from the builder's referenced done key, and no ask reaches any subject of the seat node-build-agent. A fake builder writes +// the keys on a real bus. +func TestTheBuilderABuildModuleAndTheControllerAreTakenFromKeysAndNothingIsAskedOfBuildAgent(t *testing.T) { + names := []string{sdkdelivery.BuilderModule, "mesh-build-go", "mesh-controller"} + tm := aTierMesh(t, names...) + ctx := t.Context() + inv := tm.open.inventory + b := aBuilderOnTheBus(t) + asked := make(chan string, 16) + sub, err := b.js.Conn().Subscribe("mesh.seat.node-build-agent.>", func(m *nats.Msg) { asked <- m.Subject }) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = sub.Unsubscribe() }) + + p := tm.plan(t) + p.Commit = "c5c5c5c5c5c5c5c5" + for _, m := range names { + p.Modules[m] = &inventory.PlanModule{} + } + if err := inv.SavePlan(ctx, &p); err != nil { + t.Fatal(err) + } + for i, m := range names { + fp := fpOf(byte('a' + i)) + manifest := b.indexed(t, m, "c5", "novox/mesh-catalog", "modules/"+m, p.Commit, fp) + b.built(t, m, "c5", fp, manifest, sdkdelivery.BuildDone) + } + becomes(t, 10*time.Second, "the three taken from their keys", func() bool { + advancePlans(ctx, tm.open) + q := tm.plan(t) + for _, m := range names { + if s := q.Modules[m]; s == nil || s.State != "built" { + return false + } + } + return true + }) + p = tm.plan(t) + for _, m := range names { + if s := p.Modules[m]; !s.Key || !strings.HasPrefix(s.Build, "key-") || !strings.Contains(s.Made, "taken from the builder's key") { + t.Errorf("%s was not taken from the builder's referenced key: %+v", m, s) + } + } + select { + case subject := <-asked: + t.Fatalf("an ask reached the retired build seat: %s", subject) + case <-time.After(300 * time.Millisecond): + } +}