test(dcl): de-race MxGateway Unsubscribe stops-routing under load (#288)
This commit is contained in:
+17
-1
@@ -5,6 +5,12 @@ using ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters;
|
|||||||
|
|
||||||
namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests.Adapters;
|
namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests.Adapters;
|
||||||
|
|
||||||
|
// Non-parallel with the rest of the DataConnectionManagerActor collection: these adapter
|
||||||
|
// tests pump a fire-and-forget event loop (ConnectAsync → Task.Run(RunEventLoopAsync)) whose
|
||||||
|
// thread-pool continuation must run before the WaitUntil attach-barrier observes
|
||||||
|
// fake.OnUpdate. Serializing within the assembly trims in-assembly thread-pool contention so
|
||||||
|
// that barrier (and the negative Unsubscribe assertion that follows it) is not starved.
|
||||||
|
[Collection("DataConnectionManagerActor")]
|
||||||
public class MxGatewayDataConnectionTests
|
public class MxGatewayDataConnectionTests
|
||||||
{
|
{
|
||||||
private static MxGatewayDataConnection NewAdapter(FakeMxGatewayClient fake) =>
|
private static MxGatewayDataConnection NewAdapter(FakeMxGatewayClient fake) =>
|
||||||
@@ -249,7 +255,17 @@ public class MxGatewayDataConnectionTests
|
|||||||
() => adapter.BrowseChildrenAsync(null));
|
() => adapter.BrowseChildrenAsync(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task WaitUntil(Func<bool> condition, int timeoutMs = 2000)
|
// Generous ceiling (30 s, matching the DataConnectionManagerActorCollection rationale):
|
||||||
|
// every caller polls a *monotonic, positive* barrier — fake.OnUpdate becoming non-null
|
||||||
|
// (the fire-and-forget event-loop task has attached) or a Disconnected count reaching its
|
||||||
|
// target. Both only ever transition once and never reset, so a longer ceiling merely
|
||||||
|
// tolerates thread-pool starvation under full-solution CPU oversubscription; it cannot
|
||||||
|
// produce a false pass. In Unsubscribe_stops_routing_updates this barrier establishes the
|
||||||
|
// happens-before that the loop is attached BEFORE the test removes the subscription; the
|
||||||
|
// negative assertion (hits == 0) runs afterwards and is independent of this timeout —
|
||||||
|
// the update is delivered synchronously by the test thread, so widening here neither
|
||||||
|
// weakens nor races the negative check.
|
||||||
|
private static async Task WaitUntil(Func<bool> condition, int timeoutMs = 30_000)
|
||||||
{
|
{
|
||||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||||
while (!condition() && sw.ElapsedMilliseconds < timeoutMs)
|
while (!condition() && sw.ElapsedMilliseconds < timeoutMs)
|
||||||
|
|||||||
Reference in New Issue
Block a user