A build that reported applied was sent everywhere; one that then did nothing, served no tools or broke its machine's word reached every machine. Now the first machine is judged by the component's health (the core's definitions, as doctor probes H-*, or a module's own) three times over two minutes within ten; a failing gate puts the previous build back there once, marks the build, and says it as a condition and an event. Upgrades roll out by default; the bus is a planned step; a module deleted at its source is not built (the public-acme plan failure).
60 lines
2.3 KiB
Go
60 lines
2.3 KiB
Go
package lease
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// The host's judgement of a new controller, held here as the host holds it (mesh-host internal/witness):
|
|
// the lease held by a controller on this machine, taken since the new build started, and fresh.
|
|
func TestTheWitnessJudgesANewControllerByTheLease(t *testing.T) {
|
|
started := time.Date(2026, 10, 6, 12, 0, 0, 0, time.UTC)
|
|
now := started.Add(30 * time.Second)
|
|
fresh := Holder{Instance: "controller@control pid 2", Host: "control.example", Taken: started.Add(5 * time.Second),
|
|
Renewed: now.Add(-3 * time.Second), Epoch: 9}
|
|
if ok, why := fresh.HeldBySince("control", started, now); !ok {
|
|
t.Fatalf("a new controller holding the lease was not healthy: %s", why)
|
|
}
|
|
old := fresh
|
|
old.Taken = started.Add(-time.Minute)
|
|
if ok, _ := old.HeldBySince("control", started, now); ok {
|
|
t.Error("the controller from before the build counted as the new one")
|
|
}
|
|
elsewhere := fresh
|
|
elsewhere.Host = "other"
|
|
if ok, _ := elsewhere.HeldBySince("control", started, now); ok {
|
|
t.Error("a controller on another machine counted")
|
|
}
|
|
stale := fresh
|
|
stale.Renewed = now.Add(-20 * time.Second)
|
|
stale.Taken = stale.Renewed
|
|
if ok, _ := stale.HeldBySince("control", started.Add(-time.Minute), now); ok {
|
|
t.Error("a lease not renewed within its age counted as held")
|
|
}
|
|
if ok, _ := (Holder{}).HeldBySince("control", started, now); ok {
|
|
t.Error("nobody counted as the holder")
|
|
}
|
|
}
|
|
|
|
// The outcomes the operator is woken for, and the subjects the host reads.
|
|
func TestTheWitnessContractsWords(t *testing.T) {
|
|
for outcome, urgent := range map[string]bool{OutcomeRolledBack: true, OutcomeNotReversible: true,
|
|
OutcomeRestoreFailed: true, OutcomeHalted: true, OutcomeNothingToRestore: false, OutcomeUnwitnessed: false} {
|
|
if Urgent(outcome) != urgent {
|
|
t.Errorf("%s urgent: %v", outcome, Urgent(outcome))
|
|
}
|
|
}
|
|
if got := LeaseReadSubject("mesh-controller_lease"); got != "$JS.API.DIRECT.GET.KV_mesh-controller_lease.$KV.mesh-controller_lease.holder" {
|
|
t.Errorf("the lease is read on %s", got)
|
|
}
|
|
if got := PingSubject("ace"); got != "$SRV.PING.node-tools.ace" {
|
|
t.Errorf("the node tools are asked on %s", got)
|
|
}
|
|
for c, m := range map[string]string{ComponentController: "mesh-controller", ComponentEngine: "mesh-host",
|
|
ComponentNodeTools: "node-tools"} {
|
|
if ModuleOf(c) != m {
|
|
t.Errorf("%s is delivered as %s", c, ModuleOf(c))
|
|
}
|
|
}
|
|
}
|