package catalogue import ( "strings" "testing" ) func problemsFor(t *testing.T, shelf Shelf) string { t.Helper() return strings.Join(CatalogueProblems(shelf), "; ") } func telegram() Manifest { return Manifest{Module: "telegram", Tools: []string{"status"}, DefinesSeats: []SeatDeclaration{{ Name: "telegram-sender", Scope: ScopeMesh, Accepts: []string{"send"}, Emits: []string{"delivered", "failed"}, Serves: []string{"status"}, }}, Claims: []Claim{{Name: "telegram-sender", Scope: ScopeMesh}}} } // The whole point: a module contributes a capability without the mesh being changed. func TestAModuleDeclaresItsOwnSeatAndHoldsIt(t *testing.T) { shop := Manifest{Module: "shop", Uses: []string{"telegram-sender"}} if got := problemsFor(t, Shelf{"telegram": telegram(), "shop": shop}); got != "" { t.Fatalf("a declared seat and its caller were refused: %s", got) } } // The prefix is the reservation rule, so there is no list to maintain and none to drift. func TestAModuleCannotDeclareAMeshSeat(t *testing.T) { for _, n := range []string{"mesh-broker", "mesh-anything", "mesh-store"} { m := Manifest{Module: "impostor", DefinesSeats: []SeatDeclaration{{Name: n, Accepts: []string{"x"}}}} got := strings.Join(declaredSeatProblems(m), "; ") if !strings.Contains(got, "reserved to the mesh") { t.Fatalf("%q was accepted as a module's seat: %q", n, got) } } } // A seat name meaning two protocols is the failure nobody could diagnose afterwards. func TestTwoModulesCannotDeclareTheSameSeat(t *testing.T) { other := Manifest{Module: "aardvark", DefinesSeats: []SeatDeclaration{{ Name: "telegram-sender", Scope: ScopeMesh, Accepts: []string{"something-else"}}}} got := problemsFor(t, Shelf{"telegram": telegram(), "aardvark": other}) if !strings.Contains(got, "already declares") { t.Fatalf("both declarations stood: %s", got) } // The first declarer keeps it; only the second is refused. if strings.Count(got, "already declares") != 1 { t.Fatalf("expected exactly one refusal: %s", got) } } // Where ADR 0110's guarantee lands under a derived set: a typo is refused, not resolved to // nothing at runtime. func TestUsingASeatNobodyDeclaresIsRefused(t *testing.T) { shop := Manifest{Module: "shop", Uses: []string{"telegram-sendr"}} got := problemsFor(t, Shelf{"telegram": telegram(), "shop": shop}) if !strings.Contains(got, "telegram-sendr") || !strings.Contains(got, "no module declares") { t.Fatalf("a misspelled seat was accepted: %s", got) } } // A holder that does not answer what the seat promises is a caller's timeout, found here instead. func TestAHolderMustServeWhatItsSeatPromises(t *testing.T) { m := telegram() m.Tools = nil // declares the seat, serves none of it got := problemsFor(t, Shelf{"telegram": m}) if !strings.Contains(got, "does not serve status") { t.Fatalf("a holder was accepted that answers nothing its seat promises: %s", got) } } // A seat with no protocol is a marker: which module is this node's showcase, or its packet filter. // Most node-scoped seats are markers, so refusing one would refuse the majority of the set. func TestASeatWithoutAProtocolIsAMarkerNotAMistake(t *testing.T) { m := Manifest{Module: "vague", DefinesSeats: []SeatDeclaration{{Name: "something", Scope: ScopeNode}}} if got := strings.Join(declaredSeatProblems(m), "; "); got != "" { t.Fatalf("a marker seat was refused: %s", got) } } // A claim at the wrong scope is a different seat than the one declared. func TestAClaimMustMatchTheDeclaredScope(t *testing.T) { m := telegram() m.Claims = []Claim{{Name: "telegram-sender", Scope: ScopeNode}} got := problemsFor(t, Shelf{"telegram": m}) if !strings.Contains(got, "scope") { t.Fatalf("a claim at the wrong scope was accepted: %s", got) } } // The mesh's own seats still work, and are not shadowed by the derived half. func TestTheMeshsOwnSeatsAreStillClaimable(t *testing.T) { // It delivers the bus, so its holder provides the bus — the rule this check now enforces. m := Manifest{Module: "nats", Provides: []Offer{{Name: "mesh-bus", Scope: ScopeMesh}}, Claims: []Claim{{Name: "mesh-broker", Scope: ScopeMesh}}} if got := problemsFor(t, Shelf{"nats": m}); got != "" { t.Fatalf("a mesh seat was refused by the derived check: %s", got) } } // A refusal that reorders itself between runs is a refusal nobody can diff. func TestTheProblemsAreStable(t *testing.T) { shelf := Shelf{"telegram": telegram(), "shop": {Module: "shop", Uses: []string{"nope"}}, "other": {Module: "other", Uses: []string{"also-nope"}}} first, second := problemsFor(t, shelf), problemsFor(t, shelf) if first != second { t.Fatalf("unstable:\n%s\n%s", first, second) } } // **A build machine has no store, so it may not judge a seat.** The set is data the control plane // owns (novox/hq ADR 0122), and `ParseManifest` runs on the build machine too, against whatever set // that binary was compiled with. When the two disagreed, a valid holder of the bus seat was refused // mid-rollout — the compiled row said the seat delivered one provision, the store's row said // another, and the build failed on the copy rather than the truth. The parser judges the manifest; // the seat set judges the claim, where it is loaded. func TestTheParserDoesNotJudgeWhatOnlyTheStoreKnows(t *testing.T) { was := Seats() t.Cleanup(func() { UseSeats(was) }) // A store whose bus seat delivers something this module does provide. UseSeats([]Seat{{Name: "mesh-broker", Scope: ScopeMesh, Delivers: "mesh-bus", Decision: "test"}}) raw := []byte(`{"module":"a-bus","version":"1",` + `"provides":[{"name":"mesh-bus","scope":"mesh"}],` + `"claims":[{"name":"mesh-broker","scope":"mesh"}]}`) m, err := ParseManifest(raw) if err != nil { t.Fatalf("the parser refused a claim only the seat set can judge: %v", err) } if got := CatalogueProblems(Shelf{m.Module: m}); len(got) != 0 { t.Fatalf("a holder that provides what the store says the seat delivers was refused: %v", got) } // And with the store saying the seat delivers something else, registration is what refuses it. UseSeats([]Seat{{Name: "mesh-broker", Scope: ScopeMesh, Delivers: "other-bus", Decision: "test"}}) if _, err := ParseManifest(raw); err != nil { t.Fatalf("the parser judged it the second time: %v", err) } got := strings.Join(CatalogueProblems(Shelf{m.Module: m}), "; ") if !strings.Contains(got, `does not provide "other-bus"`) { t.Fatalf("registration did not refuse a holder that cannot answer for the seat: %q", got) } }