The controller ended by its unassignment (ADR 0590), so its seat, the grants seat's lease write and hand-back and placement's take-over from it serve nothing. The dependence check becomes strict (clause 5): a read of the lease, a claim, a require or the module itself is refused like any other declaration. held and artifacts-gone are the artifact sweep seat's (ADR 0571 §2). Issue 1126 B1, B2. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
71 lines
3.1 KiB
Go
71 lines
3.1 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A served verb is written as a bare name or in full, and both read into one type (novox/hq ADR 0132).
|
|
func TestAServedVerbIsANameOrADefinition(t *testing.T) {
|
|
m, err := decodeForTest([]byte(`{"module":"till","version":"1","tools":["price","refund"],` +
|
|
`"seats":[{"name":"shop-till","serves":["price",{"name":"refund","description":"give it back",` +
|
|
`"input":{"type":"object","properties":{"order":{"type":"string"}}}}]}],` +
|
|
`"claims":[{"name":"shop-till","scope":"mesh"}]}`))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := m.DefinesSeats[0].Serves
|
|
if len(got) != 2 || got[0].Name != "price" || got[1].Name != "refund" || got[1].Description != "give it back" {
|
|
t.Fatalf("verbs not read: %+v", got)
|
|
}
|
|
if got[1].Input["type"] != "object" {
|
|
t.Fatalf("the schema did not travel with the verb: %+v", got[1].Input)
|
|
}
|
|
}
|
|
|
|
// Holding a mesh seat that serves verbs requires serving them, and the refusal names the verbs.
|
|
func TestHoldingAMeshSeatRequiresServingItsVerbs(t *testing.T) {
|
|
// 774/S34/AC1: the seat mesh-enrolment is held by a module serving its six verbs, and a seventh is refused.
|
|
enrolment, ok := SeatNamed(EnrolmentSeat)
|
|
if !ok || enrolment.Scope != ScopeMesh || len(enrolment.Emits) != 5 {
|
|
t.Fatalf("mesh-enrolment: in the set %v, %+v", ok, enrolment)
|
|
}
|
|
six := []string{"issue", "redeem", "confirm", "revoke", "tokens", "again"}
|
|
// The tunnel key is given at issue (the operator, 2026-11-02 01:05).
|
|
if issue := enrolment.Serves[0]; issue.Name != "issue" || !slices.Contains(issue.Input["required"].([]string), "overlay_key") {
|
|
t.Errorf("issue requires %v", issue.Input["required"])
|
|
}
|
|
holder := func(serves ...string) Manifest {
|
|
return Manifest{Module: "mesh-enrolment", Tools: serves,
|
|
Claims: []Claim{{Name: EnrolmentSeat, Scope: ScopeMesh, Serves: serves}}}
|
|
}
|
|
if err := CanHold(holder(six...), enrolment); err != nil {
|
|
t.Errorf("the holder serving the six verbs was refused: %v", err)
|
|
}
|
|
if err := CanHold(holder(six[:5]...), enrolment); err == nil || !strings.Contains(err.Error(), "does not serve again") {
|
|
t.Errorf("a holder missing again: %v", err)
|
|
}
|
|
if err := CanHold(holder(append(six, "mint")...), enrolment); err == nil || !strings.Contains(err.Error(), "mint") {
|
|
t.Errorf("a holder saying it serves mint: %v", err)
|
|
}
|
|
|
|
was := Seats()
|
|
t.Cleanup(func() { UseSeats(was) })
|
|
UseSeats([]Seat{{Name: "mesh-controller", Scope: ScopeMesh, Decision: "test",
|
|
Serves: []Verb{{Name: "status"}, {Name: "push"}}}})
|
|
seat, _ := SeatNamed("mesh-controller")
|
|
|
|
partial := Manifest{Module: "a-controller", Tools: []string{"status"},
|
|
Claims: []Claim{{Name: "mesh-controller", Scope: ScopeMesh}}}
|
|
err := CanHold(partial, seat)
|
|
if err == nil || !strings.Contains(err.Error(), "does not serve push") {
|
|
t.Fatalf("a holder missing a verb was not refused by name: %v", err)
|
|
}
|
|
whole := Manifest{Module: "a-controller", Tools: []string{"status", "push"},
|
|
Claims: []Claim{{Name: "mesh-controller", Scope: ScopeMesh}}}
|
|
if err := CanHold(whole, seat); err != nil {
|
|
t.Fatalf("a holder serving every verb was refused: %v", err)
|
|
}
|
|
}
|