package bootstrap import ( "context" "os" "path/filepath" "strings" "testing" ) // aCatalogue is a catalogue checkout holding these modules' manifests. func aCatalogue(t *testing.T, manifests map[string]string) string { t.Helper() dir := t.TempDir() for module, manifest := range manifests { at := filepath.Join(dir, catalogueDir, module) if err := os.MkdirAll(at, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(at, "module.json"), []byte(manifest), 0o644); err != nil { t.Fatal(err) } } return dir } // aBusModule is the nats module's manifest as far as adoption reads it: a server container by name. func aBusModule(server string) string { return `{"module": "nats", "version": "1", "claims": [{"name": "mesh-broker", "scope": "mesh"}], "bus-users": "/var/lib/nats-module/conf/accounts.conf", "resources": [{"id": "server", "type": "container", "name": "` + server + `", "ports": ["4222:4222"], "artifact": "server"}], "build": {"artifacts": [{"name": "server", "kind": "image", "from": "Dockerfile"}]}}` } func busStep(t *testing.T, catalogue string) (*asked, error) { t.Helper() rewritten, err := Rewrite(theRealBundle(t), held) if err != nil { t.Fatal(err) } runtime := &asked{answer: aMeshThatAgrees(nil)} control := controlPlane{container: "mesh-controller", run: runtime.run, timeout: 0} err = InstallBroker(context.Background(), installing(t, catalogue), control, rewritten.Declaration, func(string) {}) return runtime, err } // The broker step adopts the foundation's bus as the nats module (novox/hq ADR 0331 §1): the module // the mesh goes on managing, registered from the catalogue — never lavinmq, which left it. func TestTheBrokerStepAdoptsTheBusAsTheNatsModule(t *testing.T) { catalogue := aCatalogue(t, map[string]string{BusModule: aBusModule("mesh-broker")}) runtime, _ := busStep(t, catalogue) if !runtime.ran("module add /nats-module.json") { t.Fatalf("the nats module was not registered: %v", runtime.commands) } if runtime.ran("lavinmq") { t.Errorf("the broker step still speaks of lavinmq: %v", runtime.commands) } } // A catalogue that holds no nats module fails the step by name, before anything is registered — // which is what today's step did for lavinmq, silently adopting a module that no longer exists. func TestTheBrokerStepFailsForAModuleTheCatalogueDoesNotHold(t *testing.T) { catalogue := aCatalogue(t, map[string]string{"lavinmq": `{"module": "lavinmq", "version": "1"}`}) runtime, err := busStep(t, catalogue) if err == nil { t.Fatal("a catalogue without the nats module was adopted from") } if !strings.Contains(err.Error(), "nats module") { t.Errorf("the refusal does not name the module it looked for: %v", err) } if runtime.ran("module add") { t.Errorf("something was registered: %v", runtime.commands) } } // A bus module whose server is not the foundation's container by name would raise a second bus // beside the first; it is refused naming both, before anything is registered. func TestABusModuleWhoseServerIsNotTheFoundationsIsRefused(t *testing.T) { catalogue := aCatalogue(t, map[string]string{BusModule: aBusModule("mesh-broker-nats")}) runtime, err := busStep(t, catalogue) if err == nil { t.Fatal("a bus module with another server was adopted") } for _, named := range []string{"mesh-broker-nats", `"mesh-broker"`} { if !strings.Contains(err.Error(), named) { t.Errorf("the refusal does not name %s: %v", named, err) } } if runtime.ran("module add") { t.Errorf("something was registered: %v", runtime.commands) } }