Files
mesh-catalog/modules/mesh-issues/cmd/mesh-issues/caller_test.go
T
jschoubben b3fcf408f2 Make tests that wait for concurrent work wait on the event or a condition with a long deadline (issue 1814)
A test that slept a fixed time and then asserted what a goroutine, process or
watcher did failed under the checker's load. Each now waits for its positive
evidence (a started baseline, a call counted, a state reached) within 30 s, and
the concurrency-limit tests meet at a barrier instead of overlapping by sleep.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-01 17:24:19 +01:00

141 lines
5.0 KiB
Go

package main
import (
"bufio"
"encoding/json"
"fmt"
"io"
"strings"
"testing"
"time"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// served is the tracker's verbs served as the runtime launches them, over the SDK's stdio loop, with the caller
// read from the runtime (stdio.CallerOf): what reaches the module is what a tools/call carries.
type served struct {
in *io.PipeWriter
lines *bufio.Scanner
next int
}
func serve(t *testing.T, h *harness) *served {
t.Helper()
h.CallerOf = stdio.CallerOf
inR, inW := io.Pipe()
outR, outW := io.Pipe()
go func() { _ = stdio.ServeOn("mesh-issues", Tools(h.Tracker), inR, outW) }()
t.Cleanup(func() { _ = inW.Close() })
return &served{in: inW, lines: bufio.NewScanner(outR)}
}
// call sends one tools/call, with the runtime's `_meta` naming caller when one is given, and answers the
// verb's result or its refusal.
func (s *served) call(t *testing.T, verb, caller string, args map[string]any) (map[string]any, string) {
t.Helper()
s.next++
params := map[string]any{"name": Seat + "." + verb, "arguments": args}
if caller != "" {
params["_meta"] = map[string]any{stdio.MetaCaller: caller}
}
b, _ := json.Marshal(map[string]any{"jsonrpc": "2.0", "id": s.next, "method": "tools/call", "params": params})
_, _ = s.in.Write(append(b, '\n'))
done := make(chan []byte, 1)
go func() {
if s.lines.Scan() {
done <- append([]byte(nil), s.lines.Bytes()...)
}
}()
var line []byte
select {
case line = <-done:
case <-time.After(30 * time.Second):
t.Fatalf("%s was not answered", verb)
}
var m struct {
Result struct {
Content []struct {
Text string `json:"text"`
} `json:"content"`
IsError bool `json:"isError"`
} `json:"result"`
}
_ = json.Unmarshal(line, &m)
if len(m.Result.Content) == 0 {
t.Fatalf("%s was answered %s", verb, line)
}
text := m.Result.Content[0].Text
if m.Result.IsError {
return nil, text
}
var out map[string]any
_ = json.Unmarshal([]byte(text), &out)
return out, ""
}
// **Who acted is the caller the runtime proved** (novox/hq issue 365, ADR 0275 §5): a call whose subject named
// its caller is recorded as that bus user — on the issue it opened, the note, the link, the move and its event,
// the value set, and the number reserved.
func TestWhoActedIsTheCallerTheRuntimeProved(t *testing.T) {
h, _ := reserveHarness(t)
s := serve(t, h)
const who = "shanks.node-tools"
opened, refused := s.call(t, "open", who, map[string]any{"title": "a title", "report": "a report"})
if refused != "" || opened["by"] != who {
t.Fatalf("open answered %v %q, want by %s", opened, refused, who)
}
n := uint64(opened["number"].(float64))
other, _ := s.call(t, "open", who, map[string]any{"title": "another", "report": "another report"})
is, _ := h.Get(n)
if is.OpenedBy != who {
t.Errorf("the issue was opened by %q", is.OpenedBy)
}
if noted, refused := s.call(t, "note", who, map[string]any{"number": n, "text": "seen again"}); refused != "" || noted["by"] != who {
t.Errorf("note answered %v %q", noted, refused)
}
if linked, refused := s.call(t, "link", who, map[string]any{"number": n, "kind": "relates-to", "target": fmt.Sprint(other["number"])}); refused != "" || linked["by"] != who {
t.Errorf("link answered %v %q", linked, refused)
}
if _, refused := s.call(t, "set", who, map[string]any{"number": n, "severity": "minor"}); refused != "" {
t.Errorf("set refused: %s", refused)
}
if _, refused := s.call(t, "move", who, map[string]any{"number": n, "status": "fixing", "by": "fix-1@g14"}); refused != "" {
t.Errorf("move refused: %s", refused)
}
if reserved, refused := s.call(t, "reserve", who, map[string]any{"kind": "decision", "for": "a decision"}); refused != "" || reserved["by"] != who {
t.Errorf("reserve answered %v %q", reserved, refused)
}
is, _ = h.Get(n)
for _, note := range is.Notes {
if note.By != who {
t.Errorf("a note is by %q", note.By)
}
}
for _, e := range h.said() {
if e.Event == EventMoved && e.Body["caller"] != who {
t.Errorf("the move was said as by caller %v", e.Body["caller"])
}
}
}
// A caller named in the arguments is refused, whatever it names — an argument is the caller's to write — and a
// call the runtime proved no caller for is recorded Unproven, as it always was.
func TestACallerInTheArgumentsIsRefusedAndAnUnprovenCallSaysSo(t *testing.T) {
h := newHarness(t)
s := serve(t, h)
for _, args := range []map[string]any{
{"title": "t", "report": "r", "caller": "novox.node-tools"},
{"title": "t", "report": "r", "_meta": map[string]any{stdio.MetaCaller: "novox.node-tools"}},
{"title": "t", "report": "r", "by": "novox.node-tools"},
} {
if out, refused := s.call(t, "open", "shanks.node-tools", args); refused == "" || !strings.Contains(refused, "does not take") {
t.Errorf("an open naming a caller in its arguments %v was answered %v", args, out)
}
}
opened, refused := s.call(t, "open", "", map[string]any{"title": "t", "report": "r"})
if refused != "" || opened["by"] != Unproven {
t.Fatalf("an open the runtime named no caller for answered %v %q, want by %s", opened, refused, Unproven)
}
}