Files
mesh-controller/internal/broker/agreement_catalogue_test.go
T
jschoubben cc69737934 The agreement check knows the mesh's own roles, and was passing vacuously without them
It read the roles modules declare and not the mesh's own, so the first consumer of a
role's event was skipped as "the emitter is not installed" — which is exactly the
silence the check exists to break. It passed, and it was checking nothing.

Now it is handed the mesh's own roles too, and there is a case pinning that a consumer
of a role event the role does not emit is caught. A check that cannot fail is worse
than no check, because it reads as evidence.
2026-09-27 15:37:21 +02:00

125 lines
4.9 KiB
Go

package broker
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
)
// **Do the catalogue's emitters and consumers agree?**
//
// This is the check whose absence let issue 127 stand: every manifest was individually well-formed,
// every derivation individually correct, and no cross-module subscription in the mesh matched
// anything. A subscription that matches nothing is not an error — it is silence — so nothing
// anywhere reported it.
//
// It compares what one manifest asks to hear against what another says it emits. It cannot demand
// that every consumed event have a live emitter, because a module lives in its own repository and
// may be registered long before the one whose events it wants. Where the emitter *is* here, it must
// emit what the consumer asked for.
func TestTheCataloguesEmittersAndConsumersAgree(t *testing.T) {
emitters, consumers, seats := theCataloguesEvents(t)
if bad := Disagreements(emitters, consumers, seats); len(bad) > 0 {
t.Fatalf("%d subscription(s) in the catalogue would match nothing:\n %s",
len(bad), strings.Join(bad, "\n "))
}
}
// And the check itself catches the thing it exists for, so it cannot pass by doing nothing.
func TestTheAgreementCheckCatchesASubscriptionThatMatchesNothing(t *testing.T) {
bad := Disagreements(
[]AnEmitter{{Module: "builder", Emits: []string{"built"}}},
[]AConsumer{{Module: "mesh-catalog", Consumes: []string{"builder.finished"}}},
nil)
if len(bad) != 1 {
t.Fatalf("a consumer asking for an event its emitter does not emit was not caught: %v", bad)
}
if !strings.Contains(bad[0], "builder.finished") || !strings.Contains(bad[0], "built") {
t.Fatalf("the report names neither what was asked for nor what is emitted: %s", bad[0])
}
// A module that is not here is not a disagreement: it may be registered later.
if bad := Disagreements(nil,
[]AConsumer{{Module: "plex", Consumes: []string{"sonarr.download.completed"}}}, nil); len(bad) != 0 {
t.Fatalf("a consumer whose emitter is not installed was reported: %v", bad)
}
// A wildcard over emitters is deliberate and names no particular event to check.
if bad := Disagreements([]AnEmitter{{Module: "sonarr", Emits: []string{"download.completed"}}},
[]AConsumer{{Module: "plex", Consumes: []string{"*.download.completed"}}}, nil); len(bad) != 0 {
t.Fatalf("a wildcard over emitters was reported: %v", bad)
}
// A consumer of a role's event whose role does not emit it is caught, which is what stops the
// catalogue check above from passing by knowing nothing about roles.
if bad := Disagreements(nil,
[]AConsumer{{Module: "mesh-catalog", Consumes: []string{"mesh-build-machine.finished"}}},
[]DeclaredSeat{{Name: "mesh-build-machine", Emits: []string{"built"}}}); len(bad) != 1 {
t.Fatalf("a consumer of a role event the role does not emit was not caught: %v", bad)
}
// An event published under a seat's name is real even though no module declares it as its own.
if bad := Disagreements(nil,
[]AConsumer{{Module: "watcher", Consumes: []string{"mesh-artifact-store.image.pushed"}}},
[]DeclaredSeat{{Name: "mesh-artifact-store", Emits: []string{"image.pushed"}}}); len(bad) != 0 {
t.Fatalf("an event a seat emits was reported as matching nothing: %v", bad)
}
}
func theCataloguesEvents(t *testing.T) ([]AnEmitter, []AConsumer, []DeclaredSeat) {
t.Helper()
root := filepath.Join("..", "..", "..", "mesh-catalog", "modules")
entries, err := os.ReadDir(root)
if err != nil {
t.Skipf("catalogue sibling not present: %v", err)
}
var emitters []AnEmitter
var consumers []AConsumer
// The mesh's own roles, which emit under the seat's name rather than any module's (novox/hq
// ADR 0121). Without these the check skips every consumer of a role's event as "the emitter is
// not installed" — which is how it passed vacuously the first time one existed.
var seats []DeclaredSeat
for _, own := range catalogue.SeatsWithAProtocol() {
seats = append(seats, DeclaredSeat{Name: own.Name, Accepts: own.Accepts, Emits: own.Emits})
}
for _, e := range entries {
if !e.IsDir() {
continue
}
raw, err := os.ReadFile(filepath.Join(root, e.Name(), "module.json"))
if err != nil {
continue
}
var m struct {
Module string `json:"module"`
Emits []string `json:"emits"`
Consumes []string `json:"consumes"`
Seats []struct {
Name string `json:"name"`
Emits []string `json:"emits"`
} `json:"seats"`
}
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatalf("%s: %v", e.Name(), err)
}
if len(m.Emits) > 0 {
emitters = append(emitters, AnEmitter{Module: m.Module, Emits: m.Emits})
}
if len(m.Consumes) > 0 {
consumers = append(consumers, AConsumer{Module: m.Module, Consumes: m.Consumes})
}
for _, s := range m.Seats {
seats = append(seats, DeclaredSeat{Name: s.Name, Emits: s.Emits})
}
}
if len(emitters) == 0 {
t.Skip("no manifests found beside this checkout")
}
return emitters, consumers, seats
}