From acc3057643dd3c1b68492fb17970a84e6effb756 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 9 Nov 2026 14:18:16 -0500 Subject: [PATCH] test: de-flake NodeManagerLockTimeBenchmark budget and OpcUaClientDriverWire host-status wait (lmxopcua#769) Benchmark wall-clock budget 1 s -> 5 s (measured 5-60 ms; still catches O(N^2)). Host-status wait is already a TCS signal; its 30 s ceiling is raised to 120 s so a starved box cannot time out before the keep-alive reports the loss. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV --- .../OpcUaClientDriverWireTests.cs | 5 ++++- .../NodeManagerLockTimeBenchmarkTests.cs | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/OpcUaClientDriverWireTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/OpcUaClientDriverWireTests.cs index a3134d56..054674da 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/OpcUaClientDriverWireTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/OpcUaClientDriverWireTests.cs @@ -221,7 +221,10 @@ public sealed class OpcUaClientDriverWireTests await rig.DisposeAsync(); rig = null; - var state = await transitioned.Task.WaitAsync(TimeSpan.FromSeconds(30), ct); + // Signal-based (lmxopcua#769): the wait completes the instant the keep-alive loop reports the loss, so + // the ceiling only matters on a starved box, where server teardown plus the 10 s request timeout plus a + // 1 s keep-alive tick exceeded the old 30 s. A generous ceiling costs nothing when the signal arrives. + var state = await transitioned.Task.WaitAsync(TimeSpan.FromSeconds(120), ct); state.ShouldNotBe(HostState.Running); drv.GetHostStatuses().Single().State.ShouldNotBe(HostState.Running); } diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/NodeManagerLockTimeBenchmarkTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/NodeManagerLockTimeBenchmarkTests.cs index 7940bd09..f791298c 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/NodeManagerLockTimeBenchmarkTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/NodeManagerLockTimeBenchmarkTests.cs @@ -31,7 +31,9 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; public sealed class NodeManagerLockTimeBenchmarkTests(ITestOutputHelper output) : IDisposable { private static CancellationToken Ct => TestContext.Current.CancellationToken; - private static readonly TimeSpan Budget = TimeSpan.FromSeconds(1); + // lmxopcua#769: 1 s flaked once in a full parallel run (the 50k-node leg). Measured cost is 5-60 ms, so 5 s keeps + // >= 80x headroom against a CPU-starved CI box while still catching an order-of-magnitude (O(N^2)) regression. + private static readonly TimeSpan Budget = TimeSpan.FromSeconds(5); private readonly string _pkiRoot = Path.Combine(Path.GetTempPath(), $"otopcua-bench-{Guid.NewGuid():N}");