package runtime import ( "encoding/json" "errors" "sort" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/membership" mt "github.com/novox/mesh-tools/node-tools/internal/meshtest" ) // 1966/AC16: given a module with a ledger binding, when the runner lists its tools, then the four repair tools are // among them, marked acts or reads; a module without one has none, and a binding written later brings them. func TestTheLedgerRepairsAreToolsOfEveryLedgerOwner(t *testing.T) { mesh := mt.New(t) owner := mt.MembershipOf("owner", "anchor", true, nil) owner.Bindings = []membership.BusBinding{{Local: "records", Storage: catalogue.StorageLedger, Template: catalogue.TemplateLedger, History: "LEDGER_owner_records", Subject: "mesh.ledger.owner.records", State: "owner_records", Snapshot: "mesh.ledger-snapshot.owner.records"}} plain := mt.MembershipOf("plain", "anchor", true, nil) mesh.Issue(t, owner) mesh.Issue(t, plain) nodeTools := connect(t, "node-tools", "anchor") stop, err := Run(nodeTools, []Served{{"owner", []string{mt.Fixture("caller-echo.py")}}, {"plain", []string{mt.Fixture("caller-echo.py")}}}, nil, func(string, ...any) {}) if err != nil { t.Fatal(err) } defer stop() asker := connect(t, "console", "workstation") listed := func(module string) (string, error) { answered, err := asker.Ask(module+"."+ToolsVerb, map[string]any{}, "") if err != nil { return "", err } var got ToolsAnswer if err := json.Unmarshal(answered.Result, &got); err != nil { return "", err } var names []string for _, tool := range got.Tools { names = append(names, tool.Name+":"+tool.Effect) } sort.Strings(names) return strings.Join(names, " "), nil } for _, c := range []struct{ name, module, want string }{ {"a ledger owner lists the four repairs", "owner", "ledger_lag:reads ledger_rebuild:acts ledger_reindex:acts ledger_snapshot:acts who:"}, {"a module with no ledger has none", "plain", "who:"}, } { t.Run(c.name, func(t *testing.T) { var got string mt.Until(t, func() (err error) { got, err = listed(c.module); return }) if got != c.want { t.Fatalf("%s lists %q, want %q", c.module, got, c.want) } }) } t.Run("a ledger bound later brings them", func(t *testing.T) { plain.Bindings = owner.Bindings mesh.Issue(t, plain) mt.Until(t, func() error { got, err := listed("plain") if err == nil && !strings.Contains(got, "ledger_rebuild:acts") { err = errors.New("listed " + got) } return err }) }) }