Files
mesh-host/internal/bootstrap/registry_test.go
T
jochen cdcfcd9380
mesh/merge-gate head cdcfcd938016 merged into trunk 130c5d98a601 — pass: the change touches no module of the mesh's graph
mesh/repo-check head cdcfcd938016 merged into trunk 130c5d98a601 — pass: its merge-check.sh passed
mesh/delivery delivered
Adopt genesis's bus through the bus's planned step, its streams snapshotted first (hq issue 590, ADR 0333 §3)
The broker step sent the nats module with a plain push, and the controller refuses a push that would
replace the bus: that is a planned step, bus upgrade, which snapshots the streams first and checks
them after (ADR 0236). Genesis stopped at step 18.

The step now snapshots every stream with the module's own snapshot program (no backup holder exists
yet to be asked), asks bus upgrade with that snapshot and why, says the one restart, and waits until
the bus runs the module's image, answers, and the controller ends the step done. The bundle's bus runs
the release the module's image is built on (2.11.17, by the same digest, where it ran 2.10.29), so the
step changes no server release and is said reversible.
2026-10-13 11:47:10 +02:00

229 lines
8.8 KiB
Go

package bootstrap
import (
"context"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
// Step 7 installs the one module whose image can never come from the mesh's own registry, because
// it IS the mesh's own registry (novox/hq 04-ISSUES/029). These tests defend that, and defend the
// distinction the whole verify layer of this program is built on: a container that is up is not a
// service that answers.
// catalogueWith writes a fake catalogue checkout holding one module's manifest.
//
// A fixture here rather than the real catalogue, unlike the foundation example the rewrite tests
// use: the catalogue is a different repository on a different branch, and a test that read it
// would pass or fail according to what somebody else had checked out.
func catalogueWith(t *testing.T, module, manifest string) string {
t.Helper()
root := t.TempDir()
dir := filepath.Join(root, catalogueDir, module)
if err := os.MkdirAll(dir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "module.json"), []byte(manifest), 0o644); err != nil {
t.Fatal(err)
}
return root
}
const upstreamRegistryManifest = `{
"module": "distribution",
"version": "1",
"provides": [{"name": "artifact-store", "scope": "mesh"}],
"capabilities": ["container-runtime"],
"resources": [
{"id": "state", "type": "directory", "path": "/var/lib/mesh/registry", "mode": "0700"},
{"id": "store", "type": "container", "name": "mesh-registry",
"image": "registry@sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373",
"ports": ["5000:5000"]}
]
}`
// aMeshThatAgrees answers every command the installer issues at steps 7 and 9 the way a working
// mesh would, except for whatever a test overrides.
func aMeshThatAgrees(answers map[string]string) func(string, []string) (string, error) {
return func(name string, args []string) (string, error) {
joined := strings.Join(args, " ")
for fragment, said := range answers {
if strings.Contains(joined, fragment) {
return said, nil
}
}
switch {
case name == "sh" && len(args) == 2 && strings.Contains(args[1], "accounts.conf"):
return "", nil // the bus's users placed after a push (issue 608)
case name == "sh" && len(args) == 2 && strings.Contains(args[1], "mesh-nats-snapshot"):
return "", nil // the streams snapshotted before the bus's planned step (issue 590)
case name == "docker" && strings.HasSuffix(joined, "/mesh-controller bus"):
return "the bus is nats, built 53e51864, on anchor\nlast step 1: not known → 53e51864 on anchor by installer (" +
adoptionWhy + "): done at 2026-10-13 11:40; snapshot " + busSnapshotFile + "\n", nil
case name == "docker" && strings.Contains(joined, "/mesh-controller builds nats -n 1"):
return "nats built 53e51864 anchor\n image artifact-store://nats/server@sha256:" +
strings.Repeat("4", 64) + "\n bundle artifact-store://nats/tools/blobs/sha256:" + strings.Repeat("5", 64) + "\n", nil
case name != "docker":
return "", fmt.Errorf("unexpected program %q", name)
case strings.HasSuffix(joined, "broker accounts"):
return "accounts {}\n", nil
case args[0] == "cp":
return "", nil
case args[0] == "container":
return "true running\n", nil
case args[0] == "exec":
return "", nil
}
return "", fmt.Errorf("unexpected: %v", args)
}
}
func installing(t *testing.T, catalogue string) Options {
t.Helper()
return Options{
Node: "anchor",
Catalogue: catalogue,
Registry: "127.0.0.1:5000",
Timeout: time.Second,
Wait: 0,
}
}
// A container that is up is not a registry that serves. `/v2/` is the registry API's own "yes, I
// am one and I am ready", and the step after this pushes to it — so it is refused here rather than
// discovered inside a `docker push`.
func TestARegistryContainerThatIsUpIsNotARegistryThatServes(t *testing.T) {
previous := answerEvery
answerEvery = time.Millisecond
defer func() { answerEvery = previous }()
runtime := &asked{answer: aMeshThatAgrees(nil)}
deps := Deps{
Run: runtime.run,
Fetch: func(context.Context, string) (int, string, error) {
return http.StatusInternalServerError, "", nil
},
}
_, err := InstallRegistry(context.Background(),
installing(t, catalogueWith(t, RegistryModule, upstreamRegistryManifest)),
deps, controlPlane{container: "temp-mesh-controller", run: runtime.run, timeout: time.Second},
func(string) {})
if err == nil {
t.Fatal("a registry whose container is up and which answers 500 was accepted")
}
for _, wanted := range []string{"/v2/", "Running is not serving"} {
if !strings.Contains(err.Error(), wanted) {
t.Errorf("the refusal does not mention %q:\n%v", wanted, err)
}
}
}
// The whole of step 7, against a mesh that agrees: registered, assigned, pushed, up, and answering.
func TestARegistryThatAnswersIsAccepted(t *testing.T) {
runtime := &asked{answer: aMeshThatAgrees(nil)}
deps := Deps{
Run: runtime.run,
Fetch: func(context.Context, string) (int, string, error) {
return http.StatusOK, "{}", nil
},
}
out, err := InstallRegistry(context.Background(),
installing(t, catalogueWith(t, RegistryModule, upstreamRegistryManifest)),
deps, controlPlane{container: "temp-mesh-controller", run: runtime.run, timeout: time.Second},
func(string) {})
if err != nil {
t.Fatal(err)
}
if out.Container != "mesh-registry" {
t.Errorf("the registry's container is %q", out.Container)
}
if out.Answered != http.StatusOK {
t.Errorf("the registry answered %d", out.Answered)
}
// Registered, assigned and pushed, through the same three commands a person types.
for _, wanted := range []string{
"module add /distribution-module.json",
"assign anchor distribution",
"push anchor",
} {
if !runtime.ran(wanted) {
t.Errorf("the installer never ran %q: %v", wanted, runtime.commands)
}
}
}
// **The registry's image is upstream and it is never built.** A manifest carrying the catalogue's
// placeholder digest would mean somebody had made this module buildable — which is the cycle
// novox/hq 04-ISSUES/029 settled: a module that provides the artifact store cannot be delivered
// through the artifact store.
func TestARegistryManifestThatWantsBuildingIsRefused(t *testing.T) {
wants := strings.Replace(upstreamRegistryManifest,
"registry@sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373",
"mesh-runtime-registry@"+placeholderDigest, 1)
runtime := &asked{answer: aMeshThatAgrees(nil)}
_, err := InstallRegistry(context.Background(),
installing(t, catalogueWith(t, RegistryModule, wants)),
Deps{Run: runtime.run}, controlPlane{container: "temp-mesh-controller", run: runtime.run},
func(string) {})
if err == nil {
t.Fatal("a registry manifest naming an image the mesh would have to build was accepted")
}
if !strings.Contains(err.Error(), "04-ISSUES/029") {
t.Errorf("the refusal does not name the decision it rests on: %v", err)
}
if runtime.ran("module add") {
t.Error("it was registered anyway")
}
}
// A catalogue that is not there is said plainly, with what --catalog is. This is the most likely
// mistake anybody makes at this step and the least interesting to debug.
func TestACatalogueThatIsNotThereIsSaidPlainly(t *testing.T) {
runtime := &asked{answer: aMeshThatAgrees(nil)}
_, err := InstallRegistry(context.Background(),
installing(t, filepath.Join(t.TempDir(), "nowhere")),
Deps{Run: runtime.run}, controlPlane{container: "temp-mesh-controller", run: runtime.run},
func(string) {})
if err == nil {
t.Fatal("a catalogue that does not exist was accepted")
}
if !strings.Contains(err.Error(), "--catalog") {
t.Errorf("the refusal does not say what to fix: %v", err)
}
}
// A refusal from the control plane is repeated verbatim. mesh-controller refuses in paragraphs —
// "nothing provides route, wanted by registry" — and an installer that reported "exit status 1"
// would throw away the only thing a person can act on.
func TestWhatTheMeshRefusedIsRepeated(t *testing.T) {
refusal := "nothing provides \"route\", wanted by registry"
runtime := &asked{answer: func(name string, args []string) (string, error) {
if strings.Contains(strings.Join(args, " "), "push") {
return refusal, fmt.Errorf("exit status 1")
}
return aMeshThatAgrees(nil)(name, args)
}}
_, err := InstallRegistry(context.Background(),
installing(t, catalogueWith(t, RegistryModule, upstreamRegistryManifest)),
Deps{Run: runtime.run}, controlPlane{container: "temp-mesh-controller", run: runtime.run,
timeout: time.Second}, func(string) {})
if err == nil {
t.Fatal("a push the mesh refused was reported as successful")
}
if !strings.Contains(err.Error(), refusal) {
t.Errorf("what the mesh said is not in the failure:\n%v", err)
}
if !strings.Contains(err.Error(), "run this installer again") {
t.Errorf("the failure does not say a re-run continues from here:\n%v", err)
}
}