package catalogue import ( "strings" "testing" ) // **A seat's holder on record settles who holds it, and lets the next holder stand beside the // current one** (novox/hq ADR 0131, design 28 task 5.3). Until the record existed, two assignments // whose modules both claimed a seat were refused outright — which left no way to hand a seat over // without a moment where nobody held it, and the control plane finds its own bus through one of // these seats. That moment was the outage of 2026-09-27. func busSeatDelivering(t *testing.T, delivers string) { t.Helper() was := Seats() t.Cleanup(func() { UseSeats(was) }) UseSeats([]Seat{{Name: "mesh-broker", Scope: ScopeMesh, Delivers: delivers, Decision: "test"}}) } func oldBroker() Manifest { return Manifest{Module: "old-broker", Provides: []Offer{{Name: "mesh-bus", Scope: ScopeMesh}}, Claims: []Claim{{Name: "mesh-broker", Scope: ScopeMesh}}} } func newBroker() Manifest { return Manifest{Module: "new-broker", Provides: []Offer{{Name: "mesh-bus", Scope: ScopeMesh}}, Claims: []Claim{{Name: "mesh-broker", Scope: ScopeMesh}}} } // Nothing on record: exactly the old rule. One claimant holds; two are refused. func TestWithNoHolderOnRecordTheSoleClaimantHoldsAndTwoAreRefused(t *testing.T) { busSeatDelivering(t, "mesh-bus") node := Node{Name: "anchor"} held, problems := checkClaims([]Manifest{oldBroker()}, node, nil, nil) if len(problems) != 0 || len(held) != 1 || held[0].Module != "old-broker" { t.Fatalf("a sole claimant did not hold the seat: held=%v problems=%v", held, problems) } _, problems = checkClaims([]Manifest{oldBroker(), newBroker()}, node, nil, nil) if len(problems) != 1 || !strings.Contains(problems[0], "both claim") { t.Fatalf("two claimants with nothing on record were not refused: %v", problems) } } // With a holder on record, the other eligible assignment is silent: not refused, and not holding. func TestTheHolderOnRecordHoldsAndTheOtherClaimantStandsBesideIt(t *testing.T) { busSeatDelivering(t, "mesh-bus") node := Node{Name: "anchor"} record := []Held{{Claim: "mesh-broker", Scope: ScopeMesh, Node: "anchor", Module: "new-broker"}} held, problems := checkClaims([]Manifest{oldBroker(), newBroker()}, node, nil, record) if len(problems) != 0 { t.Fatalf("the assignment beside the holder was refused: %v", problems) } if len(held) != 1 || held[0].Module != "new-broker" { t.Fatalf("the holder on record is not the one holding: %v", held) } } // The record names a node too: an eligible module on another machine holds nothing, and its // machine's set still resolves. func TestAHolderOnRecordElsewhereLeavesThisMachinesClaimantSilent(t *testing.T) { busSeatDelivering(t, "mesh-bus") record := []Held{{Claim: "mesh-broker", Scope: ScopeMesh, Node: "anchor", Module: "new-broker"}} held, problems := checkClaims([]Manifest{oldBroker()}, Node{Name: "laptop"}, nil, record) if len(problems) != 0 || len(held) != 0 { t.Fatalf("a claimant elsewhere than the recorded holder was not simply silent: held=%v problems=%v", held, problems) } } // A record naming a seat's former name still applies to it after a rename (ADR 0122). func TestAHolderRecordedUnderAFormerNameStillHolds(t *testing.T) { busSeatDelivering(t, "mesh-bus") wasAliases := aliases t.Cleanup(func() { UseAliases(wasAliases) }) UseAliases(map[string]string{"the-broker": "mesh-broker"}) record := []Held{{Claim: "the-broker", Scope: ScopeMesh, Node: "anchor", Module: "new-broker"}} held, problems := checkClaims([]Manifest{oldBroker(), newBroker()}, Node{Name: "anchor"}, nil, record) if len(problems) != 0 || len(held) != 1 || held[0].Module != "new-broker" { t.Fatalf("a record under the former name did not settle the seat: held=%v problems=%v", held, problems) } } // CanHold is the one judgement registration and the handover share, against the store's row. func TestCanHoldJudgesClaimScopeAndWhatTheSeatDelivers(t *testing.T) { busSeatDelivering(t, "mesh-bus") seat, _ := SeatNamed("mesh-broker") if err := CanHold(newBroker(), seat); err != nil { t.Fatalf("a module that claims the seat and provides what it delivers was refused: %v", err) } noClaim := Manifest{Module: "quiet", Provides: []Offer{{Name: "mesh-bus", Scope: ScopeMesh}}} if err := CanHold(noClaim, seat); err == nil || !strings.Contains(err.Error(), "does not claim") { t.Fatalf("a module that never claimed the seat was allowed to hold it: %v", err) } wrongScope := newBroker() wrongScope.Claims[0].Scope = ScopeNode if err := CanHold(wrongScope, seat); err == nil || !strings.Contains(err.Error(), "scope") { t.Fatalf("a claim at the wrong scope was allowed: %v", err) } cannotAnswer := Manifest{Module: "amqp-only", Provides: []Offer{{Name: "amqp", Scope: ScopeMesh}}, Claims: []Claim{{Name: "mesh-broker", Scope: ScopeMesh}}} if err := CanHold(cannotAnswer, seat); err == nil || !strings.Contains(err.Error(), `does not provide "mesh-bus"`) { t.Fatalf("a holder that cannot answer for the seat was allowed: %v", err) } // And the judgement follows the store's row, not a compiled copy. busSeatDelivering(t, "amqp") seat, _ = SeatNamed("mesh-broker") if err := CanHold(cannotAnswer, seat); err != nil { t.Fatalf("with the row saying amqp, an amqp provider was refused: %v", err) } }