Held.binding is the entry's plan binding, the value its created and recreated carry, present when the bus holds the entry's objects and absent on one it does not (waiting, refused). Table rows in the reading verbs' test: the binding of a held entry equals the one its created carries; a waiting entry has none. Builds: design 25 bindings-first-view §2, §7 (hq d0760629, PR 543) Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
117 lines
5.5 KiB
Go
117 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
"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},
|
|
"later": {Plan: plan("later", "key-value", "state", ""), Waiting: "a grant not composed yet"},
|
|
}}}
|
|
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}`,
|
|
// The binding of an entry the bus holds is the one its created carries (design 25 bindings-first-view §2).
|
|
`"binding":{"bucket":"m_drafts","local":"drafts","storage":"key-value","template":"state"}`}, ""},
|
|
{"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": "later"}, []string{`"local-name":"later"`}, ""},
|
|
{"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)
|
|
}
|
|
}
|
|
// list's binding is, field by field, the binding the entry's created carries (the event's body takes the plan's binding whole).
|
|
if row.tool == "mesh-broker.list" {
|
|
var got struct {
|
|
Entries []struct {
|
|
Local string `json:"local-name"`
|
|
Binding map[string]any `json:"binding"`
|
|
} `json:"entries"`
|
|
}
|
|
var created map[string]any
|
|
wire, _ := json.Marshal(held["m"].Made["drafts"].Plan.Binding)
|
|
_ = json.Unmarshal(raw, &got)
|
|
_ = json.Unmarshal(wire, &created)
|
|
for _, e := range got.Entries {
|
|
if e.Local == "drafts" && !reflect.DeepEqual(e.Binding, created) {
|
|
t.Errorf("list names the binding %v for drafts, its created carries %v", e.Binding, created)
|
|
}
|
|
}
|
|
}
|
|
// An entry the bus does not hold has no binding.
|
|
if row.args["local-name"] == "later" && strings.Contains(string(raw), `"binding"`) {
|
|
t.Errorf("show names a binding for later, whose objects the bus does not hold: %s", raw)
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|