package catalogue import ( "encoding/json" "slices" "strings" "testing" ) // 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()) } } }