Files

92 lines
2.6 KiB
Go

package main
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
// echoBrain returns the prompt itself, so an Elder merge contains the reports.
type echoBrain struct{}
func (echoBrain) Name() string { return "echo" }
func (echoBrain) Ask(ctx context.Context, system, prompt string) (string, int, error) {
return prompt, 10, nil
}
func newEchoServer(t *testing.T) (*httptest.Server, *Server) {
t.Helper()
ts, s := newTestNestServer(t)
s.p.Flock.brain = echoBrain{}
return ts, s
}
func TestElderAddressableInNest(t *testing.T) {
ts, s := newEchoServer(t)
id := newNest(t, ts, "Lab", `"Hugin","Munin"`)
r := postRequest(t, ts, id, "conspiracy", "is this plan risky")
postDeliver(t, ts, id, "Hugin", r, "the mint Condition is fragile")
postDeliver(t, ts, id, "Munin", r, "the audit trail says otherwise")
code, _ := postMsg(t, ts, id, `{"author":"owner","kind":"request","to":"Elder","text":"merge this","refers_to":"`+r+`"}`)
if code != http.StatusCreated {
t.Fatalf("elder request: %d", code)
}
elders := awaitMsgsBy(t, ts, id, "Elder")
if len(elders) != 1 {
t.Fatalf("want exactly one Elder message, got %v", elders)
}
m := elders[0]
text, _ := m["text"].(string)
for _, want := range []string{"fragile", "otherwise"} {
if !strings.Contains(text, want) {
t.Fatalf("Elder merge must carry both reports (missing %q): %q", want, text)
}
}
if m["refers_to"] != r || m["to"] != "owner" || m["kind"] != "deliver" {
t.Fatalf("Elder reply shape wrong: %v", m)
}
_ = s
}
func TestElderOnlyMergesOnRequest(t *testing.T) {
ts, s := newEchoServer(t)
id := newNest(t, ts, "Lab", `"Hugin","Munin"`)
r := postRequest(t, ts, id, "conspiracy", "is this plan risky")
postDeliver(t, ts, id, "Hugin", r, "ship it")
postDeliver(t, ts, id, "Munin", r, "ship it too")
time.Sleep(300 * time.Millisecond)
if got := awaitMsgsBy(t, ts, id, "Elder"); len(got) != 0 {
t.Fatalf("Elder must stay silent unless asked, got %v", got)
}
_ = s
}
func TestParseAddressingServiceRole(t *testing.T) {
ts, s := newTestNestServer(t)
id := newNest(t, ts, "Lab", `"Hugin"`)
if got := parseAddressing("please @Elder merge this", nestMembers(nestOf(s, id))); got != "Elder" {
t.Fatalf("Elder must be an addressable service handle, got %q", got)
}
}
func awaitMsgsBy(t *testing.T, ts *httptest.Server, id, author string) []map[string]any {
t.Helper()
deadline := time.Now().Add(2 * time.Second)
for {
var out []map[string]any
for _, m := range nestMessages(t, ts, id) {
if m["author"] == author {
out = append(out, m)
}
}
if len(out) > 0 || time.Now().After(deadline) {
return out
}
time.Sleep(10 * time.Millisecond)
}
}