Files
mesh-catalog/modules/messenger/cmd/messenger/preview_test.go
T
jschoubben 15546f9d83
mesh/merge-gate pass: builds messenger → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
messenger: count the store's writes, and name an ask's record when it is the only one held (review of issue 422)
The review's two nits. A write of bytes identical to what is stored was
invisible to a comparison of content, so the test store counts its
writes and the preview's tests read that count: a persist from inside
Preview now fails five of them instead of one. And a router holding an
ask's record and no condition said it held none, rather than saying what
that key is; the branches are the other way round, with a test that
holds nothing else.
2026-10-11 00:49:38 +02:00

289 lines
11 KiB
Go

package main
import (
"reflect"
"strings"
"testing"
"time"
)
// A condition's message can be read before it is sent (novox/hq issue 422): the words a send would
// carry, the tracking line among them, and nothing of this router moved while they were read.
// previewHolder is a router holding one urgent condition — one a send goes out for at once, so a preview
// that sends, queues or records anything is caught — with the issues given tracking its key.
func previewHolder(t *testing.T, issues []TrackedIssue) (*Holder, *fakeChannel, *fakeChannel, *clock, *memStore, Condition) {
t.Helper()
h, tg, dt, c, st := newHolder(t)
h.Tracking = func() (map[string][]TrackedIssue, error) {
return map[string][]TrackedIssue{"mesh.hand-acts.rolled-back.healer-wanted": issues}, nil
}
k := cond("mesh.hand-acts.rolled-back.healer-wanted", Urgent, "rolled-back was repaired by hand 4 times in 14 days")
k.Explanation = "Nothing for you to do. A person repaired rolled-back by hand 4 times in 14 days, so an automatic repair is wanted for it. Nothing is broken now."
k.Needs = ""
k.Raised = c.now()
h.Condition(EventRaised, k)
settle(h, c)
if len(tg.sends) == 0 && len(dt.sends) == 0 {
t.Fatal("the condition this is read from was never sent, so a preview sending something would not show")
}
return h, tg, dt, c, st, k
}
// unmoved fails when anything a send would move has moved: the sends, the queue, the history, what is
// stored, and the record itself.
type unmoved struct {
sends, queued, recent, refusals, puts int
stored Record
held Record
}
func mark(t *testing.T, h *Holder, tg, dt *fakeChannel, st *memStore, key string) unmoved {
t.Helper()
h.mu.Lock()
defer h.mu.Unlock()
queued := 0 // the outbox is held per channel, never per condition
for _, list := range h.outbox {
queued += len(list)
}
return unmoved{sends: len(tg.sends) + len(dt.sends), queued: queued, recent: len(h.recent),
refusals: len(h.refusals), puts: st.puts, stored: st.recs[key], held: *h.open[key]}
}
func (was unmoved) check(t *testing.T, h *Holder, tg, dt *fakeChannel, st *memStore, c *clock, key string) {
t.Helper()
// A queued message waits for a tick, so the queue is read and then given one: either would catch it.
now := mark(t, h, tg, dt, st, key)
if now.sends != was.sends {
t.Errorf("a preview sent %d message(s)", now.sends-was.sends)
}
if now.queued != was.queued {
t.Errorf("a preview queued %d message(s)", now.queued-was.queued)
}
if now.recent != was.recent {
t.Errorf("a preview recorded %d send(s)", now.recent-was.recent)
}
if now.refusals != was.refusals {
t.Errorf("a preview recorded %d refusal(s): only a send does that", now.refusals-was.refusals)
}
if now.puts != was.puts {
t.Errorf("a preview wrote to the store %d time(s), even if the bytes were the same", now.puts-was.puts)
}
if !reflect.DeepEqual(now.stored, was.stored) {
t.Errorf("a preview wrote the record: %+v", now.stored)
}
if !reflect.DeepEqual(now.held, was.held) {
t.Errorf("a preview changed the record held: %+v", now.held)
}
settle(h, c)
if after := mark(t, h, tg, dt, st, key); after.sends != was.sends {
t.Errorf("a preview queued a message, which the next tick sent: %d", after.sends-was.sends)
}
}
func TestAConditionsMessageIsReadWithoutBeingSent(t *testing.T) {
h, tg, dt, c, st, k := previewHolder(t, []TrackedIssue{{Number: 352, Status: "located", Needs: "decision"}})
was := mark(t, h, tg, dt, st, k.Key)
out, err := h.Preview(k.Key, "")
if err != nil {
t.Fatal(err)
}
if out["what"] != "raised" {
t.Errorf("what %v; a preview with none asked is the first message", out["what"])
}
if out["title"] != "Urgent: mesh hand-acts rolled-back healer-wanted" {
t.Errorf("title %q", out["title"])
}
body, _ := out["body"].(string)
if !strings.Contains(body, "Tracked as issue 352: nobody is working on it; it waits for a decision first.") {
t.Errorf("the body says nothing of the issue that tracks it: %q", body)
}
if out["tracking"] != "Tracked as issue 352: nobody is working on it; it waits for a decision first." {
t.Errorf("tracking %q", out["tracking"])
}
if out["allowed"] != true {
t.Errorf("allowed %v, carried %v: these words may leave the mesh", out["allowed"], out["carried"])
}
// The verdict is left out while nobody works on the issue (ADR 0285 §4), as in a send.
if strings.Contains(body, "Nothing for you to do.") {
t.Errorf("the preview reassures where nothing is being done: %q", body)
}
keyless(t, Message{Title: out["title"].(string), Body: body})
was.check(t, h, tg, dt, st, c, k.Key)
}
func TestAPreviewSaysTheWordsTheChannelWasGiven(t *testing.T) {
issues := []TrackedIssue{{Number: 386, Status: "fixing", Worker: "fix-386@g14", Since: at(21, 10)}}
h, tg, dt, c, st, k := previewHolder(t, issues)
sent := dt.sends[len(dt.sends)-1] // the message the desk was actually handed
was := mark(t, h, tg, dt, st, k.Key)
out, err := h.Preview(k.Key, "")
if err != nil {
t.Fatal(err)
}
if out["title"] != sent.Title || out["body"] != sent.Body {
t.Fatalf("preview %q / %q; the channel was given %q / %q", out["title"], out["body"], sent.Title, sent.Body)
}
if !strings.Contains(sent.Body, "Tracked as issue 386: fix-386 on g14 is fixing it since ") {
t.Fatalf("the message this is compared against carries no tracking line: %q", sent.Body)
}
was.check(t, h, tg, dt, st, c, k.Key)
}
func TestAClearingIsPreviewedAsIfItClearedNow(t *testing.T) {
h, tg, dt, c, st, k := previewHolder(t, []TrackedIssue{{Number: 352, Status: "located"}})
c.pass(4 * time.Hour)
was := mark(t, h, tg, dt, st, k.Key)
out, err := h.Preview(k.Key, "cleared")
if err != nil {
t.Fatal(err)
}
// Composed from the open record, this said "after a moment": the clearing's own time is zero, so the
// time it was open came out negative.
if out["title"] != "Resolved: mesh hand-acts rolled-back healer-wanted, after 4.0 h" {
t.Errorf("title %q; a clearing says how long it was open", out["title"])
}
if out["as-if"] == nil {
t.Errorf("the answer does not say the clearing is composed as if it cleared now: %v", out)
}
if _, said := out["tracking"]; said {
t.Errorf("a clearing says a tracking line: %v", out["tracking"])
}
was.check(t, h, tg, dt, st, c, k.Key)
}
func TestASilenceIsPreviewedOnlyWhileThereIsOne(t *testing.T) {
h, tg, dt, c, st, k := previewHolder(t, []TrackedIssue{{Number: 352, Status: "located"}})
// Under no silence, a silence message would say a moment that does not exist.
_, err := h.Preview(k.Key, "silenced")
if err == nil || !strings.Contains(err.Error(), "under no silence") {
t.Fatalf("a silence previewed without one: %v", err)
}
h.mu.Lock()
h.open[k.Key].SilencedTill = c.now().Add(7 * 24 * time.Hour)
h.open[k.Key].SilencedWhy = "the operator knows"
h.mu.Unlock()
was := mark(t, h, tg, dt, st, k.Key)
out, err := h.Preview(k.Key, "silenced")
if err != nil {
t.Fatal(err)
}
title, _ := out["title"].(string)
if !strings.HasPrefix(title, "Silenced until ") || strings.Contains(title, "Jan 1 ") || strings.Contains(title, " 1 Jan ") {
t.Errorf("title %q; a silence says until when it is quiet", title)
}
if _, said := out["tracking"]; said {
t.Errorf("a silence says a tracking line: %v", out["tracking"])
}
was.check(t, h, tg, dt, st, c, k.Key)
}
func TestAPreviewOfWhatThisRouterDoesNotHoldIsRefusedByName(t *testing.T) {
h, _, _, _, _, k := previewHolder(t, nil)
_, err := h.Preview("machine.ace.silent", "")
if err == nil {
t.Fatal("a condition this router does not hold was previewed")
}
if !strings.Contains(err.Error(), "machine.ace.silent") || !strings.Contains(err.Error(), k.Key) {
t.Errorf("the refusal says neither what was asked nor what is held: %v", err)
}
if _, err := h.Preview("", ""); err == nil || !strings.Contains(err.Error(), "key is required") {
t.Errorf("no key: %v", err)
}
if _, err := h.Preview(k.Key, "shouted"); err == nil || !strings.Contains(err.Error(), "shouted") {
t.Errorf("an unknown message: %v", err)
}
// An ask's own record is held here too, and is said as part of an ask, never as a condition.
h.mu.Lock()
h.open["ask.someone.1"] = &Record{Key: "ask.someone.1", Origin: "ask", Severity: Urgent, Summary: "a question"}
h.mu.Unlock()
_, err = h.Preview("ask.someone.1", "")
if err == nil || !strings.Contains(err.Error(), "not a condition") || !strings.Contains(err.Error(), k.Key) {
t.Errorf("an ask's record previewed as a condition: %v", err)
}
// A router holding an ask and no condition says what that key is, not that it holds nothing.
bare, _, _, _, _ := newHolder(t)
bare.mu.Lock()
bare.open["ask.someone.2"] = &Record{Key: "ask.someone.2", Origin: "ask", Severity: Urgent, Summary: "a question"}
bare.mu.Unlock()
_, err = bare.Preview("ask.someone.2", "")
if err == nil || !strings.Contains(err.Error(), "not a condition") {
t.Errorf("the only record held is an ask's: %v", err)
}
}
func TestAPreviewAsksTheTrackerWhenItsWordWentCold(t *testing.T) {
asked := 0
h, _, _, c, _, k := previewHolder(t, []TrackedIssue{{Number: 352, Status: "located"}})
h.Tracking = func() (map[string][]TrackedIssue, error) {
asked++
return map[string][]TrackedIssue{k.Key: {{Number: 352, Status: "located"}}}, nil
}
c.pass(TrackingKept + time.Minute) // older than an answer is used for
out, err := h.Preview(k.Key, "quiet-reminder")
if err != nil {
t.Fatal(err)
}
if asked != 1 {
t.Fatalf("the tracker was asked %d times; a preview on a cold word asks once", asked)
}
if out["tracking"] != "Tracked as issue 352: nobody is working on it." {
t.Errorf("tracking %q; a preview that asked should say what it heard", out["tracking"])
}
}
func TestAPreviewSaysTheReducedWordsAndWhyWhenItsOwnMayNotLeave(t *testing.T) {
h, tg, dt, c, st, _ := previewHolder(t, nil)
stated := 0
h.Emit = func(string, any) error { stated++; return nil }
// A warning that needs nothing is held, not sent, so this refusal is one no send has met yet.
k := cond("machine.ace.unreadable", Warning, "a file on it could not be read")
k.Explanation = "Nothing for you to do. A file at /home/someone/secrets.txt could not be read."
k.Needs = ""
k.Raised = c.now()
h.Condition(EventRaised, k)
settle(h, c)
was := mark(t, h, tg, dt, st, k.Key)
out, err := h.Preview(k.Key, "")
if err != nil {
t.Fatal(err)
}
if out["allowed"] != false || out["carried"] == nil {
t.Fatalf("allowed %v, carried %v; the content rule refuses a path", out["allowed"], out["carried"])
}
// The words said are the ones that would go out, not the refused ones.
body, _ := out["body"].(string)
if strings.Contains(body, "/home/") {
t.Errorf("the preview says words no send would carry: %q", body)
}
if !strings.Contains(body, "withheld") {
t.Errorf("body %q; a reduced message says that part of it was withheld", body)
}
if !strings.Contains(body, "a file path") {
t.Errorf("body %q; a reduced message says what it carried", body)
}
if out["instead"] == nil {
t.Errorf("the answer does not say these are the reduced words: %v", out)
}
// Reading it recorded no refusal, stated nothing on the bus, and left the record's own words alone.
if stated != 0 {
t.Errorf("a preview stated %d fact(s) on the bus", stated)
}
if was.held.Refused != "" {
t.Fatalf("the record was already refused before the preview: %q", was.held.Refused)
}
was.check(t, h, tg, dt, st, c, k.Key)
}