diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs index 0eba864a..ca9abb80 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs @@ -172,7 +172,7 @@ public sealed class DriverReconnectE2eTests List snapshot; lock (captureLock) snapshot = captured.Where(c => c.DriverInstanceId == DriverId).ToList(); - HasReconnectThenHealthy(captured).ShouldBeTrue( + HasReconnectThenHealthy(snapshot).ShouldBeTrue( "Expected a Reconnecting push followed by a later Healthy push for the deployed driver. " + $"States seen: [{string.Join(", ", snapshot.Select(c => c.State))}]"); @@ -254,6 +254,8 @@ public sealed class DriverReconnectE2eTests await db.SaveChangesAsync(Ct); } + /// Polls every 100 ms until it returns true or + /// elapses (then throws ). private static async Task WaitForAsync(Func> condition, TimeSpan timeout) { var deadline = DateTime.UtcNow + timeout; diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/Fakes/FakeReconnectDriverFactory.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/Fakes/FakeReconnectDriverFactory.cs index bad9995f..ceec98f6 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/Fakes/FakeReconnectDriverFactory.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/Fakes/FakeReconnectDriverFactory.cs @@ -96,13 +96,16 @@ public sealed class FakeReconnectDriver : IDriver /// Timestamp of the most recent successful initialize; surfaced as the last successful read. private DateTime _lastSuccess = DateTime.UtcNow; + /// Backing field for ; mutated via . + private int _initializeCount; + /// /// Number of times has been invoked. Read by the test to prove a /// reconnect genuinely re-initialised the driver through the full cluster path (≥ 2 means the - /// initial connect plus at least one reconnect retry). Mutated via since - /// the actor's retry path runs on a thread-pool thread. + /// initial connect plus at least one reconnect retry). The actor's retry path runs on a thread-pool + /// thread, so the increment is and the read is . /// - public int InitializeCount; + public int InitializeCount => Volatile.Read(ref _initializeCount); /// /// Marks the driver as having lost its connection so the next poll reports @@ -123,7 +126,7 @@ public sealed class FakeReconnectDriver : IDriver /// A completed task — initialization always succeeds. public Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken) { - Interlocked.Increment(ref InitializeCount); + Interlocked.Increment(ref _initializeCount); _lastSuccess = DateTime.UtcNow; _reconnecting = false; return Task.CompletedTask; @@ -151,7 +154,7 @@ public sealed class FakeReconnectDriver : IDriver /// A reflecting the controllable connection state. public DriverHealth GetHealth() => _reconnecting ? new DriverHealth(DriverState.Reconnecting, _lastSuccess, null) - : new DriverHealth(DriverState.Healthy, DateTime.UtcNow, null); + : new DriverHealth(DriverState.Healthy, _lastSuccess, null); /// Returns a zero memory footprint (the fake holds no driver-attributable caches). /// Always 0.