Files
mesh-controller/internal/link/stale_report_test.go
T
jschoubben 1ebad3786c The mesh says what it applied, and the replay has an address it may use
The pipeline was observable from a merge to an artifact and went dark where it touched a machine: a
node's report is control traffic only the control plane reads, so nothing said which version a
machine runs, or that it refused to (novox/hq ADR 0134). The control plane now states both under the
seat it holds — a role's events belong to the role and keep their address when the holder is
replaced — and only when the report is news, because a machine reconciles every minute and a fact per
report would be a fact per minute per machine.

Whether a report is news is the store's answer: it holds the previous one, so the listener returns it
and the server states the fact. That also gives the catch-up replay a subject the controller may
publish: it was published as a module's event from a module called "control-plane", which does not
exist, so the controller's own account refused it and every catalogue that asked what it missed was
answered with nothing.
2026-09-28 16:07:18 +02:00

136 lines
5.5 KiB
Go

package link
import (
"context"
"errors"
"testing"
)
// Supersession as a check rather than a memory (design 25 §3).
//
// Holding a message in memory let the controller drop an older report when a newer one for the
// same node arrived. On the bus being built the message belongs to the server and comes back
// whatever happened meanwhile — so the older report is redelivered *after* the newer was applied,
// and acting on it would undo the newer.
//
// The answer was already in the message: a report carries the digest of the declaration it is
// about, so "is this the past?" is a question the message answers.
// sentAndHeard records reports and knows what was last sent, which is the pair the check needs.
type sentAndHeard struct {
sent string
heard []Report
err error
}
func (s *sentAndHeard) Heard(_ context.Context, r Report) (bool, error) {
if s.err != nil {
return false, s.err
}
s.heard = append(s.heard, r)
return true, nil
}
func (s *sentAndHeard) Outstanding(context.Context, string) (string, error) { return s.sent, nil }
// A report about a declaration the mesh has moved past is settled and not acted on. Settled rather
// than dropped, because there is nothing wrong with the message — it is simply the past, and
// redelivering it for ever is worse than letting it go.
func TestAReportAboutASupersededDeclarationIsNotActedOn(t *testing.T) {
store := &sentAndHeard{sent: "d2"}
s, in := serving()
s.listener = store
to := &settled{}
s.act(context.Background(), in.sends(t, to, KindReport, aReport("anchor", "d1")))
if len(store.heard) != 0 {
t.Fatalf("a report about a superseded declaration was acted on: %+v", store.heard)
}
if !to.acked {
t.Fatalf("a superseded report was not settled, so it comes back for ever: %+v", *to)
}
}
// The report about the declaration that *is* outstanding is acted on, and so is one from a node
// the mesh has no digest for — an older host that says nothing about which declaration it applied
// has nothing to be judged against, and refusing it would silence every node built before reports
// carried the digest.
func TestAReportAboutTheOutstandingDeclarationIsActedOn(t *testing.T) {
for _, c := range []struct{ what, sent, declared string }{
{"the one outstanding", "d2", "d2"},
{"a report that says nothing about which", "d2", ""},
{"a node nothing was ever sent", "", "d1"},
} {
store := &sentAndHeard{sent: c.sent}
s, in := serving()
s.listener = store
to := &settled{}
s.act(context.Background(), in.sends(t, to, KindReport, aReport("anchor", c.declared)))
if len(store.heard) != 1 || !to.acked {
t.Errorf("%s: was not acted on and acknowledged: heard %+v, settled %+v",
c.what, store.heard, *to)
}
}
}
// **Staleness is decided before the store is waited on**, not after: a redelivery that lost its
// race is not worth holding a slot in the window that a current message needs.
func TestASupersededReportIsNotHeldForTheStore(t *testing.T) {
store := &sentAndHeard{sent: "d2", err: errors.Join(ErrTryAgain, errors.New("starting up"))}
s, in := serving()
s.listener = store
to := &settled{}
s.act(context.Background(), in.sends(t, to, KindReport, aReport("anchor", "d1")))
if !to.acked || len(in.held) != 0 {
t.Fatalf("a superseded report waited for the store: %+v, %d held", *to, len(in.held))
}
}
// **Half of a report is not about a declaration, and that half is never stale.**
//
// What the machine *is* — the tunnel it took over, the ports its own bundle holds, what an adopted
// node found and is keeping, a node moving its overlay key — reaches the mesh on a report and
// nowhere else. A rekey set aside as stale is a node whose overlay key never moves, and no retry is
// coming, because the node said it once. So a report carrying any of these is acted on whenever it
// arrives, however far the mesh has moved on.
func TestAReportCarryingWhatOnlyTheNodeKnowsIsActedOnHoweverOldItIs(t *testing.T) {
for _, c := range []struct {
what string
report Report
}{
{"a rekey", Report{Node: "anchor", Declared: "d1",
Rekey: &Rekey{Previous: "k1", OverlayKey: "k2"}}},
{"the tunnel it carried", Report{Node: "anchor", Declared: "d1",
Tunnel: &CarriedTunnel{Interface: "wg0", State: "taken"}}},
{"what an adopted node holds", Report{Node: "anchor", Declared: "d1",
Held: []Held{{ID: "conf", Module: "web", Kind: "file"}}}},
{"the firewall it found", Report{Node: "anchor", Declared: "d1", Firewall: "ufw"}},
{"what is reachable on it", Report{Node: "anchor", Declared: "d1",
Reachable: []Reach{{Protocol: "tcp", Port: 443}}}},
{"the ports its own bundle holds", Report{Node: "anchor", Declared: "d1",
Carried: []int{5432}}},
} {
store := &sentAndHeard{sent: "d9"}
s, in := serving()
s.listener = store
to := &settled{}
s.act(context.Background(), in.sends(t, to, KindReport, c.report))
if len(store.heard) != 1 {
t.Errorf("%s was set aside as stale, and the mesh will never hear it again: %+v",
c.what, *to)
}
}
}
// A heartbeat is not held for the store: the next one is a minute away, and one kept for two
// minutes to be written late says nothing the one after it will not say better.
func TestAHeartbeatIsNotHeldForTheStore(t *testing.T) {
s, in := serving()
s.listener = heardWith{err: errors.Join(ErrTryAgain, errors.New("starting up"))}
to := &settled{}
s.act(context.Background(), in.sends(t, to, KindHeartbeat, Alive{Node: "anchor"}))
if !to.acked || len(in.held) != 0 {
t.Fatalf("a heartbeat was held for the store: %+v, %d held", *to, len(in.held))
}
}