Files
mesh-contracts/go/seats/meshmoduleassigner/contract_test.go
T
jschoubben 5e95cbed59 A-316: the assigner's candidate gains added, the version and parts the want it would write carries
The state candidates' value (CandidatesByProposalNodeValue) gains `added`, by module name, each an AddedModule
with `version` and `parts` in the want's own forms. It is a copy of the two properties of the seat mesh-wants'
state wants, because the seat-definition format cannot reuse another repository's seat's forms (includes take only
parts/ of the same repository, and a part holds no state value); a fixture holds both to the want's wire.
Regenerated with seatgen. The node names the first round-2 pass left in fixtures lines equal to base lines are
role names now, the generated tests with them.

Builds: design 47 G A-316 (corrected, hq #594), §626
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 22:48:01 +01:00

109 lines
7.9 KiB
Go

// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package meshmoduleassigner
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/mesh-module-assigner/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
func TestFixtures(t *testing.T) {
cases := []struct {
name, subject, given, wire string
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "a proposal says assignments-proposed", subject: "mesh.seat.mesh-module-assigner.event.assignments-proposed", given: "{\"proposal\":{\"at\":\"2026-11-05T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"module\":\"plex\",\"node\":\"ace\",\"op\":\"place\",\"ports\":{\"32400\":32400}}],\"id\":\"p-20261105t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"move plex\"}}", wire: "{\"proposal\":{\"at\":\"2026-11-05T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"module\":\"plex\",\"node\":\"ace\",\"op\":\"place\",\"ports\":{\"32400\":32400}}],\"id\":\"p-20261105t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"move plex\"}}",
decode: func(b []byte) (any, error) {
var v AssignmentsProposedEvent
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-module-assigner\\.event\\.assignments-proposed$")},
{name: "a node's key", subject: "", given: "{\"decided\":{\"address\":\"10.0.0.2\"},\"modules\":[{\"digest\":\"0123456789abcdef\",\"module\":\"plex\"}],\"node\":\"ace\",\"v\":1}", wire: "{\"decided\":{\"address\":\"10.0.0.2\"},\"modules\":[{\"digest\":\"0123456789abcdef\",\"module\":\"plex\"}],\"node\":\"ace\",\"v\":1}",
decode: func(b []byte) (any, error) {
var v AssignmentsByNodeNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node that came with a tunnel", subject: "", given: "{\"decided\":{\"tunnel\":{\"interface\":\"wg0\",\"peers\":[{\"address\":\"10.77.0.9/32\",\"public-key\":\"k2\"}],\"port\":51820,\"public-key\":\"k1\"}},\"modules\":[],\"node\":\"ace\",\"v\":1}", wire: "{\"decided\":{\"tunnel\":{\"interface\":\"wg0\",\"peers\":[{\"address\":\"10.77.0.9/32\",\"public-key\":\"k2\"}],\"port\":51820,\"public-key\":\"k1\"}},\"modules\":[],\"node\":\"ace\",\"v\":1}",
decode: func(b []byte) (any, error) {
var v AssignmentsByNodeNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a module's key", subject: "", given: "{\"node\":\"ace\",\"placed\":{\"bindings\":{\"database\":{\"module\":\"postgres\",\"node\":\"ace\"}},\"module\":\"plex\",\"ports\":{\"32400\":32400}},\"v\":1}", wire: "{\"node\":\"ace\",\"placed\":{\"bindings\":{\"database\":{\"module\":\"postgres\",\"node\":\"ace\"}},\"module\":\"plex\",\"ports\":{\"32400\":32400}},\"v\":1}",
decode: func(b []byte) (any, error) {
var v AssignmentsByNodeModuleValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a module's key on a watched branch and a build", subject: "", given: "{\"node\":\"home-server\",\"placed\":{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"plex\"},\"v\":1}", wire: "{\"node\":\"home-server\",\"placed\":{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"plex\"},\"v\":1}",
decode: func(b []byte) (any, error) {
var v AssignmentsByNodeModuleValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "an open proposal", subject: "", given: "{\"at\":\"2026-11-05T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"module\":\"plex\",\"node\":\"ace\",\"op\":\"place\",\"ports\":{\"32400\":32400}}],\"id\":\"p-20261105t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"move plex\"}", wire: "{\"at\":\"2026-11-05T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"module\":\"plex\",\"node\":\"ace\",\"op\":\"place\",\"ports\":{\"32400\":32400}}],\"id\":\"p-20261105t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"move plex\"}",
decode: func(b []byte) (any, error) {
var v ProposalsByProposalValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a proposal placing a module on a watched branch at an earlier build", subject: "", given: "{\"at\":\"2026-11-10T12:00:00Z\",\"base\":{\"home-server\":3},\"by\":\"operator\",\"changes\":[{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"nats\",\"node\":\"home-server\",\"op\":\"place\"}],\"id\":\"p-20261110t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"run nats from beta, back one build\"}", wire: "{\"at\":\"2026-11-10T12:00:00Z\",\"base\":{\"home-server\":3},\"by\":\"operator\",\"changes\":[{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"nats\",\"node\":\"home-server\",\"op\":\"place\"}],\"id\":\"p-20261110t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"run nats from beta, back one build\"}",
decode: func(b []byte) (any, error) {
var v ProposalsByProposalValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a candidate, with the modules it adds and what their wants would carry", subject: "", given: "{\"added\":{\"mesh-build-go\":{\"parts\":{\"mesh-build-go:go-binary\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"1.4.0\"}},\"proposal\":\"p-20261105t120000-aabbccdd\",\"v\":1}", wire: "{\"added\":{\"mesh-build-go\":{\"parts\":{\"mesh-build-go:go-binary\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"1.4.0\"}},\"proposal\":\"p-20261105t120000-aabbccdd\",\"v\":1}",
decode: func(b []byte) (any, error) {
var v CandidatesByProposalNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "the bound on an answer", subject: "", given: "{\"v\":1}", wire: "{\"v\":1}",
decode: func(b []byte) (any, error) {
var v PulsesByAnswerProposalNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a seat held once", subject: "", given: "{\"holders\":[{\"module\":\"mesh-delivery-assigner\",\"node\":\"novox\"}],\"scope\":\"mesh\",\"seat\":\"mesh-module-assigner\",\"v\":1}", wire: "{\"holders\":[{\"module\":\"mesh-delivery-assigner\",\"node\":\"novox\"}],\"scope\":\"mesh\",\"seat\":\"mesh-module-assigner\",\"v\":1}",
decode: func(b []byte) (any, error) { var v SeatHoldersBySeatValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a node seat on a node", subject: "", given: "{\"holders\":[{\"module\":\"node-files\",\"node\":\"ace\"}],\"node\":\"ace\",\"scope\":\"node\",\"seat\":\"node-files\",\"v\":1}", wire: "{\"holders\":[{\"module\":\"node-files\",\"node\":\"ace\"}],\"node\":\"ace\",\"scope\":\"node\",\"seat\":\"node-files\",\"v\":1}",
decode: func(b []byte) (any, error) {
var v SeatHoldersBySeatNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
if err != nil {
t.Errorf("%s: does not decode: %v", c.name, err)
continue
}
back, err := json.Marshal(v)
if err != nil {
t.Errorf("%s: does not encode: %v", c.name, err)
continue
}
var got, want any
if err := json.Unmarshal(back, &got); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
}
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
}
}
}