From 7674b37a24dba20783b76a026641fbdb3af603f0 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 19 Jun 2026 00:33:48 -0400 Subject: [PATCH] test(dcl): stabilize flaky DCL002 crash/restart subscription-preservation with condition-based wait (#234) --- .../DataConnectionManagerActorTests.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs index 77a47908..093f0ccf 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs @@ -76,7 +76,7 @@ public class DataConnectionManagerActorTests : TestKit } [Fact] - public async Task DCL002_ConnectionActorCrash_PreservesSubscriptionState() + public void DCL002_ConnectionActorCrash_PreservesSubscriptionState() { // Regression test for DataConnectionLayer-002. The supervisor used // Directive.Restart, which discards the connection actor's in-memory @@ -103,7 +103,12 @@ public class DataConnectionManagerActorTests : TestKit new DataConnectionManagerActor(_mockFactory, _options, _mockHealthCollector))); manager.Tell(new CreateConnectionCommand("conn1", "OpcUa", new Dictionary(), null, 3)); - await Task.Delay(300); // connection actor reaches Connected + // Wait until the connection actor has called ConnectAsync (i.e. reached Connected) + // rather than sleeping a fixed 300 ms that can expire before the async connect + // completes under CPU contention. + AwaitCondition( + () => mockAdapter.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ConnectAsync"), + TimeSpan.FromSeconds(5)); // Register a subscription. manager.Tell(new SubscribeTagsRequest("c1", "inst1", "conn1", ["tag1"], DateTimeOffset.UtcNow)); @@ -111,7 +116,13 @@ public class DataConnectionManagerActorTests : TestKit // Crash the connection actor via a synchronously-throwing write. manager.Tell(new WriteTagRequest("c2", "conn1", "tag1", 42, DateTimeOffset.UtcNow)); - await Task.Delay(300); // supervisor handles the failure + // Wait until WriteAsync was invoked, proving the WriteTagRequest was fully + // processed by the connection actor (and the supervisor's Resume directive + // applied) before we query health. A fixed sleep can expire before the + // actor processes the message under CPU load. + AwaitCondition( + () => mockAdapter.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "WriteAsync"), + TimeSpan.FromSeconds(5)); // After the crash the subscription state must survive: the health report // still shows the subscribed/resolved tag. With Restart it would be 0.