From 480b000f533f831a1b8253735b13140471623c0e Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 9 Oct 2026 06:02:24 -0400 Subject: [PATCH 1/2] test(mtconnect): wait on ReconnectAttempts itself, not a sample-call proxy (#661) Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe --- .../MTConnectSubscribeTests.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs index f7863089..95ba88dc 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs @@ -995,6 +995,14 @@ public sealed class MTConnectSubscribeTests client.SampleCallCount.ShouldBe(3); } + private static async Task WaitForReconnectAttemptsAboveAsync(MTConnectDriver driver, int floor) + { + while (driver.ReconnectAttempts <= floor) + { + await Task.Delay(5).ConfigureAwait(false); + } + } + /// /// …and the counter still accumulates when nothing is delivered, which is the case the /// backoff exists for. Asserted as monotonic growth rather than an exact value, because the @@ -1015,7 +1023,11 @@ public sealed class MTConnectSubscribeTests await client.WaitForSampleCallsAsync(3).WaitAsync(Watchdog, Ct); var early = driver.ReconnectAttempts; - await client.WaitForSampleCallsAsync(6).WaitAsync(Watchdog, Ct); + // Wait on the counter itself, not on a sample-call count: the pump advances it AFTER a + // call fails, and `early` may have been read late (already past the 6th call) under load, + // so a call-count barrier can observe the counter unchanged. The failure is sticky, so a + // working backoff keeps growing it; a frozen one never satisfies this within the watchdog. + await WaitForReconnectAttemptsAboveAsync(driver, early).WaitAsync(Watchdog, Ct); early.ShouldBeGreaterThanOrEqualTo(2); driver.ReconnectAttempts.ShouldBeGreaterThan(early); @@ -1065,7 +1077,11 @@ public sealed class MTConnectSubscribeTests await client.WaitForSampleCallsAsync(3).WaitAsync(Watchdog, Ct); var early = driver.ReconnectAttempts; - await client.WaitForSampleCallsAsync(6).WaitAsync(Watchdog, Ct); + // Wait on the counter itself, not on a sample-call count: the pump advances it AFTER a + // call fails, and `early` may have been read late (already past the 6th call) under load, + // so a call-count barrier can observe the counter unchanged. The failure is sticky, so a + // working backoff keeps growing it; a frozen one never satisfies this within the watchdog. + await WaitForReconnectAttemptsAboveAsync(driver, early).WaitAsync(Watchdog, Ct); early.ShouldBeGreaterThanOrEqualTo(2); driver.ReconnectAttempts.ShouldBeGreaterThan(early); From 31e2148a279c95abc6a423362c811e894bd37693 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 9 Oct 2026 06:03:05 -0400 Subject: [PATCH 2/2] test(mtconnect): #661 make the reconnect-counter wait cancellable (no background spin after the watchdog) Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe --- .../MTConnectSubscribeTests.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs index 95ba88dc..d2bd8256 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectSubscribeTests.cs @@ -995,11 +995,13 @@ public sealed class MTConnectSubscribeTests client.SampleCallCount.ShouldBe(3); } - private static async Task WaitForReconnectAttemptsAboveAsync(MTConnectDriver driver, int floor) + private static async Task WaitForReconnectAttemptsAboveAsync(MTConnectDriver driver, int floor, CancellationToken ct) { + using var watchdog = CancellationTokenSource.CreateLinkedTokenSource(ct); + watchdog.CancelAfter(Watchdog); while (driver.ReconnectAttempts <= floor) { - await Task.Delay(5).ConfigureAwait(false); + await Task.Delay(5, watchdog.Token).ConfigureAwait(false); } } @@ -1027,7 +1029,7 @@ public sealed class MTConnectSubscribeTests // call fails, and `early` may have been read late (already past the 6th call) under load, // so a call-count barrier can observe the counter unchanged. The failure is sticky, so a // working backoff keeps growing it; a frozen one never satisfies this within the watchdog. - await WaitForReconnectAttemptsAboveAsync(driver, early).WaitAsync(Watchdog, Ct); + await WaitForReconnectAttemptsAboveAsync(driver, early, Ct); early.ShouldBeGreaterThanOrEqualTo(2); driver.ReconnectAttempts.ShouldBeGreaterThan(early); @@ -1081,7 +1083,7 @@ public sealed class MTConnectSubscribeTests // call fails, and `early` may have been read late (already past the 6th call) under load, // so a call-count barrier can observe the counter unchanged. The failure is sticky, so a // working backoff keeps growing it; a frozen one never satisfies this within the watchdog. - await WaitForReconnectAttemptsAboveAsync(driver, early).WaitAsync(Watchdog, Ct); + await WaitForReconnectAttemptsAboveAsync(driver, early, Ct); early.ShouldBeGreaterThanOrEqualTo(2); driver.ReconnectAttempts.ShouldBeGreaterThan(early);