Files
mesh-catalog/modules/mesh-cli/cmd/mesh-cli/manifest_test.go
T
jschoubben a3e9f2cc0f mesh-cli requires the console's endpoint and writes its address
nox now reaches the mesh through this machine's console, so the module
requires mcp-endpoint and writes the bound address to /etc/mesh-cli/console
rather than trusting a fixed port. No invokes: mesh-cli has no bus account,
and one nothing dials would only be minted.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 10:42:03 +01:00

100 lines
3.6 KiB
Go

package main
import (
"encoding/json"
"os"
"testing"
)
// **The archive places exactly one file, /usr/local/bin/mesh-cli**, and the console's address is one file more (review of novox/hq ADR 0272): one archive
// resource, unpacking one artifact into /usr/local/bin, and that artifact a compiled Go bundle — the builder writes
// such a bundle as its binary alone (`go build -o <out>/<binary>`), named mesh-cli — with nothing the runtime would
// load or put beside it. A second file in the bundle, or a second resource writing there, fails here.
func TestTheArchivePlacesExactlyOneFileAndTheConsolesAddressOne(t *testing.T) {
raw, err := os.ReadFile("../../module.json")
if err != nil {
t.Fatal(err)
}
var m struct {
Resources []map[string]any `json:"resources"`
Build struct {
Artifacts []map[string]any `json:"artifacts"`
} `json:"build"`
}
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
// Beside the program, one directory and one file: the console's address, from the mcp-endpoint it requires
// (novox/hq issue 1126). Nothing else.
var r map[string]any
for _, res := range m.Resources {
switch {
case res["type"] == "archive":
if r != nil {
t.Fatalf("two archives: %v", res)
}
r = res
case res["type"] == "directory" && res["path"] == "/etc/mesh-cli":
case res["type"] == "file" && res["path"] == consoleFile && res["template"] == "files/console":
default:
t.Fatalf("the module declares %v beside the program and the console's address", res)
}
}
if len(m.Resources) != 3 || r == nil || r["path"] != "/usr/local/bin" {
t.Fatalf("its resources are %v", m.Resources)
}
// The build has a second artifact, the files archive the controller reads the templates back from; it
// places no file. The artifact the resource unpacks is the one that does.
var a map[string]any
for _, candidate := range m.Build.Artifacts {
if candidate["name"] == r["artifact"] {
if a != nil {
t.Fatalf("two artifacts are named %v", r["artifact"])
}
a = candidate
} else if candidate["kind"] != "archive" || candidate["from"] != "files" {
t.Fatalf("it builds %v beside the artifact that places the file", candidate)
}
}
if a == nil {
t.Fatalf("no artifact is named %v", r["artifact"])
}
if a["name"] != r["artifact"] || a["kind"] != "bundle" || a["language"] != "go" || a["binary"] != "mesh-cli" ||
a["from"] != "cmd/mesh-cli" {
t.Fatalf("its artifact is %v, unpacked as %v", a, r["artifact"])
}
for _, extra := range []string{"loads", "env", "context", "files"} {
if _, has := a[extra]; has {
t.Fatalf("its artifact says %q, which would put more than the binary in the bundle or load it", extra)
}
}
entries, err := os.ReadDir(".")
if err != nil {
t.Fatal(err)
}
for _, e := range entries {
if e.IsDir() {
t.Fatalf("cmd/mesh-cli holds a directory %s, which a build could carry into the bundle", e.Name())
}
}
}
// The console's address is written from the mcp-endpoint the module requires, as claude-code writes it, so it follows
// the port node-tools is bound on.
func TestTheConsolesAddressIsBoundFromTheEndpoint(t *testing.T) {
raw, err := os.ReadFile("../../module.json")
if err != nil {
t.Fatal(err)
}
var m struct {
Requires []string `json:"requires"`
}
if err := json.Unmarshal(raw, &m); err != nil || len(m.Requires) != 1 || m.Requires[0] != "mcp-endpoint" {
t.Fatalf("it requires %v (%v)", m.Requires, err)
}
tpl, err := os.ReadFile("../../files/console")
if err != nil || string(tpl) != "http://127.0.0.1:${bound:mcp-endpoint:port}/mcp\n" {
t.Fatalf("files/console is %q (%v)", tpl, err)
}
}