mesh-config resolves a module's config values per node from which module runs where and what each registered module declares, and both lived only in the controller's store (hq issue 652, design 57 F3). The controller now keeps two record mirrors, mesh-controller_assignments (<node>.<module>) and mesh-controller_declared-config (<module>), built from the store by the lease holder every ten seconds and written only where a value differs, by compare-and-set, with one assignment-changed or declared-config-changed per write and a purge said as removed (ADR 0289, design 54 §2-3). A module reads them through `reads` as mesh-controller.<mirror>; the writers table keeps every other writer out. Neither holds a secret: an assignment names its node and module, a declaration is what the public manifest declares. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
5.0 KiB
Go
110 lines
5.0 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A module declares the state it keeps and the state it reads (novox/hq ADR 0201), a bucket by its
|
|
// bare name or with the owner's options.
|
|
func TestAManifestMaySayWhatStateItKeepsAndReads(t *testing.T) {
|
|
m, err := ParseManifest([]byte(`{"module":"claude-code","version":"1",` +
|
|
`"state":["servers",{"name":"seen","history":5,"ttl-seconds":3600}],` +
|
|
`"reads":["licence-manager.bindings"]}`))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(m.State) != 2 || m.State[0].Name != "servers" || m.State[1].History != 5 || m.State[1].TTLSeconds != 3600 {
|
|
t.Fatalf("state not read: %+v", m.State)
|
|
}
|
|
if len(m.Reads) != 1 || m.Reads[0] != "licence-manager.bindings" {
|
|
t.Fatalf("reads not read: %v", m.Reads)
|
|
}
|
|
// Written back as it came in: the short form where nothing else is said.
|
|
out, _ := json.Marshal(m.State)
|
|
if string(out) != `["servers",{"name":"seen","history":5,"ttl-seconds":3600}]` {
|
|
t.Fatalf("written back as %s", out)
|
|
}
|
|
}
|
|
|
|
// A name the bus could not hold, or that would let two modules derive one bucket, is refused at
|
|
// registration in the manifest's words.
|
|
func TestAStateNameIsLocalAndOneToken(t *testing.T) {
|
|
for _, c := range []struct{ manifest, says string }{
|
|
{`{"module":"a","version":"1","state":["mesh.servers"]}`, `keeps state "mesh.servers": a state is named locally`},
|
|
{`{"module":"a","version":"1","state":["my_servers"]}`, `keeps state "my_servers"`},
|
|
{`{"module":"a","version":"1","state":["s","s"]}`, `keeps state "s" twice`},
|
|
{`{"module":"a","version":"1","state":[{"name":"s","history":65}]}`, `a key keeps between 1 and 64`},
|
|
{`{"module":"a.b","version":"1","state":["s"]}`, `no dot`},
|
|
{`{"module":"a","version":"1","reads":["bindings"]}`, `a read is <module>.<name>`},
|
|
{`{"module":"a","version":"1","reads":["a.s"]}`, `which is its own state`},
|
|
{`{"module":"a","version":"1","state":[{"name":"s","shared":true}]}`, `{name, history, ttl-seconds, per-machine}`},
|
|
} {
|
|
_, err := ParseManifest([]byte(c.manifest))
|
|
if err == nil {
|
|
t.Errorf("%s was accepted", c.manifest)
|
|
continue
|
|
}
|
|
if !strings.Contains(err.Error(), c.says) {
|
|
t.Errorf("%s refused for the wrong reason: %v", c.manifest, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A read whose owner is present must name a state that owner keeps; an absent owner says nothing,
|
|
// because a module may be installed before the one whose state it reads.
|
|
func TestAReadNamesStateItsOwnerKeeps(t *testing.T) {
|
|
owner := Manifest{Module: "licence-manager", State: []StateDeclaration{{Name: "bindings"}}}
|
|
good := Manifest{Module: "claude-code", Reads: []string{"licence-manager.bindings", "absent.anything"}}
|
|
bad := Manifest{Module: "other", Reads: []string{"licence-manager.tokens"}}
|
|
if p := StateReadsNothingDeclares([]Manifest{owner, good}); len(p) != 0 {
|
|
t.Fatalf("a read of declared state was refused: %v", p)
|
|
}
|
|
p := StateReadsNothingDeclares([]Manifest{owner, bad})
|
|
if len(p) != 1 || !strings.Contains(p[0], `licence-manager keeps no state called "tokens"`) {
|
|
t.Fatalf("a read of state nobody keeps was not named: %v", p)
|
|
}
|
|
}
|
|
|
|
// **The controller's record mirrors are kept state** (design 54 §5, design 57 F3): a module may read
|
|
// `mesh-controller.assignments` and `mesh-controller.declared-config` although the controller's manifest
|
|
// declares no `state`; a read of anything else of the controller's is still named.
|
|
func TestAReadOfTheControllersMirrorsIsAReadOfKeptState(t *testing.T) {
|
|
controller := Manifest{Module: ControllerSeatName}
|
|
reader := Manifest{Module: "mesh-config", Reads: []string{"mesh-controller.assignments", "mesh-controller.declared-config"}}
|
|
if p := StateReadsNothingDeclares([]Manifest{controller, reader}); len(p) != 0 {
|
|
t.Fatalf("a read of the controller's mirrors was refused: %v", p)
|
|
}
|
|
other := Manifest{Module: "other", Reads: []string{"mesh-controller.calls"}}
|
|
if p := StateReadsNothingDeclares([]Manifest{controller, other}); len(p) != 1 {
|
|
t.Fatalf("a read of the controller's own calls was not named: %v", p)
|
|
}
|
|
}
|
|
|
|
// **Across the whole catalogue**: every state name is local, and every read whose owner is present
|
|
// names state that owner keeps.
|
|
func TestEveryManifestsStateIsLocalAndEveryReadIsKept(t *testing.T) {
|
|
manifests := theCatalogue(t)
|
|
var problems []string
|
|
for _, m := range manifests {
|
|
problems = append(problems, StateProblems(m)...)
|
|
}
|
|
problems = append(problems, StateReadsNothingDeclares(manifests)...)
|
|
if len(problems) > 0 {
|
|
t.Fatalf("the catalogue's state is not what ADR 0201 says:\n %s", strings.Join(problems, "\n "))
|
|
}
|
|
}
|
|
|
|
// `module check` says it too: the cross-catalogue pass names a read nothing on the shelf keeps.
|
|
func TestTheCataloguePassNamesAReadItsOwnerDoesNotKeep(t *testing.T) {
|
|
shelf := Shelf{
|
|
"licence-manager": {Module: "licence-manager", State: []StateDeclaration{{Name: "bindings"}}},
|
|
"claude-code": {Module: "claude-code", Reads: []string{"licence-manager.tokens"}},
|
|
}
|
|
problems := CatalogueProblems(shelf)
|
|
if len(problems) != 1 || !strings.Contains(problems[0], `keeps no state called "tokens"`) {
|
|
t.Fatalf("the catalogue pass said %v", problems)
|
|
}
|
|
}
|