package link import ( "encoding/json" "os" "path/filepath" "regexp" "strings" "testing" "time" "github.com/novox/mesh-controller/internal/beside" ) // The Go implementation, held to the shared fixtures (novox/hq ADR 0074, design 19). // // **Read from the SDK's own conformance directory, never copied by hand**: a fixture written into each // implementation is two fixtures, and two fixtures drift, which is the failure the suite exists to prevent. // Which SDK is read is named, never the one a desktop happens to hold beside this checkout (novox/hq issue // 449): in a merge check the SDK the build seat clones beside it, at the commit this controller's go.mod // pins, and a missing clone fails the test; elsewhere the copy captured in testdata/beside at that same // commit (internal/beside, testdata/beside/CAPTURED), held to go.mod by TestTheCapturedSDKIsTheOneGoModPins. 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(beside.Dir(t, "mesh-sdk"), "conformance", name) raw, err := os.ReadFile(path) if err != nil { // Failed, never skipped: a skip here passed the suite with nothing judged. t.Fatalf("the SDK's conformance fixture %s: %v", name, err) } var f fixture if err := json.Unmarshal(raw, &f); err != nil { t.Fatalf("%s: %v", name, err) } return f } // The captured SDK is the one this controller is built against: when go.mod moves the SDK, the copy moves // with it, or the tests away from a merge check judge an SDK the controller no longer uses (novox/hq issue // 449). func TestTheCapturedSDKIsTheOneGoModPins(t *testing.T) { mod, err := os.ReadFile(filepath.Join("..", "..", "go.mod")) if err != nil { t.Fatal(err) } pinned := regexp.MustCompile(`(?m)^\s*git\.novox\.be/novox/mesh-sdk/go v\S+-([0-9a-f]{12})$`).FindSubmatch(mod) if pinned == nil { t.Fatal("go.mod pins no commit of git.novox.be/novox/mesh-sdk/go as a pseudo-version; say here how a " + "release's tag is matched against testdata/beside/CAPTURED") } captured, err := os.ReadFile(filepath.Join(beside.Captured(), "CAPTURED")) if err != nil { t.Fatal(err) } at := regexp.MustCompile(`(?m)^mesh-sdk\s+([0-9a-f]{40})\s`).FindSubmatch(captured) if at == nil { t.Fatal("testdata/beside/CAPTURED names no commit for mesh-sdk") } if !strings.HasPrefix(string(at[1]), string(pinned[1])) { t.Errorf("the SDK is captured at %s but go.mod pins %s: capture it again at the pinned commit, as "+ "testdata/beside/CAPTURED says", at[1], pinned[1]) } } // 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", } }