package main import ( "bytes" "os" "path/filepath" "strings" "testing" "github.com/novox/mesh-controller/internal/beside" "github.com/novox/mesh-controller/internal/catalogue" ) // The check anybody can run is the check registration runs (novox/hq issue 148, ADR 0037): a manifest // with a known fault is named, and one without passes, with no store opened. func TestModuleCheckNamesAFaultAndNeedsNoMesh(t *testing.T) { dir := t.TempDir() good := filepath.Join(dir, "good.json") bad := filepath.Join(dir, "bad.json") os.WriteFile(good, []byte(`{"module":"shop","version":"1","tools":["price"],"invokes":["mesh-catalog.catalog_modules"]}`), 0o600) os.WriteFile(bad, []byte(`{"module":"till","version":"1","invokes":["shop"]}`), 0o600) var out bytes.Buffer if err := moduleCheck([]string{good}, &out); err != nil { t.Fatalf("a sound manifest was refused: %v\n%s", err, out.String()) } if !strings.Contains(out.String(), "shop: ok, 1 tool(s), invokes mesh-catalog.catalog_modules") { t.Fatalf("the report does not say what it checked:\n%s", out.String()) } out.Reset() err := moduleCheck([]string{good, bad}, &out) if err == nil { t.Fatal("a manifest invoking a module and no tool passed") } if !strings.Contains(out.String(), `till invokes "shop", which does not name a tool`) { t.Fatalf("the fault is not named in the manifest's words:\n%s", out.String()) } } // The rules between manifests run over what was given together: a seat two modules declare is // refused, which no single-manifest check can see. func TestModuleCheckJudgesBetweenTheManifestsGiven(t *testing.T) { dir := t.TempDir() a := filepath.Join(dir, "a.json") b := filepath.Join(dir, "b.json") os.WriteFile(a, []byte(`{"module":"a","version":"1","seats":[{"name":"printer","scope":"mesh"}]}`), 0o600) os.WriteFile(b, []byte(`{"module":"b","version":"1","seats":[{"name":"printer","scope":"mesh"}]}`), 0o600) var out bytes.Buffer if err := moduleCheck([]string{a, b}, &out); err == nil { t.Fatalf("two declarations of one seat passed:\n%s", out.String()) } if !strings.Contains(out.String(), "a seat name means one protocol") { t.Fatalf("the cross-manifest rule was not the one named:\n%s", out.String()) } } // The real catalogue passes the command, the way it passes the test that used to be the only check. func TestModuleCheckPassesTheCatalogue(t *testing.T) { root := beside.Catalogue(t) paths, err := manifestsUnder(root) if err != nil || len(paths) == 0 { t.Fatalf("no manifests under %s: %v", root, err) } var out bytes.Buffer if err := moduleCheck(paths, &out); err != nil { t.Fatalf("the catalogue does not pass its own check: %v\n%s", err, out.String()) } } func TestRegistrationRefusesADefinitionNamingAnInstallation(t *testing.T) { // novox/hq ADR 0155: the check moves to registration once the catalogue passes it. Both // ways in — `module add` and a build's result — go through this, and a name declared on // purpose passes with its reason. named := catalogue.Manifest{Module: "idp", Resources: []map[string]any{ {"id": "server", "type": "container", "image": "x@sha256:aa", "env": map[string]any{"KC_HOSTNAME": "https://login.mesh-one.be"}}, }} err := namesNoInstallation(named) if err == nil || !strings.Contains(err.Error(), "login.mesh-one.be") || !strings.Contains(err.Error(), catalogue.NamesOnPurpose) { t.Fatalf("a definition naming an installation is refused with the name and the way out; got %v", err) } meant := catalogue.Manifest{Module: "site", Resources: []map[string]any{ {"id": "server", "type": "container", "image": "registry.mesh-one.be/org/site@sha256:cc", catalogue.NamesOnPurpose: map[string]any{ "registry.mesh-one.be": "built outside the mesh until its repository is a build source here"}}, }} if err := namesNoInstallation(meant); err != nil { t.Fatalf("a name declared on purpose passes; got %v", err) } } // **The controller's own manifest names every verb of its seat** (novox/hq ADR 0132): its tools lagged // the seat's verbs for weeks, and `module check` — the gate's first step for a change touching it — // refused it. Held here, so a verb added to the table without the manifest fails this repository's // own suite rather than its next pull request's gate. func TestTheControllersManifestServesEveryVerbOfItsSeat(t *testing.T) { var out strings.Builder if err := moduleCheck([]string{"../../module.json"}, &out); err != nil { t.Fatalf("the controller's own module.json fails module check: %v\n%s", err, out.String()) } } // A module that uses a seat another module declares (novox/hq issue 364): refused over the whole catalogue when the // declarer is missing, a note when the gate says it gives only the manifests a change touches. func TestASeatAnotherModuleDeclaresIsANoteOverSomeManifests(t *testing.T) { dir := t.TempDir() user := filepath.Join(dir, "user.json") os.WriteFile(user, []byte(`{"module":"asker","version":"1","uses":["operator-channel"]}`), 0o600) var out bytes.Buffer if err := moduleCheck([]string{user}, &out); err == nil { t.Fatalf("a use of a seat nothing given declares passed the whole-catalogue check:\n%s", out.String()) } t.Setenv(SomeManifestsVar, "1") out.Reset() if err := moduleCheck([]string{user}, &out); err != nil { t.Fatalf("over some manifests the use was refused:\n%s", out.String()) } if !strings.Contains(out.String(), "note: asker uses the seat \"operator-channel\"") { t.Fatalf("the note was not said:\n%s", out.String()) } }