The controller plans config, templates and moved providers' provisions, hands bus accounts to the vault and judges the new manifest words, on the feature's SDK and node-engine validator (feature 57, config and provisioning).
136 lines
5.1 KiB
Go
136 lines
5.1 KiB
Go
package broker
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The families ADR 0367 §5 starts the grant with, resolved as the inventory resolves a manifest: a seat's
|
|
// event under the seat's namespace, a module's under the module's.
|
|
var firstFamilies = []Wait{
|
|
{Name: "mesh-knowledge.reviewed", Emitter: "mesh-knowledge", Event: "reviewed"},
|
|
{Name: "mesh-delivery.transition", Emitter: "mesh-delivery", Event: "transition"},
|
|
{Name: "gitea.forge.status", Emitter: "gitea", Event: "forge.status"},
|
|
{Name: "mesh-controller.checked", Emitter: "mesh-controller", Seat: true, Event: "checked"},
|
|
{Name: "operator-channel.decided.claude-code", Emitter: "operator-channel", Seat: true, Event: "decided.claude-code"},
|
|
}
|
|
|
|
var firstSubjects = []string{
|
|
"mesh.mod.gitea.event.forge.status",
|
|
"mesh.mod.mesh-delivery.event.transition",
|
|
"mesh.mod.mesh-knowledge.event.reviewed",
|
|
"mesh.seat.mesh-controller.event.checked",
|
|
"mesh.seat.operator-channel.event.decided.claude-code",
|
|
}
|
|
|
|
func runtimeCarrying(waits []Wait) Principal {
|
|
return Principal{Kind: KindNodeTools, Node: "desk", Module: RuntimeModule, PasswordHash: "x", Carries: []Declared{
|
|
{Module: "shop", Emits: []string{"order.placed"}, Consumes: []string{"billing.paid"}, Serves: []string{"price"}},
|
|
{Module: RuntimeModule, Invokes: []string{"*"}, Waits: waits},
|
|
}}
|
|
}
|
|
|
|
func without(all, some []string) []string {
|
|
drop := map[string]bool{}
|
|
for _, s := range some {
|
|
drop[s] = true
|
|
}
|
|
var out []string
|
|
for _, s := range all {
|
|
if !drop[s] {
|
|
out = append(out, s)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// novox/hq ADR 0367 "How it is checked": the account's wait grant equals the manifest's families. The tool
|
|
// runner's account subscribes exactly the families' subjects beyond what it had without them — nothing
|
|
// published, nothing wider — and the membership it is issued names the same subjects.
|
|
func TestTheToolRunnersWaitGrantIsTheManifestsFamiliesAlone(t *testing.T) {
|
|
before, err := PermissionsFor(runtimeCarrying(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
after, err := PermissionsFor(runtimeCarrying(firstFamilies))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
added := without(after.Subscribe, before.Subscribe)
|
|
sort.Strings(added)
|
|
if !reflect.DeepEqual(added, firstSubjects) {
|
|
t.Errorf("the wait grant is %v, want the families' subjects %v", added, firstSubjects)
|
|
}
|
|
if extra := without(after.Publish, before.Publish); len(extra) > 0 {
|
|
t.Errorf("waiting granted a publish: %v", extra)
|
|
}
|
|
for _, s := range after.Subscribe {
|
|
if strings.HasPrefix(s, "mesh.mod.*.event") || s == "mesh.>" || s == ">" || strings.HasSuffix(s, ".event.>") {
|
|
t.Errorf("the runtime may subscribe every event: %s", s)
|
|
}
|
|
}
|
|
for _, other := range []string{"mesh.seat.operator-channel.event.decided.shop",
|
|
"mesh.mod.mesh-knowledge.event.proposed", "mesh.mod.gitea.event.forge.push"} {
|
|
if MaySubscribe(after, other) {
|
|
t.Errorf("the runtime may subscribe %s, which no family names", other)
|
|
}
|
|
}
|
|
|
|
issued := MembershipFor("desk", runtimeCarrying(firstFamilies).Carries[1], Placements{})
|
|
var subjects []string
|
|
for _, w := range issued.Waits {
|
|
subjects = append(subjects, w.Subject)
|
|
}
|
|
sort.Strings(subjects)
|
|
if !reflect.DeepEqual(subjects, firstSubjects) {
|
|
t.Errorf("the membership names %v, want the grant %v", subjects, firstSubjects)
|
|
}
|
|
if issued.Waits[0].Event != "mesh-knowledge.reviewed" {
|
|
t.Errorf("a family is issued under its manifest name: %+v", issued.Waits[0])
|
|
}
|
|
if shop := MembershipFor("desk", runtimeCarrying(firstFamilies).Carries[0], Placements{}); len(shop.Waits) > 0 {
|
|
t.Errorf("a module beside the runtime is issued waits: %+v", shop.Waits)
|
|
}
|
|
}
|
|
|
|
// **A subscription for the call, never a durable consumer** (ADR 0367 §2): composing the users makes no
|
|
// consumer that filters a family, and none for the runtime's module at all.
|
|
func TestAWaitMakesNoDurableConsumer(t *testing.T) {
|
|
for _, c := range ConsumersOf([]Principal{runtimeCarrying(firstFamilies)}) {
|
|
if c.Module == RuntimeModule {
|
|
t.Errorf("the runtime's module has a durable consumer: %+v", c.Consumer)
|
|
}
|
|
for _, f := range c.Consumer.Filters {
|
|
for _, s := range firstSubjects {
|
|
if f == s {
|
|
t.Errorf("%s's consumer filters the family %s", c.Module, s)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Only the tool runner's module waits (ADR 0367 §2): a carried module declaring waits is refused at
|
|
// composition, naming it, and no name that would widen a subject is composed.
|
|
func TestAWaitIsComposedOnlyForTheToolRunnerAndOnlyWhole(t *testing.T) {
|
|
p := runtimeCarrying(nil)
|
|
p.Carries[0].Waits = []Wait{{Name: "mesh-knowledge.reviewed", Emitter: "mesh-knowledge", Event: "reviewed"}}
|
|
if _, err := PermissionsFor(p); err == nil || !strings.Contains(err.Error(), "shop") {
|
|
t.Errorf("a carried module's waits were composed: %v", err)
|
|
}
|
|
for _, w := range []Wait{
|
|
{Name: "x", Emitter: "mesh-knowledge", Event: "*"},
|
|
{Name: "x", Emitter: "mesh-knowledge", Event: "a.>"},
|
|
{Name: "x", Emitter: "*", Event: "reviewed"},
|
|
{Name: "x", Emitter: "mesh.knowledge", Event: "reviewed"},
|
|
{Name: "x", Emitter: "mesh-knowledge", Event: ""},
|
|
{Name: "x", Emitter: "mesh-knowledge", Event: "a..b"},
|
|
} {
|
|
if _, err := PermissionsFor(runtimeCarrying([]Wait{w})); err == nil {
|
|
t.Errorf("%+v was composed", w)
|
|
}
|
|
}
|
|
}
|