Issue 1585, S19: the strict parser, every manifest problem function and the judge's tables (192 declarations, about 5,200 lines) and their 244 tests leave; composition keeps its own refusals and the helpers it uses. The catalogue's tests decode the manifests they build. ParseManifest, ParseManifestWith, ParseManifestForInputs, CatalogueProblems and the rest are gone; mesh-delivery-indexer/judge holds them. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
114 lines
3.8 KiB
Go
114 lines
3.8 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// A process resource may declare `bus` (novox/hq ADR 0436 §1): what it emits, the module's own work-queue
|
|
// streams it consumes, the module's own state it reads and writes, whether it reads the router's records of
|
|
// this module's own asks, and the tools and seat verbs it calls. The fixture is mesh-mail's future manifest
|
|
// shape (ADR 0436 §7, §8), copied from mesh-catalog/modules/mesh-mail/module.json and extended as settled by
|
|
// the lead: process id "send" is the manifest's own `id` (internal/catalogue/runtime.go:72-74 is the model for
|
|
// a process id); the account file uses the controller's real JSON tags (modules.go:1041-1056 issueWith).
|
|
func mailSenderProcessManifest(t *testing.T, bus string) string {
|
|
t.Helper()
|
|
process := `{"id":"send","type":"process","run":["./mesh-mail","send"],"user":"mesh-mail-send"`
|
|
if bus != "" {
|
|
process += `,"bus":` + bus
|
|
}
|
|
process += `}`
|
|
// The stream itself is plain here, not retention work-queue: 1179 checks only that a process names a
|
|
// stream the module owns, never its retention — that rule is 1178's (WorkQueueStreamProblems), and is
|
|
// tested against its own fixture there (work_queue_consumer_test.go) so this one stays accepted whether
|
|
// or not a process currently names "mail-sends" in bus.queues.
|
|
return `{"module":"mesh-mail","version":"1","emits":["mail.send.sent","mail.send.failed"],` +
|
|
`"state":["sends"],"streams":[{"name":"mail-sends","events":["mail.send.approved"],"max-age-days":1,` +
|
|
`"max-mib":64}],"resources":[{"id":"account","type":"user","name":"mesh-mail-send"},` + process + `]}`
|
|
}
|
|
|
|
const mailSenderBus = `{"emits":["mail.send.sent","mail.send.failed"],"queues":["mail-sends"],` +
|
|
`"state":["sends"],"asks":true,"invokes":["seat:operator-channel.tell"]}`
|
|
|
|
func strSliceEqual(a, b []string) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for i := range a {
|
|
if a[i] != b[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// 1179/AC5: a process declaring bus is composed with no bus key on the wire, and is otherwise byte for byte
|
|
// what main composes for the same process without bus.
|
|
func TestAProcessesBusNeverReachesTheWire(t *testing.T) {
|
|
withBus, err := decodeForTest([]byte(mailSenderProcessManifest(t, mailSenderBus)))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
withoutBus, err := decodeForTest([]byte(mailSenderProcessManifest(t, "")))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
with := Rendering{Needed: map[string]map[string]string{}}
|
|
outWith, err := Resolution{Node: "novox", Modules: []Manifest{withBus}}.Declaration(with)
|
|
if err != nil {
|
|
t.Fatalf("composing with bus: %v", err)
|
|
}
|
|
outWithout, err := Resolution{Node: "novox", Modules: []Manifest{withoutBus}}.Declaration(with)
|
|
if err != nil {
|
|
t.Fatalf("composing without bus: %v", err)
|
|
}
|
|
var withProcess, withoutProcess map[string]any
|
|
for _, r := range outWith {
|
|
if r["id"] == "mesh-mail.send" {
|
|
withProcess = r
|
|
}
|
|
}
|
|
for _, r := range outWithout {
|
|
if r["id"] == "mesh-mail.send" {
|
|
withoutProcess = r
|
|
}
|
|
}
|
|
if withProcess == nil || withoutProcess == nil {
|
|
t.Fatalf("the process was not composed at all: with=%v without=%v", withProcess, withoutProcess)
|
|
}
|
|
if _, has := withProcess["bus"]; has {
|
|
t.Fatalf("the process resource carried a bus key onto the wire: %v", withProcess)
|
|
}
|
|
delete(withProcess, "bus")
|
|
if !mapsEqual(withProcess, withoutProcess) {
|
|
t.Fatalf("with bus declared, the process composed differently: %+v\nwant: %+v", withProcess, withoutProcess)
|
|
}
|
|
}
|
|
|
|
func mapsEqual(a, b map[string]any) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for k, v := range a {
|
|
bv, ok := b[k]
|
|
if !ok {
|
|
return false
|
|
}
|
|
if av, ok := v.([]any); ok {
|
|
bbv, ok := bv.([]any)
|
|
if !ok || len(av) != len(bbv) {
|
|
return false
|
|
}
|
|
for i := range av {
|
|
if av[i] != bbv[i] {
|
|
return false
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
if v != bv {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|