Files
mesh-sdk/go/catalogue/seat_pass_test.go
T
jschoubben 3379b24c80
mesh/delivery merged: source.main moved to novox/mesh-sdk@c861bd8adf96
mesh/delivery-group group fix/1966-seat-pass-shared merged: every member is merged
mesh/check checking 3379b24c8092 on c861bd8adf96 | novox/mesh-sdk#172 in group fix/1966-seat-pass-shared
SeatsToPassOn tests: a claimant whose running manifest does not claim is not counted; the answer names the settling command
Claude-Session: https://claude.ai/code/session_01NcbgfFfQ4Z9UE5jK32PmE5
2026-11-08 15:30:47 +01:00

97 lines
4.4 KiB
Go

package catalogue
import (
"strings"
"testing"
)
func passSeat(t *testing.T) {
t.Helper()
was := Seats()
t.Cleanup(func() { UseSeats(was) })
UseSeats([]Seat{
{Name: "mesh-broker", Scope: ScopeMesh, Delivers: "mesh-bus", Decision: "test"},
{Name: "mesh-dns-resolver", Scope: ScopeMesh, Replicated: true, Decision: "test"},
})
}
func broker(module string) Manifest {
return Manifest{Module: module, Provides: []Offer{{Name: "mesh-bus", Scope: ScopeMesh}},
Claims: []Claim{{Name: "mesh-broker", Scope: ScopeMesh}}}
}
// A module that still runs but no longer claims the seat.
func dropped(module string) Manifest { return Manifest{Module: module} }
func recorded(node, module string) []Held {
return []Held{{Claim: "mesh-broker", Scope: ScopeMesh, Node: node, Module: module}}
}
// novox/hq ADR 0660 "How it is checked", and ADR 0449 §4's original case.
func TestSeatsToPassOn(t *testing.T) {
passSeat(t)
rec := recorded("novox", "old")
cases := []struct {
name string
rec []Held
as []Assignment
to string // "node/module" of the one pass, "" for none
saidW []string
}{
{"holder assigned nowhere, one claimant (ADR 0449 §4)", rec,
[]Assignment{{Node: "novox", Manifest: broker("new")}}, "novox/new", nil},
{"holder assigned but its manifest dropped the claim", rec,
[]Assignment{{Node: "novox", Manifest: dropped("old")}, {Node: "novox", Manifest: broker("new")}}, "novox/new", nil},
{"holder claims but cannot hold the seat", rec,
[]Assignment{{Node: "novox", Manifest: Manifest{Module: "old", Claims: []Claim{{Name: "mesh-broker", Scope: ScopeMesh}}}},
{Node: "ace", Manifest: broker("new")}}, "ace/new", nil},
{"the running build still claims: the holder keeps the seat", rec,
[]Assignment{{Node: "novox", Manifest: broker("old")}, {Node: "novox", Manifest: broker("new")}}, "", nil},
{"one of the holder's two nodes still claims it", rec,
[]Assignment{{Node: "novox", Manifest: dropped("old")}, {Node: "ace", Manifest: broker("old")},
{Node: "g14", Manifest: broker("new")}}, "", nil},
{"holder's manifest unread: still assigned", rec,
[]Assignment{{Node: "novox", Manifest: Manifest{Module: "old"}, Unread: true}, {Node: "novox", Manifest: broker("new")}}, "", nil},
{"an unread assignment is no claimant", rec,
[]Assignment{{Node: "novox", Manifest: dropped("old")}, {Node: "ace", Manifest: Manifest{Module: "new"}, Unread: true}}, "", nil},
{"a claimant whose running manifest does not claim is not counted", rec,
[]Assignment{{Node: "novox", Manifest: dropped("old")}, {Node: "ace", Manifest: dropped("new")}}, "", nil},
{"no claimant keeps the record", rec,
[]Assignment{{Node: "novox", Manifest: dropped("old")}, {Node: "novox", Manifest: dropped("other")}}, "", nil},
{"holder gone, no claimant keeps the record", rec, nil, "", nil},
{"one module on two nodes is two claimants: none passed, said", rec,
[]Assignment{{Node: "novox", Manifest: dropped("old")}, {Node: "ace", Manifest: broker("new")}, {Node: "novox", Manifest: broker("new")}},
"", []string{"old", "new on ace", "new on novox", "seat mesh-broker --to <node>/<module>"}},
{"two claimants, holder gone: said", rec,
[]Assignment{{Node: "novox", Manifest: broker("a")}, {Node: "ace", Manifest: broker("b")}},
"", []string{"a on novox", "b on ace", "seat mesh-broker --to <node>/<module>"}},
{"a seat with two holders on record is not read", append(rec[:1:1], Held{Claim: "mesh-broker", Scope: ScopeMesh, Node: "ace", Module: "x"}),
[]Assignment{{Node: "novox", Manifest: broker("new")}}, "", nil},
{"a replicated seat is never passed",
[]Held{{Claim: "mesh-dns-resolver", Scope: ScopeMesh, Node: "novox", Module: "gone"}},
[]Assignment{{Node: "novox", Manifest: Manifest{Module: "r", Claims: []Claim{{Name: "mesh-dns-resolver", Scope: ScopeMesh}}}}}, "", nil},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
passes, said := SeatsToPassOn(c.rec, c.as)
if c.to == "" && len(passes) != 0 || c.to != "" && len(passes) != 1 {
t.Fatalf("passes=%+v said=%v", passes, said)
}
if c.to != "" {
p := passes[0]
if p.Seat.Name != "mesh-broker" || p.From.Module != "old" || p.To.Node+"/"+p.To.Module != c.to {
t.Fatalf("the pass is %+v", p)
}
}
if (len(c.saidW) == 0) != (len(said) == 0) {
t.Fatalf("said=%v, want %v", said, c.saidW)
}
for _, w := range c.saidW {
if !strings.Contains(said[0], w) {
t.Fatalf("the answer does not say %q: %s", w, said[0])
}
}
})
}
}