Files
mesh-controller/cmd/mesh-controller/push_test.go
jschoubben 0a8a592ef4 An empty declaration is sent, so a node drops what it last held (hq 127)
push skipped any node whose declaration composed to zero resources. A
node that HELD something before — the broker opening a placement gave
an adopted node, say — then kept it forever: the empty declaration that
would drop it was never sent, and the node's own heartbeat re-applied
the stale resource with no way for the mesh to say it is gone. Now the
empty declaration is sent; the host drops what the mesh owned and keeps
what it found. A node that never held anything applies it as a no-op.
Surfaced on ace: the foundation-opening fix (#74) removed its only
resource, and the correction could not reach it until this.
2026-09-26 23:32:30 +02:00

77 lines
3.1 KiB
Go

package main
import (
"errors"
"strings"
"testing"
)
// One machine that cannot be worked out is not a reason to leave the mesh unconverged.
//
// A whole-mesh push refused outright the moment any single node failed to resolve, so a module on
// the anchor requiring a provision nobody had assigned a provider for stopped every OTHER machine
// from being sent anything — machines with no relation to the fault, and nothing wrong with them.
// The failure and the punishment were on different machines.
//
// It is the same rule an un-hostable module already follows one level down (a92c11b: one module on
// the wrong machine no longer refuses the whole node), applied one level up.
func TestOneUnresolvableNodeStillLetsTheRestBeSent(t *testing.T) {
sending, refusals := composeEach(
[]string{"anchor", "home-server", "laptop"},
func(node string) (sendable, error) {
if node == "anchor" {
return sendable{}, errors.New(`nothing provides "acme-ca", wanted by route-proxy`)
}
return sendable{Resources: []map[string]any{{"id": node + ".thing"}}}, nil
})
var told []string
for _, s := range sending {
told = append(told, s.node)
}
if strings.Join(told, ",") != "home-server,laptop" {
t.Errorf("a machine with nothing wrong with it was not sent: %v", told)
}
if len(refusals) != 1 || !strings.Contains(refusals[0], "anchor") ||
!strings.Contains(refusals[0], "acme-ca") {
t.Errorf("the machine that could not be worked out was not named with its reason: %v",
refusals)
}
}
// A machine whose declaration composes to nothing is SENT the empty declaration, not skipped
// (novox/hq issue 127): it may have held something before, and only sending the empty
// declaration tells it to drop what the mesh owned. It is never a refusal.
func TestAnEmptyDeclarationIsSentSoTheNodeDropsWhatItHeld(t *testing.T) {
sending, refusals := composeEach([]string{"spare"},
func(string) (sendable, error) { return sendable{}, nil })
if len(sending) != 1 || len(refusals) != 0 {
t.Errorf("an empty declaration must be sent, not skipped or refused: %v / %v", sending, refusals)
}
}
// A push that skipped a machine still ends badly, and says what was sent.
//
// **Skipping is not succeeding.** The mesh is not in the state somebody asked for, so the command
// exits non-zero — but it says how many machines it did reach, because the old message ("nothing
// was sent") was the very claim that had become untrue.
func TestASkippedMachineIsStillAnError(t *testing.T) {
if err := couldNotBeResolved(nil, 3); err != nil {
t.Fatalf("a push that resolved every machine reported a problem: %v", err)
}
err := couldNotBeResolved([]string{"anchor:\nnothing provides \"acme-ca\""}, 2)
if err == nil {
t.Fatal("a push that could not work out a machine reported success")
}
said := err.Error()
if strings.Contains(said, "nothing was sent") {
t.Errorf("the push says nothing was sent, and it sent two machines: %q", said)
}
for _, want := range []string{"anchor", "acme-ca", "2 other node(s) were"} {
if !strings.Contains(said, want) {
t.Errorf("the refusal does not say %q: %q", want, said)
}
}
}