Files
mesh-catalog/modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go
T

205 lines
8.3 KiB
Go

package main
import (
"encoding/json"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
)
// The manifest says what the code does (novox/hq to-be 55 §1): the seat it declares and holds once for the mesh
// with the verbs it serves, the events it says, what it uses and invokes, the database it requires, its two
// long-running processes with their health, and its settings.
type manifest struct {
Module string `json:"module"`
Requires []string `json:"requires"`
Contributes map[string]map[string]any `json:"contributes"`
Seats []seat `json:"seats"`
Claims []seat `json:"claims"`
Tools []string `json:"tools"`
Emits []string `json:"emits"`
Consumes []string `json:"consumes"`
Uses []string `json:"uses"`
Invokes []string `json:"invokes"`
State []json.RawMessage `json:"state"`
Resources []map[string]any `json:"resources"`
Build struct {
Artifacts []struct {
From string `json:"from"`
Binary string `json:"binary"`
Loads []string `json:"loads"`
Env map[string]string `json:"env"`
} `json:"artifacts"`
} `json:"build"`
}
type seat struct {
Name string `json:"name"`
Scope string `json:"scope"`
Serves []string `json:"serves"`
}
func readManifest(t *testing.T) (manifest, string) {
t.Helper()
raw, err := os.ReadFile(filepath.Join("..", "..", "module.json"))
if err != nil {
t.Fatal(err)
}
var m manifest
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
return m, string(raw)
}
func TestItDeclaresAndHoldsTheKnowledgeBaseSeatOnceForTheMesh(t *testing.T) {
m, raw := readManifest(t)
want := []seat{{Name: Seat, Scope: "mesh", Serves: Verbs}}
if m.Module != Module || !reflect.DeepEqual(m.Seats, want) || !reflect.DeepEqual(m.Claims, want) {
t.Fatalf("module %q, seats %+v, claims %+v", m.Module, m.Seats, m.Claims)
}
if !reflect.DeepEqual(Verbs, []string{"ask", "get", "holds", "links", "history", "reserve", "propose", "import", "return"}) {
t.Fatalf("the verbs are not ADR 0290 rule 6's: %v", Verbs)
}
if !reflect.DeepEqual(m.Emits, Events) {
t.Fatalf("emits %v, the code says %v", m.Emits, Events)
}
// Its records are in a database in the store (ADR 0290 rule 7), not in buckets.
if !reflect.DeepEqual(m.Requires, []string{"postgres-database"}) || m.Contributes["postgres-database"]["name"] != "knowledge" || len(m.State) != 0 {
t.Fatalf("requires %v, contributes %v, state %v", m.Requires, m.Contributes, m.State)
}
// It asks the operator on the router, hears the router's word, and calls exactly what it calls.
if !reflect.DeepEqual(m.Uses, []string{"operator-channel"}) || len(m.Consumes) != 0 {
t.Fatalf("uses %v, consumes %v", m.Uses, m.Consumes)
}
if !reflect.DeepEqual(m.Invokes, []string{"seat:issue-tracker.reserve", "claude-code.claude_code_judge", "records.records_status",
"records.records_list", "records.records_read", "seat:operator-channel.notify"}) {
t.Fatalf("invokes %v", m.Invokes)
}
src := ""
for _, f := range []string{"main.go", "hq.go"} {
src += readFile(t, f)
}
for _, inv := range m.Invokes {
if !strings.Contains(src, `"`+inv) {
t.Errorf("the manifest invokes %s, which the code never calls", inv)
}
}
if len(m.Build.Artifacts) != 1 || m.Build.Artifacts[0].From != "cmd/mesh-knowledge" || m.Build.Artifacts[0].Binary != Module ||
m.Build.Artifacts[0].Env["DATABASE_URL_FILE"] == "" || m.Build.Artifacts[0].Env["MESH_KNOWLEDGE_SETTINGS"] == "" ||
m.Build.Artifacts[0].Env["MESH_KNOWLEDGE_STATUS"] == "" || !reflect.DeepEqual(m.Build.Artifacts[0].Loads, []string{Module}) {
t.Fatalf("build %+v", m.Build)
}
for _, never := range []string{"/home/", "jochen", "shanks", "novox.be"} {
if strings.Contains(strings.ToLower(raw), never) {
t.Errorf("module.json names %q", never)
}
}
}
// Its processes: the preparation step once, keep judged by its unit, watch by the health tool, which the module
// serves; the status file watch writes is the one the bundle's health tool reads.
func TestItsProcessesAreThePreparationTheActAndTheJudge(t *testing.T) {
m, _ := readManifest(t)
byID := map[string]map[string]any{}
for _, r := range m.Resources {
byID[r["id"].(string)] = r
}
prep, keep, watch := byID["prepare"], byID["keep"], byID["watch"]
if prep == nil || prep["run-once"] != true || prep["run"].([]any)[1] != "prepare" {
t.Fatalf("prepare %v", prep)
}
if keep == nil || keep["run"].([]any)[1] != "keep" || keep["health"].(map[string]any)["kind"] != "unit" {
t.Fatalf("keep %v", keep)
}
h, _ := watch["health"].(map[string]any)
if watch == nil || watch["run"].([]any)[1] != "watch" || h["kind"] != "tool" || h["tool"] != HealthTool ||
!reflect.DeepEqual(m.Tools, []string{HealthTool, HighestTool}) {
t.Fatalf("watch %v, tools %v", watch, m.Tools)
}
if watch["env"].(map[string]any)["MESH_KNOWLEDGE_STATUS"] != m.Build.Artifacts[0].Env["MESH_KNOWLEDGE_STATUS"] {
t.Fatal("watch writes another status file than the health tool reads")
}
// The health tool reads the status file as the account the runtime runs the bundle as, and the mesh gives that
// account the state directory (and nothing a process writes there later). A watch running as root wrote the
// file root's, 0600, and the tool could not open it (hq issue 479): watch runs as that account, as zfs's does.
if watch["user"] != "${machine:account}" {
t.Fatalf("watch runs as %v, not as the account the health tool reads its verdict as", watch["user"])
}
settings := byID["settings"]
var s Settings
if err := json.Unmarshal([]byte(settings["content"].(string)), &s); err != nil || s.JudgeModel == "" || s.ReservedFor != "168h" {
t.Fatalf("the settings the manifest writes are not the module's: %v %+v", err, s)
}
if d, err := time.ParseDuration(s.ReservedFor); err != nil || d != DefaultReservedFor {
t.Fatalf("reserved-for %q is not the default the code holds", s.ReservedFor)
}
}
// The tools are the seat's verbs and the health tool, each said in plain words with what it refuses.
func TestTheToolsAreTheSeatsVerbsAndSayWhatTheyDo(t *testing.T) {
m, _ := readManifest(t)
var verbs []string
for _, tool := range Tools(&KB{}, callerOf) {
s, verb, ok := strings.Cut(tool.Name, ".")
if !ok || s != Seat {
t.Errorf("%s is not a verb of %s", tool.Name, Seat)
}
verbs = append(verbs, verb)
if len(tool.Description) < 120 {
t.Errorf("%s says too little of what it does", tool.Name)
}
for _, internal := range []string{"ADR", "to-be", "bucket", "postgres", "KV"} {
if strings.Contains(tool.Description, internal) {
t.Errorf("%s's description uses the internal name %q", tool.Name, internal)
}
}
}
if !reflect.DeepEqual(verbs, m.Claims[0].Serves) {
t.Fatalf("verbs %v, claim %v", verbs, m.Claims[0].Serves)
}
}
// No argument can name the caller: who acted is the runtime's word, unproven until it gives one.
func TestNoArgumentNamesTheCaller(t *testing.T) {
for _, tool := range Tools(&KB{}, callerOf) {
props := tool.Input["properties"].(map[string]any)
for _, who := range []string{"by", "caller", "author", "reviewer", "who"} {
if _, ok := props[who]; ok {
t.Errorf("%s takes %s", tool.Name, who)
}
}
if tool.Input["additionalProperties"] != false {
t.Errorf("%s takes arguments it does not name", tool.Name)
}
}
if callerOf(map[string]any{"by": "someone@else"}) != Unproven {
t.Fatal("the caller was read from an argument")
}
}
func TestTheHealthToolReadsTheWatchsVerdictAndSaysWhenItIsStale(t *testing.T) {
path := filepath.Join(t.TempDir(), "health.json")
now := time.Date(2026, 10, 11, 9, 0, 0, 0, time.UTC)
if a := ReadStatus(path, now); a.Healthy {
t.Fatal("healthy with no verdict")
}
if err := writeStatus(path, HealthAnswer{State: "unhealthy", Why: "the rule cited: ADR 0300 is accepted and nothing cites it", At: now}); err != nil {
t.Fatal(err)
}
if a := ReadStatus(path, now.Add(time.Minute)); a.Healthy || !strings.Contains(a.Why, "ADR 0300") {
t.Fatalf("%+v", a)
}
_ = writeStatus(path, HealthAnswer{State: "healthy", Why: "fine", At: now})
if a := ReadStatus(path, now.Add(time.Minute)); !a.Healthy {
t.Fatalf("%+v", a)
}
if a := ReadStatus(path, now.Add(StatusStale+time.Second)); a.Healthy || !strings.Contains(a.Why, "has not looked") {
t.Fatalf("a stale verdict: %+v", a)
}
}