G-delivery 2: sdk/heard's cases are rows of the watchman's findings table

mesh-delivery is over its unit budget, so the new function goes; its three cases run as rows of an existing
table of a user of the package.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 18:10:16 +01:00
parent e5011e1f83
commit 121c6d9c48
2 changed files with 40 additions and 54 deletions
@@ -9,6 +9,7 @@ import (
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-delivery/sdk/heard"
"git.novox.be/novox/mesh-sdk/go/provisions"
@@ -152,6 +153,45 @@ func TestTheWatchmansFindings(t *testing.T) {
w.NotHeard("membership", "a consumer not there yet is not opened", errors.New("no bucket"))
w.Heard("EVENTS")
w.Heard("membership")
// sdk/heard's Writer, as the indexer, the assigner and the builder use it: Bind writes the finding with why
// when the consumer does not bind and answers the error, deletes it when it binds, and with no findings
// state says it in the log alone.
at := time.Date(2026, 11, 4, 17, 0, 0, 0, time.UTC)
for _, row := range []struct {
name string
bindErr error
noState bool
want string
}{
{name: "not there yet", bindErr: errors.New("consumer not found"),
want: "mesh-delivery-indexer does not hear assigner-views: the placement is the first view's alone (consumer not found)"},
{name: "bound"},
{name: "no findings state", bindErr: errors.New("consumer not found"), noState: true},
} {
key := heard.Key("mesh-delivery-indexer", "assigner-views")
kept := map[string][]byte{key: []byte("{}")}
var logs []string
hw := heard.Writer{Observer: "mesh-delivery-indexer", Now: func() time.Time { return at }, Logf: func(f string, a ...any) { logs = append(logs, f) }}
if !row.noState {
hw.Put = func(k string, v []byte) error { kept[k] = v; return nil }
hw.Delete = func(k string) error { delete(kept, k); return nil }
}
if err := hw.Bind("assigner-views", "the placement is the first view's alone", func() error { return row.bindErr }); !errors.Is(err, row.bindErr) {
t.Errorf("%s: Bind answered %v, want %v", row.name, err, row.bindErr)
}
raw, stands := kept[key]
switch {
case row.noState && len(logs) == 0:
t.Errorf("%s: nothing said", row.name)
case !row.noState && row.want == "" && stands:
t.Errorf("%s: the finding stands once bound", row.name)
case row.want != "":
f, err := health.DecodeFinding(raw)
if err != nil || f.Kind != heard.Kind || f.Summary != row.want || f.Observer != "mesh-delivery-indexer" {
t.Errorf("%s: the finding %+v (%v), want summary %q", row.name, f, err, row.want)
}
}
}
}, map[string]string{}},
{"ADR 0601 §4: what a node keeps of a module as it runs, for a manifest that does not say it yet, is a warning until the have says none", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) {
have := func(kept ...string) []byte {
-54
View File
@@ -1,54 +0,0 @@
package heard
import (
"errors"
"strings"
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/health"
)
// Review round 1 of the registry milestone (ADR 0615 §5): a consumer that does not bind is a finding naming the observer
// and the family, with why; binding deletes it; no findings state still says it in the log.
func TestAConsumerNotHeardIsAFindingUntilItBinds(t *testing.T) {
at := time.Date(2026, 11, 4, 17, 0, 0, 0, time.UTC)
for _, row := range []struct {
name string
bindErr error
noState bool
want string // the finding's summary, or "" when none stands
}{
{name: "not there yet", bindErr: errors.New("consumer not found"),
want: "mesh-delivery-indexer does not hear assigner-views: the placement is the first view's alone (consumer not found)"},
{name: "bound"},
{name: "no findings state", bindErr: errors.New("consumer not found"), noState: true},
} {
kept := map[string][]byte{Key("mesh-delivery-indexer", "assigner-views"): []byte("{}")}
var logs []string
w := Writer{Observer: "mesh-delivery-indexer", Now: func() time.Time { return at },
Logf: func(f string, a ...any) { logs = append(logs, f) }}
if !row.noState {
w.Put = func(k string, v []byte) error { kept[k] = v; return nil }
w.Delete = func(k string) error { delete(kept, k); return nil }
}
err := w.Bind("assigner-views", "the placement is the first view's alone", func() error { return row.bindErr })
if !errors.Is(err, row.bindErr) {
t.Errorf("%s: Bind answered %v, want %v", row.name, err, row.bindErr)
}
raw, stands := kept[Key("mesh-delivery-indexer", "assigner-views")]
switch {
case row.noState:
if len(logs) == 0 {
t.Errorf("%s: nothing said", row.name)
}
case row.want == "" && stands:
t.Errorf("%s: the finding stands once bound", row.name)
case row.want != "":
f, err := health.DecodeFinding(raw)
if err != nil || f.Kind != Kind || f.Summary != row.want || f.Observer != "mesh-delivery-indexer" || !strings.Contains(f.Subject.ID, "assigner-views") {
t.Errorf("%s: the finding %+v (%v), want summary %q", row.name, f, err, row.want)
}
}
}
}