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) } }) } }