diff --git a/cmd/mesh-controller/away_integration_test.go b/cmd/mesh-controller/away_integration_test.go index c1d37e74..ff9a4c55 100644 --- a/cmd/mesh-controller/away_integration_test.go +++ b/cmd/mesh-controller/away_integration_test.go @@ -8,6 +8,7 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "testing" "time" @@ -15,6 +16,7 @@ import ( "git.novox.be/novox/mesh-sdk/go/catalogue" "github.com/novox/mesh-controller/internal/broker" + "github.com/novox/mesh-controller/internal/builderkeys" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" "github.com/novox/mesh-controller/internal/testbus" @@ -68,6 +70,16 @@ func TestAPlanGoesOnWithoutAMachineAwayWhenItsTierIsSent(t *testing.T) { var mu sync.Mutex var sends [][]string everyKeyDone(t) // the builds of the tiers: each module is taken from a done key as soon as the walk reaches it + // Except tier 1's module b, whose key is not built until the test says so: a walk that takes it in the same look + // goes on through tier 1's send and overwrites the note of the move before the test reads it (the old build ask + // was where the walk paused). + wholeKeys := openPlanKeys + var holdB atomic.Bool + holdB.Store(true) + openPlanKeys = func() (planKeyReads, func(), error) { + all, done, err := wholeKeys() + return keysHolding{all, "b", &holdB}, done, err + } digests := 0 wasSend := sendRollout sendRollout = func(ctx context.Context, open *stores, names []string) ([]string, error) { @@ -189,7 +201,9 @@ func TestAPlanGoesOnWithoutAMachineAwayWhenItsTierIsSent(t *testing.T) { if !strings.Contains(moved, "laptop was away: sent when it is heard again") || strings.Contains(moved, "anchor") { t.Errorf("1161/AC2: the plan says %q; want laptop named away and not anchor", moved) } - // Tier 1's module is taken from its key, which the walk's look does by itself. + // Tier 1's module is taken from its key once that is built, which the walk's look does by itself. + holdB.Store(false) + askToLook() eventually(t, "tier 1 sent to anchor alone", func() bool { mu.Lock() defer mu.Unlock() @@ -211,3 +225,17 @@ func TestAPlanGoesOnWithoutAMachineAwayWhenItsTierIsSent(t *testing.T) { t.Errorf("1161/AC2: the plan keeps %v away; want laptop", got) } } + +// keysHolding is the stand-in builder's keys but for one module, whose key is not built while held. +type keysHolding struct { + planKeyReads + module string + held *atomic.Bool +} + +func (k keysHolding) Build(ctx context.Context, module, fp string) (builderkeys.Key, error) { + if module == k.module && k.held.Load() { + return builderkeys.Key{Module: module, Fingerprint: fp}, nil + } + return k.planKeyReads.Build(ctx, module, fp) +} diff --git a/cmd/mesh-controller/backups_before_send_integration_test.go b/cmd/mesh-controller/backups_before_send_integration_test.go index 2baca74b..33e30492 100644 --- a/cmd/mesh-controller/backups_before_send_integration_test.go +++ b/cmd/mesh-controller/backups_before_send_integration_test.go @@ -211,8 +211,12 @@ func TestADeliveryThatMovesABackedUpModuleWaitsForItsBackupAndAFailedOneHoldsItA } seats["laptop"].answers("notes", true, "") advancePlans(ctx, open) - if got := read("plan-two"); got.Backups.State != inventory.BackupDone || len(*asked) != 2 { - t.Fatalf("the plan did not go on: %+v builds=%v", got.Backups, *asked) + // One key taken, not two: plan-one and plan-two carry the same module at the same commit, so they share one key + // build id (key_takein.go keyBuildID), and a walk finds a key already taken (keyTakes.taken, plan_keys.go) and takes + // it in no more. So that the smaller count hides no plan that stopped, plan-two's module must be built from that key. + if got := read("plan-two"); got.Backups.State != inventory.BackupDone || len(*asked) != 1 || + got.Modules["notes"].Build == "" || got.Modules["notes"].State == "failed" || got.Modules["notes"].Key && got.Modules["notes"].State == "asked" { + t.Fatalf("the plan did not go on: %+v module=%+v builds=%v", got.Backups, got.Modules["notes"], *asked) } if said, _ := probeBackupHeld(ctx, &doctor{open: open}); len(said) != 0 { t.Fatalf("the condition stays: %+v", said)