test: de-flake NodeManagerLockTimeBenchmark budget and OpcUaClientDriverWire host-status wait (lmxopcua#769)
v2-ci / unit-tests (push) Waiting to run

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
This commit is contained in:
Joseph Doherty
2026-11-09 14:18:16 -05:00
parent b8d2fc37ce
commit acc3057643
2 changed files with 7 additions and 2 deletions
@@ -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);
}
@@ -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}");