Main reverted G's half merge (#189, reverted by8afc3ebin #191) and then took the reader release's S1-S5, which copied G's code. G's form holds where they differ (process_bus.go, seats.go, state.go and their tests); the release's kept names stay so main's callers keep building: SeatViewPrefix beside SeatReadPrefix, and QueueInvoke's empty strings on not-ok (with its test TestQueueInvoke). The tree differs from G's headf30dee54only by those and the release's two tests (objects cap option, seat states and stream kinds). Builds: design 47 G (the milestone's sdk part, as atf30dee54) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
99 lines
4.3 KiB
Go
99 lines
4.3 KiB
Go
package buscompose
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The mesh's event subjects are named in one place: EveryEvent, EventSubjects, EventName and Overlaps (design 34
|
|
// every-event §1, §25, §26, §34, §37).
|
|
func TestTheEventSubjectsAreNamedInOnePlace(t *testing.T) {
|
|
// EE-S1/AC1 (E §1, §25): the three subjects, in order.
|
|
if got, want := EveryEvent(), []string{"mesh.seat.*.event.>", "mesh.mod.*.event.>", "mesh.stream.*.event.>"}; !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("EveryEvent is %v, want %v", got, want)
|
|
}
|
|
|
|
// EE-S1/AC2, AC3 (E §1, §26): a name's subjects, all six or one namespace's two, and the refusals naming the rule.
|
|
subjects := []struct {
|
|
name, from string
|
|
want []string
|
|
refused string
|
|
}{
|
|
{name: "operator-channel.decided.claude-code", want: []string{
|
|
"mesh.seat.operator-channel.event.decided.claude-code", "mesh.seat.operator-channel.event.decided.claude-code.>",
|
|
"mesh.mod.operator-channel.event.decided.claude-code", "mesh.mod.operator-channel.event.decided.claude-code.>",
|
|
"mesh.stream.operator-channel.event.decided.claude-code", "mesh.stream.operator-channel.event.decided.claude-code.>",
|
|
}},
|
|
{name: "mesh-delivery-view.delivered", from: "seat", want: []string{
|
|
"mesh.seat.mesh-delivery-view.event.delivered", "mesh.seat.mesh-delivery-view.event.delivered.>"}},
|
|
{name: "mesh-delivery-view.delivered", from: "module", want: []string{
|
|
"mesh.mod.mesh-delivery-view.event.delivered", "mesh.mod.mesh-delivery-view.event.delivered.>"}},
|
|
{name: "mesh-mail.mail", from: "stream", want: []string{
|
|
"mesh.stream.mesh-mail.event.mail", "mesh.stream.mesh-mail.event.mail.>"}},
|
|
{name: "mesh-delivery-view", refused: "fewer than two tokens"},
|
|
{name: "mesh-delivery-view..delivered", refused: "[A-Za-z0-9_-]+"},
|
|
{name: "mesh-delivery-view.*", refused: "[A-Za-z0-9_-]+"},
|
|
{name: "mesh-delivery-view.>", refused: "[A-Za-z0-9_-]+"},
|
|
{name: "mesh-delivery-view.delivered", from: "bench", refused: "none of seat, module or stream"},
|
|
}
|
|
for _, c := range subjects {
|
|
got, err := EventSubjects(c.name, c.from)
|
|
if c.refused != "" {
|
|
if err == nil || !strings.Contains(err.Error(), c.refused) {
|
|
t.Errorf("EventSubjects(%q, %q) answered %v, %v; want refused naming %q", c.name, c.from, got, err, c.refused)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil || !reflect.DeepEqual(got, c.want) {
|
|
t.Errorf("EventSubjects(%q, %q) answered %v, %v; want %v", c.name, c.from, got, err, c.want)
|
|
}
|
|
// EE-S1/AC5 (E §1): every subject it answers is covered by one of EveryEvent's.
|
|
for _, s := range got {
|
|
covered := false
|
|
for _, e := range EveryEvent() {
|
|
covered = covered || Overlaps(e, s)
|
|
}
|
|
if !covered {
|
|
t.Errorf("%s is covered by none of EveryEvent", s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// EE-S1/AC4 (E §1, §26): a heard subject's name and namespace, and any other subject not an event.
|
|
names := []struct{ subject, name, from string }{
|
|
{"mesh.seat.operator-channel.event.decided.claude-code", "operator-channel.decided.claude-code", "seat"},
|
|
{"mesh.mod.mesh-delivery-view.event.delivered", "mesh-delivery-view.delivered", "module"},
|
|
{"mesh.stream.mesh-delivery-checker.event.verdict", "mesh-delivery-checker.verdict", "stream"},
|
|
{"mesh.seat.intake.call.accept.ace", "", ""},
|
|
{"mesh.mod.netcheck.call.netcheck_dns", "", ""},
|
|
{"$KV.views.x", "", ""},
|
|
{"mesh.seat..event.x", "", ""},
|
|
}
|
|
for _, c := range names {
|
|
name, from, ok := EventName(c.subject)
|
|
if name != c.name || from != c.from || ok != (c.name != "") {
|
|
t.Errorf("EventName(%q) answered %q, %q, %v; want %q, %q", c.subject, name, from, ok, c.name, c.from)
|
|
}
|
|
}
|
|
|
|
// EE-S1/AC6 (E §34, §37): overlapping subjects, a wildcard on either side.
|
|
overlaps := []struct {
|
|
a, b string
|
|
want bool
|
|
}{
|
|
{"mesh.stream.mail.event.mail.>", "mesh.stream.mail.event.mail.*.message", true},
|
|
{"mesh.mod.mail.event.x", "mesh.stream.mail.event.x", false},
|
|
{"mesh.mod.mail.event.x.>", "mesh.mod.mail.event.x", false},
|
|
{"mesh.mod.mail.event.*", "mesh.mod.*.event.x", true},
|
|
{"mesh.mod.mail.event.x", "mesh.mod.mail.event.x", true},
|
|
{"mesh.mod.*.event.>", "mesh.mod.mail.event.x.ace", true},
|
|
{"mesh.mod.mail.event.x.ace", "mesh.mod.mail.event.x", false},
|
|
}
|
|
for _, c := range overlaps {
|
|
if Overlaps(c.a, c.b) != c.want || Overlaps(c.b, c.a) != c.want {
|
|
t.Errorf("Overlaps(%q, %q) is not %v both ways", c.a, c.b, c.want)
|
|
}
|
|
}
|
|
}
|