test(dcl): stabilize flaky DCL002 crash/restart subscription-preservation with condition-based wait (#234)
This commit is contained in:
+14
-3
@@ -76,7 +76,7 @@ public class DataConnectionManagerActorTests : TestKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DCL002_ConnectionActorCrash_PreservesSubscriptionState()
|
public void DCL002_ConnectionActorCrash_PreservesSubscriptionState()
|
||||||
{
|
{
|
||||||
// Regression test for DataConnectionLayer-002. The supervisor used
|
// Regression test for DataConnectionLayer-002. The supervisor used
|
||||||
// Directive.Restart, which discards the connection actor's in-memory
|
// Directive.Restart, which discards the connection actor's in-memory
|
||||||
@@ -103,7 +103,12 @@ public class DataConnectionManagerActorTests : TestKit
|
|||||||
new DataConnectionManagerActor(_mockFactory, _options, _mockHealthCollector)));
|
new DataConnectionManagerActor(_mockFactory, _options, _mockHealthCollector)));
|
||||||
|
|
||||||
manager.Tell(new CreateConnectionCommand("conn1", "OpcUa", new Dictionary<string, string>(), null, 3));
|
manager.Tell(new CreateConnectionCommand("conn1", "OpcUa", new Dictionary<string, string>(), 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.
|
// Register a subscription.
|
||||||
manager.Tell(new SubscribeTagsRequest("c1", "inst1", "conn1", ["tag1"], DateTimeOffset.UtcNow));
|
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.
|
// Crash the connection actor via a synchronously-throwing write.
|
||||||
manager.Tell(new WriteTagRequest("c2", "conn1", "tag1", 42, DateTimeOffset.UtcNow));
|
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
|
// After the crash the subscription state must survive: the health report
|
||||||
// still shows the subscribed/resolved tag. With Restart it would be 0.
|
// still shows the subscribed/resolved tag. With Restart it would be 0.
|
||||||
|
|||||||
Reference in New Issue
Block a user