test(site-runtime): SR5 cancel-queued-redeploy test observes which predecessor is queued instead of assuming Queued4

Deploys are compile-warmed off the actor thread and reach the four-slot
predecessor-stop queue in warm-completion order (cross-instance ordering is
not guaranteed by design). Since SR-P5 moved the config deserialization into
that warm task, the fifth-sent deploy often finishes warming before one of the
first four, takes a slot, and Queued4 terminated inside the 100 ms no-message
window (16/20 failures under parallel load). The test now waits for the four
in-flight predecessors to terminate, cancels the one still alive, and also
asserts the cancelled redeploy is answered Failed/superseded.
This commit is contained in:
Joseph Doherty
2026-10-22 10:35:22 -04:00
parent 7be22d2ac2
commit e7896494f1
@@ -397,12 +397,29 @@ public class RedeployStaticOverrideResetTests : TestKit, IDisposable
Assert.True(ExpectMsg<SetStaticAttributeResponse>().Success);
manager.Tell(new DeployInstanceCommand("next" + i, name, "sha256:next", MakeConfigJson(name), "admin", DateTimeOffset.UtcNow), pending.Ref);
}
Watch(actors[4]);
// Each deploy is compile-warmed off the actor thread and only reaches the four-slot
// predecessor-stop queue when ITS warm completes, so cross-instance arrival order is not
// the send order (by design — only same-instance ordering is guaranteed). Which instance
// ends up queued is therefore not necessarily "Queued4": observe it rather than assume it.
// The four in-flight predecessors terminate promptly (Terminated does not wait for the
// flush); the fifth must stay alive while every flush slot is pinned by the blocker.
foreach (var actor in actors) Watch(actor);
var stopped = new HashSet<IActorRef>();
for (var i = 0; i < 4; i++)
stopped.Add(ExpectMsg<Terminated>(TimeSpan.FromSeconds(5)).ActorRef);
ExpectNoMsg(TimeSpan.FromMilliseconds(100)); // fifth predecessor waits for one of four flush slots
var queuedIndex = actors.FindIndex(actor => !stopped.Contains(actor));
Assert.Equal(4, stopped.Count);
var queuedName = "Queued" + queuedIndex;
var cancellation = CreateTestProbe();
if (delete) manager.Tell(new DeleteInstanceCommand("cancel", "Queued4", DateTimeOffset.UtcNow), cancellation.Ref);
else manager.Tell(new DisableInstanceCommand("cancel", "Queued4", DateTimeOffset.UtcNow), cancellation.Ref);
ExpectTerminated(actors[4], TimeSpan.FromSeconds(2));
if (delete) manager.Tell(new DeleteInstanceCommand("cancel", queuedName, DateTimeOffset.UtcNow), cancellation.Ref);
else manager.Tell(new DisableInstanceCommand("cancel", queuedName, DateTimeOffset.UtcNow), cancellation.Ref);
ExpectTerminated(actors[queuedIndex], TimeSpan.FromSeconds(2));
// The cancelled redeploy is answered as superseded; the four others are still parked
// behind their blocked flushes, so this is the only reply so far.
var superseded = pending.ExpectMsg<DeploymentStatusResponse>(TimeSpan.FromSeconds(2));
Assert.Equal(queuedName, superseded.InstanceUniqueName);
Assert.Equal(DeploymentStatus.Failed, superseded.Status);
transaction.Commit();
}