diff --git a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploySiteAsyncTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploySiteAsyncTests.cs index d4fb73b7..463c98a1 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploySiteAsyncTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploySiteAsyncTests.cs @@ -434,7 +434,14 @@ public class DeploySiteAsyncTests : TestKit var commActor = Sys.ActorOf(Props.Create(() => new SilentQuerySiteActor(() => Interlocked.Increment(ref queryCount)))); - var reconcileTimeout = TimeSpan.FromMilliseconds(300); + // The deadline must dwarf scheduler/JIT jitter (#92): the reconcile deadline + // covers the repo reads and the Ask itself, so a deadline of a few hundred ms + // can expire before the query is even sent when the full suite runs in + // parallel, and the old fixed 2 s wall-clock cap was blown by ~2.3 s of + // starvation on top of 6 x 300 ms. The breaker is proven STRUCTURALLY by the + // query count below; the elapsed check is only a coarse "not six deadlines" + // bound whose threshold is derived from the deadline, not a magic number. + var reconcileTimeout = TimeSpan.FromSeconds(2); var service = CreateService(commActor, maxParallelism: 3, reconcileTimeout: reconcileTimeout); var sw = Stopwatch.StartNew(); @@ -446,8 +453,10 @@ public class DeploySiteAsyncTests : TestKit // The circuit-breaker opened after the first unanswered reconcile. Assert.Equal(1, Volatile.Read(ref queryCount)); - // Prepare therefore cost ONE reconcile deadline, not six. - Assert.True(sw.Elapsed < TimeSpan.FromSeconds(2), + // Prepare therefore cost ONE reconcile deadline, not six: without the breaker + // the serial prepare alone would take >= instanceCount x deadline. + var withoutBreakerFloor = instanceCount * reconcileTimeout; + Assert.True(sw.Elapsed < withoutBreakerFloor - reconcileTimeout, $"bulk prepare took {sw.ElapsedMilliseconds} ms — the per-batch reconcile bound is not holding"); // A skipped reconcile is not a failed deploy: every instance still went out.