Merge pull request 'The node-engine passes seats with the SDK's one rule, by the build its node runs, and says the pass (ADR 0660, issue 1966, recovery)' (#212) from fix/1966-seat-pass-shared into main
This commit was merged in pull request #212.
This commit is contained in:
@@ -60,7 +60,8 @@ type Declared struct {
|
|||||||
ForeseenPorts []string
|
ForeseenPorts []string
|
||||||
// CoreBoxesWanted are the core credentials whose box the send must ask the vault for and keep.
|
// CoreBoxesWanted are the core credentials whose box the send must ask the vault for and keep.
|
||||||
CoreBoxesWanted []CoreBoxWanted
|
CoreBoxesWanted []CoreBoxWanted
|
||||||
// Passes are the seats the mesh would pass on, for the caller to record, and Said the lines found while composing.
|
// Passes are the seats composed as passed to their only claimant (ADR 0660), recorded by nobody here, and Said the lines found
|
||||||
|
// while composing, the passes among them.
|
||||||
Passes Passes
|
Passes Passes
|
||||||
Said []string
|
Said []string
|
||||||
}
|
}
|
||||||
@@ -228,6 +229,8 @@ func (c *composer) declaration(nodeName string, mode Mode) (Declared, error) {
|
|||||||
return Declared{}, err
|
return Declared{}, err
|
||||||
}
|
}
|
||||||
out.Passes = passes
|
out.Passes = passes
|
||||||
|
// A pass is composed, never recorded (ADR 0660 §4): the answer says it, with what two claimants leave unsettled.
|
||||||
|
out.Said = append(out.Said, passes.Lines()...)
|
||||||
for _, l := range left {
|
for _, l := range left {
|
||||||
out.Said = append(out.Said, l.String())
|
out.Said = append(out.Said, l.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
package resolution
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SeatsToPassOn reads the mesh for seats held once whose holder on record has left (novox/hq ADR 0449 §4).
|
|
||||||
//
|
|
||||||
// **A holder on record that is assigned on no machine holds nothing, and a seat that answers nothing is
|
|
||||||
// the day a delivery removed its module.** Of such a seat, exactly one assignment in the mesh able to hold
|
|
||||||
// it (it claims the seat at its scope and CanHold accepts it) takes it over: that is a pass, and the caller
|
|
||||||
// records it and writes the hand act. With no such assignment the record stays; with two or more nothing is
|
|
||||||
// recorded and the answer says so, naming both and the `seat --to` that settles it. A holder still assigned
|
|
||||||
// anywhere changes nothing: the other claimants stand beside it, eligible and silent (ADR 0131). Only mesh
|
|
||||||
// seats held once are read: a replicated seat's holders are added by an act (ADR 0223), a kinded bench is held
|
|
||||||
// by its claims, and a seat with several holders on record is a store that disagrees with the mesh (refused
|
|
||||||
// by the resolver).
|
|
||||||
func SeatsToPassOn(holdings []mcat.Held, assignments []mcat.Assignment) ([]mcat.SeatPass, []string) {
|
|
||||||
assigned := map[string]bool{}
|
|
||||||
for _, a := range assignments {
|
|
||||||
assigned[a.Manifest.Module] = true
|
|
||||||
}
|
|
||||||
bySeat := map[string][]mcat.Held{}
|
|
||||||
var order []string
|
|
||||||
for _, h := range holdings {
|
|
||||||
s, ok := mcat.SeatNamed(h.Claim)
|
|
||||||
if !ok || s.Replicated || s.Scope != mcat.ScopeMesh || h.Scope != mcat.ScopeMesh || mcat.KindedBenches[s.Name] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, seen := bySeat[s.Name]; !seen {
|
|
||||||
order = append(order, s.Name)
|
|
||||||
}
|
|
||||||
bySeat[s.Name] = append(bySeat[s.Name], h)
|
|
||||||
}
|
|
||||||
sort.Strings(order)
|
|
||||||
|
|
||||||
var passes []mcat.SeatPass
|
|
||||||
var said []string
|
|
||||||
for _, name := range order {
|
|
||||||
recs := bySeat[name]
|
|
||||||
if len(recs) != 1 || assigned[recs[0].Module] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seat, _ := mcat.SeatNamed(name)
|
|
||||||
var claimants []mcat.Held
|
|
||||||
for _, a := range assignments {
|
|
||||||
if mcat.CanHold(a.Manifest, seat) != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
claimants = append(claimants, mcat.Held{Claim: seat.Name, Scope: seat.Scope, Node: a.Node, Module: a.Manifest.Module})
|
|
||||||
}
|
|
||||||
sort.Slice(claimants, func(i, j int) bool {
|
|
||||||
if claimants[i].Node != claimants[j].Node {
|
|
||||||
return claimants[i].Node < claimants[j].Node
|
|
||||||
}
|
|
||||||
return claimants[i].Module < claimants[j].Module
|
|
||||||
})
|
|
||||||
switch len(claimants) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
passes = append(passes, mcat.SeatPass{Seat: seat, From: recs[0], To: claimants[0]})
|
|
||||||
default:
|
|
||||||
said = append(said, fmt.Sprintf(
|
|
||||||
"%s on %s is on record as the holder of %q and is assigned nowhere, and %s on %s and %s on %s both claim it "+
|
|
||||||
"— nothing is recorded; `seat %s --to <node>/<module>` records the one that holds it",
|
|
||||||
recs[0].Module, recs[0].Node, seat.Name, claimants[0].Module, claimants[0].Node,
|
|
||||||
claimants[1].Module, claimants[1].Node, seat.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return passes, said
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package resolution
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
||||||
)
|
|
||||||
|
|
||||||
func onRecord(node, module string) []mcat.Held {
|
|
||||||
return []mcat.Held{{Claim: "mesh-broker", Scope: mcat.ScopeMesh, Node: node, Module: module}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1317/AC1
|
|
||||||
func TestASeatWhoseHolderIsAssignedNowhereIsPassedToItsOnlyClaimant(t *testing.T) {
|
|
||||||
busSeatDelivering(t, "mesh-bus")
|
|
||||||
passes, said := SeatsToPassOn(onRecord("novox", "old-broker"),
|
|
||||||
[]mcat.Assignment{{Node: "novox", Manifest: newBroker()}})
|
|
||||||
if len(said) != 0 || len(passes) != 1 {
|
|
||||||
t.Fatalf("the only claimant was not given the seat: passes=%v said=%v", passes, said)
|
|
||||||
}
|
|
||||||
p := passes[0]
|
|
||||||
if p.Seat.Name != "mesh-broker" || p.From.Module != "old-broker" || p.From.Node != "novox" ||
|
|
||||||
p.To.Module != "new-broker" || p.To.Node != "novox" {
|
|
||||||
t.Fatalf("the pass does not name the seat, the former holder and the new one: %+v", p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1317/AC2
|
|
||||||
func TestWithTwoClaimantsAndTheHolderGoneNothingIsPassedAndTheRefusalNamesBoth(t *testing.T) {
|
|
||||||
busSeatDelivering(t, "mesh-bus")
|
|
||||||
passes, said := SeatsToPassOn(onRecord("novox", "gone"), []mcat.Assignment{
|
|
||||||
{Node: "novox", Manifest: newBroker()}, {Node: "ace", Manifest: oldBroker()}})
|
|
||||||
if len(passes) != 0 || len(said) != 1 {
|
|
||||||
t.Fatalf("two claimants: passes=%v said=%v", passes, said)
|
|
||||||
}
|
|
||||||
for _, want := range []string{"old-broker", "new-broker", "seat mesh-broker --to"} {
|
|
||||||
if !strings.Contains(said[0], want) {
|
|
||||||
t.Fatalf("the refusal does not say %q: %s", want, said[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1317/AC3
|
|
||||||
func TestAHolderStillAssignedSomewhereChangesNothing(t *testing.T) {
|
|
||||||
busSeatDelivering(t, "mesh-bus")
|
|
||||||
// Assigned on another machine than the record names: still assigned somewhere.
|
|
||||||
passes, said := SeatsToPassOn(onRecord("novox", "old-broker"), []mcat.Assignment{
|
|
||||||
{Node: "ace", Manifest: oldBroker()}, {Node: "novox", Manifest: newBroker()}})
|
|
||||||
if len(passes) != 0 || len(said) != 0 {
|
|
||||||
t.Fatalf("a holder still assigned lost its seat: passes=%v said=%v", passes, said)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1317/AC4
|
|
||||||
func TestWithNoClaimantTheRecordStays(t *testing.T) {
|
|
||||||
busSeatDelivering(t, "mesh-bus")
|
|
||||||
passes, said := SeatsToPassOn(onRecord("novox", "old-broker"), []mcat.Assignment{
|
|
||||||
{Node: "novox", Manifest: mcat.Manifest{Module: "other"}}})
|
|
||||||
if len(passes) != 0 || len(said) != 0 {
|
|
||||||
t.Fatalf("with no claimant: passes=%v said=%v", passes, said)
|
|
||||||
}
|
|
||||||
// A claimant that cannot hold the seat (it does not provide what the seat delivers) is no claimant.
|
|
||||||
bad := mcat.Manifest{Module: "no-bus", Claims: []mcat.Claim{{Name: "mesh-broker", Scope: mcat.ScopeMesh}}}
|
|
||||||
passes, said = SeatsToPassOn(onRecord("novox", "old-broker"), []mcat.Assignment{{Node: "novox", Manifest: bad}})
|
|
||||||
if len(passes) != 0 || len(said) != 0 {
|
|
||||||
t.Fatalf("a module that cannot hold the seat was passed it: passes=%v said=%v", passes, said)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A replicated seat is never passed: its holders are added by an act (ADR 0223).
|
|
||||||
func TestAReplicatedSeatIsNeverPassed(t *testing.T) {
|
|
||||||
record := []mcat.Held{{Claim: "mesh-dns-resolver", Scope: mcat.ScopeMesh, Node: "novox", Module: "gone"}}
|
|
||||||
resolver := mcat.Manifest{Module: "resolver", Provides: []mcat.Offer{{Name: "wildcard-resolution", Scope: mcat.ScopeMesh}},
|
|
||||||
Claims: []mcat.Claim{{Name: "mesh-dns-resolver", Scope: mcat.ScopeMesh}}}
|
|
||||||
passes, _ := SeatsToPassOn(record, []mcat.Assignment{{Node: "novox", Manifest: resolver}})
|
|
||||||
if len(passes) != 0 {
|
|
||||||
t.Fatalf("a replicated seat was passed: %v", passes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+37
-14
@@ -25,9 +25,10 @@ func unresolvable(err error) bool {
|
|||||||
return errors.As(err, &n)
|
return errors.As(err, &n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Passes is what a composition found that the mesh must record, and did not: each seat held once whose holder on record
|
// Passes is what a composition found and composed with: each seat held once whose holder on record has left it (assigned
|
||||||
// is assigned nowhere that exactly one claimant takes over (novox/hq ADR 0449 clause 4), and the lines that say what was
|
// nowhere, or none of its assignments' manifests claims the seat) that exactly one claimant takes over (novox/hq ADR 0449
|
||||||
// found. The caller records a pass and writes its hand act; this package does neither.
|
// clause 4, widened by ADR 0660), and the lines that say what was found. A pass is composed and said, never recorded: neither
|
||||||
|
// this package nor its caller writes the holdings (ADR 0660 clause 4).
|
||||||
type Passes struct {
|
type Passes struct {
|
||||||
// Passes are the seats to pass, in the order they were found.
|
// Passes are the seats to pass, in the order they were found.
|
||||||
Passes []catalogue.SeatPass
|
Passes []catalogue.SeatPass
|
||||||
@@ -92,8 +93,8 @@ func (c *composer) theRestOfTheMeshNow(exclude string) (catalogue.World, Passes,
|
|||||||
pins map[string]catalogue.Chosen
|
pins map[string]catalogue.Chosen
|
||||||
}
|
}
|
||||||
var others []candidate
|
var others []candidate
|
||||||
// Every machine's assignments, before the holdings are read by any resolution (novox/hq ADR 0449 clause 4): a seat
|
// Every machine's assignments, before the holdings are read by any resolution (novox/hq ADR 0449 clause 4, ADR 0660): a
|
||||||
// held once whose holder on record is assigned on no machine passes to its only claimant here.
|
// seat held once whose holder on record has left it passes to its only claimant here, composed and not recorded.
|
||||||
everyAssigned := map[string][]string{}
|
everyAssigned := map[string][]string{}
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
if len(n.Assigned) > 0 {
|
if len(n.Assigned) > 0 {
|
||||||
@@ -101,7 +102,7 @@ func (c *composer) theRestOfTheMeshNow(exclude string) (catalogue.World, Passes,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var passes Passes
|
var passes Passes
|
||||||
holdings, passes = passSeatsOn(holdings, assignmentsOf(shelf, everyAssigned))
|
holdings, passes = passSeatsOn(holdings, c.assignmentsOf(shelf, everyAssigned))
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
if n.Name == exclude {
|
if n.Name == exclude {
|
||||||
continue
|
continue
|
||||||
@@ -175,11 +176,11 @@ func (c *composer) theRestOfTheMeshNow(exclude string) (catalogue.World, Passes,
|
|||||||
return world, passes, left, nil
|
return world, passes, left, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// passSeatsOn finds, in the composition that finds it, the new holder of each seat held once whose holder on record is
|
// passSeatsOn finds, in the composition that finds it, the new holder of each seat held once whose holder on record has left
|
||||||
// assigned nowhere and which has exactly one claimant able to hold it (novox/hq ADR 0449 clause 4), and answers the
|
// it and which has exactly one claimant able to hold it (catalogue.SeatsToPassOn, novox/hq ADR 0660), and answers the
|
||||||
// holdings as they are after it, with the passes. Nothing is recorded.
|
// holdings as they are after it, with the passes. Nothing is recorded.
|
||||||
func passSeatsOn(holdings []catalogue.Held, assignments []catalogue.Assignment) ([]catalogue.Held, Passes) {
|
func passSeatsOn(holdings []catalogue.Held, assignments []catalogue.Assignment) ([]catalogue.Held, Passes) {
|
||||||
passes, said := resolution.SeatsToPassOn(holdings, assignments)
|
passes, said := catalogue.SeatsToPassOn(holdings, assignments)
|
||||||
out := Passes{Said: said}
|
out := Passes{Said: said}
|
||||||
for _, p := range passes {
|
for _, p := range passes {
|
||||||
out.Passes = append(out.Passes, p)
|
out.Passes = append(out.Passes, p)
|
||||||
@@ -196,9 +197,11 @@ func passSeatsOn(holdings []catalogue.Held, assignments []catalogue.Assignment)
|
|||||||
return holdings, out
|
return holdings, out
|
||||||
}
|
}
|
||||||
|
|
||||||
// assignmentsOf are the assignments of every machine, as the passing of a seat reads them. A module assigned and
|
// assignmentsOf are the assignments of every machine, as the passing of a seat reads them (novox/hq ADR 0660 clause 2): each
|
||||||
// missing from the shelf is still assigned: an assignment with no claims, so its holder is not taken for gone.
|
// with the manifest of the build its node runs where the Input holds it (the node's Kept: what it runs of a module kept at
|
||||||
func assignmentsOf(shelf map[string]catalogue.Manifest, assigned map[string][]string) []catalogue.Assignment {
|
// that build), else the trunk's on the shelf, which for the composing node's own modules is already the build they are
|
||||||
|
// wanted at. A module assigned and missing from both is still assigned, marked unread, so its holder is not taken for gone.
|
||||||
|
func (c *composer) assignmentsOf(shelf map[string]catalogue.Manifest, assigned map[string][]string) []catalogue.Assignment {
|
||||||
var out []catalogue.Assignment
|
var out []catalogue.Assignment
|
||||||
names := make([]string, 0, len(assigned))
|
names := make([]string, 0, len(assigned))
|
||||||
for node := range assigned {
|
for node := range assigned {
|
||||||
@@ -206,17 +209,37 @@ func assignmentsOf(shelf map[string]catalogue.Manifest, assigned map[string][]st
|
|||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, node := range names {
|
for _, node := range names {
|
||||||
|
var kept map[string]catalogue.Manifest
|
||||||
|
for _, n := range c.in.Nodes {
|
||||||
|
if n.Name == node {
|
||||||
|
kept = n.Kept
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, module := range assigned[node] {
|
for _, module := range assigned[node] {
|
||||||
m, ok := shelf[module]
|
m, ok := kept[module]
|
||||||
|
if !ok {
|
||||||
|
m, ok = shelf[module]
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
m = catalogue.Manifest{Module: module}
|
m = catalogue.Manifest{Module: module}
|
||||||
}
|
}
|
||||||
out = append(out, catalogue.Assignment{Node: node, Manifest: m})
|
out = append(out, catalogue.Assignment{Node: node, Manifest: m, Unread: !ok})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lines are what the passes say, one each, then what the finding itself says: a pass is composed so and recorded by nobody
|
||||||
|
// (ADR 0660 clause 4).
|
||||||
|
func (p Passes) Lines() []string {
|
||||||
|
var out []string
|
||||||
|
for _, x := range p.Passes {
|
||||||
|
out = append(out, fmt.Sprintf("%s: %s on %s is on record as its holder and holds it no more; composed as held by %s on %s, not recorded",
|
||||||
|
x.Seat.Name, x.From.Module, x.From.Node, x.To.Module, x.To.Node))
|
||||||
|
}
|
||||||
|
return append(out, p.Said...)
|
||||||
|
}
|
||||||
|
|
||||||
// servedOnNode is what a module on a node tells a consumer of one of its provisions, with THAT node's ports on it: the
|
// servedOnNode is what a module on a node tells a consumer of one of its provisions, with THAT node's ports on it: the
|
||||||
// port the node was given over the one the mesh assigned over the manifest's own, settled with the node's settings
|
// port the node was given over the one the mesh assigned over the manifest's own, settled with the node's settings
|
||||||
// layers. The one derivation for every reader of a provider's address.
|
// layers. The one derivation for every reader of a provider's address.
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
|
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
|
||||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||||
"github.com/novox/mesh-host/internal/compose/resolution"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// objects and files are the provider and consumer of mesh-controller's facts_test.go aMeshWithSecrets (cmd/mesh-controller at
|
// objects and files are the provider and consumer of mesh-controller's facts_test.go aMeshWithSecrets (cmd/mesh-controller at
|
||||||
@@ -184,9 +183,9 @@ func TestNoSeatIsPassedForTwoClaimantsAnAssignedHolderOrNoClaimant(t *testing.T)
|
|||||||
// seat_pass_test.go TestAHolderAssignedButNotOnTheShelfIsNotTakenForGone.
|
// seat_pass_test.go TestAHolderAssignedButNotOnTheShelfIsNotTakenForGone.
|
||||||
func TestAHolderAssignedButNotOnTheShelfIsNotTakenForGone(t *testing.T) {
|
func TestAHolderAssignedButNotOnTheShelfIsNotTakenForGone(t *testing.T) {
|
||||||
withSeat(t)
|
withSeat(t)
|
||||||
as := assignmentsOf(map[string]catalogue.Manifest{"gate": aBrokerClaiming("gate")},
|
as := (&composer{}).assignmentsOf(map[string]catalogue.Manifest{"gate": aBrokerClaiming("gate")},
|
||||||
map[string][]string{"novox": {"gate", "old-broker"}})
|
map[string][]string{"novox": {"gate", "old-broker"}})
|
||||||
passes, _ := resolution.SeatsToPassOn(
|
passes, _ := catalogue.SeatsToPassOn(
|
||||||
[]catalogue.Held{{Claim: "mesh-broker", Scope: catalogue.ScopeMesh, Node: "novox", Module: "old-broker"}}, as)
|
[]catalogue.Held{{Claim: "mesh-broker", Scope: catalogue.ScopeMesh, Node: "novox", Module: "old-broker"}}, as)
|
||||||
if len(passes) != 0 {
|
if len(passes) != 0 {
|
||||||
t.Fatalf("a holder missing from the shelf lost its seat: %+v", passes)
|
t.Fatalf("a holder missing from the shelf lost its seat: %+v", passes)
|
||||||
@@ -230,3 +229,53 @@ func TestEachNodeIsResolvedWithItsOwnPinsInTheRestOfTheMesh(t *testing.T) {
|
|||||||
t.Fatalf("a pin to a provider that does not answer did not leave the consumer out: %v %v", left, err)
|
t.Fatalf("a pin to a provider that does not answer did not leave the consumer out: %v %v", left, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ADR 0660: a holder on record that is still assigned, whose manifest no longer claims the seat, has left it; the seat is
|
||||||
|
// composed with the one claimant, the pass is returned and said, and Input's holdings (the record) are not written.
|
||||||
|
func TestAHolderWhoseManifestDroppedTheSeatGoesToItsOnlyClaimant(t *testing.T) {
|
||||||
|
withSeat(t)
|
||||||
|
mk := func(claimants ...string) Input {
|
||||||
|
cat := map[string]catalogue.Manifest{"old-broker": {Module: "old-broker"}}
|
||||||
|
assigned := []string{"old-broker"}
|
||||||
|
for _, c := range claimants {
|
||||||
|
cat[c] = aBrokerClaiming(c)
|
||||||
|
assigned = append(assigned, c)
|
||||||
|
}
|
||||||
|
return Input{Catalogue: cat,
|
||||||
|
Nodes: []Node{{Name: "novox", Place: Place{Site: "here"}, Assigned: assigned}},
|
||||||
|
Holdings: []catalogue.Held{{Claim: "mesh-broker", Scope: catalogue.ScopeMesh, Node: "novox", Module: "old-broker", Site: "here"}}}
|
||||||
|
}
|
||||||
|
in := mk("gate")
|
||||||
|
w, passes, _, err := TheRestOfTheMesh(in, "")
|
||||||
|
if err != nil || len(passes.Passes) != 1 || passes.Passes[0].To.Module != "gate" || passes.Passes[0].From.Module != "old-broker" {
|
||||||
|
t.Fatalf("%v %+v", err, passes)
|
||||||
|
}
|
||||||
|
if len(w.Holdings) != 1 || w.Holdings[0].Module != "gate" {
|
||||||
|
t.Fatalf("the composition does not hold the pass: %+v", w.Holdings)
|
||||||
|
}
|
||||||
|
unchanged(t, func() Input { return mk("gate") }, func(in Input) {
|
||||||
|
if _, _, _, err := TheRestOfTheMesh(in, ""); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
_, passes, _, err = TheRestOfTheMesh(mk("gate", "other"), "")
|
||||||
|
said := strings.Join(passes.Said, "\n")
|
||||||
|
if err != nil || len(passes.Passes) != 0 || !strings.Contains(said, "gate") || !strings.Contains(said, "other") ||
|
||||||
|
!strings.Contains(said, "seat mesh-broker --to <node>/<module>") {
|
||||||
|
t.Fatalf("two claimants: %v %+v", err, passes)
|
||||||
|
}
|
||||||
|
// The build the holder's node runs still claims the seat, though the trunk dropped it: the holder keeps it (ADR 0660 §2).
|
||||||
|
running := mk("gate")
|
||||||
|
running.Nodes[0].Kept = map[string]catalogue.Manifest{"old-broker": aBrokerClaiming("old-broker")}
|
||||||
|
_, passes, _, err = TheRestOfTheMesh(running, "")
|
||||||
|
if err != nil || len(passes.Passes) != 0 || len(passes.Said) != 0 {
|
||||||
|
t.Fatalf("a holder whose running build claims the seat lost it: %v %+v", err, passes)
|
||||||
|
}
|
||||||
|
// And a pass is said in the composition's answer, not recorded.
|
||||||
|
var d Declared
|
||||||
|
d, _, err = Compose(mk("gate"), "novox")
|
||||||
|
said = strings.Join(d.Said, "\n")
|
||||||
|
if err != nil || !strings.Contains(said, "mesh-broker: old-broker on novox") || !strings.Contains(said, "held by gate on novox, not recorded") {
|
||||||
|
t.Fatalf("the answer does not say the pass: %v %q", err, said)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user