Files
mesh-catalog/modules/nats/cmd/nats-tools/broker_test.go
T
jschoubben 45688f196e CAT-N7: the seat mesh-broker's reading verbs answer the seat's contract
list, show and orphans answer meshbroker.ListAnswer, Held and OrphansAnswer; check answers CheckAnswer with each
differing entry's settings asked and held by stream and whether the difference only grows; show takes the contract's
local-name. Built against mesh-contracts' seats/meshbroker module in the workspace; the group pin adds its require.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 13:10:43 +01:00

90 lines
4.1 KiB
Go

package main
import (
"encoding/json"
"fmt"
"strings"
"testing"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"nats-tools/internal/keeper"
)
// The seat's reading verbs and nats_history (design 25 § 12.3; CAT-N7): list and show answer every entry the keeper
// made with its settings asked and held and its fill against its cap; check names what is missing or differs; orphans
// what no manifest asks for; history one entry's events in order. Each from the keeper's own state and the bus's
// monitoring endpoint.
func TestTheSeatsReadingVerbsAnswerFromTheKeeperAndTheBus(t *testing.T) {
plan := func(local, storage, template string, options string) keeper.Plan {
e := catalogue.BusStateEntry{Name: local, Storage: storage, Template: template}
if options != "" {
_ = json.Unmarshal([]byte(options), &e.Options)
}
p, err := keeper.PlanOf("m", e)
if err != nil {
t.Fatal(err)
}
return p
}
held := map[string]keeper.Asked{"m": {Module: "m", Made: map[string]keeper.Made{
"drafts": {Plan: plan("drafts", "key-value", "state", ""), Created: true},
"log": {Plan: plan("log", "stream", "log", `{"max-mib":16}`), Created: true, Drift: "m_log: max-bytes asked 16777216, held 33554432"},
"old": {Plan: plan("old", "stream", "events", ""), Created: true, Orphaned: true},
}}}
jsz := `{"account_details":[{"stream_detail":[
{"name":"KV_m_drafts","config":{"name":"KV_m_drafts","retention":"limits","discard":"new","max_bytes":67108864,"max_msgs_per_subject":1,"max_msg_size":262144},"state":{"messages":3,"bytes":1048576}},
{"name":"m_log","config":{"name":"m_log","retention":"limits","discard":"new","max_bytes":33554432,"max_msg_size":262144},"state":{"messages":9,"bytes":9000}}]}]}`
tools := map[string]stdio.Tool{}
for _, tl := range brokerTools(func() (map[string]keeper.Asked, error) { return held, nil },
func() ([]byte, error) { return []byte(jsz), nil },
func(module, local string, limit int) ([]keeper.Event, error) {
return []keeper.Event{{Module: module, Local: local, Why: "first"}, {Module: module, Local: local, Why: "second"}}[:limit], nil
}) {
tools[tl.Name] = tl
}
for _, row := range []struct {
tool string
args map[string]any
want []string
err string
}{
// Each answers the seat's contract (mesh-contracts meshbroker ListAnswer, Held, CheckAnswer, OrphansAnswer).
{"mesh-broker.list", nil, []string{`{"entries":[`, `"bus-name":"m_drafts"`, `"local-name":"drafts"`, `"storage-type":"key-value"`,
`"KV_m_drafts":{"max-bytes":67108864`, `"fill":{"bytes":1048576,"cap":67108864,"count":3}`, `"options":{"max-mib":16}`}, ""},
{"mesh-broker.show", map[string]any{"module": "m", "local-name": "log"}, []string{`"bus-name":"m_log"`, `"template":"log"`,
`"m_log":{"max-bytes":33554432`}, ""},
{"mesh-broker.show", map[string]any{"module": "m", "local-name": "none"}, nil, `made no entry "none" of "m"`},
{"mesh-broker.check", nil, []string{`{"differences":[{`, `"local-name":"log"`, `"asked":{"m_log":{"max-bytes":16777216`,
`"held":{"m_log":{"max-bytes":33554432`}, ""},
{"mesh-broker.check", map[string]any{"module": "x"}, []string{`{"differences":[]}`}, ""},
{"mesh-broker.orphans", nil, []string{`{"entries":[{`, `"local-name":"old"`}, ""},
{"nats_history", map[string]any{"module": "m", "local": "log", "limit": float64(1)}, []string{`"why":"first"`}, ""},
{"nats_history", map[string]any{"module": "m"}, nil, "names one entry"},
} {
t.Run(fmt.Sprintf("%s %v", row.tool, row.args), func(t *testing.T) {
args := row.args
if args == nil {
args = map[string]any{}
}
out, err := tools[row.tool].Run(args)
if row.err != "" {
if err == nil || !strings.Contains(err.Error(), row.err) {
t.Fatalf("answered %v (%v): refused, naming %q", out, err, row.err)
}
return
}
raw, _ := json.Marshal(out)
for _, w := range row.want {
if !strings.Contains(string(raw), w) {
t.Errorf("%s lacks %s", raw, w)
}
}
if row.tool == "mesh-broker.check" && strings.Contains(string(raw), `"local-name":"drafts"`) {
t.Errorf("check names drafts, which the bus holds as asked: %s", raw)
}
})
}
}