package link import ( "encoding/json" "os" "path/filepath" "regexp" "testing" "time" ) // The Go implementation, held to the shared fixtures (novox/hq ADR 0074, design 19). // // **Read from the sdk's conformance directory by sibling path**, the way the lab finds its // siblings — deliberately not copied here. A fixture copied into each implementation is two // fixtures, and two fixtures drift, which is the exact failure the suite exists to prevent. type fixture struct { Name string `json:"name"` Given struct { Module string `json:"module"` Node string `json:"node"` Key string `json:"key"` Body map[string]any `json:"body"` Headers map[string]string `json:"headers"` } `json:"given"` Wire struct { Subject string `json:"subject"` RequiredHeaders []string `json:"requiredHeaders"` HeaderFormats map[string]string `json:"headerFormats"` } `json:"wire"` } func loadFixture(t *testing.T, name string) fixture { t.Helper() path := filepath.Join("..", "..", "..", "mesh-sdk", "conformance", name) raw, err := os.ReadFile(path) if err != nil { t.Skipf("the sdk's conformance fixtures are not beside this checkout: %v", err) } var f fixture if err := json.Unmarshal(raw, &f); err != nil { t.Fatalf("%s: %v", name, err) } return f } // Every header the fixture requires is one this implementation actually sets. func TestTheGoEmitterSetsEveryRequiredHeader(t *testing.T) { f := loadFixture(t, "events/module-event.json") sent := goEventHeaders(f.Given.Key, f.Given.Module, f.Given.Node) for _, want := range f.Wire.RequiredHeaders { if _, ok := sent[want]; !ok { t.Errorf("the Go emitter does not set %q, which the fixture requires — an event it "+ "emits is one a conforming consumer refuses", want) } } } // And each value is in the shape the fixture pins, because a header present but differently // formatted is the disagreement that does not announce itself. func TestTheGoEmittersHeaderFormatsMatch(t *testing.T) { f := loadFixture(t, "events/module-event.json") sent := goEventHeaders(f.Given.Key, f.Given.Module, f.Given.Node) if got := sent["content-type"]; got != f.Wire.HeaderFormats["content-type"] { t.Errorf("content-type is %q, the fixture says %q", got, f.Wire.HeaderFormats["content-type"]) } if _, err := time.Parse(time.RFC3339, sent["x-time"]); err != nil { t.Errorf("x-time %q is not RFC3339, which the fixture requires: %v", sent["x-time"], err) } if pattern := f.Wire.HeaderFormats["x-event-id"]; pattern != "" { if !regexp.MustCompile(pattern).MatchString(sent["x-event-id"]) { t.Errorf("x-event-id %q does not match %q", sent["x-event-id"], pattern) } } // The origin the envelope claims is the one the bus enforces by namespace. A disagreement // here means the envelope is lying about where it came from. if sent["x-source"] != f.Given.Module { t.Errorf("x-source is %q for module %q", sent["x-source"], f.Given.Module) } } // The subject a module's event lands on is derived, not carried — so this implementation must // derive the same one the fixture names. func TestTheGoSubjectMatchesTheFixture(t *testing.T) { f := loadFixture(t, "events/module-event.json") got := "mesh.mod." + f.Given.Module + ".event." + f.Given.Key if got != f.Wire.Subject { t.Errorf("this implementation would publish on %q; the fixture says %q", got, f.Wire.Subject) } } // goEventHeaders is the header set EmitEvent produces, factored so conformance can see it // without a broker. Kept beside the emitter so the two cannot drift apart silently. func goEventHeaders(eventType, source, node string) map[string]string { id, err := eventID() if err != nil { panic(err) } return map[string]string{ "x-event-id": id, "x-source": source, "x-node": node, "x-time": time.Now().UTC().Format(time.RFC3339), "content-type": "application/json", } }