From e7896494f1d56b727f7b6fd84193e23ed7b62f22 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 22 Oct 2026 10:35:22 -0400 Subject: [PATCH] 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. --- .../RedeployStaticOverrideResetTests.cs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Actors/RedeployStaticOverrideResetTests.cs b/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Actors/RedeployStaticOverrideResetTests.cs index b736ffb6..2ee5174d 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Actors/RedeployStaticOverrideResetTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Actors/RedeployStaticOverrideResetTests.cs @@ -397,12 +397,29 @@ public class RedeployStaticOverrideResetTests : TestKit, IDisposable Assert.True(ExpectMsg().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(); + for (var i = 0; i < 4; i++) + stopped.Add(ExpectMsg(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(TimeSpan.FromSeconds(2)); + Assert.Equal(queuedName, superseded.InstanceUniqueName); + Assert.Equal(DeploymentStatus.Failed, superseded.Status); transaction.Commit(); }