Files
mesh-sdk/go/catalogue/reader_release_test.go
T
jschoubben 09d6070ebd
mesh/delivery merged: source.main moved to novox/mesh-sdk@e42b9491c931
mesh/delivery-group group fix/47-G-reader-release-2 merged: every member is merged
mesh/check checking 09d6070ebd86 on e42b9491c931 | novox/mesh-sdk#188 in group fix/47-G-reader-release-2
RR2-5: the reader reads a seat-named view in consumes and a seat's views
G's builder and checker follow the assigner's views by the seat,
seat:mesh-module-assigner.views.assignments; SeatViewConsume splits that
form, and a seat compiled from its definition names the states it offers
as views, which the validator checks the form against.

Builds: design 47 G §621, §616, §699

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 03:09:33 +01:00

102 lines
5.5 KiB
Go

package catalogue
import (
"encoding/json"
"slices"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/seatdef"
)
// A manifest carrying the words design 47 G writes is read whole by the reader release (design 47 G §340, §409):
// `version` as MAJOR.MINOR (§368), a `*` emitter in `consumes` (§386), an observer's finding stream (§387) and an
// artifact's `needs` (§47, §432).
func TestTheReaderReleaseReadsTheManifestWordsGWrites(t *testing.T) {
m, err := decodeForTest([]byte(`{"module":"mesh-watcher","version":"1.4","needs-approval":["restart","node-engine.composition","finding-written"],` +
`"consumes":["*.finding-written","mesh-conditions.findings-asked"],` +
`"streams":[{"name":"mesh-watcher-findings","events":["finding-written","finding-cleared","findings-stated"],"max-age-days":7,"max-mib":16}],` +
`"build":{"artifacts":[{"name":"program","kind":"bundle","language":"go","needs":["mesh-grants:program","node-tools:runtime"]}]}}`))
if err != nil {
t.Fatalf("a manifest with G's words was refused: %v", err)
}
if len(m.UnknownField()) != 0 || len(m.NeedsApproval) != 3 {
t.Fatalf("a word was set aside: %v (needs-approval %v)", m.UnknownField(), m.NeedsApproval)
}
if m.Version != "1.4" || m.Consumes[0] != "*.finding-written" || m.Streams[0].Name != "mesh-watcher-findings" ||
len(m.Build.Artifacts[0].Needs) != 2 || m.Build.Artifacts[0].Needs[0] != "mesh-grants:program" {
t.Fatalf("read as %+v", m)
}
}
// The second reader release reads the words G's manifests write beyond the first's (design 47 G §494, §621): each row a
// manifest read whole, or refused naming what is wrong, and what the reader gives of it.
func TestTheSecondReaderReleaseReadsGsManifestWords(t *testing.T) {
for _, c := range []struct {
name, raw, refused string
check func(Manifest) bool
}{
{name: "a state's cap (§469)", raw: `{"module":"m","version":"1.0","state":["plain",{"name":"pipelines","max-mib":256}]}`,
check: func(m Manifest) bool { return m.State[0].MaxMiB == 0 && m.State[1].MaxMiB == 256 }},
{name: "a state's cap out of the objects section's bounds (§469)",
raw: `{"module":"m","version":"1.0","state":[{"name":"pipelines","max-mib":0}]}`, refused: "max-mib is between 1 and 8192"},
{name: "a package's calls and the tool runner's states (§605, §545)",
raw: `{"module":"m","version":"1.0","build":{"artifacts":[{"name":"go","kind":"package","language":"go","calls":["put-sessions"]},` +
`{"name":"runtime","kind":"bundle","language":"go","states":["put-sessions","finding-calls"]}]}}`,
check: func(m Manifest) bool {
a := m.Build.Artifacts
return len(a) == 2 && len(a[0].Calls) == 1 && a[0].Calls[0] == "put-sessions" && len(a[1].States) == 2
}},
{name: "* with two long-form invokes (§617)",
raw: `{"module":"m","version":"1.0","invokes":["*",{"verb":"seat:mesh-catalog.revision","fields":["none-yet"]},` +
`{"verb":"seat:mesh-catalog.entry"}]}`,
check: func(m Manifest) bool {
out, _ := json.Marshal(m)
return slices.Equal(m.Invokes, []string{"*", "seat:mesh-catalog.revision", "seat:mesh-catalog.entry"}) &&
len(m.InvokeFields) == 1 && slices.Equal(m.InvokeFields["seat:mesh-catalog.revision"], []string{"none-yet"}) &&
strings.Contains(string(out), `"invokes":["*",{"verb":"seat:mesh-catalog.revision","fields":["none-yet"]},"seat:mesh-catalog.entry"]`)
}},
{name: "a long-form invoke with a word it does not know (§617)",
raw: `{"module":"m","version":"1.0","invokes":[{"verb":"seat:mesh-catalog.revision","field":["none-yet"]}]}`,
refused: `invokes[0]: a verb, or {verb, fields}`},
} {
m, err := decodeForTest([]byte(c.raw))
switch {
case c.refused != "" && (err == nil || !strings.Contains(err.Error(), c.refused)):
t.Errorf("%s: read as %v, want refused naming %q", c.name, err, c.refused)
case c.refused == "" && err != nil:
t.Errorf("%s: refused: %v", c.name, err)
case c.refused == "" && (len(m.UnknownField()) != 0 || !c.check(m)):
t.Errorf("%s: read as %+v (set aside %v)", c.name, m, m.UnknownField())
}
}
}
// A consumed view of a seat, `seat:<seat>.views.<state>`, is read apart from a consumed event, and a seat's compiled form
// names the states its definition offers as views (design 47 G §616, §699, §621).
func TestTheSecondReaderReleaseReadsASeatNamedView(t *testing.T) {
for _, row := range []struct {
consume, seat, state string
ok, bad bool
}{
{"seat:mesh-module-assigner.views.assignments", "mesh-module-assigner", "assignments", true, false},
{"mesh-delivery-assigner.views.assignments", "", "", false, false},
{"seat:mesh-module-assigner.assignments", "", "", true, true},
{"seat:.views.assignments", "", "", true, true},
} {
seat, state, ok, err := SeatViewConsume(row.consume)
if seat != row.seat || state != row.state || ok != row.ok || (err != nil) != row.bad {
t.Errorf("SeatViewConsume(%q) = %q, %q, %v, %v", row.consume, seat, state, ok, err)
}
}
m, err := decodeForTest([]byte(`{"module":"m","version":"1.0","consumes":["seat:mesh-module-assigner.views.assignments"]}`))
if err != nil || len(m.UnknownField()) != 0 || m.Consumes[0] != "seat:mesh-module-assigner.views.assignments" {
t.Errorf("a seat-named view in consumes read as %v, %v", m.Consumes, err)
}
s := SeatFromDefinition(seatdef.Definition{Seat: "mesh-module-assigner", Scope: "mesh",
States: []seatdef.State{{Name: "assignments", View: true}, {Name: "placement"}}})
if !slices.Equal(s.Views, []string{"assignments"}) {
t.Errorf("the seat's views = %v", s.Views)
}
}