9dc26459ea
gates / gates (push) Successful in 10s
R-218's declaration half shipped in v0.201.0 and works. Its consume half never existed. Reconcile ran exactly twice per process — at start-up and when the recovery screen drives it — and BOTH fire before the hub has anything staged, because the hub stages in RESPONSE to the declaration those runs precede. Measured on the R-201 re-walk: unlock reconcile 11:43:07, hub staged 11:44:57 saying 'next cycle', a full report cycle ran 11:55:46, still unconsumed at 12:06. A guest command line applied it in 18 seconds — everything correct except the trigger. Bridge.RetryIfDeclared re-runs the SAME reconcile on a 5-minute tick, driven from the box's own published declaration (OffboxReportStatus().State) — the very statement the hub acts on, so the two cannot disagree. Poll, not an ACK flag, decided on the promise: the no-target message says 'amint megvannak' (no deadline) and the card says 'within a day'. Five minutes is inside both by a wide margin and needs no hub change. It stops by construction — a healthy box does no work and logs nothing — and the settle gate is deliberately kept via ReconcileWhenSettled. The marker was investigated and left alone: applied_marker lives in the guest's DataDir, which a rebuild destroys, so it cannot suppress a legitimate re-run. R-220's customer half: the refusal no longer tells the customer to choose from a list that may be empty. It names the rebuild, points at the Meghajtók page, and promises no outcome. Red-proofs: remove the retry -> credential uncollected (the dead end reproduced); drop the stop condition -> a healthy box hammers the hub; call Reconcile instead of ReconcileWhenSettled -> settle gate bypassed; restore the old sentence -> the impossible action returns. 28 packages ok, vet clean, all controller gates OK.
102 lines
4.6 KiB
Go
102 lines
4.6 KiB
Go
package offsiteapply
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// ── R-218's CONSUME HALF ─────────────────────────────────────────────────────────────────────────
|
|
//
|
|
// Measured on the R-201 re-walk, 2026-08-06: the hub staged a credential at 11:44:57 and logged
|
|
// "the box re-consumes on its next cycle"; a full report cycle ran at 11:55:46; at 12:06 it was still
|
|
// unconsumed, and a guest command line applied it in 18 seconds. Everything was correct except that
|
|
// nothing ever re-ran the reconcile.
|
|
//
|
|
// These assert the EFFECT — was a reconcile attempted, and did the tier get applied — not that a
|
|
// helper returned a bool.
|
|
|
|
// ── SCENARIO A — a credential staged AFTER start-up is collected, unaided ────────────────────────
|
|
//
|
|
// RED-PROOF: make RetryIfDeclared return (false, nil) unconditionally — i.e. remove the retry, which
|
|
// is the pre-v0.203.0 world — and this FAILS with the credential still sitting unconsumed. That is
|
|
// the re-walk's first dead end, reproduced.
|
|
func TestRetryIfDeclared_CollectsACredentialStagedAfterStartup(t *testing.T) {
|
|
b, cons, _, en, _ := newBridge(t, goodOffsite())
|
|
|
|
// The box declares: it was rebuilt, has no target, and the hub holds a package for it.
|
|
attempted, err := b.RetryIfDeclared(context.Background(), func() bool { return true })
|
|
if err != nil {
|
|
t.Fatalf("retry: %v", err)
|
|
}
|
|
if !attempted {
|
|
t.Fatal("R-218 RETURNED: the box declared a need and no reconcile was attempted")
|
|
}
|
|
// EFFECT: the one-time password was actually consumed and the tier configured.
|
|
if cons.calls == 0 {
|
|
t.Fatal("the staged credential was never collected")
|
|
}
|
|
if en.calls == 0 {
|
|
t.Fatal("the off-site tier was never configured after collecting the credential")
|
|
}
|
|
}
|
|
|
|
// ── SCENARIO C — a healthy box does not retry, and makes no noise ────────────────────────────────
|
|
//
|
|
// RED-PROOF: drop the `!declared()` guard so the tick always reconciles → this FAILS, and a box whose
|
|
// tier already works hammers the hub forever.
|
|
func TestRetryIfDeclared_HealthyBoxDoesNothing(t *testing.T) {
|
|
b, cons, inst, en, logbuf := newBridge(t, goodOffsite())
|
|
|
|
attempted, err := b.RetryIfDeclared(context.Background(), func() bool { return false })
|
|
if err != nil {
|
|
t.Fatalf("retry: %v", err)
|
|
}
|
|
if attempted {
|
|
t.Fatal("a box that declares NO need must not reconcile")
|
|
}
|
|
if cons.calls != 0 || inst.calls != 0 || en.calls != 0 {
|
|
t.Fatalf("a healthy box touched the hub: consume=%d install=%d enable=%d", cons.calls, inst.calls, en.calls)
|
|
}
|
|
if strings.TrimSpace(logbuf.String()) != "" {
|
|
t.Fatalf("a healthy box logged noise every tick: %q", logbuf.String())
|
|
}
|
|
}
|
|
|
|
// A nil bridge (off-site not configured for this customer) is a silent no-op, not a panic — main.go
|
|
// wires nil in exactly that case.
|
|
func TestRetryIfDeclared_NilBridgeIsSilent(t *testing.T) {
|
|
var b *Bridge
|
|
attempted, err := b.RetryIfDeclared(context.Background(), func() bool { return true })
|
|
if attempted || err != nil {
|
|
t.Fatalf("a nil bridge must be a silent no-op, got attempted=%v err=%v", attempted, err)
|
|
}
|
|
}
|
|
|
|
// ── SCENARIO D — the settle gate still holds on the retry path ───────────────────────────────────
|
|
//
|
|
// The retry must not become a back door around the day-0 floor race the gate exists for. It goes
|
|
// through ReconcileWhenSettled, so an unsettled box WAITS rather than reconciling immediately.
|
|
//
|
|
// RED-PROOF: change RetryIfDeclared to call Reconcile directly instead of ReconcileWhenSettled →
|
|
// this FAILS, because the reconcile happens while the floor is still unknown.
|
|
func TestRetryIfDeclared_HonoursTheSettleGate(t *testing.T) {
|
|
b, cons, _, _, _ := newBridge(t, goodOffsite())
|
|
// Floor never becomes known → the gate must hold the reconcile off until its own bound expires.
|
|
b.Settle = SettleFunc(func() (string, string, bool, bool) { return "0.203.0", "", false, false })
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel() // the gate observes a cancelled context and must not proceed to reconcile
|
|
|
|
attempted, err := b.RetryIfDeclared(ctx, func() bool { return true })
|
|
if !attempted {
|
|
t.Fatal("the box declared, so a retry attempt must be reported even when the gate stops it")
|
|
}
|
|
if err == nil {
|
|
t.Fatal("a cancelled gate must surface an error, not silently reconcile")
|
|
}
|
|
if cons.calls != 0 {
|
|
t.Fatal("SETTLE GATE BYPASSED: the retry consumed a password while the floor was unknown")
|
|
}
|
|
}
|