Files
mesh-contracts/go/clients/nodeengineclient/enginereads/enginereads_test.go
T
jschoubben c584f4570b C3: the engine-reads keeper keeps the fallback or the last statement at the first fault while the kept call asks on (issue 1966, ADR 0668 §3; review round 1, finding 1)
A part whose node answers nothing waited out busretry.Bound (30 s) before it acted on the node's record: Once asks the verb once, and its fault is taken at once.

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
2026-11-10 04:11:07 +01:00

78 lines
3.9 KiB
Go

package enginereads
import (
"context"
"encoding/json"
"errors"
"strings"
"testing"
"time"
)
// The answer and the event are judged as the contract lays them out and its reader checks: the layout's version, a node
// that is a name, no empty capability, a time, and an event's why one of the two.
func TestTheAnswerAndTheEventAreJudged(t *testing.T) {
const at = "2026-11-05T12:00:00Z"
for name, c := range map[string]struct{ body, bad string }{
"whole": {`{"v":1,"node":"ace","manifest-reads":["mesh-config.resolved"],"stated-at":"` + at + `"}`, ""},
"old layout": {`{"v":2,"node":"ace","stated-at":"` + at + `"}`, "version"},
"bad node": {`{"v":1,"node":"a.b","stated-at":"` + at + `"}`, "no node"},
"empty read": {`{"v":1,"node":"ace","manifest-reads":[" "],"stated-at":"` + at + `"}`, "empty reader"},
"no time": {`{"v":1,"node":"ace","stated-at":"yesterday"}`, "RFC 3339"},
} {
_, _, err := DecodeAnswer([]byte(c.body))
if (c.bad == "") != (err == nil) || (err != nil && !strings.Contains(err.Error(), c.bad)) {
t.Errorf("answer %s: %v, want %q", name, err, c.bad)
}
}
for name, c := range map[string]struct{ body, bad string }{
"whole": {`{"v":1,"node":"ace","why":"started","manifest-reads":["a.b"],"at":"` + at + `"}`, ""},
"returned": {`{"v":1,"node":"ace","why":"returned","at":"` + at + `"}`, ""},
"old layout": {`{"v":2,"node":"ace","why":"started","at":"` + at + `"}`, "version"},
"no node": {`{"v":1,"node":"","why":"started","at":"` + at + `"}`, "no node"},
"another why": {`{"v":1,"node":"ace","why":"bored","at":"` + at + `"}`, "bored"},
"no time": {`{"v":1,"node":"ace","why":"started","at":"yesterday"}`, "RFC 3339"},
} {
_, err := DecodeChanged([]byte(c.body))
if (c.bad == "") != (err == nil) || (err != nil && !strings.Contains(err.Error(), c.bad)) {
t.Errorf("event %s: %v, want %q", name, err, c.bad)
}
}
// Issue 1966 note 155, ADR 0668 §4: a part whose first call of a node timed out, and whose consumer was bound after
// the node's event was said, calls every node once at the bind, and the node is then held as it answered.
calls := map[string]int{}
k := &Keeper{Sync: true, Call: func(node, _ string, _ any) (json.RawMessage, error) {
calls[node]++
if node == "ace" && calls[node] == 1 {
return nil, context.DeadlineExceeded
}
return json.RawMessage(`{"v":1,"node":"` + node + `","manifest-reads":["a.b"],"stated-at":"` + at + `"}`), nil
}}
k.AskNode("ace", "the first view")
if k.Statements()["ace"].Answered {
t.Errorf("a call that timed out reads as answered")
}
k.AtBind(func() []string { return []string{"ace", "g14"} })(time.Unix(0, 0))
if p := k.Present([]string{"ace", "g14"}); len(p["ace"]) != 1 || len(p["g14"]) != 1 || calls["ace"] != 2 || calls["g14"] != 1 {
t.Errorf("after the bind: present %v, calls %v", p, calls)
}
// Review round 1 (ADR 0668 §3): a node whose engine answers nothing reads as its record at the first fault of the call
// made once, while the kept call asks on; what the kept call answers then stands.
var during Statement
f := &Keeper{Sync: true, Fallback: func(string) ([]string, bool) { return []string{"r.s"}, true },
Once: func(string, string, any) (json.RawMessage, error) {
return nil, errors.New("nats: no responders available for request")
}}
f.Call = func(node, _ string, _ any) (json.RawMessage, error) {
during = f.Statements()[node]
return json.RawMessage(`{"v":1,"node":"` + node + `","manifest-reads":["a.b"],"stated-at":"` + at + `"}`), nil
}
f.AskNode("g14", "the first view")
if during.From != FromRecord || during.Answered || f.Statements()["g14"].From != FromVerb {
t.Errorf("while the kept call asked g14 read %+v; after it %+v", during, f.Statements()["g14"])
}
if Verb != "manifest-reads" || Event != "manifest-reads-changed" || Consumes != "node-engine.manifest-reads-changed" || Invoke != "seat:node-engine.manifest-reads" {
t.Errorf("the names are %s %s %s %s", Verb, Event, Consumes, Invoke)
}
}