mesh/merge-gate head 54d8d139ad5b merged into trunk f4584e6fa285 — pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus…
mesh/repo-check head 54d8d139ad5b merged into trunk f4584e6fa285 — pass: its merge-check.sh passed
mesh/delivery delivered
102 lines
4.1 KiB
Go
102 lines
4.1 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
"github.com/novox/mesh-controller/internal/link"
|
|
)
|
|
|
|
// asksWithPaths records every build a merge asks for, as repository, path and ref. The merge window's goroutine and
|
|
// the test's own may ask at once, so the record is written under a lock (issue 1543).
|
|
func asksWithPaths(t *testing.T) *[][3]string {
|
|
t.Helper()
|
|
var asked [][3]string
|
|
var mu sync.Mutex
|
|
was := askABuild
|
|
askABuild = func(_ context.Context, source buildSource, path, ref string) (string, error) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
asked = append(asked, [3]string{source.Repository, path, ref})
|
|
return "b-" + path, nil
|
|
}
|
|
t.Cleanup(func() { askABuild = was })
|
|
return &asked
|
|
}
|
|
|
|
// The live case of 2026-10-07 (novox/hq issue 300), replayed: a merge of the catalogue adds one module's
|
|
// directory and touches nothing else the mesh holds. Its delivery plan said "builds new: …, sent nowhere";
|
|
// the merge said it changed nothing any module the mesh holds is built from, and built nothing, so the
|
|
// module was never registered and `assign` refused it. The merge asks for its build, at the branch merged
|
|
// into, from the repository as the mesh spells it — and opens no plan, since nothing it holds moved.
|
|
func TestAMergeBuildsTheNewModuleItAdds(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
inv := open.inventory
|
|
asked := asksWithPaths(t)
|
|
if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: "networkmanager", Version: "1"},
|
|
inventory.Source{Repository: "novox/mesh-catalog", Seat: "git", Path: "modules/networkmanager", Ref: "main",
|
|
BuiltFrom: "c0", Head: "c0"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := link.SourceMoved{Owner: "novox", Repo: "mesh-catalog", Base: "main", Commit: "3da80a4b00",
|
|
Paths: []string{"modules/systemd-resolved/module.json", "modules/systemd-resolved/cmd/main.go"},
|
|
ModuleDirs: []string{"modules/systemd-resolved"}, ModuleDirsSaid: true}
|
|
if err := (following{open: open}).SourceMoved(ctx, m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := [3]string{"novox/mesh-catalog", "modules/systemd-resolved", "main"}
|
|
if len(*asked) != 1 || (*asked)[0] != want {
|
|
t.Fatalf("the merge adding modules/systemd-resolved asked for %v, not %v", *asked, want)
|
|
}
|
|
if plans, err := inv.OpenPlans(ctx); err != nil || len(plans) != 0 {
|
|
t.Fatalf("a merge moving nothing the mesh holds opened a plan: %+v %v", plans, err)
|
|
}
|
|
}
|
|
|
|
// A merge that changes a held module and adds a new one does both: the held one walks its plan, the new
|
|
// one is asked for beside it. A merge adding nothing builds nothing new.
|
|
func TestAMergeBuildsItsNewModuleBesideItsPlan(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
inv := open.inventory
|
|
asked := asksWithPaths(t)
|
|
if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: "app", Version: "1"},
|
|
inventory.Source{Repository: "novox/mesh-catalog", Seat: "git", Path: "modules/app", Ref: "main",
|
|
BuiltFrom: "c0", Head: "c0"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := link.SourceMoved{Owner: "novox", Repo: "mesh-catalog", Base: "main", Commit: "c1aaaaaaaa",
|
|
Paths: []string{"modules/app/index.ts", "modules/fresh/module.json"},
|
|
ModuleDirs: []string{"modules/app", "modules/fresh"}, ModuleDirsSaid: true}
|
|
if err := (following{open: open}).SourceMoved(ctx, m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
paths := map[string]bool{}
|
|
for _, a := range *asked {
|
|
paths[a[1]] = true
|
|
}
|
|
if !paths["modules/fresh"] || !paths["modules/app"] || len(*asked) != 2 {
|
|
t.Fatalf("asked %v; want the new module and the plan's first tier", *asked)
|
|
}
|
|
plans, err := inv.OpenPlans(ctx)
|
|
if err != nil || len(plans) != 1 || plans[0].Modules["fresh"] != nil || plans[0].Modules["app"] == nil {
|
|
t.Fatalf("the plan should walk app alone: %+v %v", plans, err)
|
|
}
|
|
|
|
*asked = nil
|
|
m2 := link.SourceMoved{Owner: "novox", Repo: "mesh-catalog", Base: "main", Commit: "c2aaaaaaaa",
|
|
Paths: []string{"README.md"}, ModuleDirsSaid: true}
|
|
if err := (following{open: open}).SourceMoved(ctx, m2); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(*asked) != 0 {
|
|
t.Fatalf("a merge adding no module asked for %v", *asked)
|
|
}
|
|
}
|