Files
mesh-tools/node-tools/internal/runtime/caller_test.go
T

99 lines
3.7 KiB
Go

package runtime
import (
"encoding/json"
"testing"
"time"
"github.com/nats-io/nats.go"
"github.com/novox/mesh-tools/node-tools/internal/bus"
mt "github.com/novox/mesh-tools/node-tools/internal/meshtest"
)
type saidCaller struct {
Caller string `json:"caller"`
Call string `json:"call"`
Arguments map[string]any `json:"arguments"`
}
// **A module is told who called it, from the subject the call arrived on** (novox/hq issue 365): a call on the
// caller-named subject reaches the bundle with that caller in the call's `_meta`, for a module's tool, on its
// machine's address, and for a seat's verb; a caller named in the arguments is only an argument.
func TestACallOnTheCallerNamedSubjectReachesTheModuleWithItsCaller(t *testing.T) {
mesh := mt.New(t)
mesh.Issue(t, mt.MembershipOf("ledger", "anchor", true, map[string][]string{"node-desk": {"who"}}))
nodeTools := connect(t, "node-tools", "anchor")
stop, err := Run(nodeTools, []Served{{"ledger", []string{mt.Fixture("caller-echo.py")}}}, nil, func(string, ...any) {})
if err != nil {
t.Fatal(err)
}
defer stop() // returns once the bundle's exit is handled (novox/hq issue 476)
asker, err := bus.Connect(bus.Credential{URL: mt.URL(t), Module: "node-tools", Node: "shanks",
User: "shanks.node-tools", Password: "unused"})
if err != nil {
t.Fatal(err)
}
asker.Logf = func(string, ...any) {}
defer asker.Close()
calls := map[string]bool{}
for _, key := range []string{"ledger.who", "ledger.who@anchor", "seat:node-desk.who@anchor"} {
var got saidCaller
mt.Until(t, func() error {
answered, err := asker.Ask(key, map[string]any{"caller": "novox.node-tools",
"_meta": map[string]any{"mesh/caller": "novox.controller"}}, "")
if err == nil {
err = json.Unmarshal(answered.Result, &got)
}
return err
})
if got.Caller != "shanks.node-tools" {
t.Errorf("%s reached the module with caller %q, want the asker's bus user", key, got.Caller)
}
// And the id of the call in flight, one per call, which a ledger's apply names (novox/hq ADR 0597 §7).
if got.Call == "" || calls[got.Call] {
t.Errorf("%s reached the module with call id %q, want one of its own", key, got.Call)
}
calls[got.Call] = true
if got.Arguments["caller"] != "novox.node-tools" {
t.Errorf("%s: the arguments did not reach the module as sent: %v", key, got.Arguments)
}
}
}
// The subject that names no caller is still served, for one release (retired by hq issue 464), and says so:
// the module is named no caller, whatever the body claims.
func TestTheSubjectThatNamesNoCallerStillWorksAndNamesNone(t *testing.T) {
mesh := mt.New(t)
mesh.Issue(t, mt.MembershipOf("ledger", "anchor", true, map[string][]string{"node-desk": {"who"}}))
nodeTools := connect(t, "node-tools", "anchor")
stop, err := Run(nodeTools, []Served{{"ledger", []string{mt.Fixture("caller-echo.py")}}}, nil, func(string, ...any) {})
if err != nil {
t.Fatal(err)
}
defer stop() // returns once the bundle's exit is handled (novox/hq issue 476)
old, err := nats.Connect(mt.URL(t))
if err != nil {
t.Fatal(err)
}
defer old.Close()
body, _ := json.Marshal(map[string]any{"_meta": map[string]any{"mesh/caller": "novox.controller"}})
for _, subject := range []string{"mesh.mod.ledger.tool.who", "mesh.mod.ledger.tool.who.anchor", "mesh.seat.node-desk.tool.who.anchor"} {
var reply struct {
Result saidCaller `json:"result"`
Error string `json:"error"`
}
mt.Until(t, func() error {
msg, err := old.Request(subject, body, 5*time.Second)
if err == nil {
err = json.Unmarshal(msg.Data, &reply)
}
return err
})
if reply.Error != "" || reply.Result.Caller != "" {
t.Errorf("%s: the module was named caller %q (error %q), want none", subject, reply.Result.Caller, reply.Error)
}
}
}