From 1d7a4b7a53a972f47a7d0cf4822822c72edf0192 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 9 Nov 2026 13:19:34 -0500 Subject: [PATCH] test: pass TestContext.Current.CancellationToken at xUnit1051 call sites (analyzer code fix, 451 sites) (lmxopcua#725) Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV --- .../AlarmsCommandTests.cs | 30 +- .../EventHandlerLifecycleTests.cs | 4 +- .../SubscribeCommandSummaryTests.cs | 8 +- .../SubscribeCommandTests.cs | 16 +- .../FailoverEpochTests.cs | 34 +-- .../OpcUaClientServiceTests.cs | 267 +++++++++--------- .../BrowseTreeViewModelTests.cs | 8 +- .../ClusterAuditQueryTests.cs | 12 +- .../ClusterNodeTransportPortsTests.cs | 14 +- .../DraftSnapshotFactorySqlServerTests.cs | 12 +- .../DraftSnapshotFactoryTests.cs | 16 +- .../ScriptedAlarmEngineRunGuardTests.cs | 2 +- .../ScriptedAlarmEngineTests.cs | 22 +- .../ScriptedAlarmSourceLoggingTests.cs | 2 +- .../ScriptedAlarmSourceTests.cs | 16 +- .../ScriptCancellationTokenTests.cs | 2 +- .../DriverResiliencePipelineBuilderTests.cs | 12 +- .../AbCipAlarmProjectionTests.cs | 2 +- .../AbCipAlmaProjectionTests.cs | 4 +- .../AbCipDeviceRefusalTests.cs | 6 +- .../AbCipLifecycleConcurrencyTests.cs | 12 +- .../AbCipProbeRefusalTests.cs | 2 +- .../AbCipReadWindowTests.cs | 2 +- .../AbCipWriteHealthTests.cs | 2 +- .../AbLegacyAnsweredStatusTests.cs | 6 +- .../AbLegacyBatchSubscribeTests.cs | 2 +- .../AbLegacyDeviceIsolationTests.cs | 4 +- .../AbLegacyFamilyAddressingTests.cs | 2 +- .../AbLegacyHealthEvidenceTests.cs | 16 +- .../AbLegacyLifecycleConcurrencyTests.cs | 6 +- .../AbLegacyShutdownJoinTests.cs | 14 +- .../CalculationDriverRemediationTests.cs | 2 +- .../CalculationDriverTests.cs | 16 +- .../FocasCapabilityTests.cs | 2 +- .../FocasConcurrentConnectTests.cs | 10 +- .../FocasDeviceTableLifecycleTests.cs | 22 +- .../FocasFixedTreeConcurrencyTests.cs | 10 +- .../FocasHandleRecycleTests.cs | 4 +- .../FocasProgramInfoQualityTests.cs | 2 +- .../FocasReadHealthContractTests.cs | 8 +- .../FocasShutdownJoinTests.cs | 6 +- .../FocasWireProtocolTests.cs | 8 +- .../FocasWireV3Tests.cs | 2 +- .../Browse/DeployWatcherTests.cs | 28 +- .../GalaxyDriverApiKeyResolverTests.cs | 16 +- .../GalaxyDriverFactoryTests.cs | 2 +- .../Health/HostStatusAggregatorTests.cs | 2 +- .../Runtime/EventPumpBoundedChannelTests.cs | 2 +- .../Runtime/EventPumpStreamFaultTests.cs | 2 +- .../Runtime/GalaxyDriverFixRound1Tests.cs | 6 +- .../Runtime/GalaxyDriverFixRound2Tests.cs | 22 +- .../Runtime/GalaxyDriverProbeWiringTests.cs | 4 +- .../Runtime/GalaxyDriverReadTests.cs | 8 +- .../Runtime/GalaxyDriverShutdownTests.cs | 2 +- .../Runtime/GalaxyDriverSubscribeTests.cs | 4 +- .../Runtime/GalaxyMxSessionCloseTests.cs | 2 +- ...GatewayGalaxyDataWriterConcurrencyTests.cs | 8 +- .../Runtime/ReconnectSupervisorTests.cs | 2 +- .../AlarmWriterTests.cs | 14 +- .../ProvisioningTests.cs | 4 +- .../RetentionTests.cs | 22 +- .../SchemaBootstrapIntegrationTests.cs | 18 +- .../MTConnectDriverProbeTests.cs | 4 +- .../ModbusBatchSubscriptionTests.cs | 2 +- .../ModbusDriverProbeTests.cs | 6 +- .../ModbusLifecycleHygieneTests.cs | 18 +- .../ModbusProbeTests.cs | 10 +- .../ModbusSubscriptionTests.cs | 8 +- .../MqttDriverDiscoveryTests.cs | 6 +- .../MqttDriverSessionLifecycleTests.cs | 2 +- .../MqttDriverWriteTests.cs | 18 +- .../S7DriverReconnectTests.cs | 2 +- .../TwinCATCapabilityTests.cs | 4 +- .../TwinCATDiagnosticsTests.cs | 6 +- .../TwinCATDriverProbeTests.cs | 2 +- .../TwinCATReconnectReplayTests.cs | 2 +- .../TwinCATSumChunkWarningTests.cs | 2 +- 77 files changed, 452 insertions(+), 457 deletions(-) diff --git a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/AlarmsCommandTests.cs b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/AlarmsCommandTests.cs index fb8864170..4f9ce7fa6 100644 --- a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/AlarmsCommandTests.cs +++ b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/AlarmsCommandTests.cs @@ -21,9 +21,9 @@ public class AlarmsCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -46,9 +46,9 @@ public class AlarmsCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -71,9 +71,9 @@ public class AlarmsCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -91,13 +91,13 @@ public class AlarmsCommandTests var command = new AlarmsCommand(factory) { Url = "opc.tcp://localhost:4840" }; using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); fakeService.RaiseAlarmEvent(new Client.Shared.Models.AlarmEventArgs( "src", "cond", 500, "msg", true, true, false, DateTime.UtcNow, eventId: [0xAB, 0x01, 0xFF], conditionNodeId: "ns=2;s=Plant/cond")); - await Task.Delay(500); + await Task.Delay(500, TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -123,9 +123,9 @@ public class AlarmsCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -146,9 +146,9 @@ public class AlarmsCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -168,9 +168,9 @@ public class AlarmsCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; diff --git a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/EventHandlerLifecycleTests.cs b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/EventHandlerLifecycleTests.cs index b5197fcea..424233a28 100644 --- a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/EventHandlerLifecycleTests.cs +++ b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/EventHandlerLifecycleTests.cs @@ -49,9 +49,9 @@ public class EventHandlerLifecycleTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => await command.ExecuteAsync(console)); + var task = Task.Run(async () => await command.ExecuteAsync(console), TestContext.Current.CancellationToken); - await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeAlarmsInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; diff --git a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandSummaryTests.cs b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandSummaryTests.cs index 272d73c10..8c265ada8 100644 --- a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandSummaryTests.cs +++ b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandSummaryTests.cs @@ -55,7 +55,7 @@ public class SubscribeCommandSummaryTests }; using var console = TestConsoleHelper.CreateConsole(); - var runTask = Task.Run(async () => await command.ExecuteAsync(console)); + var runTask = Task.Run(async () => await command.ExecuteAsync(console), TestContext.Current.CancellationToken); // Wait until the subscription is registered by the fake. await WaitForAsync(() => fakeService.SubscribeCalls.Count == 1); @@ -86,7 +86,7 @@ public class SubscribeCommandSummaryTests }; using var console = TestConsoleHelper.CreateConsole(); - var runTask = Task.Run(async () => await command.ExecuteAsync(console)); + var runTask = Task.Run(async () => await command.ExecuteAsync(console), TestContext.Current.CancellationToken); await WaitForAsync(() => fakeService.SubscribeCalls.Count == 1); @@ -143,7 +143,7 @@ public class SubscribeCommandSummaryTests }; using var console = TestConsoleHelper.CreateConsole(); - var runTask = Task.Run(async () => await command.ExecuteAsync(console)); + var runTask = Task.Run(async () => await command.ExecuteAsync(console), TestContext.Current.CancellationToken); await WaitForAsync(() => fakeService.SubscribeCalls.Count == 1); fakeService.RaiseDataChanged( @@ -180,7 +180,7 @@ public class SubscribeCommandSummaryTests await command.ExecuteAsync(console); File.Exists(tempFile).ShouldBeTrue(); - var contents = await File.ReadAllTextAsync(tempFile); + var contents = await File.ReadAllTextAsync(tempFile, TestContext.Current.CancellationToken); contents.ShouldContain("SUMMARY"); contents.ShouldContain("Total subscribed: 1"); } diff --git a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandTests.cs b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandTests.cs index 1216cbb72..82454a388 100644 --- a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandTests.cs +++ b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/SubscribeCommandTests.cs @@ -24,10 +24,10 @@ public class SubscribeCommandTests // The subscribe command waits for cancellation. We need to cancel it. // Use the console's cancellation to trigger stop. - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); // Wait until the command has actually subscribed (deterministic — no fixed-sleep race), then cancel - await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -50,9 +50,9 @@ public class SubscribeCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -73,9 +73,9 @@ public class SubscribeCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; @@ -98,9 +98,9 @@ public class SubscribeCommandTests using var console = TestConsoleHelper.CreateConsole(); - var task = Task.Run(async () => { await command.ExecuteAsync(console); }); + var task = Task.Run(async () => { await command.ExecuteAsync(console); }, TestContext.Current.CancellationToken); - await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10)); + await fakeService.SubscribeInvoked.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); console.RequestCancellation(); await task; diff --git a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/FailoverEpochTests.cs b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/FailoverEpochTests.cs index 362bc4564..df4508b91 100644 --- a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/FailoverEpochTests.cs +++ b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/FailoverEpochTests.cs @@ -58,12 +58,12 @@ public sealed class FailoverEpochTests : IDisposable _factory.EnqueueSession(userSession); // dequeued by the user's Connect (the failover is still held) _factory.EnqueueSession(failoverSession); // dequeued by the failover once released - await _service.DisconnectAsync(); - await _service.ConnectAsync(Settings()); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); + await _service.ConnectAsync(Settings(), TestContext.Current.CancellationToken); lock (_states) _states.Clear(); gate.SetResult(); - await failover.WaitAsync(Wait); + await failover.WaitAsync(Wait, TestContext.Current.CancellationToken); failoverSession.Disposed.ShouldBeTrue(); userSession.Disposed.ShouldBeFalse(); @@ -79,14 +79,14 @@ public sealed class FailoverEpochTests : IDisposable var (_, failover, gate) = await StartHeldFailoverAsync(); _factory.EnqueueSession(new FakeSessionAdapter()); - await _service.DisconnectAsync(); - await _service.ConnectAsync(Settings()); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); + await _service.ConnectAsync(Settings(), TestContext.Current.CancellationToken); lock (_states) _states.Clear(); var createsBefore = _factory.CreateCallCount; _factory.ThrowOnCreate = true; gate.SetResult(); - await failover.WaitAsync(Wait); + await failover.WaitAsync(Wait, TestContext.Current.CancellationToken); _service.IsConnected.ShouldBeTrue(); lock (_states) _states.ShouldBeEmpty(); @@ -94,8 +94,8 @@ public sealed class FailoverEpochTests : IDisposable _factory.CreateCallCount.ShouldBe(createsBefore); // And the user can still disconnect / reconnect normally afterwards. _factory.ThrowOnCreate = false; - await _service.DisconnectAsync(); - await _service.ConnectAsync(Settings()); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); + await _service.ConnectAsync(Settings(), TestContext.Current.CancellationToken); _service.IsConnected.ShouldBeTrue(); } @@ -107,7 +107,7 @@ public sealed class FailoverEpochTests : IDisposable _factory.EnqueueSession(new FakeSessionAdapter()); gate.SetResult(); - await failover.WaitAsync(Wait); + await failover.WaitAsync(Wait, TestContext.Current.CancellationToken); _service.IsConnected.ShouldBeTrue(); _service.CurrentConnectionInfo!.EndpointUrl.ShouldBe(Backup); @@ -123,15 +123,15 @@ public sealed class FailoverEpochTests : IDisposable { var s1 = new FakeSessionAdapter(); _factory.EnqueueSession(s1); - await _service.ConnectAsync(Settings()); - await _service.DisconnectAsync(); + await _service.ConnectAsync(Settings(), TestContext.Current.CancellationToken); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); _factory.EnqueueSession(new FakeSessionAdapter()); - await _service.ConnectAsync(Settings()); + await _service.ConnectAsync(Settings(), TestContext.Current.CancellationToken); var creates = _factory.CreateCallCount; lock (_states) _states.Clear(); s1.SimulateKeepAlive(false); - if (_service.LastFailover is { } t) await t.WaitAsync(Wait); + if (_service.LastFailover is { } t) await t.WaitAsync(Wait, TestContext.Current.CancellationToken); _factory.CreateCallCount.ShouldBe(creates); lock (_states) _states.ShouldBeEmpty(); @@ -150,7 +150,7 @@ public sealed class FailoverEpochTests : IDisposable failover.IsCompleted.ShouldBeFalse(); _factory.EnqueueSession(new FakeSessionAdapter()); gate.SetResult(); - await failover.WaitAsync(Wait); + await failover.WaitAsync(Wait, TestContext.Current.CancellationToken); } /// @@ -163,15 +163,15 @@ public sealed class FailoverEpochTests : IDisposable { var sub = new FakeSubscriptionAdapter(); _factory.EnqueueSession(new FakeSessionAdapter { NextSubscription = sub }); - await _service.ConnectAsync(Settings()); + await _service.ConnectAsync(Settings(), TestContext.Current.CancellationToken); var node = new Opc.Ua.NodeId("ns=2;s=X"); - await _service.SubscribeAsync(node); + await _service.SubscribeAsync(node, ct: TestContext.Current.CancellationToken); sub.ThrowOnRemove = true; await Should.ThrowAsync(() => _service.UnsubscribeAsync(node)); sub.ThrowOnRemove = false; - await _service.SubscribeAsync(node); + await _service.SubscribeAsync(node, ct: TestContext.Current.CancellationToken); sub.AddDataChangeCount.ShouldBe(2); } } diff --git a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/OpcUaClientServiceTests.cs b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/OpcUaClientServiceTests.cs index a0b89bb95..9c7fb1f6c 100644 --- a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/OpcUaClientServiceTests.cs +++ b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/OpcUaClientServiceTests.cs @@ -47,7 +47,7 @@ public class OpcUaClientServiceTests : IDisposable [Fact] public async Task ConnectAsync_ValidSettings_ReturnsConnectionInfo() { - var info = await _service.ConnectAsync(ValidSettings()); + var info = await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); info.ShouldNotBeNull(); info.EndpointUrl.ShouldBe("opc.tcp://localhost:4840"); @@ -84,7 +84,7 @@ public class OpcUaClientServiceTests : IDisposable }; _sessionFactory.EnqueueSession(session); - var info = await _service.ConnectAsync(ValidSettings()); + var info = await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); info.ServerName.ShouldBe("MyServer"); info.SecurityMode.ShouldBe("Sign"); @@ -102,7 +102,7 @@ public class OpcUaClientServiceTests : IDisposable var events = new List(); _service.ConnectionStateChanged += (_, e) => events.Add(e); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); events.Count.ShouldBe(2); events[0].OldState.ShouldBe(ConnectionState.Disconnected); @@ -137,7 +137,7 @@ public class OpcUaClientServiceTests : IDisposable settings.Username = "admin"; settings.Password = "secret"; - await _service.ConnectAsync(settings); + await _service.ConnectAsync(settings, TestContext.Current.CancellationToken); _configFactory.LastSettings!.Username.ShouldBe("admin"); _configFactory.LastSettings!.Password.ShouldBe("secret"); @@ -151,10 +151,10 @@ public class OpcUaClientServiceTests : IDisposable [Fact] public async Task DisconnectAsync_WhenConnected_ClosesSession() { - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); var session = _sessionFactory.CreatedSessions[0]; - await _service.DisconnectAsync(); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); session.Closed.ShouldBeTrue(); _service.IsConnected.ShouldBeFalse(); @@ -167,7 +167,7 @@ public class OpcUaClientServiceTests : IDisposable [Fact] public async Task DisconnectAsync_WhenNotConnected_IsIdempotent() { - await _service.DisconnectAsync(); // Should not throw + await _service.DisconnectAsync(TestContext.Current.CancellationToken); // Should not throw _service.IsConnected.ShouldBeFalse(); } @@ -177,9 +177,9 @@ public class OpcUaClientServiceTests : IDisposable [Fact] public async Task DisconnectAsync_CalledTwice_IsIdempotent() { - await _service.ConnectAsync(ValidSettings()); - await _service.DisconnectAsync(); - await _service.DisconnectAsync(); // Should not throw + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); // Should not throw } // --- Read tests --- @@ -195,9 +195,9 @@ public class OpcUaClientServiceTests : IDisposable ReadResponse = new DataValue(new Variant(42), StatusCodes.Good) }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.ReadValueAsync(new NodeId("ns=2;s=MyNode")); + var result = await _service.ReadValueAsync(new NodeId("ns=2;s=MyNode"), TestContext.Current.CancellationToken); result.Value.ShouldBe(42); session.ReadCount.ShouldBe(1); @@ -221,7 +221,7 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter { ThrowOnRead = true }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); await Should.ThrowAsync(() => _service.ReadValueAsync(new NodeId("ns=2;s=MyNode"))); @@ -241,9 +241,9 @@ public class OpcUaClientServiceTests : IDisposable WriteResponse = StatusCodes.Good }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), 42); + var result = await _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), 42, TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.WriteCount.ShouldBe(1); @@ -260,9 +260,9 @@ public class OpcUaClientServiceTests : IDisposable ReadResponse = new DataValue(new Variant(0), StatusCodes.Good) // int type }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), "42"); + await _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), "42", TestContext.Current.CancellationToken); session.WriteCount.ShouldBe(1); session.ReadCount.ShouldBe(1); // Read for type inference @@ -276,9 +276,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), 42); + await _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), 42, TestContext.Current.CancellationToken); session.WriteCount.ShouldBe(1); session.ReadCount.ShouldBe(0); // No read for non-string values @@ -306,7 +306,7 @@ public class OpcUaClientServiceTests : IDisposable ReadResponse = new DataValue(StatusCodes.BadNodeIdUnknown) // Bad status, null Value }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); var ex = await Should.ThrowAsync(() => _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), "42")); @@ -326,7 +326,7 @@ public class OpcUaClientServiceTests : IDisposable ReadResponse = new DataValue(StatusCodes.BadNotReadable) }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); var ex = await Should.ThrowAsync(() => _service.WriteValueAsync(new NodeId("ns=2;s=MyNode"), "42")); @@ -355,9 +355,9 @@ public class OpcUaClientServiceTests : IDisposable ] }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var results = await _service.BrowseAsync(); + var results = await _service.BrowseAsync(ct: TestContext.Current.CancellationToken); results.Count.ShouldBe(1); results[0].DisplayName.ShouldBe("Child1"); @@ -376,9 +376,9 @@ public class OpcUaClientServiceTests : IDisposable BrowseResponse = [] }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.BrowseAsync(); + await _service.BrowseAsync(ct: TestContext.Current.CancellationToken); session.BrowseCount.ShouldBe(1); } @@ -416,9 +416,9 @@ public class OpcUaClientServiceTests : IDisposable ] }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var results = await _service.BrowseAsync(); + var results = await _service.BrowseAsync(ct: TestContext.Current.CancellationToken); results.Select(r => r.HasChildren).ShouldBe([true, true, false]); session.BrowseCount.ShouldBe(1); @@ -455,9 +455,9 @@ public class OpcUaClientServiceTests : IDisposable BrowseNextContinuationPoint = null }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var results = await _service.BrowseAsync(); + var results = await _service.BrowseAsync(ct: TestContext.Current.CancellationToken); results.Count.ShouldBe(2); session.BrowseNextCount.ShouldBe(1); @@ -482,9 +482,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode"), 500); + await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode"), 500, TestContext.Current.CancellationToken); session.CreatedSubscriptions.Count.ShouldBe(1); session.CreatedSubscriptions[0].AddDataChangeCount.ShouldBe(1); @@ -498,10 +498,10 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode")); - await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode")); // duplicate + await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode"), ct: TestContext.Current.CancellationToken); + await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode"), ct: TestContext.Current.CancellationToken); // duplicate session.CreatedSubscriptions[0].AddDataChangeCount.ShouldBe(1); } @@ -515,12 +515,12 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); DataChangedEventArgs? received = null; _service.DataChanged += (_, e) => received = e; - await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode"), 500); + await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode"), 500, TestContext.Current.CancellationToken); // Simulate data change var handle = fakeSub.ActiveHandles.First(); @@ -540,10 +540,10 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode")); - await _service.UnsubscribeAsync(new NodeId("ns=2;s=MyNode")); + await _service.SubscribeAsync(new NodeId("ns=2;s=MyNode"), ct: TestContext.Current.CancellationToken); + await _service.UnsubscribeAsync(new NodeId("ns=2;s=MyNode"), TestContext.Current.CancellationToken); fakeSub.RemoveCount.ShouldBe(1); } @@ -556,9 +556,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.UnsubscribeAsync(new NodeId("ns=2;s=NotSubscribed")); + await _service.UnsubscribeAsync(new NodeId("ns=2;s=NotSubscribed"), TestContext.Current.CancellationToken); // Should not throw } @@ -582,9 +582,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); session.CreatedSubscriptions.Count.ShouldBe(1); session.CreatedSubscriptions[0].AddEventCount.ShouldBe(1); @@ -598,10 +598,10 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAlarmsAsync(); - await _service.SubscribeAlarmsAsync(); // duplicate + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); // duplicate session.CreatedSubscriptions.Count.ShouldBe(1); } @@ -615,12 +615,12 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); AlarmEventArgs? received = null; _service.AlarmEvent += (_, e) => received = e; - await _service.SubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); // Simulate alarm event with proper field count var handle = fakeSub.ActiveHandles.First(); @@ -663,10 +663,10 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAlarmsAsync(); - await _service.UnsubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); + await _service.UnsubscribeAlarmsAsync(TestContext.Current.CancellationToken); fakeSub.Deleted.ShouldBeTrue(); } @@ -679,9 +679,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.UnsubscribeAlarmsAsync(); // Should not throw + await _service.UnsubscribeAlarmsAsync(TestContext.Current.CancellationToken); // Should not throw } /// @@ -693,10 +693,10 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAlarmsAsync(); - await _service.RequestConditionRefreshAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); + await _service.RequestConditionRefreshAsync(TestContext.Current.CancellationToken); fakeSub.ConditionRefreshCalled.ShouldBeTrue(); } @@ -709,7 +709,7 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); await Should.ThrowAsync(() => _service.RequestConditionRefreshAsync()); @@ -740,10 +740,9 @@ public class OpcUaClientServiceTests : IDisposable }; var session = new FakeSessionAdapter { HistoryReadRawResponse = expectedValues }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var results = await _service.HistoryReadRawAsync( - new NodeId("ns=2;s=Temp"), DateTime.UtcNow.AddHours(-1), DateTime.UtcNow); + var results = await _service.HistoryReadRawAsync(new NodeId("ns=2;s=Temp"), DateTime.UtcNow.AddHours(-1), DateTime.UtcNow, ct: TestContext.Current.CancellationToken); results.Count.ShouldBe(2); session.HistoryReadRawCount.ShouldBe(1); @@ -767,7 +766,7 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter { ThrowOnHistoryReadRaw = true }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); await Should.ThrowAsync(() => _service.HistoryReadRawAsync(new NodeId("ns=2;s=Temp"), DateTime.UtcNow.AddHours(-1), DateTime.UtcNow)); @@ -785,11 +784,9 @@ public class OpcUaClientServiceTests : IDisposable }; var session = new FakeSessionAdapter { HistoryReadAggregateResponse = expectedValues }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var results = await _service.HistoryReadAggregateAsync( - new NodeId("ns=2;s=Temp"), DateTime.UtcNow.AddHours(-1), DateTime.UtcNow, - AggregateType.Average); + var results = await _service.HistoryReadAggregateAsync(new NodeId("ns=2;s=Temp"), DateTime.UtcNow.AddHours(-1), DateTime.UtcNow, AggregateType.Average, ct: TestContext.Current.CancellationToken); results.Count.ShouldBe(1); session.HistoryReadAggregateCount.ShouldBe(1); @@ -815,7 +812,7 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter { ThrowOnHistoryReadAggregate = true }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); await Should.ThrowAsync(() => _service.HistoryReadAggregateAsync( @@ -847,9 +844,9 @@ public class OpcUaClientServiceTests : IDisposable } }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var info = await _service.GetRedundancyInfoAsync(); + var info = await _service.GetRedundancyInfoAsync(TestContext.Current.CancellationToken); info.Mode.ShouldBe("Warm"); info.ServiceLevel.ShouldBe((byte)200); @@ -877,9 +874,9 @@ public class OpcUaClientServiceTests : IDisposable } }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var info = await _service.GetRedundancyInfoAsync(); + var info = await _service.GetRedundancyInfoAsync(TestContext.Current.CancellationToken); info.Mode.ShouldBe("None"); info.ServiceLevel.ShouldBe((byte)100); @@ -917,9 +914,9 @@ public class OpcUaClientServiceTests : IDisposable } }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var info = await _service.GetRedundancyInfoAsync(); + var info = await _service.GetRedundancyInfoAsync(TestContext.Current.CancellationToken); info.Mode.ShouldBe("Warm"); info.ServiceLevel.ShouldBe((byte)200); @@ -944,9 +941,9 @@ public class OpcUaClientServiceTests : IDisposable } }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var info = await _service.GetRedundancyInfoAsync(); + var info = await _service.GetRedundancyInfoAsync(TestContext.Current.CancellationToken); info.Mode.ShouldBe("None"); info.ServiceLevel.ShouldBe((byte)0); @@ -964,12 +961,12 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); AlarmEventArgs? received = null; _service.AlarmEvent += (_, e) => received = e; - await _service.SubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); var handle = fakeSub.ActiveHandles.First(); // Only 3 fields — EventId, EventType, SourceName — fewer than the old < 6 threshold @@ -998,12 +995,12 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); var eventCount = 0; _service.AlarmEvent += (_, _) => eventCount++; - await _service.SubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); var handle = fakeSub.ActiveHandles.First(); fakeSub.SimulateEvent(handle, new EventFieldList { EventFields = [] }); @@ -1022,9 +1019,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.AcknowledgeAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "acked"); + var result = await _service.AcknowledgeAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "acked", TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.CallMethodCount.ShouldBe(1); @@ -1045,9 +1042,9 @@ public class OpcUaClientServiceTests : IDisposable StatusCodes.BadConditionAlreadyEnabled, "already acked") }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.AcknowledgeAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "acked"); + var result = await _service.AcknowledgeAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "acked", TestContext.Current.CancellationToken); StatusCode.IsBad(result).ShouldBeTrue(); result.Code.ShouldBe(StatusCodes.BadConditionAlreadyEnabled); @@ -1062,10 +1059,10 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.AcknowledgeAlarmAsync("ns=2;s=Plant/Alarm1", new byte[] { 1, 2 }, "acked"); - await _service.ConfirmAlarmAsync("ns=2;s=Plant/Alarm1", new byte[] { 1, 2 }, "confirmed"); + await _service.AcknowledgeAlarmAsync("ns=2;s=Plant/Alarm1", new byte[] { 1, 2 }, "acked", TestContext.Current.CancellationToken); + await _service.ConfirmAlarmAsync("ns=2;s=Plant/Alarm1", new byte[] { 1, 2 }, "confirmed", TestContext.Current.CancellationToken); session.CallMethodObjectIds.ShouldAllBe(id => id == NodeId.Parse("ns=2;s=Plant/Alarm1")); session.CallMethodMethodIds[0].ShouldBe(MethodIds.AcknowledgeableConditionType_Acknowledge); @@ -1083,9 +1080,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.ConfirmAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "confirmed"); + var result = await _service.ConfirmAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "confirmed", TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.CallMethodCount.ShouldBe(1); @@ -1104,9 +1101,9 @@ public class OpcUaClientServiceTests : IDisposable StatusCodes.BadConditionAlreadyEnabled, "already confirmed") }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.ConfirmAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "confirmed"); + var result = await _service.ConfirmAlarmAsync("ns=2;s=Cond", new byte[] { 1, 2 }, "confirmed", TestContext.Current.CancellationToken); StatusCode.IsBad(result).ShouldBeTrue(); result.Code.ShouldBe(StatusCodes.BadConditionAlreadyEnabled); @@ -1122,9 +1119,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.OneShot); + var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.OneShot, ct: TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.CallMethodCount.ShouldBe(1); @@ -1142,10 +1139,10 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); const double durationSeconds = 30.0; - var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.Timed, durationSeconds); + var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.Timed, durationSeconds, TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.CallMethodCount.ShouldBe(1); @@ -1161,9 +1158,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.Unshelve); + var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.Unshelve, ct: TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.CallMethodCount.ShouldBe(1); @@ -1185,9 +1182,9 @@ public class OpcUaClientServiceTests : IDisposable StatusCodes.BadConditionAlreadyShelved, "already shelved") }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.OneShot); + var result = await _service.ShelveAlarmAsync("ns=2;s=Cond", ShelveKind.OneShot, ct: TestContext.Current.CancellationToken); StatusCode.IsBad(result).ShouldBeTrue(); result.Code.ShouldBe(StatusCodes.BadConditionAlreadyShelved); @@ -1204,9 +1201,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.EnableAsync("ns=2;s=Cond"); + var result = await _service.EnableAsync("ns=2;s=Cond", TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.CallMethodCount.ShouldBe(1); @@ -1224,9 +1221,9 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.DisableAsync("ns=2;s=Cond"); + var result = await _service.DisableAsync("ns=2;s=Cond", TestContext.Current.CancellationToken); result.ShouldBe(StatusCodes.Good); session.CallMethodCount.ShouldBe(1); @@ -1248,9 +1245,9 @@ public class OpcUaClientServiceTests : IDisposable StatusCodes.BadConditionAlreadyEnabled, "already enabled") }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.EnableAsync("ns=2;s=Cond"); + var result = await _service.EnableAsync("ns=2;s=Cond", TestContext.Current.CancellationToken); StatusCode.IsBad(result).ShouldBeTrue(); result.Code.ShouldBe(StatusCodes.BadConditionAlreadyEnabled); @@ -1269,9 +1266,9 @@ public class OpcUaClientServiceTests : IDisposable StatusCodes.BadConditionAlreadyDisabled, "already disabled") }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - var result = await _service.DisableAsync("ns=2;s=Cond"); + var result = await _service.DisableAsync("ns=2;s=Cond", TestContext.Current.CancellationToken); StatusCode.IsBad(result).ShouldBeTrue(); result.Code.ShouldBe(StatusCodes.BadConditionAlreadyDisabled); @@ -1290,12 +1287,12 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); AlarmEventArgs? received = null; _service.AlarmEvent += (_, e) => received = e; - await _service.SubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); var handle = fakeSub.ActiveHandles.First(); var fields = new EventFieldList @@ -1348,13 +1345,13 @@ public class OpcUaClientServiceTests : IDisposable var stateChanges = new List(); _service.ConnectionStateChanged += (_, e) => stateChanges.Add(e); - await _service.ConnectAsync(settings); + await _service.ConnectAsync(settings, TestContext.Current.CancellationToken); // Simulate keep-alive failure session1.SimulateKeepAlive(false); // Give async failover time to complete - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); // Should have reconnected stateChanges.ShouldContain(e => e.NewState == ConnectionState.Reconnecting); @@ -1380,9 +1377,9 @@ public class OpcUaClientServiceTests : IDisposable var settings = ValidSettings("opc.tcp://primary:4840"); settings.FailoverUrls = ["opc.tcp://backup:4840"]; - await _service.ConnectAsync(settings); + await _service.ConnectAsync(settings, TestContext.Current.CancellationToken); session1.SimulateKeepAlive(false); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); _service.CurrentConnectionInfo!.EndpointUrl.ShouldBe("opc.tcp://backup:4840"); _service.CurrentConnectionInfo.ServerName.ShouldBe("BackupServer"); @@ -1397,12 +1394,12 @@ public class OpcUaClientServiceTests : IDisposable var session1 = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session1); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); // After the first session, make factory fail _sessionFactory.ThrowOnCreate = true; session1.SimulateKeepAlive(false); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); _service.IsConnected.ShouldBeFalse(); } @@ -1423,7 +1420,7 @@ public class OpcUaClientServiceTests : IDisposable var settings = ValidSettings("opc.tcp://primary:4840"); settings.FailoverUrls = ["opc.tcp://backup:4840"]; - await _service.ConnectAsync(settings); + await _service.ConnectAsync(settings, TestContext.Current.CancellationToken); var createCountAfterConnect = _sessionFactory.CreateCallCount; // 1 // Hold the failover's session creation open so it stays in-flight. @@ -1439,7 +1436,7 @@ public class OpcUaClientServiceTests : IDisposable // Release the gate so the in-flight failover completes. gate.SetResult(); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); // Exactly one extra session created by the single failover loop. _sessionFactory.CreateCallCount.ShouldBe(createCountAfterConnect + 1); @@ -1455,7 +1452,7 @@ public class OpcUaClientServiceTests : IDisposable { var session1 = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session1); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); await Should.ThrowAsync(() => _service.ConnectAsync(ValidSettings())); @@ -1463,8 +1460,8 @@ public class OpcUaClientServiceTests : IDisposable session1.Disposed.ShouldBeFalse(); _service.IsConnected.ShouldBeTrue(); - await _service.DisconnectAsync(); - await _service.ConnectAsync(ValidSettings()); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); _sessionFactory.CreateCallCount.ShouldBe(2); _service.IsConnected.ShouldBeTrue(); } @@ -1484,26 +1481,26 @@ public class OpcUaClientServiceTests : IDisposable _sessionFactory.EnqueueSession(session2); var settings = ValidSettings("opc.tcp://primary:4840"); settings.FailoverUrls = ["opc.tcp://backup:4840"]; - await _service.ConnectAsync(settings); + await _service.ConnectAsync(settings, TestContext.Current.CancellationToken); var gate = new TaskCompletionSource(); session1.CreateSubscriptionGate = gate; - var subscribe = _service.SubscribeAsync(new NodeId("ns=2;s=Racer"), 1000); - await session1.CreateSubscriptionEntered.Task.WaitAsync(TimeSpan.FromSeconds(10)); + var subscribe = _service.SubscribeAsync(new NodeId("ns=2;s=Racer"), 1000, TestContext.Current.CancellationToken); + await session1.CreateSubscriptionEntered.Task.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); session1.SimulateKeepAlive(false); var failover = _service.LastFailover.ShouldNotBeNull(); gate.SetResult(); - await subscribe.WaitAsync(TimeSpan.FromSeconds(10)); - await failover.WaitAsync(TimeSpan.FromSeconds(10)); + await subscribe.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); + await failover.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); _service.CurrentConnectionInfo!.EndpointUrl.ShouldBe("opc.tcp://backup:4840"); var replayed = session2.CreatedSubscriptions.ShouldHaveSingleItem(); replayed.AddDataChangeCount.ShouldBe(1); // And it is the live subscription: unsubscribing removes it from session2's subscription, not session1's. - await _service.UnsubscribeAsync(new NodeId("ns=2;s=Racer")); + await _service.UnsubscribeAsync(new NodeId("ns=2;s=Racer"), TestContext.Current.CancellationToken); replayed.RemoveCount.ShouldBe(1); replayed.ActiveHandles.ShouldBeEmpty(); } @@ -1522,16 +1519,16 @@ public class OpcUaClientServiceTests : IDisposable _sessionFactory.EnqueueSession(session2); var settings = ValidSettings("opc.tcp://primary:4840"); settings.FailoverUrls = ["opc.tcp://backup:4840"]; - await _service.ConnectAsync(settings); + await _service.ConnectAsync(settings, TestContext.Current.CancellationToken); var gate = new TaskCompletionSource(); _sessionFactory.CreateGate = gate; session1.SimulateKeepAlive(false); var failover = _service.LastFailover.ShouldNotBeNull(); - await _service.DisconnectAsync(); + await _service.DisconnectAsync(TestContext.Current.CancellationToken); gate.SetResult(); - await failover.WaitAsync(TimeSpan.FromSeconds(10)); + await failover.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); _service.IsConnected.ShouldBeFalse(); session2.Disposed.ShouldBeTrue(); @@ -1547,7 +1544,7 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); var tasks = new List(); for (var i = 0; i < 50; i++) @@ -1574,7 +1571,7 @@ public class OpcUaClientServiceTests : IDisposable { var session = new FakeSessionAdapter(); _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); _service.Dispose(); @@ -1645,14 +1642,14 @@ public class OpcUaClientServiceTests : IDisposable // Second CreateSubscription call should return the alarm fake. // We wire it by overriding the factory queue after the first subscribe. _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); // Subscribe data (uses dataFakeSub from session.NextSubscription). - await _service.SubscribeAsync(new NodeId("ns=2;s=Node1")); + await _service.SubscribeAsync(new NodeId("ns=2;s=Node1"), ct: TestContext.Current.CancellationToken); // Now set NextSubscription on the session so SubscribeAlarmsAsync gets the alarm fake. session.NextSubscription = alarmFakeSub; - await _service.SubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); // Both subscriptions are now active. Disconnect with a cancellable token. using var cts = new CancellationTokenSource(); @@ -1681,7 +1678,7 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); // Fire many concurrent SubscribeAlarmsAsync calls — only one should "win". var tasks = Enumerable.Range(0, 20).Select(_ => @@ -1706,9 +1703,9 @@ public class OpcUaClientServiceTests : IDisposable var fakeSub = new FakeSubscriptionAdapter(); var session = new FakeSessionAdapter { NextSubscription = fakeSub }; _sessionFactory.EnqueueSession(session); - await _service.ConnectAsync(ValidSettings()); + await _service.ConnectAsync(ValidSettings(), TestContext.Current.CancellationToken); - await _service.SubscribeAlarmsAsync(); + await _service.SubscribeAlarmsAsync(ct: TestContext.Current.CancellationToken); using var cts = new CancellationTokenSource(); await _service.UnsubscribeAlarmsAsync(cts.Token); diff --git a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.UI.Tests/BrowseTreeViewModelTests.cs b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.UI.Tests/BrowseTreeViewModelTests.cs index 92eb1b6cf..0c1a87c94 100644 --- a/tests/Client/ZB.MOM.WW.OtOpcUa.Client.UI.Tests/BrowseTreeViewModelTests.cs +++ b/tests/Client/ZB.MOM.WW.OtOpcUa.Client.UI.Tests/BrowseTreeViewModelTests.cs @@ -106,7 +106,7 @@ public class BrowseTreeViewModelTests parent.IsExpanded = true; // Allow async operation to complete - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); _service.BrowseCallCount.ShouldBe(initialBrowseCount + 1); parent.Children.Count.ShouldBe(1); @@ -131,13 +131,13 @@ public class BrowseTreeViewModelTests var parent = _vm.RootNodes[0]; parent.IsExpanded = true; - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); var browseCountAfterFirst = _service.BrowseCallCount; parent.IsExpanded = false; parent.IsExpanded = true; - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); _service.BrowseCallCount.ShouldBe(browseCountAfterFirst); } @@ -157,7 +157,7 @@ public class BrowseTreeViewModelTests var parent = _vm.RootNodes[0]; parent.IsExpanded = true; - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // After completion, IsLoading should be false parent.IsLoading.ShouldBeFalse(); diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterAuditQueryTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterAuditQueryTests.cs index ee121383e..7667fa680 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterAuditQueryTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterAuditQueryTests.cs @@ -67,9 +67,9 @@ public sealed class ClusterAuditQueryTests : IDisposable // Noise that must NOT appear: other cluster's structured row + an orphan NodeId. SeedAudit("Published", clusterId: null, nodeId: "OTHER-A", ts: t0.AddMinutes(3)); SeedAudit("Published", clusterId: null, nodeId: "UNKNOWN-NODE", ts: t0.AddMinutes(4)); - await _db.SaveChangesAsync(); + await _db.SaveChangesAsync(TestContext.Current.CancellationToken); - var rows = await ClusterAuditQuery.ForClusterAsync(_db, "LINE3-OPCUA", pageSize: 200); + var rows = await ClusterAuditQuery.ForClusterAsync(_db, "LINE3-OPCUA", pageSize: 200, ct: TestContext.Current.CancellationToken); rows.Select(r => r.EventType).ShouldBe( ["NodeApplied", "DraftEdited", "Published"], // newest first @@ -83,9 +83,9 @@ public sealed class ClusterAuditQueryTests : IDisposable SeedNode("LINE3-OPCUA", "LINE3-OPCUA-A"); var t0 = new DateTime(2026, 6, 2, 10, 0, 0, DateTimeKind.Utc); SeedAudit("Published", clusterId: "OTHER-CLUSTER", nodeId: null, ts: t0); - await _db.SaveChangesAsync(); + await _db.SaveChangesAsync(TestContext.Current.CancellationToken); - var rows = await ClusterAuditQuery.ForClusterAsync(_db, "LINE3-OPCUA", pageSize: 200); + var rows = await ClusterAuditQuery.ForClusterAsync(_db, "LINE3-OPCUA", pageSize: 200, ct: TestContext.Current.CancellationToken); rows.ShouldBeEmpty(); } @@ -98,9 +98,9 @@ public sealed class ClusterAuditQueryTests : IDisposable var t0 = new DateTime(2026, 6, 2, 10, 0, 0, DateTimeKind.Utc); for (var i = 0; i < 5; i++) SeedAudit("DraftEdited", clusterId: null, nodeId: "LINE3-OPCUA-A", ts: t0.AddMinutes(i)); - await _db.SaveChangesAsync(); + await _db.SaveChangesAsync(TestContext.Current.CancellationToken); - var rows = await ClusterAuditQuery.ForClusterAsync(_db, "LINE3-OPCUA", pageSize: 3); + var rows = await ClusterAuditQuery.ForClusterAsync(_db, "LINE3-OPCUA", pageSize: 3, ct: TestContext.Current.CancellationToken); rows.Count.ShouldBe(3); rows.First().Timestamp.ShouldBe(t0.AddMinutes(4)); // newest diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterNodeTransportPortsTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterNodeTransportPortsTests.cs index 0e7df9cd4..c2e578143 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterNodeTransportPortsTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ClusterNodeTransportPortsTests.cs @@ -35,16 +35,16 @@ public sealed class ClusterNodeTransportPortsTests(SchemaComplianceFixture fixtu // GrpcPort is deliberately nullable: nothing listens on it until Phase 5, and a non-null // default would assert a port that does not exist. ctx.ClusterNodes.Add(NewNode(clusterId, "defaulted")); - await ctx.SaveChangesAsync(); + await ctx.SaveChangesAsync(TestContext.Current.CancellationToken); await using var read = NewContext(); var explicitNode = await read.ClusterNodes.AsNoTracking() - .SingleAsync(n => n.NodeId == $"{clusterId}-explicit:4053"); + .SingleAsync(n => n.NodeId == $"{clusterId}-explicit:4053", cancellationToken: TestContext.Current.CancellationToken); explicitNode.AkkaPort.ShouldBe(4055); explicitNode.GrpcPort.ShouldBe(5223); var defaulted = await read.ClusterNodes.AsNoTracking() - .SingleAsync(n => n.NodeId == $"{clusterId}-defaulted:4053"); + .SingleAsync(n => n.NodeId == $"{clusterId}-defaulted:4053", cancellationToken: TestContext.Current.CancellationToken); defaulted.AkkaPort.ShouldBe(4053); defaulted.GrpcPort.ShouldBeNull(); } @@ -74,12 +74,12 @@ public sealed class ClusterNodeTransportPortsTests(SchemaComplianceFixture fixtu cmd.Parameters.AddWithValue("@clusterId", clusterId); cmd.Parameters.AddWithValue("@host", $"{clusterId}-raw"); cmd.Parameters.AddWithValue("@uri", $"urn:OtOpcUa:{clusterId}-raw"); - await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); } await using var read = NewContext(); var row = await read.ClusterNodes.AsNoTracking() - .SingleAsync(n => n.NodeId == $"{clusterId}-raw:4053"); + .SingleAsync(n => n.NodeId == $"{clusterId}-raw:4053", cancellationToken: TestContext.Current.CancellationToken); row.AkkaPort.ShouldBe(4053); row.GrpcPort.ShouldBeNull(); } @@ -96,13 +96,13 @@ public sealed class ClusterNodeTransportPortsTests(SchemaComplianceFixture fixtu var clusterId = await SeedClusterAsync(ctx); ctx.ClusterNodes.Add(NewNode(clusterId, "a", n => n.GrpcPort = 5223)); ctx.ClusterNodes.Add(NewNode(clusterId, "b")); - await ctx.SaveChangesAsync(); + await ctx.SaveChangesAsync(TestContext.Current.CancellationToken); await using var read = NewContext(); var contacts = await read.ClusterNodes.AsNoTracking() .Where(n => n.ClusterId == clusterId && n.GrpcPort != null) .Select(n => new { n.Host, n.AkkaPort, n.GrpcPort }) - .ToListAsync(); + .ToListAsync(cancellationToken: TestContext.Current.CancellationToken); contacts.Count.ShouldBe(1); contacts[0].AkkaPort.ShouldBe(4053); diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactorySqlServerTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactorySqlServerTests.cs index aa16ead6d..9dde59003 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactorySqlServerTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactorySqlServerTests.cs @@ -52,7 +52,7 @@ public sealed class DraftSnapshotFactorySqlServerTests ClusterId = clusterId, Name = "snapshot-read", Enterprise = "zb", Site = "test", NodeCount = 1, RedundancyMode = RedundancyMode.None, CreatedBy = "test", }); - await seed.SaveChangesAsync(); + await seed.SaveChangesAsync(TestContext.Current.CancellationToken); } try @@ -64,7 +64,7 @@ public sealed class DraftSnapshotFactorySqlServerTests await using (var db = new OtOpcUaConfigDbContext(options)) { - var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(db); + var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(db, TestContext.Current.CancellationToken); // The interceptor committed a Script while ServerClusters (the FIRST table read) was being // materialised. Scripts is read later in the same transaction and must not see it. snapshot.ServerClusters.ShouldContain(c => c.ClusterId == clusterId); @@ -74,16 +74,16 @@ public sealed class DraftSnapshotFactorySqlServerTests await using (var verify = NewContext()) { // Positive control: the edit really landed, and a read started afterwards sees it. - (await verify.Scripts.AnyAsync(s => s.ScriptId == scriptId)).ShouldBeTrue(); - var later = await DraftSnapshotFactory.FromConfigDbAsync(verify); + (await verify.Scripts.AnyAsync(s => s.ScriptId == scriptId, cancellationToken: TestContext.Current.CancellationToken)).ShouldBeTrue(); + var later = await DraftSnapshotFactory.FromConfigDbAsync(verify, TestContext.Current.CancellationToken); later.Scripts.ShouldContain(s => s.ScriptId == scriptId); } } finally { await using var cleanup = NewContext(); - await cleanup.Scripts.Where(s => s.ScriptId == scriptId).ExecuteDeleteAsync(); - await cleanup.ServerClusters.Where(c => c.ClusterId == clusterId).ExecuteDeleteAsync(); + await cleanup.Scripts.Where(s => s.ScriptId == scriptId).ExecuteDeleteAsync(cancellationToken: TestContext.Current.CancellationToken); + await cleanup.ServerClusters.Where(c => c.ClusterId == clusterId).ExecuteDeleteAsync(cancellationToken: TestContext.Current.CancellationToken); } } diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactoryTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactoryTests.cs index df1fad5af..0ba5350d0 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactoryTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftSnapshotFactoryTests.cs @@ -39,9 +39,9 @@ public sealed class DraftSnapshotFactoryTests : IDisposable _db.Tags.Add(BuildTag(name: "speed")); _db.VirtualTags.Add(BuildVirtualTag(equipmentId: "eq-1", name: "speed", suffix: "a")); _db.VirtualTags.Add(BuildVirtualTag(equipmentId: "eq-1", name: "speed", suffix: "b")); - await _db.SaveChangesAsync(); + await _db.SaveChangesAsync(TestContext.Current.CancellationToken); - var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db); + var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db, TestContext.Current.CancellationToken); snapshot.Tags.Count.ShouldBe(1); snapshot.VirtualTags.Count.ShouldBe(2); @@ -56,9 +56,9 @@ public sealed class DraftSnapshotFactoryTests : IDisposable SeedEquipment("eq-1"); _db.Tags.Add(BuildTag(name: "speed")); _db.VirtualTags.Add(BuildVirtualTag(equipmentId: "eq-1", name: "temperature")); - await _db.SaveChangesAsync(); + await _db.SaveChangesAsync(TestContext.Current.CancellationToken); - var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db); + var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db, TestContext.Current.CancellationToken); snapshot.Tags.Count.ShouldBe(1); snapshot.VirtualTags.Count.ShouldBe(1); @@ -94,9 +94,9 @@ public sealed class DraftSnapshotFactoryTests : IDisposable ReleasedBy = "test", ReleaseReason = "retired", }); - await _db.SaveChangesAsync(); + await _db.SaveChangesAsync(TestContext.Current.CancellationToken); - var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db); + var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db, TestContext.Current.CancellationToken); snapshot.ActiveReservations.Count.ShouldBe(1); snapshot.ActiveReservations[0].Value.ShouldBe("ZT-001"); @@ -124,9 +124,9 @@ public sealed class DraftSnapshotFactoryTests : IDisposable { ApiKeyId = "k1", Name = "scada", SecretHash = "hash", Principal = "scadabridge", Enabled = true, }); - await _db.SaveChangesAsync(); + await _db.SaveChangesAsync(TestContext.Current.CancellationToken); - var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db); + var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db, TestContext.Current.CancellationToken); snapshot.ServerClusters.ShouldHaveSingleItem().ClusterId.ShouldBe("SITE-A"); snapshot.ClusterNodes.ShouldHaveSingleItem().NodeId.ShouldBe("site-a-1:4053"); diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineRunGuardTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineRunGuardTests.cs index ab2fde044..3e472fe1a 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineRunGuardTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineRunGuardTests.cs @@ -107,7 +107,7 @@ public sealed class ScriptedAlarmEngineRunGuardTests await WaitForAsync(() => eng.RunGuard.StartedRunCount > before); } eng.RunGuard.StartedRunCount.ShouldBe(1 + 1 + pushes, "one runaway dispatch, then healthy-only dispatches"); - await Task.Delay(300); // absence window for trailing emissions + await Task.Delay(300, TestContext.Current.CancellationToken); // absence window for trailing emissions ScriptedAlarmEvent[] snapshot; lock (events) snapshot = events.ToArray(); diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineTests.cs index af5fae066..d023a8f49 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmEngineTests.cs @@ -215,7 +215,7 @@ public sealed class ScriptedAlarmEngineTests eng.OnEvent += (_, e) => events.Add(e); up.Push("Temp", 150); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); events.Any(e => e.Emission == EmissionKind.Activated).ShouldBeFalse( "OneShot shelve suppresses activation emission"); @@ -252,7 +252,7 @@ public sealed class ScriptedAlarmEngineTests await eng.DisableAsync("HighTemp", "alice", TestContext.Current.CancellationToken); up.Push("Temp", 150); - await Task.Delay(100); + await Task.Delay(100, TestContext.Current.CancellationToken); eng.GetState("HighTemp")!.Active.ShouldBe(AlarmActiveState.Inactive, "disabled alarm ignores predicate"); @@ -353,7 +353,7 @@ public sealed class ScriptedAlarmEngineTests up.Push($"Temp{round % alarmCount}", round % 2 == 0 ? 150 : 50); round++; } - }); + }, TestContext.Current.CancellationToken); // Readers: continuously touch the three unguarded read paths. var readers = Enumerable.Range(0, 4).Select(_reader => Task.Run(() => @@ -839,7 +839,7 @@ public sealed class ScriptedAlarmEngineTests // Dispose must wait for the in-flight reevaluation to complete rather // than returning while a background task still runs. - var disposeTask = Task.Run(() => eng.Dispose()); + var disposeTask = Task.Run(() => eng.Dispose(), TestContext.Current.CancellationToken); // Verify Dispose does NOT complete immediately — it should block waiting // for the in-flight task. Without the -006 fix Dispose returns straight @@ -1003,7 +1003,7 @@ public sealed class ScriptedAlarmEngineTests // load could keep firing between the failed second load and Dispose. // After the fix, it is stopped at the START of every LoadAsync attempt // (successful or not), so Dispose always finds a clean timer state. - var disposeTask = Task.Run(() => eng.Dispose()); + var disposeTask = Task.Run(() => eng.Dispose(), TestContext.Current.CancellationToken); await disposeTask.WaitAsync(TimeSpan.FromSeconds(3), TestContext.Current.CancellationToken); // If Dispose threw or hung, the WaitAsync would surface it. } @@ -1748,12 +1748,12 @@ public sealed class ScriptedAlarmEngineTests eng.TrackBackgroundTaskForTest(() => gate.Task); eng.InFlightCountForTest.ShouldBe(1); - var disposeTask = Task.Run(() => eng.Dispose()); + var disposeTask = Task.Run(() => eng.Dispose(), TestContext.Current.CancellationToken); var raced = await Task.WhenAny(disposeTask, Task.Delay(300)); raced.ShouldNotBe(disposeTask, "Dispose must not return while registered background work is still running"); gate.SetResult(); - await disposeTask.WaitAsync(TimeSpan.FromSeconds(5)); + await disposeTask.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); eng.InFlightCountForTest.ShouldBe(0, "completed work must unregister itself"); } @@ -1785,7 +1785,7 @@ public sealed class ScriptedAlarmEngineTests () => throw new InvalidOperationException("factory failed (test)"))); eng.InFlightCountForTest.ShouldBe(0, "work that never started must not be left registered"); - await Task.Run(() => eng.Dispose()).WaitAsync(TimeSpan.FromSeconds(5)); + await Task.Run(() => eng.Dispose(), TestContext.Current.CancellationToken).WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); } /// Verifies a faulted background task is still drained by Dispose and its failure is @@ -1801,11 +1801,11 @@ public sealed class ScriptedAlarmEngineTests // Fault it while Dispose is actually blocked on the drain, so the WhenAll observes // the failure rather than finding an already-unregistered task. - var disposeTask = Task.Run(() => Should.NotThrow(() => eng.Dispose())); - await Task.Delay(200); + var disposeTask = Task.Run(() => Should.NotThrow(() => eng.Dispose()), TestContext.Current.CancellationToken); + await Task.Delay(200, TestContext.Current.CancellationToken); gate.SetException(new InvalidOperationException("background failed (test)")); - await disposeTask.WaitAsync(TimeSpan.FromSeconds(5)); + await disposeTask.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); eng.InFlightCountForTest.ShouldBe(0); } diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceLoggingTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceLoggingTests.cs index 94c0408c9..9f93d3e3e 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceLoggingTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceLoggingTests.cs @@ -46,7 +46,7 @@ public sealed class ScriptedAlarmSourceLoggingTests if (sinkCapture.Events.Any(e => e.Level == LogEventLevel.Warning && e.Exception?.Message == "subscriber broke")) break; } - await Task.Delay(25); + await Task.Delay(25, TestContext.Current.CancellationToken); } LogEvent warning; diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceTests.cs index f3851326f..ed0f25b74 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ScriptedAlarmSourceTests.cs @@ -53,7 +53,7 @@ public sealed class ScriptedAlarmSourceTests var handle = await source.SubscribeAlarmsAsync([], TestContext.Current.CancellationToken); up.Push("Temp", 150); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); events.Count.ShouldBe(1); events[0].ConditionId.ShouldBe("Plant/Line1::HighTemp"); @@ -80,7 +80,7 @@ public sealed class ScriptedAlarmSourceTests var handle = await source.SubscribeAlarmsAsync(["Plant/Line1"], TestContext.Current.CancellationToken); up.Push("Temp", 150); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); events.Count.ShouldBe(1); events[0].SourceNodeId.ShouldBe("Plant/Line1"); @@ -102,7 +102,7 @@ public sealed class ScriptedAlarmSourceTests await source.UnsubscribeAlarmsAsync(handle, TestContext.Current.CancellationToken); up.Push("Temp", 150); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); events.Count.ShouldBe(0); } @@ -124,7 +124,7 @@ public sealed class ScriptedAlarmSourceTests // Drive HighTemp's input Bad: the predicate freezes (no transition), but the worst-quality bucket // moves Good→Bad → the engine emits QualityChanged. The source must swallow it. up.Push("Temp", 50, 0x80000000u); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); events.ShouldBeEmpty(); } @@ -138,7 +138,7 @@ public sealed class ScriptedAlarmSourceTests using var _s = source; up.Push("Temp", 150); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); engine.GetState("Plant/Line1::HighTemp")!.Acked.ShouldBe(AlarmAckedState.Unacknowledged); await source.AcknowledgeAsync([new AlarmAcknowledgeRequest( @@ -165,7 +165,7 @@ public sealed class ScriptedAlarmSourceTests // Supplied principal -> honored. up.Push("Temp", 150); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); await source.AcknowledgeAsync([new AlarmAcknowledgeRequest( "Plant/Line1", "Plant/Line1::HighTemp", "ack as bob", "bob")], TestContext.Current.CancellationToken); @@ -173,9 +173,9 @@ public sealed class ScriptedAlarmSourceTests // No principal -> default audit identity. up.Push("Temp", 50); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); up.Push("Temp", 150); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); await source.AcknowledgeAsync([new AlarmAcknowledgeRequest( "Plant/Line1", "Plant/Line1::HighTemp", "ack anon", null)], TestContext.Current.CancellationToken); diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptCancellationTokenTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptCancellationTokenTests.cs index a465d2d4a..da79d3149 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptCancellationTokenTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptCancellationTokenTests.cs @@ -36,7 +36,7 @@ public sealed class ScriptCancellationTokenTests { using var eval = ScriptEvaluator.Compile("return 1;"); var ctx = new FakeScriptContext(); - (await eval.RunAsync(ctx)).ShouldBe(1); + (await eval.RunAsync(ctx, TestContext.Current.CancellationToken)).ShouldBe(1); ctx.CancellationToken.ShouldBe(CancellationToken.None, "the token is scoped to the run, not left on the context"); } diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Tests/Resilience/DriverResiliencePipelineBuilderTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Tests/Resilience/DriverResiliencePipelineBuilderTests.cs index 4d6c87848..246d33460 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Tests/Resilience/DriverResiliencePipelineBuilderTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Tests/Resilience/DriverResiliencePipelineBuilderTests.cs @@ -26,7 +26,7 @@ public sealed class DriverResiliencePipelineBuilderTests attempts++; if (attempts < 3) throw new InvalidOperationException("transient"); await Task.Yield(); - }); + }, TestContext.Current.CancellationToken); attempts.ShouldBe(3); } @@ -141,7 +141,7 @@ public sealed class DriverResiliencePipelineBuilderTests { liveAttempts++; await Task.Yield(); - }); + }, TestContext.Current.CancellationToken); liveAttempts.ShouldBe(1, "healthy sibling host must not be affected by dead peer"); } @@ -200,7 +200,7 @@ public sealed class DriverResiliencePipelineBuilderTests { await Task.Yield(); ran = true; - }); + }, TestContext.Current.CancellationToken); ran.ShouldBeTrue("the breaker must stay closed after refusals"); } @@ -341,7 +341,7 @@ public sealed class DriverResiliencePipelineBuilderTests // Elapse the break duration (15 s) so the breaker half-opens, then let a probe succeed → OnClosed. clock.Advance(TimeSpan.FromSeconds(16)); - await pipeline.ExecuteAsync(async _ => await Task.Yield()); + await pipeline.ExecuteAsync(async _ => await Task.Yield(), TestContext.Current.CancellationToken); var snap = tracker.TryGet("drv-trk", "host-c")!; snap.LastBreakerClosedUtc.ShouldNotBeNull("OnClosed must stamp the close time on recovery"); @@ -404,7 +404,7 @@ public sealed class DriverResiliencePipelineBuilderTests await Task.Yield(); throw new InvalidOperationException("dead"); })); - await live.ExecuteAsync(async _ => await Task.Yield()); + await live.ExecuteAsync(async _ => await Task.Yield(), TestContext.Current.CancellationToken); tracker.TryGet("drv-trk", "dead")!.ConsecutiveFailures.ShouldBeGreaterThan(0); tracker.TryGet("drv-trk", "live").ShouldBeNull(); @@ -428,7 +428,7 @@ public sealed class DriverResiliencePipelineBuilderTests attempts++; if (attempts < 3) throw new InvalidOperationException("transient"); await Task.Yield(); - }); + }, TestContext.Current.CancellationToken); attempts.ShouldBe(3); logger.Entries.ShouldContain(e => diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlarmProjectionTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlarmProjectionTests.cs index 11979e9d4..53a59b003 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlarmProjectionTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlarmProjectionTests.cs @@ -392,7 +392,7 @@ public sealed class AbCipAlarmProjectionTests int Reads() => factory.Tags.Values.Sum(t => t.ReadCount); // the loop may re-create its runtime on the new device state var frozen = Reads(); - await Task.Delay(300); // ~15 poll intervals; a live loop would advance the count + await Task.Delay(300, TestContext.Current.CancellationToken); // ~15 poll intervals; a live loop would advance the count Reads().ShouldBe(frozen); await drv.ShutdownAsync(CancellationToken.None); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlmaProjectionTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlmaProjectionTests.cs index d93616e89..78ff1b161 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlmaProjectionTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipAlmaProjectionTests.cs @@ -357,7 +357,7 @@ public sealed class AbCipAlmaProjectionTests await Next(r, x => x.Kind == AlarmTransitionKind.Raise); r.Factory.Customise = p => new FakeAbCipTag(p) { Status = (int)AbStatus.NotFound }; r.Factory.Tags[$"{Tag}.HHSeverity"].Status = (int)AbStatus.NotFound; - await Task.Delay(150); + await Task.Delay(150, TestContext.Current.CancellationToken); await Settled(r); await r.StopAsync(); Snapshot(r).Count.ShouldBe(1, "no Retrigger/update from a Bad severity read"); @@ -394,7 +394,7 @@ public sealed class AbCipAlmaProjectionTests factory.Tags[$"{Tag}.HInAlarm"].Value = true; await WaitFor(() => { lock (events) return events.Count >= 2; }); - await Task.Delay(100); + await Task.Delay(100, TestContext.Current.CancellationToken); await drv.UnsubscribeAlarmsAsync(handle, CancellationToken.None); await drv.ShutdownAsync(CancellationToken.None); List evs; lock (events) evs = [.. events]; diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipDeviceRefusalTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipDeviceRefusalTests.cs index e4e23d7cb..fe2cc443f 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipDeviceRefusalTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipDeviceRefusalTests.cs @@ -89,7 +89,7 @@ public sealed class AbCipDeviceRefusalTests var (drv, factory) = Build(p => new RefusingTag(p) { ReadThrows = p.TagName == "Arr[999]" ? status : null, Value = 1 }); await drv.InitializeAsync("{}", CancellationToken.None); var before = drv.GetHealth().LastSuccessfulRead!.Value; - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); for (var i = 0; i < 3; i++) { @@ -239,7 +239,7 @@ public sealed class AbCipDeviceRefusalTests : new RefusingTag(p) { ReadThrows = AbStatus.Unsupported }); await drv.InitializeAsync("{}", CancellationToken.None); var before = drv.GetHealth().LastSuccessfulRead!.Value; - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); (await drv.ReadAsync(["Bad"], CancellationToken.None))[0].StatusCode.ShouldBe(AbCipStatusMapper.BadNotSupported); drv.GetHealth().LastSuccessfulRead.ShouldBe(before); @@ -278,7 +278,7 @@ public sealed class AbCipDeviceRefusalTests }, "abcip-refusal", factory); await drv.InitializeAsync("{}", CancellationToken.None); var before = drv.GetHealth().LastSuccessfulRead!.Value; - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); (await drv.WriteAsync([new WriteRequest("Ro", 5)], CancellationToken.None))[0].StatusCode .ShouldBe(AbCipStatusMapper.BadNotWritable); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipLifecycleConcurrencyTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipLifecycleConcurrencyTests.cs index 6811afccd..b975c245a 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipLifecycleConcurrencyTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipLifecycleConcurrencyTests.cs @@ -104,14 +104,14 @@ public sealed class AbCipLifecycleConcurrencyTests // The second init's own release waits on the slow first probe loop; the shutdown overtakes it there. var init = drv.InitializeAsync("{}", CancellationToken.None); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); await drv.ShutdownAsync(CancellationToken.None); var superseded = await Should.ThrowAsync(() => init); superseded.ShouldNotBeAssignableTo(); // M4: distinct from a caller cancellation drv.GetDeviceState(Host).ShouldBeNull(); drv.GetHostStatuses().ShouldBeEmpty(); - await Task.Delay(100); + await Task.Delay(100, TestContext.Current.CancellationToken); factory.Tags["ProbeTag"].ShouldBeSameAs(firstProbe); // no second probe loop ever created a runtime drv.GetHealth().State.ShouldNotBe(DriverState.Healthy); @@ -164,7 +164,7 @@ public sealed class AbCipLifecycleConcurrencyTests } return reads; }); - await started.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await started.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); for (var i = 0; i < 200; i++) await drv.InitializeAsync("{}", CancellationToken.None); @@ -204,7 +204,7 @@ public sealed class AbCipLifecycleConcurrencyTests await drv.InitializeAsync("{}", CancellationToken.None); await WaitUntilAsync(() => factory.Tags.ContainsKey("ProbeTag"), "probe never started"); var loop = drv.GetDeviceState(Host)!.ProbeTask!; - await Task.Delay(50); // the probe is inside its slow, cancellation-deaf read + await Task.Delay(50, TestContext.Current.CancellationToken); // the probe is inside its slow, cancellation-deaf read var sw = System.Diagnostics.Stopwatch.StartNew(); ((IDisposable)drv).Dispose(); @@ -225,10 +225,10 @@ public sealed class AbCipLifecycleConcurrencyTests var (drv, factory) = Build(probeReadDelay: TimeSpan.FromMilliseconds(400)); await drv.InitializeAsync("{}", CancellationToken.None); await WaitUntilAsync(() => factory.Tags.ContainsKey("ProbeTag"), "probe never started"); - await Task.Delay(30); // inside the slow probe read + await Task.Delay(30, TestContext.Current.CancellationToken); // inside the slow probe read var shutdown = drv.ShutdownAsync(CancellationToken.None); - await Task.Delay(30); + await Task.Delay(30, TestContext.Current.CancellationToken); await drv.InitializeAsync("{}", CancellationToken.None); // newer: publishes while the shutdown still joins await shutdown; diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipProbeRefusalTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipProbeRefusalTests.cs index c0693b8b6..3a6279fb2 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipProbeRefusalTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipProbeRefusalTests.cs @@ -59,7 +59,7 @@ public sealed class AbCipProbeRefusalTests var (drv, logger) = Build(new AbTransportException(AbStatus.NotFound, "NotFound")); await drv.InitializeAsync("{}", CancellationToken.None); await WaitUntilAsync(() => drv.GetHostStatuses().Single().State == HostState.Running); - await Task.Delay(100); // many probe ticks + await Task.Delay(100, TestContext.Current.CancellationToken); // many probe ticks var r = await drv.ReadAsync(["Speed"], CancellationToken.None); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipReadWindowTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipReadWindowTests.cs index 45cd34894..03f8b2905 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipReadWindowTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipReadWindowTests.cs @@ -84,7 +84,7 @@ public sealed class AbCipReadWindowTests await read; throw new ShouldAssertException("device A's read waited behind device B's blocked cold create"); } - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); } read.IsCompleted.ShouldBeFalse(); // B is still blocked — A was read regardless diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipWriteHealthTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipWriteHealthTests.cs index db68d1f51..c2537b994 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipWriteHealthTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipWriteHealthTests.cs @@ -84,7 +84,7 @@ public sealed class AbCipWriteHealthTests await drv.ReadAsync(["Broken"], CancellationToken.None); var degraded = drv.GetHealth(); degraded.State.ShouldBe(DriverState.Degraded); - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); var r = await drv.WriteAsync([new WriteRequest("D", 5)], CancellationToken.None); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyAnsweredStatusTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyAnsweredStatusTests.cs index 1b209131b..c2e9027c3 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyAnsweredStatusTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyAnsweredStatusTests.cs @@ -173,7 +173,7 @@ public sealed class AbLegacyAnsweredStatusTests var healthyAt = drv.GetHealth().LastSuccessfulRead; // positive control: Good reads DID advance it healthyAt.ShouldNotBeNull(); foreach (var t in factory.Tags.Values) t.Status = RemoteErr; - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); for (var poll = 0; poll < 3; poll++) (await drv.ReadAsync(["X", "Y"], CancellationToken.None)).ShouldAllBe(s => s.StatusCode == AbLegacyStatusMapper.BadCommunicationError); @@ -203,7 +203,7 @@ public sealed class AbLegacyAnsweredStatusTests var healthyAt = drv.GetHealth().LastSuccessfulRead; drv.GetDeviceState(Host)!.Runtimes.TryRemove("X", out _); factory.Customise = p => new ThrowingTag(p, status); - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); var r = await drv.ReadAsync(["X"], CancellationToken.None); @@ -220,7 +220,7 @@ public sealed class AbLegacyAnsweredStatusTests var drv = NewDriver(factory, coalesce: false, new AbLegacyTagDefinition("X", Host, "N7:0", AbLegacyDataType.Int)); await drv.InitializeAsync("{}", CancellationToken.None); var before = drv.GetHealth().LastSuccessfulRead; - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); (await drv.ReadAsync(["X"], CancellationToken.None))[0].StatusCode.ShouldBe(AbLegacyStatusMapper.BadNodeIdUnknown); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyBatchSubscribeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyBatchSubscribeTests.cs index 08c422b0e..859b3df4f 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyBatchSubscribeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyBatchSubscribeTests.cs @@ -36,7 +36,7 @@ public sealed class AbLegacyBatchSubscribeTests var handle = await drv.SubscribeAsync(["A", "B"], TimeSpan.FromMilliseconds(100), CancellationToken.None); var deadline = DateTime.UtcNow.AddSeconds(5); - while (batches.IsEmpty && DateTime.UtcNow < deadline) await Task.Delay(10); + while (batches.IsEmpty && DateTime.UtcNow < deadline) await Task.Delay(10, TestContext.Current.CancellationToken); batches.TryPeek(out var first).ShouldBeTrue(); first!.SubscriptionHandle.ShouldBe(handle); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyDeviceIsolationTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyDeviceIsolationTests.cs index 16064b8de..21b9537e0 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyDeviceIsolationTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyDeviceIsolationTests.cs @@ -101,7 +101,7 @@ public sealed class AbLegacyDeviceIsolationTests new AbLegacyTagDefinition("B", HostB, "N7:0", AbLegacyDataType.Int)); await drv.InitializeAsync("{}", CancellationToken.None); - var r = await drv.ReadAsync(["A", "B"], CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(5)); + var r = await drv.ReadAsync(["A", "B"], CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); r[0].Value.ShouldBe(1); r[1].Value.ShouldBe(2); @@ -157,7 +157,7 @@ public sealed class AbLegacyDeviceIsolationTests }, "drv-p7", factory, logger); await drv.InitializeAsync("{}", CancellationToken.None); var initHealth = drv.GetHealth(); - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); var r1 = await drv.ReadAsync(["X"], CancellationToken.None); var r2 = await drv.ReadAsync(["X"], CancellationToken.None); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyFamilyAddressingTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyFamilyAddressingTests.cs index 587162283..c8ac3190b 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyFamilyAddressingTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyFamilyAddressingTests.cs @@ -289,7 +289,7 @@ public sealed class AbLegacyFamilyAddressingTests await drv.InitializeAsync("{}", CancellationToken.None); var deadline = DateTime.UtcNow.AddSeconds(5); - while (!factory.Tags.ContainsKey("I:15") && DateTime.UtcNow < deadline) await Task.Delay(20); + while (!factory.Tags.ContainsKey("I:15") && DateTime.UtcNow < deadline) await Task.Delay(20, TestContext.Current.CancellationToken); await drv.ShutdownAsync(CancellationToken.None); factory.Tags.ContainsKey("I:15").ShouldBeTrue(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyHealthEvidenceTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyHealthEvidenceTests.cs index e5e15fcfc..8915412f9 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyHealthEvidenceTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyHealthEvidenceTests.cs @@ -53,7 +53,7 @@ public sealed class AbLegacyHealthEvidenceTests var drv = await DegradedDriverAsync(f, new AbLegacyTagDefinition("X", Host, "N7:0", AbLegacyDataType.Int)); var before = drv.GetHealth().LastSuccessfulRead; f.Make = p => new FakeAbLegacyTag(p) { Status = (int)AbStatus.NotFound }; - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); var r = await drv.ReadAsync(["X"], CancellationToken.None); @@ -75,7 +75,7 @@ public sealed class AbLegacyHealthEvidenceTests new AbLegacyTagDefinition("W", Host, "N7:5", AbLegacyDataType.Int)); var before = drv.GetHealth().LastSuccessfulRead; f.Make = p => new FakeAbLegacyTag(p) { WriteStatusOverride = writeStatus }; - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); var w = await drv.WriteAsync([new WriteRequest("W", 3)], CancellationToken.None); @@ -113,7 +113,7 @@ public sealed class AbLegacyHealthEvidenceTests new AbLegacyTagDefinition("Bad", Host, "N7:6", AbLegacyDataType.Int)); await drv.InitializeAsync("{}", CancellationToken.None); var before = drv.GetHealth().LastSuccessfulRead; - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); var w = await drv.WriteAsync([new WriteRequest("Good", 1), new WriteRequest("Bad", 2)], CancellationToken.None); @@ -207,7 +207,7 @@ public sealed class AbLegacyHealthEvidenceTests await entered.Task; var shutdown = drv.ShutdownAsync(CancellationToken.None); // parks joining the wedged probe loop - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); shutdown.IsCompleted.ShouldBeFalse(); await drv.InitializeAsync("{}", CancellationToken.None); // a newer initialise wins drv.GetHealth().State.ShouldBe(DriverState.Healthy); @@ -242,13 +242,13 @@ public sealed class AbLegacyHealthEvidenceTests var first = f.Tags["N7:0"]; var gate = state.GetRuntimeLock("X"); - await gate.WaitAsync(); + await gate.WaitAsync(TestContext.Current.CancellationToken); // Signalled at exactly "handle fetched, about to wait on the gate" — no sleep, so the eviction below always // lands between the reader's fetch and its use (review 07 r1 test nit: the sleep could pass vacuously). var atGate = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); state.BeforeOperationGate = key => { if (key == "X") atGate.TrySetResult(); }; var read = drv.ReadAsync(["X"], CancellationToken.None); - await atGate.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await atGate.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); state.Runtimes.TryRemove("X", out var evicted).ShouldBeTrue(); evicted!.Dispose(); gate.Release(); @@ -285,11 +285,11 @@ public sealed class AbLegacyHealthEvidenceTests state.Runtimes.ContainsKey(key).ShouldBeTrue(); var gate = state.GetRuntimeLock(key); - await gate.WaitAsync(); + await gate.WaitAsync(TestContext.Current.CancellationToken); var atGate = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); state.BeforeOperationGate = k => { if (k == key) atGate.TrySetResult(); }; var read = drv.ReadAsync(["Ind"], CancellationToken.None); - await atGate.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await atGate.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); // What the sweep does when the index moves: evict the resolution, then forget its gate. state.Runtimes.TryRemove(key, out var swept).ShouldBeTrue(); swept!.Dispose(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyLifecycleConcurrencyTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyLifecycleConcurrencyTests.cs index 58f4f95de..1b2551344 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyLifecycleConcurrencyTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyLifecycleConcurrencyTests.cs @@ -189,7 +189,7 @@ public sealed class AbLegacyLifecycleConcurrencyTests await probe!.Entered.Task; var shutdown = drv.ShutdownAsync(CancellationToken.None); // parks joining the wedged probe loop - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); shutdown.IsCompleted.ShouldBeFalse(); Should.NotThrow(() => drv.Dispose()); @@ -232,14 +232,14 @@ public sealed class AbLegacyLifecycleConcurrencyTests await first!.Entered.Task; var abandoned = drv.InitializeAsync("{}", CancellationToken.None); // parks joining the wedged loop - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); abandoned.IsCompleted.ShouldBeFalse(); await drv.ShutdownAsync(CancellationToken.None); release.SetResult(); await Should.ThrowAsync(() => abandoned); var createdAfter = probes.Count; - await Task.Delay(150); // several probe intervals + await Task.Delay(150, TestContext.Current.CancellationToken); // several probe intervals drv.DeviceCount.ShouldBe(0); drv.GetHealth().State.ShouldBe(DriverState.Unknown); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyShutdownJoinTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyShutdownJoinTests.cs index c9cb080b2..2b32ce092 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyShutdownJoinTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/AbLegacyShutdownJoinTests.cs @@ -38,16 +38,16 @@ public sealed class AbLegacyShutdownJoinTests Probe = new AbLegacyProbeOptions { Enabled = true, Interval = TimeSpan.FromMilliseconds(50), ProbeAddress = "S:0" }, }, "drv-join", factory); await drv.InitializeAsync("{}", CancellationToken.None); - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); var shutdown = drv.ShutdownAsync(CancellationToken.None); - await Task.Delay(300); + await Task.Delay(300, TestContext.Current.CancellationToken); shutdown.IsCompleted.ShouldBeFalse("shutdown must join the probe loop parked in runtime init"); // Positive control: releasing the parked call lets shutdown finish, with the probe runtime released. release.SetResult(); - await shutdown.WaitAsync(TimeSpan.FromSeconds(5)); + await shutdown.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); factory.Tags["S:0"].Disposed.ShouldBeTrue(); } @@ -68,16 +68,16 @@ public sealed class AbLegacyShutdownJoinTests Probe = new AbLegacyProbeOptions { Enabled = true, Interval = TimeSpan.FromMilliseconds(50), ProbeAddress = "S:0" }, }, "drv-join-dispose", factory); await drv.InitializeAsync("{}", CancellationToken.None); - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); - var dispose = Task.Run(drv.Dispose); + var dispose = Task.Run(drv.Dispose, TestContext.Current.CancellationToken); - await Task.Delay(300); + await Task.Delay(300, TestContext.Current.CancellationToken); dispose.IsCompleted.ShouldBeFalse("Dispose must join the probe loop parked in runtime init"); // Positive control: releasing the parked call lets Dispose finish, with the probe runtime released. release.SetResult(); - await dispose.WaitAsync(TimeSpan.FromSeconds(5)); + await dispose.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); factory.Tags["S:0"].Disposed.ShouldBeTrue(); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverRemediationTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverRemediationTests.cs index 0372ea151..3ab38981e 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverRemediationTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverRemediationTests.cs @@ -61,7 +61,7 @@ public sealed class CalculationDriverRemediationTests await driver.InitializeAsync("{}", TestContext.Current.CancellationToken); driver.OnDependencyValue("src/a", 1, StatusGood, DateTime.UtcNow); var deadline = DateTime.UtcNow.AddSeconds(10); - while (driver.IsEvaluationIdle && DateTime.UtcNow < deadline) await Task.Delay(5); + while (driver.IsEvaluationIdle && DateTime.UtcNow < deadline) await Task.Delay(5, TestContext.Current.CancellationToken); driver.IsEvaluationIdle.ShouldBeFalse("positive control: a run is in flight when Dispose lands"); var sw = System.Diagnostics.Stopwatch.StartNew(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverTests.cs index cf22038b1..cf6839b06 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Tests/CalculationDriverTests.cs @@ -74,7 +74,7 @@ public sealed class CalculationDriverTests { var (driver, published, _) = Build( CalcTag("calc/e/sum", "return (double)ctx.GetTag(\"src/a\").Value + (double)ctx.GetTag(\"src/b\").Value;")); - await driver.InitializeAsync("{}", default); + await driver.InitializeAsync("{}", TestContext.Current.CancellationToken); // Only one of two deps arrived → the change-gate holds. driver.OnDependencyValue("src/a", 10.0, StatusGood, DateTime.UtcNow); @@ -197,7 +197,7 @@ public sealed class CalculationDriverTests { var (driver, published, _) = Build( CalcTag("calc/e/dbl", "return (double)ctx.GetTag(\"src/a\").Value * 2.0;")); - await driver.InitializeAsync("{}", default); + await driver.InitializeAsync("{}", TestContext.Current.CancellationToken); // Each arrival is queued with the dependency snapshot that triggered it, so the three evaluations // see 5 / 5 / 7 in that order however far the pump lags behind them. @@ -216,7 +216,7 @@ public sealed class CalculationDriverTests { var (driver, published, logs) = Build( CalcTag("calc/e/div", "return 100 / (int)ctx.GetTag(\"src/a\").Value;")); - await driver.InitializeAsync("{}", default); + await driver.InitializeAsync("{}", TestContext.Current.CancellationToken); // a = 0 → DivideByZero → Failure → Bad (carrying last-known = null) + one script-log. driver.OnDependencyValue("src/a", 0, StatusGood, DateTime.UtcNow); @@ -254,7 +254,7 @@ public sealed class CalculationDriverTests // No dependencies (constant script) so only the timer can drive it. var (driver, published, _) = Build( CalcTag("calc/e/const", "return 42.0;", changeTriggered: false, timerMs: 50)); - await driver.InitializeAsync("{}", default); + await driver.InitializeAsync("{}", TestContext.Current.CancellationToken); var fired = await WaitUntil(() => !published.IsEmpty, TimeSpan.FromSeconds(3)); fired.ShouldBeTrue("the timer trigger should have computed the tag within 3s"); @@ -262,7 +262,7 @@ public sealed class CalculationDriverTests e!.FullReference.ShouldBe("calc/e/const"); e.Snapshot.Value.ShouldBe(42.0); - await driver.ShutdownAsync(default); + await driver.ShutdownAsync(TestContext.Current.CancellationToken); } // ── IReadable ───────────────────────────────────────────────────────────────────────────── @@ -271,14 +271,14 @@ public sealed class CalculationDriverTests public async Task Read_returns_BadWaitingForInitialData_before_first_eval_then_the_computed_value() { var (driver, _, _) = Build(CalcTag("calc/e/x", "return (double)ctx.GetTag(\"src/a\").Value * 2.0;")); - await driver.InitializeAsync("{}", default); + await driver.InitializeAsync("{}", TestContext.Current.CancellationToken); - var before = await driver.ReadAsync(new[] { "calc/e/x" }, default); + var before = await driver.ReadAsync(new[] { "calc/e/x" }, TestContext.Current.CancellationToken); before[0].StatusCode.ShouldBe(StatusBadWaitingForInitialData); driver.OnDependencyValue("src/a", 3.0, StatusGood, DateTime.UtcNow); await Settle(driver); - var after = await driver.ReadAsync(new[] { "calc/e/x" }, default); + var after = await driver.ReadAsync(new[] { "calc/e/x" }, TestContext.Current.CancellationToken); after[0].StatusCode.ShouldBe(StatusGood); after[0].Value.ShouldBe(6.0); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs index a6cc26235..638eb0244 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs @@ -111,7 +111,7 @@ public sealed class FocasCapabilityTests await drv.ShutdownAsync(CancellationToken.None); var afterShutdown = events.Count; - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); events.Count.ShouldBe(afterShutdown); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasConcurrentConnectTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasConcurrentConnectTests.cs index a92b195cb..33cddd73a 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasConcurrentConnectTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasConcurrentConnectTests.cs @@ -60,7 +60,7 @@ public sealed class FocasConcurrentConnectTests // Deterministic: the first caller is now parked INSIDE its connect (client created, not yet connected) — // the exact window the race needs. The second caller then runs synchronously up to its first real await: // pre-fix that is "dispose the first client, Create() a second"; with the gate it parks on ConnectGate. - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); var second = drv.ReadAsync(["B"], CancellationToken.None); release.SetResult(); var results = await Task.WhenAll(first, second); @@ -89,9 +89,9 @@ public sealed class FocasConcurrentConnectTests (await drv.ReadAsync(["A"], CancellationToken.None)).Single().StatusCode .ShouldNotBe(FocasStatusMapper.Good); // Past the 1 s initial connect backoff window, the next caller must be able to connect. - await Task.Delay(TimeSpan.FromMilliseconds(1100)); + await Task.Delay(TimeSpan.FromMilliseconds(1100), TestContext.Current.CancellationToken); var read = drv.ReadAsync(["A"], CancellationToken.None); - (await read.WaitAsync(TimeSpan.FromSeconds(5))).Single().StatusCode.ShouldBe(FocasStatusMapper.Good); + (await read.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken)).Single().StatusCode.ShouldBe(FocasStatusMapper.Good); } /// @@ -120,12 +120,12 @@ public sealed class FocasConcurrentConnectTests using var cts = new CancellationTokenSource(); var cancelled = drv.ReadAsync(["A"], cts.Token); - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); cts.Cancel(); try { await cancelled; } catch (OperationCanceledException) { /* either surfaced or mapped — both fine */ } // Immediately — well inside the 1 s initial backoff window a recorded failure would have opened. - var next = await drv.ReadAsync(["A"], CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(5)); + var next = await drv.ReadAsync(["A"], CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); next.Single().StatusCode.ShouldBe(FocasStatusMapper.Good, "a caller's own cancellation must not throttle the next connect"); factory.Clients.Count.ShouldBe(2); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDeviceTableLifecycleTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDeviceTableLifecycleTests.cs index 056b7ca8a..e9d7b2b72 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDeviceTableLifecycleTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDeviceTableLifecycleTests.cs @@ -67,11 +67,11 @@ public sealed class FocasDeviceTableLifecycleTests } catch (Exception ex) { lock (errors) errors.Add(ex); } } - }); + }, TestContext.Current.CancellationToken); for (var i = 0; i < 100; i++) await drv.InitializeAsync("{}", CancellationToken.None); - await Task.Delay(100); + await Task.Delay(100, TestContext.Current.CancellationToken); stop.Cancel(); await reader; await drv.ShutdownAsync(CancellationToken.None); @@ -105,13 +105,13 @@ public sealed class FocasDeviceTableLifecycleTests await drv.InitializeAsync("{}", CancellationToken.None); var read = drv.ReadAsync(["raw/R"], CancellationToken.None); - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); var shutdown = drv.ShutdownAsync(CancellationToken.None); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); release.SetResult(); - await shutdown.WaitAsync(TimeSpan.FromSeconds(10)); - var snaps = await read.WaitAsync(TimeSpan.FromSeconds(5)); + await shutdown.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); + var snaps = await read.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); factory.Clients.Count.ShouldBe(1); factory.Clients[0].IsConnected.ShouldBeFalse("a connect finishing on a retired device must dispose its client"); @@ -137,13 +137,13 @@ public sealed class FocasDeviceTableLifecycleTests return new FocasDriverBinding(options, factory); }); - var init = Task.Run(() => drv.InitializeAsync("{\"devices\":[]}", CancellationToken.None)); - await inRebind.Task.WaitAsync(TimeSpan.FromSeconds(5)); + var init = Task.Run(() => drv.InitializeAsync("{\"devices\":[]}", CancellationToken.None), TestContext.Current.CancellationToken); + await inRebind.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); await drv.ShutdownAsync(CancellationToken.None); gate.Set(); await Should.ThrowAsync(() => init.WaitAsync(TimeSpan.FromSeconds(10))); - await Task.Delay(200); // several probe intervals — a started loop would have connected by now + await Task.Delay(200, TestContext.Current.CancellationToken); // several probe intervals — a started loop would have connected by now drv.DeviceCount.ShouldBe(0); factory.Clients.ShouldBeEmpty(); drv.GetHealth().State.ShouldNotBe(DriverState.Healthy); @@ -180,11 +180,11 @@ public sealed class FocasDeviceTableLifecycleTests var shutdown = drv.ShutdownAsync(CancellationToken.None); var dispose = drv.DisposeAsync().AsTask(); - await dispose.WaitAsync(TimeSpan.FromSeconds(10)); + await dispose.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); factory.Clients.ShouldAllBe(c => !c.IsConnected); factory.Clients.ShouldAllBe(c => c.DisposeCount >= 1); - await shutdown.WaitAsync(TimeSpan.FromSeconds(10)); + await shutdown.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); drv.DeviceCount.ShouldBe(0); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasFixedTreeConcurrencyTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasFixedTreeConcurrencyTests.cs index d608ba595..c8d1bbdd6 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasFixedTreeConcurrencyTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasFixedTreeConcurrencyTests.cs @@ -85,11 +85,11 @@ public sealed class FocasFixedTreeConcurrencyTests var tasks = new List { - Task.Run(() => Writer(0)), - Task.Run(() => Writer(1)), - Task.Run(() => Writer(2)), - Task.Run(Reader), - Task.Run(Reader), + Task.Run(() => Writer(0), TestContext.Current.CancellationToken), + Task.Run(() => Writer(1), TestContext.Current.CancellationToken), + Task.Run(() => Writer(2), TestContext.Current.CancellationToken), + Task.Run(Reader, TestContext.Current.CancellationToken), + Task.Run(Reader, TestContext.Current.CancellationToken), }; await Task.WhenAll(tasks); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasHandleRecycleTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasHandleRecycleTests.cs index 4c287b4ff..4b69ebaf5 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasHandleRecycleTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasHandleRecycleTests.cs @@ -53,7 +53,7 @@ public sealed class FocasHandleRecycleTests await drv.InitializeAsync("{}", CancellationToken.None); await drv.ReadAsync(["R"], CancellationToken.None); - await Task.Delay(150); + await Task.Delay(150, TestContext.Current.CancellationToken); // With recycle off the same client stays live — no Dispose during the window. factory.Clients.Count.ShouldBe(1); @@ -119,7 +119,7 @@ public sealed class FocasHandleRecycleTests var addr = FocasAddress.TryParse("R100")!; var read = sync.ReadAsync(addr, FocasDataType.Byte, CancellationToken.None); - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); sync.PendingOperations.ShouldBe(1); var dispose = sync.DisposeWhenIdleAsync(TimeSpan.FromSeconds(5)); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasProgramInfoQualityTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasProgramInfoQualityTests.cs index ad2479b1f..16a9e7134 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasProgramInfoQualityTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasProgramInfoQualityTests.cs @@ -71,7 +71,7 @@ public sealed class FocasProgramInfoQualityTests var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(5); while (DateTime.UtcNow < deadline && drv.GetDeviceState(Host)?.LastProgramInfo is null) - await Task.Delay(15); + await Task.Delay(15, TestContext.Current.CancellationToken); var read = await drv.ReadAsync( [$"{Host}/Program/Name", $"{Host}/Program/BlockCount", $"{Host}/Program/ONumber", diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasReadHealthContractTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasReadHealthContractTests.cs index 923ec354a..f7f8fe62d 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasReadHealthContractTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasReadHealthContractTests.cs @@ -67,7 +67,7 @@ public sealed class FocasReadHealthContractTests for (var i = 0; i < 3; i++) { - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); var snap = (await drv.ReadAsync(["raw/R100"], CancellationToken.None))[0]; snap.StatusCode.ShouldBe(refusal); } @@ -170,16 +170,16 @@ public sealed class FocasReadHealthContractTests await drv.InitializeAsync("{}", CancellationToken.None); var stale = drv.ReadAsync(["raw/R100"], CancellationToken.None); - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); await drv.InitializeAsync("{}", CancellationToken.None); // a new generation, Healthy release.SetResult(); - (await stale.WaitAsync(TimeSpan.FromSeconds(5)))[0].StatusCode.ShouldBe(FocasStatusMapper.BadCommunicationError); + (await stale.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken))[0].StatusCode.ShouldBe(FocasStatusMapper.BadCommunicationError); drv.GetHealth().State.ShouldBe(DriverState.Healthy, "the old generation's failure must not land on the new one"); // Positive control: a failure under the live generation degrades. var live = drv.ReadAsync(["raw/R100"], CancellationToken.None); - (await live.WaitAsync(TimeSpan.FromSeconds(5)))[0].StatusCode.ShouldBe(FocasStatusMapper.BadCommunicationError); + (await live.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken))[0].StatusCode.ShouldBe(FocasStatusMapper.BadCommunicationError); drv.GetHealth().State.ShouldBe(DriverState.Degraded); await drv.ShutdownAsync(CancellationToken.None); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasShutdownJoinTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasShutdownJoinTests.cs index 6e07ae925..7b4e96f49 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasShutdownJoinTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasShutdownJoinTests.cs @@ -39,16 +39,16 @@ public sealed class FocasShutdownJoinTests }; var drv = new FocasDriver(options, "focas-1", factory); await drv.InitializeAsync("{}", CancellationToken.None); - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); var shutdown = drv.ShutdownAsync(CancellationToken.None); - await Task.Delay(300); + await Task.Delay(300, TestContext.Current.CancellationToken); shutdown.IsCompleted.ShouldBeFalse("shutdown must join the probe loop parked in connect"); // Positive control: releasing the parked connect lets shutdown finish. release.SetResult(); - await shutdown.WaitAsync(TimeSpan.FromSeconds(5)); + await shutdown.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); factory.Clients.ShouldNotBeEmpty(); factory.Clients.ShouldAllBe(c => c.DisposeCount >= 1); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireProtocolTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireProtocolTests.cs index eb501502e..e7c68474c 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireProtocolTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireProtocolTests.cs @@ -66,7 +66,7 @@ public sealed class FocasWireProtocolTests var (client, server) = await ConnectedPairAsync(); try { - await server.GetStream().WriteAsync(pdu); + await server.GetStream().WriteAsync(pdu, TestContext.Current.CancellationToken); var read = await FocasWireProtocol.ReadPduAsync(client.GetStream(), CancellationToken.None); read.Type.ShouldBe(FocasWireProtocol.TypeData); @@ -84,7 +84,7 @@ public sealed class FocasWireProtocolTests var (client, server) = await ConnectedPairAsync(); try { - await server.GetStream().WriteAsync(bad); + await server.GetStream().WriteAsync(bad, TestContext.Current.CancellationToken); await Should.ThrowAsync(async () => await FocasWireProtocol.ReadPduAsync(client.GetStream(), CancellationToken.None)); } @@ -100,7 +100,7 @@ public sealed class FocasWireProtocolTests var (client, server) = await ConnectedPairAsync(); try { - await server.GetStream().WriteAsync(header); + await server.GetStream().WriteAsync(header, TestContext.Current.CancellationToken); await Should.ThrowAsync(async () => await FocasWireProtocol.ReadPduAsync(client.GetStream(), CancellationToken.None)); } @@ -127,7 +127,7 @@ public sealed class FocasWireProtocolTests var (client, server) = await ConnectedPairAsync(); try { - await server.GetStream().WriteAsync(pdu); + await server.GetStream().WriteAsync(pdu, TestContext.Current.CancellationToken); var read = await FocasWireProtocol.ReadPduAsync(client.GetStream(), CancellationToken.None); read.Type.ShouldBe(FocasWireProtocol.TypeData); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireV3Tests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireV3Tests.cs index c0b6c6388..8e531b4fe 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireV3Tests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasWireV3Tests.cs @@ -147,7 +147,7 @@ public sealed class FocasWireV3Tests try { // Send only 5 of the 10 header bytes, then stall forever — the cnc_rdsvmeter hang shape. - await server.GetStream().WriteAsync(new byte[] { 0xa0, 0xa0, 0xa0, 0xa0, 0x00 }); + await server.GetStream().WriteAsync(new byte[] { 0xa0, 0xa0, 0xa0, 0xa0, 0x00 }, TestContext.Current.CancellationToken); using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(300)); var sw = Stopwatch.StartNew(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Browse/DeployWatcherTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Browse/DeployWatcherTests.cs index 942889bec..5728e953b 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Browse/DeployWatcherTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Browse/DeployWatcherTests.cs @@ -131,11 +131,11 @@ public sealed class DeployWatcherTests await watcher.StartAsync(CancellationToken.None); // Push only the bootstrap event. - await channel.Writer.WriteAsync(Event(0, DateTimeOffset.Parse("2026-01-01T00:00:00Z"))); + await channel.Writer.WriteAsync(Event(0, DateTimeOffset.Parse("2026-01-01T00:00:00Z")), TestContext.Current.CancellationToken); // Give the loop a moment to consume + ack. await WaitUntilAsync(() => source.CallCount > 0 && channel.Reader.Count == 0, TimeSpan.FromSeconds(2)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); captured.ShouldBeEmpty(); @@ -156,8 +156,8 @@ public sealed class DeployWatcherTests await watcher.StartAsync(CancellationToken.None); - await channel.Writer.WriteAsync(Event(0, t0)); // bootstrap - await channel.Writer.WriteAsync(Event(1, t1)); // real change + await channel.Writer.WriteAsync(Event(0, t0), TestContext.Current.CancellationToken); // bootstrap + await channel.Writer.WriteAsync(Event(1, t1), TestContext.Current.CancellationToken); // real change await WaitUntilAsync(() => captured.Count >= 1, TimeSpan.FromSeconds(2)); @@ -183,11 +183,11 @@ public sealed class DeployWatcherTests await watcher.StartAsync(CancellationToken.None); - await channel.Writer.WriteAsync(Event(0, t0)); // bootstrap - await channel.Writer.WriteAsync(Event(2, t0)); // duplicate state — gateway re-sent + await channel.Writer.WriteAsync(Event(0, t0), TestContext.Current.CancellationToken); // bootstrap + await channel.Writer.WriteAsync(Event(2, t0), TestContext.Current.CancellationToken); // duplicate state — gateway re-sent await WaitUntilAsync(() => channel.Reader.Count == 0, TimeSpan.FromSeconds(2)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); captured.ShouldBeEmpty(); @@ -208,9 +208,9 @@ public sealed class DeployWatcherTests await watcher.StartAsync(CancellationToken.None); // Bootstrap with absent deploy time (Galaxy never deployed). - await channel.Writer.WriteAsync(Event(0, deployTime: null)); + await channel.Writer.WriteAsync(Event(0, deployTime: null), TestContext.Current.CancellationToken); // Now a deploy lands and the present flag flips. - await channel.Writer.WriteAsync(Event(1, t1)); + await channel.Writer.WriteAsync(Event(1, t1), TestContext.Current.CancellationToken); await WaitUntilAsync(() => captured.Count >= 1, TimeSpan.FromSeconds(2)); @@ -232,7 +232,7 @@ public sealed class DeployWatcherTests await watcher.StartAsync(CancellationToken.None); // Push bootstrap so the loop enters its enumeration body before stop. - await channel.Writer.WriteAsync(Event(0, DateTimeOffset.UtcNow)); + await channel.Writer.WriteAsync(Event(0, DateTimeOffset.UtcNow), TestContext.Current.CancellationToken); await WaitUntilAsync(() => source.CallCount > 0, TimeSpan.FromSeconds(2)); // StopAsync should complete without throwing and within a reasonable window. @@ -251,11 +251,11 @@ public sealed class DeployWatcherTests var watcher = new DeployWatcher(source); await watcher.StartAsync(CancellationToken.None); - await channel.Writer.WriteAsync(Event(0, DateTimeOffset.UtcNow)); + await channel.Writer.WriteAsync(Event(0, DateTimeOffset.UtcNow), TestContext.Current.CancellationToken); await WaitUntilAsync(() => source.CallCount > 0, TimeSpan.FromSeconds(2)); // Should not throw, should not hang. - var disposeTask = Task.Run(watcher.Dispose); + var disposeTask = Task.Run(watcher.Dispose, TestContext.Current.CancellationToken); var completed = await Task.WhenAny(disposeTask, Task.Delay(TimeSpan.FromSeconds(5))); completed.ShouldBe(disposeTask); await disposeTask; @@ -295,8 +295,8 @@ public sealed class DeployWatcherTests await WaitUntilAsync(() => source.CallCount >= 2, TimeSpan.FromSeconds(2)); // Now feed bootstrap + real event into the second channel. - await secondChannel.Writer.WriteAsync(Event(0, t0)); - await secondChannel.Writer.WriteAsync(Event(1, t1)); + await secondChannel.Writer.WriteAsync(Event(0, t0), TestContext.Current.CancellationToken); + await secondChannel.Writer.WriteAsync(Event(1, t1), TestContext.Current.CancellationToken); await WaitUntilAsync(() => captured.Count >= 1, TimeSpan.FromSeconds(2)); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverApiKeyResolverTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverApiKeyResolverTests.cs index 0f010b44c..08a6bbd85 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverApiKeyResolverTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverApiKeyResolverTests.cs @@ -30,7 +30,7 @@ public sealed class GalaxyDriverApiKeyResolverTests [Fact] public async Task Literal_string_is_returned_unchanged() { - (await GalaxySecretRef.ResolveApiKeyAsync("plain-text-key", FakeResolver())) + (await GalaxySecretRef.ResolveApiKeyAsync("plain-text-key", FakeResolver(), ct: TestContext.Current.CancellationToken)) .ShouldBe("plain-text-key"); } @@ -42,7 +42,7 @@ public sealed class GalaxyDriverApiKeyResolverTests Environment.SetEnvironmentVariable(name, "key-from-env"); try { - (await GalaxySecretRef.ResolveApiKeyAsync($"env:{name}", FakeResolver())) + (await GalaxySecretRef.ResolveApiKeyAsync($"env:{name}", FakeResolver(), ct: TestContext.Current.CancellationToken)) .ShouldBe("key-from-env"); } finally @@ -72,7 +72,7 @@ public sealed class GalaxyDriverApiKeyResolverTests File.WriteAllText(path, " key-from-file \n"); try { - (await GalaxySecretRef.ResolveApiKeyAsync($"file:{path}", FakeResolver())) + (await GalaxySecretRef.ResolveApiKeyAsync($"file:{path}", FakeResolver(), ct: TestContext.Current.CancellationToken)) .ShouldBe("key-from-file"); } finally @@ -98,7 +98,7 @@ public sealed class GalaxyDriverApiKeyResolverTests [Fact] public async Task Secret_prefix_resolves_through_secret_resolver() { - (await GalaxySecretRef.ResolveApiKeyAsync($"secret:{KnownSecretName}", FakeResolver())) + (await GalaxySecretRef.ResolveApiKeyAsync($"secret:{KnownSecretName}", FakeResolver(), ct: TestContext.Current.CancellationToken)) .ShouldBe(KnownSecretValue); } @@ -122,7 +122,7 @@ public sealed class GalaxyDriverApiKeyResolverTests public async Task Secret_prefix_does_not_emit_literal_warning() { var logger = new CaptureLogger(); - await GalaxySecretRef.ResolveApiKeyAsync($"secret:{KnownSecretName}", FakeResolver(), logger); + await GalaxySecretRef.ResolveApiKeyAsync($"secret:{KnownSecretName}", FakeResolver(), logger, TestContext.Current.CancellationToken); logger.Entries.ShouldNotContain(e => e.Level == LogLevel.Warning); } @@ -136,7 +136,7 @@ public sealed class GalaxyDriverApiKeyResolverTests // in the DriverConfig JSON. The resolver must surface a warning so an // operator who committed one by accident sees it at startup. var logger = new CaptureLogger(); - var key = await GalaxySecretRef.ResolveApiKeyAsync("plain-text-key", FakeResolver(), logger); + var key = await GalaxySecretRef.ResolveApiKeyAsync("plain-text-key", FakeResolver(), logger, TestContext.Current.CancellationToken); key.ShouldBe("plain-text-key"); logger.Entries.ShouldContain(e => @@ -151,7 +151,7 @@ public sealed class GalaxyDriverApiKeyResolverTests // key (dev / parity rig). The resolver must accept it AND suppress the // warning so production logs aren't polluted on a deliberate dev choice. var logger = new CaptureLogger(); - var key = await GalaxySecretRef.ResolveApiKeyAsync("dev:plain-text-key", FakeResolver(), logger); + var key = await GalaxySecretRef.ResolveApiKeyAsync("dev:plain-text-key", FakeResolver(), logger, TestContext.Current.CancellationToken); key.ShouldBe("plain-text-key"); logger.Entries.ShouldNotContain(e => e.Level == LogLevel.Warning); @@ -166,7 +166,7 @@ public sealed class GalaxyDriverApiKeyResolverTests try { var logger = new CaptureLogger(); - await GalaxySecretRef.ResolveApiKeyAsync($"env:{name}", FakeResolver(), logger); + await GalaxySecretRef.ResolveApiKeyAsync($"env:{name}", FakeResolver(), logger, TestContext.Current.CancellationToken); logger.Entries.ShouldNotContain(e => e.Level == LogLevel.Warning); } finally diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverFactoryTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverFactoryTests.cs index 5272b2050..62c27c65f 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverFactoryTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/GalaxyDriverFactoryTests.cs @@ -222,7 +222,7 @@ public sealed class GalaxyDriverFactoryTests var firstStamp = driver.GetHealth().LastSuccessfulRead!.Value; // Force a measurable clock delta so the comparison is stable on fast machines. - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); await driver.ReinitializeAsync(equivalentConfig, CancellationToken.None); driver.GetHealth().State.ShouldBe(DriverState.Healthy); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Health/HostStatusAggregatorTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Health/HostStatusAggregatorTests.cs index e3403ab9c..1b6b16108 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Health/HostStatusAggregatorTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Health/HostStatusAggregatorTests.cs @@ -140,7 +140,7 @@ public sealed class HostStatusAggregatorTests } })).ToArray(); - Task.WaitAll(tasks); + Task.WaitAll(tasks, TestContext.Current.CancellationToken); agg.Snapshot().Count.ShouldBeLessThanOrEqualTo(32); } } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpBoundedChannelTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpBoundedChannelTests.cs index 6ae7f2ff1..a2f5e124a 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpBoundedChannelTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpBoundedChannelTests.cs @@ -82,7 +82,7 @@ public sealed class EventPumpBoundedChannelTests // Stage 1 — one event, then wait for the dispatcher to take it and block. After this the // channel is provably empty and exactly one event is in flight inside the handler. await subscriber.EmitAsync(itemHandle: 7, value: 0); - await handlerEntered.Task.WaitAsync(Budget); + await handlerEntered.Task.WaitAsync(Budget, TestContext.Current.CancellationToken); // Stage 2 — the rest. `channelCapacity` are accepted; the remainder must be dropped. for (var i = 1; i < totalEvents; i++) diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpStreamFaultTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpStreamFaultTests.cs index cd4a5a47c..9d43ed2d7 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpStreamFaultTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/EventPumpStreamFaultTests.cs @@ -97,7 +97,7 @@ public sealed class EventPumpStreamFaultTests oldPump.OnDataChange += (_, _) => staleObserved = true; oldPump.Start(); faulted.FaultStream(new IOException("simulated gateway transport drop")); - await Task.Delay(100); + await Task.Delay(100, TestContext.Current.CancellationToken); // In-place Start() after a fault is a no-op — the loop task is non-null but done. oldPump.Start(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound1Tests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound1Tests.cs index 9876c09f6..c7529e15c 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound1Tests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound1Tests.cs @@ -324,7 +324,7 @@ public sealed class GalaxyDriverFixRound1Tests // Never leave the teardown parked: it holds the lifecycle gate the await-using dispose needs. sub.ReleaseUnsubscribe(); } - await shutdown.WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + await shutdown.WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); driver.HasEventPumpForTests.ShouldBeFalse("no pump may survive the teardown"); driver.TrackedSubscriptionCountForTests.ShouldBe(0); @@ -354,7 +354,7 @@ public sealed class GalaxyDriverFixRound1Tests }; var sw = System.Diagnostics.Stopwatch.StartNew(); - await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); sw.Stop(); closeEntered.Task.IsCompleted.ShouldBeTrue("positive control: the close was attempted"); @@ -398,7 +398,7 @@ public sealed class GalaxyDriverFixRound1Tests driver.TrackedSubscriptionCountForTests.ShouldBe(0); sub.ReleaseSubscribe(); - await replay.WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + await replay.WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); driver.TrackedSubscriptionCountForTests.ShouldBe(0, "a Rebind after the teardown would resurrect dead handles"); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound2Tests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound2Tests.cs index ddd970236..27134ba66 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound2Tests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverFixRound2Tests.cs @@ -84,14 +84,14 @@ public sealed class GalaxyDriverFixRound2Tests try { var sw = System.Diagnostics.Stopwatch.StartNew(); - await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget); + await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget, TestContext.Current.CancellationToken); sw.Stop(); driver.GetHealth().State.ShouldBe(DriverState.Healthy); await Entered(platforms.Entered, "positive control: the seed fetch was started"); sw.Elapsed.ShouldBeLessThan(InitBudget); - await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); var token = await platforms.ParkedToken.Task; token.IsCancellationRequested.ShouldBeTrue("the teardown must cancel a seed still in flight"); } @@ -109,7 +109,7 @@ public sealed class GalaxyDriverFixRound2Tests var platforms = new ThrowingPlatformSource(new OperationCanceledException("gateway deadline")); await using var driver = new GalaxyDriver("drv", Opts(), hierarchySource: null, subscriber: sub, platformSource: platforms); - await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget); + await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget, TestContext.Current.CancellationToken); driver.GetHealth().State.ShouldBe(DriverState.Healthy); await WaitUntilAsync(() => platforms.Calls == 1, "positive control: the seed fetch ran"); @@ -136,7 +136,7 @@ public sealed class GalaxyDriverFixRound2Tests try { initCts.CancelAfter(TimeSpan.FromMilliseconds(300)); // the Polly Initialize timeout, shrunk - await driver.InitializeAsync("{}", initCts.Token).WaitAsync(InitBudget); + await driver.InitializeAsync("{}", initCts.Token).WaitAsync(InitBudget, TestContext.Current.CancellationToken); driver.GetHealth().State.ShouldBe(DriverState.Healthy); await Entered(platforms.Entered, "the seed fetch must be in flight"); @@ -162,7 +162,7 @@ public sealed class GalaxyDriverFixRound2Tests await using var driver = new GalaxyDriver("drv", Opts(), hierarchySource: null, subscriber: sub, platformSource: platforms); try { - await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget); + await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget, TestContext.Current.CancellationToken); await Entered(platforms.Entered, "the seed must be parked"); driver.ProbeWatcherForTests.ShouldNotBeNull().WatchedPlatforms.ShouldBeEmpty(); } @@ -197,11 +197,11 @@ public sealed class GalaxyDriverFixRound2Tests await using var driver = new GalaxyDriver("drv", Opts(), hierarchySource: null, subscriber: sub, platformSource: platforms); try { - await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget); + await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget, TestContext.Current.CancellationToken); await Entered(platforms.Entered, "runtime 1's seed must be parked"); - await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); - await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget); + await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); + await driver.InitializeAsync("{}", CancellationToken.None).WaitAsync(InitBudget, TestContext.Current.CancellationToken); } finally { @@ -242,7 +242,7 @@ public sealed class GalaxyDriverFixRound2Tests await watcher.StopAsync(CancellationToken.None); sub.ReleaseSubscribe(); - await sync.WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + await sync.WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); registry.Contains(SubscriptionRegistry.ProbeSubscriptionId).ShouldBeFalse("a stopped watcher must not re-register"); watcher.WatchedPlatforms.ShouldBeEmpty(); @@ -271,7 +271,7 @@ public sealed class GalaxyDriverFixRound2Tests try { await Entered(sub.SubscribeEntered, "the subscribe must be parked in SubscribeBulk"); - await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); driver.TrackedSubscriptionCountForTests.ShouldBe(0); } finally @@ -299,7 +299,7 @@ public sealed class GalaxyDriverFixRound2Tests try { await Entered(sub.SubscribeEntered, "the read must be parked in SubscribeBulk"); - await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + await driver.ShutdownAsync(CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); } finally { diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverProbeWiringTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverProbeWiringTests.cs index af842c930..e0b1bb839 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverProbeWiringTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverProbeWiringTests.cs @@ -197,7 +197,7 @@ public sealed class GalaxyDriverProbeWiringTests }; await driver.InitializeAsync("{}", CancellationToken.None); var initStamp = driver.GetHealth().LastSuccessfulRead.ShouldNotBeNull(); - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); var delivered = 0; driver.OnDataChange += (_, _) => Interlocked.Increment(ref delivered); @@ -209,7 +209,7 @@ public sealed class GalaxyDriverProbeWiringTests var first = driver.GetHealth().LastSuccessfulRead.ShouldNotBeNull(); first.ShouldBeGreaterThan(initStamp, "data on the stream is liveness evidence"); - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); await sub.EmitDoubleAsync(handle, 2.0); await WaitUntilAsync(() => Volatile.Read(ref delivered) == 2, "second event must be delivered"); driver.GetHealth().LastSuccessfulRead.ShouldBe(first, "inside the throttle window the stamp holds still"); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverReadTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverReadTests.cs index ea6c5c9d9..462adfc98 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverReadTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverReadTests.cs @@ -109,7 +109,7 @@ public sealed class GalaxyDriverReadTests var readTask = driver.ReadAsync(["Tank.Level"], CancellationToken.None); // Push the "initial value" event the gw would emit immediately after SubscribeBulk. - await Task.Delay(50); // give SubscribeBulk a beat to register + handler to attach + await Task.Delay(50, TestContext.Current.CancellationToken); // give SubscribeBulk a beat to register + handler to attach var itemHandle = subscriber.Map["Tank.Level"]; await subscriber.EmitOnDataChangeAsync(itemHandle, 42.0); @@ -131,7 +131,7 @@ public sealed class GalaxyDriverReadTests "g", Opts(), hierarchySource: null, dataReader: null, dataWriter: null, subscriber: subscriber); var readTask = driver.ReadAsync(["Good", "Bad"], CancellationToken.None); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); await subscriber.EmitOnDataChangeAsync(subscriber.Map["Good"], 1.0); var result = await readTask; @@ -197,7 +197,7 @@ public sealed class GalaxyDriverReadTests }; var result = await driver.ReadAsync(["Slow.A", "Slow.B"], CancellationToken.None) - .WaitAsync(TimeSpan.FromSeconds(10)); + .WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); result.Count.ShouldBe(2); result.ShouldAllBe(r => r.StatusCode == StatusCodeMap.BadTimeout); @@ -205,7 +205,7 @@ public sealed class GalaxyDriverReadTests // The RPC finally completes after the read gave up; its handles must not leak. subscriber.Gate.SetResult(); var deadline = DateTime.UtcNow.AddSeconds(10); - while (subscriber.UnsubscribedHandles.Count < 2 && DateTime.UtcNow < deadline) await Task.Delay(20); + while (subscriber.UnsubscribedHandles.Count < 2 && DateTime.UtcNow < deadline) await Task.Delay(20, TestContext.Current.CancellationToken); subscriber.UnsubscribedHandles.OrderBy(h => h).ShouldBe([101, 102]); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverShutdownTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverShutdownTests.cs index cdb2ec696..a2e4b0ef3 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverShutdownTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverShutdownTests.cs @@ -257,7 +257,7 @@ public sealed class GalaxyDriverShutdownTests await source.PushAsync(1, new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero)); await source.PushAsync(2, new DateTimeOffset(2026, 1, 2, 0, 0, 0, TimeSpan.Zero)); await WaitUntilAsync(() => Volatile.Read(ref raised) >= 1, "positive control: a deploy change must raise rediscovery"); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); Volatile.Read(ref raised).ShouldBe(1, "stacked watchers would each raise for the same deploy"); await driver.ShutdownAsync(CancellationToken.None); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverSubscribeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverSubscribeTests.cs index 7d13f3e9f..637900ee0 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverSubscribeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyDriverSubscribeTests.cs @@ -195,7 +195,7 @@ public sealed class GalaxyDriverSubscribeTests // Good has an itemHandle; Bad doesn't (item handle 0). An event with handle 0 // must NOT be dispatched (no subscribers registered against it). await subscriber.EmitOnDataChangeAsync(itemHandle: 0, value: 999.0); - await Task.Delay(50); // give the pump a chance + await Task.Delay(50, TestContext.Current.CancellationToken); // give the pump a chance captured.ShouldBeEmpty(); } @@ -219,7 +219,7 @@ public sealed class GalaxyDriverSubscribeTests var captured = new List(); driver.OnDataChange += (_, args) => captured.Add(args); await subscriber.EmitOnDataChangeAsync(itemHandle, 11.0); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); captured.ShouldBeEmpty(); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionCloseTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionCloseTests.cs index aa6219c3c..ed61eec84 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionCloseTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionCloseTests.cs @@ -26,7 +26,7 @@ public sealed class GalaxyMxSessionCloseTests using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(200)); var sw = System.Diagnostics.Stopwatch.StartNew(); - await session.CloseAsync(cts.Token).WaitAsync(TimeSpan.FromSeconds(10)); + await session.CloseAsync(cts.Token).WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); sw.Stop(); sw.Elapsed.ShouldBeLessThan(TimeSpan.FromSeconds(5)); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GatewayGalaxyDataWriterConcurrencyTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GatewayGalaxyDataWriterConcurrencyTests.cs index 51b4cdfb0..2cbbc2869 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GatewayGalaxyDataWriterConcurrencyTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GatewayGalaxyDataWriterConcurrencyTests.cs @@ -88,7 +88,7 @@ public sealed class GatewayGalaxyDataWriterConcurrencyTests var writes = Enumerable.Range(0, 16).Select(i => new WriteRequest($"Tag{i}.PV", (double)i)).ToArray(); var results = await NewWriter().WriteBatchForTestAsync(ops, writes, Free, CancellationToken.None) - .WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + .WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); ops.Peak.ShouldBe(GatewayGalaxyDataWriter.MaxConcurrentWriteLanes, "first-touch lanes must overlap (serial = 1) and stay bounded (unbounded > 8)"); @@ -112,7 +112,7 @@ public sealed class GatewayGalaxyDataWriterConcurrencyTests }; var results = await NewWriter().WriteBatchForTestAsync(ops, writes, Free, CancellationToken.None) - .WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + .WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); results.Count.ShouldBe(4); results.ShouldAllBe(r => r.StatusCode == StatusCodeMap.Good); @@ -146,7 +146,7 @@ public sealed class GatewayGalaxyDataWriterConcurrencyTests }; var results = await NewWriter().WriteBatchForTestAsync(ops, writes, Free, CancellationToken.None) - .WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + .WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); results.Select(r => r.StatusCode).ShouldBe( [StatusCodeMap.Good, StatusCodeMap.BadCommunicationError, StatusCodeMap.Good], @@ -161,7 +161,7 @@ public sealed class GatewayGalaxyDataWriterConcurrencyTests var writes = new[] { new WriteRequest("X.PV", 1.0), new WriteRequest("X.PV", 2.0) }; var results = await NewWriter().WriteBatchForTestAsync(ops, writes, Free, CancellationToken.None) - .WaitAsync(TimeSpan.FromMilliseconds(WaitMs)); + .WaitAsync(TimeSpan.FromMilliseconds(WaitMs), TestContext.Current.CancellationToken); results.Count.ShouldBe(2); ops.Peak.ShouldBe(1); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/ReconnectSupervisorTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/ReconnectSupervisorTests.cs index 91376cf85..b875f8f73 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/ReconnectSupervisorTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/ReconnectSupervisorTests.cs @@ -163,7 +163,7 @@ public sealed class ReconnectSupervisorTests options: FastBackoff()); sup.ReportTransportFailure(new IOException("kick off")); - await Task.Delay(50); // let the loop start the long reopen + await Task.Delay(50, TestContext.Current.CancellationToken); // let the loop start the long reopen Should.NotThrow(() => sup.Dispose()); cancelled.ShouldBeTrue(); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/AlarmWriterTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/AlarmWriterTests.cs index 36faa9fcb..a32e0cb81 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/AlarmWriterTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/AlarmWriterTests.cs @@ -33,11 +33,11 @@ public sealed class AlarmWriterTests(SqlHistorianFixture fx) (await w.WriteBatchAsync([Ev(kind: "Cleared")], CancellationToken.None)).ShouldBe([HistorianWriteOutcome.Ack]); await using var c = new SqlConnection(fx.ConnectionString); - await c.OpenAsync(); + await c.OpenAsync(TestContext.Current.CancellationToken); await using var cmd = c.CreateCommand(); cmd.CommandText = $"SELECT SourceName, AlarmId, AlarmName, AlarmTypeName, Severity, EventKind, Message, UserName, Comment, EventTimeUtc, ReceivedTimeUtc FROM [{s}].Event WHERE EventKind='Activated'"; - await using var r = await cmd.ExecuteReaderAsync(); - (await r.ReadAsync()).ShouldBeTrue(); + await using var r = await cmd.ExecuteReaderAsync(TestContext.Current.CancellationToken); + (await r.ReadAsync(TestContext.Current.CancellationToken)).ShouldBeTrue(); r.GetString(0).ShouldBe("Plant/Line/Eq"); r.GetString(1).ShouldBe("alarm-1"); r.GetString(2).ShouldBe("HiTemp"); @@ -48,10 +48,10 @@ public sealed class AlarmWriterTests(SqlHistorianFixture fx) r.GetString(8).ShouldBe("c"); SqlHistorianConnection.GetUtc(r, 9).Ticks.ShouldBe(T.Ticks); (DateTime.UtcNow - SqlHistorianConnection.GetUtc(r, 10)).ShouldBeLessThan(TimeSpan.FromMinutes(1)); - (await r.ReadAsync()).ShouldBeFalse(); + (await r.ReadAsync(TestContext.Current.CancellationToken)).ShouldBeFalse(); await r.CloseAsync(); cmd.CommandText = $"SELECT COUNT(*) FROM [{s}].Event"; - Convert.ToInt32(await cmd.ExecuteScalarAsync()).ShouldBe(2); + Convert.ToInt32(await cmd.ExecuteScalarAsync(TestContext.Current.CancellationToken)).ShouldBe(2); } [Fact] @@ -72,10 +72,10 @@ public sealed class AlarmWriterTests(SqlHistorianFixture fx) var rs = await Task.WhenAll(Enumerable.Range(0, 12).Select(_ => Task.Run(() => w.WriteBatchAsync([Ev()], CancellationToken.None)))); rs.ShouldAllBe(x => x[0] == HistorianWriteOutcome.Ack); await using var c = new SqlConnection(fx.ConnectionString); - await c.OpenAsync(); + await c.OpenAsync(TestContext.Current.CancellationToken); await using var cmd = c.CreateCommand(); cmd.CommandText = $"SELECT COUNT(*) FROM [{s}].Event WHERE EventKind='Activated'"; - Convert.ToInt32(await cmd.ExecuteScalarAsync()).ShouldBe(1); + Convert.ToInt32(await cmd.ExecuteScalarAsync(TestContext.Current.CancellationToken)).ShouldBe(1); } [Fact] diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/ProvisioningTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/ProvisioningTests.cs index 904457ba4..3fff0450c 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/ProvisioningTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/ProvisioningTests.cs @@ -90,10 +90,10 @@ public sealed class ProvisioningTests(SqlHistorianFixture fx) } await using var c = new SqlConnection(fx.ConnectionString); - await c.OpenAsync(); + await c.OpenAsync(TestContext.Current.CancellationToken); await using var cmd = c.CreateCommand(); cmd.CommandText = $"SELECT COUNT(*) FROM [{s}].Tag"; - Convert.ToInt32(await cmd.ExecuteScalarAsync()).ShouldBe(20 * 6 + 1); + Convert.ToInt32(await cmd.ExecuteScalarAsync(TestContext.Current.CancellationToken)).ShouldBe(20 * 6 + 1); } [Fact] diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/RetentionTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/RetentionTests.cs index 35309fdbf..8fe343ad6 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/RetentionTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/RetentionTests.cs @@ -117,11 +117,11 @@ public sealed class RetentionTests(SqlHistorianFixture fx) // Hold the same session applock the purger takes, on a separate connection. await using var holder = new SqlConnection(fx.ConnectionString); - await holder.OpenAsync(); + await holder.OpenAsync(TestContext.Current.CancellationToken); await using (var cmd = holder.CreateCommand()) { cmd.CommandText = $"EXEC sp_getapplock @Resource = N'OtOpcUa.Historian.Retention.{s}', @LockMode = 'Exclusive', @LockOwner = 'Session', @LockTimeout = 0;"; - await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); } var purger = new SqlServerHistorianRetention(c, b, TimeSpan.FromHours(1), 30, 4000, time: new FixedTime(Now)); @@ -131,7 +131,7 @@ public sealed class RetentionTests(SqlHistorianFixture fx) await using (var cmd = holder.CreateCommand()) { cmd.CommandText = $"EXEC sp_releaseapplock @Resource = N'OtOpcUa.Historian.Retention.{s}', @LockOwner = 'Session';"; - await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); } (await purger.PurgeAsync(CancellationToken.None)).ShouldNotBeEmpty(); (await CountAsync($"SELECT COUNT(*) FROM [{s}].Sample")).ShouldBe(6); @@ -187,20 +187,20 @@ public sealed class RetentionTests(SqlHistorianFixture fx) // A second session holds an exclusive table lock, so the purger's first DELETE blocks server-side. await using var holder = new SqlConnection(fx.ConnectionString); - await holder.OpenAsync(); - await using var tx = (SqlTransaction)await holder.BeginTransactionAsync(); + await holder.OpenAsync(TestContext.Current.CancellationToken); + await using var tx = (SqlTransaction)await holder.BeginTransactionAsync(TestContext.Current.CancellationToken); await using (var cmd = holder.CreateCommand()) { cmd.Transaction = tx; cmd.CommandText = $"SELECT COUNT(*) FROM [{s}].Sample WITH (TABLOCKX, HOLDLOCK)"; - await cmd.ExecuteScalarAsync(); + await cmd.ExecuteScalarAsync(TestContext.Current.CancellationToken); } short holderSpid; await using (var cmd = holder.CreateCommand()) { cmd.Transaction = tx; cmd.CommandText = "SELECT CAST(@@SPID AS smallint)"; - holderSpid = (short)(await cmd.ExecuteScalarAsync())!; + holderSpid = (short)(await cmd.ExecuteScalarAsync(TestContext.Current.CancellationToken))!; } using var cts = new CancellationTokenSource(); @@ -215,7 +215,7 @@ public sealed class RetentionTests(SqlHistorianFixture fx) { purge.IsCompleted.ShouldBeFalse("the purge finished without ever blocking on the holder's table lock"); DateTime.UtcNow.ShouldBeLessThan(deadline, "the purge's DELETE never blocked behind the holder"); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); } cts.Cancel(); @@ -223,7 +223,7 @@ public sealed class RetentionTests(SqlHistorianFixture fx) var ex = await Should.ThrowAsync(() => purge); (ex is OperationCanceledException or SqlException).ShouldBeTrue($"unexpected {ex.GetType().Name}: {ex.Message}"); - await tx.RollbackAsync(); + await tx.RollbackAsync(TestContext.Current.CancellationToken); (await LockIsFreeAsync(s)).ShouldBeTrue(); (await CountAsync($"SELECT COUNT(*) FROM [{s}].Sample")).ShouldBe(21); } @@ -301,11 +301,11 @@ public sealed class RetentionTests(SqlHistorianFixture fx) await SeedAsync(b, s); await using var holder = new SqlConnection(fx.ConnectionString); - await holder.OpenAsync(); + await holder.OpenAsync(TestContext.Current.CancellationToken); await using (var cmd = holder.CreateCommand()) { cmd.CommandText = $"EXEC sp_getapplock @Resource = N'OtOpcUa.Historian.Retention.{s}', @LockMode = 'Exclusive', @LockOwner = 'Session', @LockTimeout = 0;"; - await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); } var log = new CapturingLogger(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/SchemaBootstrapIntegrationTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/SchemaBootstrapIntegrationTests.cs index 5ec131ad1..93b8c627a 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/SchemaBootstrapIntegrationTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/SchemaBootstrapIntegrationTests.cs @@ -44,12 +44,12 @@ public sealed class SchemaBootstrapIntegrationTests(SqlHistorianFixture fx) await Boot(Opts(s)).EnsureAsync(CancellationToken.None); var script = new StreamReader(typeof(SqlServerSchemaBootstrapper).Assembly.GetManifestResourceStream("Schema.001_initial.sql")!).ReadToEnd(); await using var c = new SqlConnection(fx.ConnectionString); - await c.OpenAsync(); + await c.OpenAsync(TestContext.Current.CancellationToken); foreach (var b in SqlServerSchemaBootstrapper.SplitBatches(script.Replace("$(Schema)", s))) { await using var cmd = c.CreateCommand(); cmd.CommandText = b; - await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); } (await ScalarAsync($"SELECT COUNT(*) FROM [{s}].SchemaVersion")).ShouldBe(SqlServerSchemaBootstrapper.ModifiedTrailVersion); } @@ -68,17 +68,17 @@ public sealed class SchemaBootstrapIntegrationTests(SqlHistorianFixture fx) var v1 = new StreamReader(typeof(SqlServerSchemaBootstrapper).Assembly.GetManifestResourceStream("Schema.001_initial.sql")!).ReadToEnd(); await using (var c = new SqlConnection(fx.ConnectionString)) { - await c.OpenAsync(); + await c.OpenAsync(TestContext.Current.CancellationToken); foreach (var b in SqlServerSchemaBootstrapper.SplitBatches(v1.Replace("$(Schema)", s))) { await using var cmd = c.CreateCommand(); cmd.CommandText = b; - await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); } await using var seed = c.CreateCommand(); seed.CommandText = $"INSERT [{s}].Tag (Name, DataType, CreatedUtc, UpdatedUtc) VALUES (N'old', 1, SYSUTCDATETIME(), SYSUTCDATETIME()); " + $"INSERT [{s}].Sample (TagId, SourceTimeUtc, ValueKind, NumValue, StatusCode, ServerTimeUtc) SELECT TagId, '2026-01-01', 1, 4.0, 0, SYSUTCDATETIME() FROM [{s}].Tag"; - await seed.ExecuteNonQueryAsync(); + await seed.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); } (await ScalarAsync($"SELECT COUNT(*) FROM sys.tables WHERE name = 'SampleModified' AND schema_id = SCHEMA_ID('{s}')")).ShouldBe(0); @@ -178,7 +178,7 @@ public sealed class SchemaBootstrapIntegrationTests(SqlHistorianFixture fx) start.Wait(); return await cat.GetOrCreateTagIdAsync(name, 1, CancellationToken.None); })).ToArray(); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); start.Set(); (await Task.WhenAll(ids)).Distinct().Count().ShouldBe(1); (await ScalarAsync($"SELECT COUNT(*) FROM [{s}].Tag WHERE Name = N'{name}'")).ShouldBe(1); @@ -203,10 +203,10 @@ public sealed class SchemaBootstrapIntegrationTests(SqlHistorianFixture fx) cmd.Parameters.AddWithValue("@id", tagId); conn.AddStructured(cmd, "@rows", "SampleRow", SampleRowMapper.ToSampleRecords([new HistorianSampleRow(t, ZB.MOM.WW.OtOpcUa.Core.Abstractions.HistorianValue.FromDouble(1), 0u)])); - await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(TestContext.Current.CancellationToken); await using var q = conn.CreateCommand(c, $"SELECT SourceTimeUtc FROM {conn.Q("Sample")}"); - await using var r = await q.ExecuteReaderAsync(); - (await r.ReadAsync()).ShouldBeTrue(); + await using var r = await q.ExecuteReaderAsync(TestContext.Current.CancellationToken); + (await r.ReadAsync(TestContext.Current.CancellationToken)).ShouldBeTrue(); SqlHistorianConnection.GetUtc(r, 0).Ticks.ShouldBe(t.Ticks); } } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectDriverProbeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectDriverProbeTests.cs index 8dd14e9d7..9fcc0af89 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectDriverProbeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests/MTConnectDriverProbeTests.cs @@ -74,14 +74,14 @@ public sealed class MTConnectDriverProbeTests public async Task Probe_on_unreachable_agent_returns_not_ok_and_does_not_throw() { var probe = new MTConnectDriverProbe(); - var r = await probe.ProbeAsync("{\"agentUri\":\"http://127.0.0.1:1/\"}", TimeSpan.FromMilliseconds(300), default); + var r = await probe.ProbeAsync("{\"agentUri\":\"http://127.0.0.1:1/\"}", TimeSpan.FromMilliseconds(300), TestContext.Current.CancellationToken); r.Ok.ShouldBeFalse(); r.Message.ShouldNotBeNull(); } [Fact] public async Task Probe_on_blank_config_returns_not_ok() - => (await new MTConnectDriverProbe().ProbeAsync("{}", TimeSpan.FromSeconds(1), default)).Ok.ShouldBeFalse(); + => (await new MTConnectDriverProbe().ProbeAsync("{}", TimeSpan.FromSeconds(1), TestContext.Current.CancellationToken)).Ok.ShouldBeFalse(); // ── unparseable JSON ────────────────────────────────────────────────────── diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusBatchSubscriptionTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusBatchSubscriptionTests.cs index 9f40e07d6..85aeee2d5 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusBatchSubscriptionTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusBatchSubscriptionTests.cs @@ -165,7 +165,7 @@ public sealed class ModbusBatchSubscriptionTests // it as a batch item, but the driver's deadband suppresses the publish — so neither // event fires and no batch is raised for that cycle at all. fake.HoldingRegisters[0] = 102; - await Task.Delay(600); + await Task.Delay(600, TestContext.Current.CancellationToken); perTag.Count.ShouldBe(1, "under-threshold change is suppressed on the per-tag event"); batches.Count.ShouldBe(1, "a cycle whose only change is deadband-suppressed raises no batch"); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusDriverProbeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusDriverProbeTests.cs index 6cd2f1fcf..28b66e849 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusDriverProbeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusDriverProbeTests.cs @@ -181,7 +181,7 @@ public sealed class ModbusDriverProbeTests var result = await _probe.ProbeAsync(Config(port), QuickTimeout, CancellationToken.None); // The server task should have completed (or close enough). - await serverTask.WaitAsync(TimeSpan.FromSeconds(2)).ConfigureAwait(false); + await serverTask.WaitAsync(TimeSpan.FromSeconds(2), TestContext.Current.CancellationToken).ConfigureAwait(false); result.Ok.ShouldBeFalse(); result.Message.ShouldNotBeNull(); @@ -211,7 +211,7 @@ public sealed class ModbusDriverProbeTests var result = await _probe.ProbeAsync(Config(port), QuickTimeout, CancellationToken.None); - await serverTask.WaitAsync(TimeSpan.FromSeconds(3)).ConfigureAwait(false); + await serverTask.WaitAsync(TimeSpan.FromSeconds(3), TestContext.Current.CancellationToken).ConfigureAwait(false); result.Ok.ShouldBeTrue(); result.Message.ShouldBe("Modbus FC03 OK"); @@ -241,7 +241,7 @@ public sealed class ModbusDriverProbeTests var result = await _probe.ProbeAsync(Config(port), QuickTimeout, CancellationToken.None); - await serverTask.WaitAsync(TimeSpan.FromSeconds(3)).ConfigureAwait(false); + await serverTask.WaitAsync(TimeSpan.FromSeconds(3), TestContext.Current.CancellationToken).ConfigureAwait(false); result.Ok.ShouldBeTrue(); result.Message.ShouldNotBeNull(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusLifecycleHygieneTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusLifecycleHygieneTests.cs index 6bd7f9a83..781dd92b7 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusLifecycleHygieneTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusLifecycleHygieneTests.cs @@ -245,7 +245,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) // new sends. Tolerate at most one in-flight send straddling the cancel. fake.DisposeCount.ShouldBe(1); var sendsAfterDispose = Interlocked.CompareExchange(ref fake.SendCount, 0, 0); - await Task.Delay(300); + await Task.Delay(300, TestContext.Current.CancellationToken); var sendsAtRest = Interlocked.CompareExchange(ref fake.SendCount, 0, 0); (sendsAtRest - sendsAfterDispose).ShouldBeLessThanOrEqualTo(1, "background loops must stop after DisposeAsync"); } @@ -267,7 +267,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) // Spin up a polled subscription; the PollGroupEngine schedules a background Task that // will keep issuing SendAsync until either Unsubscribe or DisposeAsync stops it. var handle = await drv.SubscribeAsync(["A"], TimeSpan.FromMilliseconds(100), CancellationToken.None); - await Task.Delay(250); + await Task.Delay(250, TestContext.Current.CancellationToken); var beforeDispose = Interlocked.CompareExchange(ref fake.SendCount, 0, 0); beforeDispose.ShouldBeGreaterThan(0); @@ -275,7 +275,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) await drv.DisposeAsync(); var atDispose = Interlocked.CompareExchange(ref fake.SendCount, 0, 0); - await Task.Delay(400); + await Task.Delay(400, TestContext.Current.CancellationToken); var atRest = Interlocked.CompareExchange(ref fake.SendCount, 0, 0); (atRest - atDispose).ShouldBeLessThanOrEqualTo(1, @@ -353,7 +353,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) var drv = new ModbusDriver(opts, "modbus-1", _ => Interlocked.Increment(ref handed) == 1 ? first : second); await drv.InitializeAsync("{}", CancellationToken.None); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); Interlocked.CompareExchange(ref first.SendCount, 0, 0).ShouldBeGreaterThan(0, "precondition: the first initialize's probe loop must actually be sending"); @@ -361,7 +361,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) // Tolerate one in-flight send straddling the cancel; a leaked loop produces ~16 in 400ms. var atReinit = Interlocked.CompareExchange(ref first.SendCount, 0, 0); - await Task.Delay(400); + await Task.Delay(400, TestContext.Current.CancellationToken); var atRest = Interlocked.CompareExchange(ref first.SendCount, 0, 0); (atRest - atReinit).ShouldBeLessThanOrEqualTo(1, "the previous initialize's probe loop must be cancelled by the next initialize"); @@ -442,7 +442,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) Activator.CreateInstance(stateType, nonPublic: true)!); await drv.InitializeAsync("{}", CancellationToken.None); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); Interlocked.CompareExchange(ref first.SendCount, 0, 0).ShouldBeGreaterThan(0, "precondition: the seeded prohibition must make the re-probe loop actually send"); @@ -464,7 +464,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) prohibitions.Count.ShouldBe(1, "a re-initialize must not clear the prohibition set"); var atReinit = Interlocked.CompareExchange(ref second.SendCount, 0, 0); - await Task.Delay(400); + await Task.Delay(400, TestContext.Current.CancellationToken); var atRest = Interlocked.CompareExchange(ref second.SendCount, 0, 0); (atRest - atReinit).ShouldBeLessThanOrEqualTo(1, "the previous initialize's re-probe loop must be cancelled by the next initialize"); @@ -723,7 +723,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) { try { while (!cts.IsCancellationRequested) await drv.ReadAsync(["A"], CancellationToken.None); } catch (Exception ex) { faults.Enqueue(ex); } - }); + }, TestContext.Current.CancellationToken); var reader = Task.Run(() => { try @@ -737,7 +737,7 @@ public sealed class ModbusLifecycleHygieneTests(ITestOutputHelper output) } } catch (Exception ex) { faults.Enqueue(ex); } - }); + }, TestContext.Current.CancellationToken); await Task.WhenAll(writer, reader); faults.ShouldBeEmpty(); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusProbeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusProbeTests.cs index f2359f1a5..6167c4c95 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusProbeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusProbeTests.cs @@ -89,11 +89,11 @@ public sealed class ModbusProbeTests // Wait for the first probe to complete. var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(2); - while (fake.ProbeCount == 0 && DateTime.UtcNow < deadline) await Task.Delay(25); + while (fake.ProbeCount == 0 && DateTime.UtcNow < deadline) await Task.Delay(25, TestContext.Current.CancellationToken); // Then wait for the event to actually arrive. deadline = DateTime.UtcNow + TimeSpan.FromSeconds(1); - while (transitions.Count == 0 && DateTime.UtcNow < deadline) await Task.Delay(25); + while (transitions.Count == 0 && DateTime.UtcNow < deadline) await Task.Delay(25, TestContext.Current.CancellationToken); transitions.Count.ShouldBeGreaterThanOrEqualTo(1); transitions.TryDequeue(out var t).ShouldBeTrue(); @@ -169,7 +169,7 @@ public sealed class ModbusProbeTests await drv.InitializeAsync("{}", CancellationToken.None); await WaitForStateAsync(drv, HostState.Running, TimeSpan.FromSeconds(2)); - await Task.Delay(500); // several more probe ticks, all successful — state shouldn't thrash + await Task.Delay(500, TestContext.Current.CancellationToken); // several more probe ticks, all successful — state shouldn't thrash transitions.Count.ShouldBe(1); // only the initial Unknown→Running await drv.ShutdownAsync(CancellationToken.None); @@ -184,7 +184,7 @@ public sealed class ModbusProbeTests drv.OnHostStatusChanged += (_, e) => transitions.Enqueue(e); await drv.InitializeAsync("{}", CancellationToken.None); - await Task.Delay(300); + await Task.Delay(300, TestContext.Current.CancellationToken); transitions.Count.ShouldBe(0); drv.GetHostStatuses()[0].State.ShouldBe(HostState.Unknown); @@ -206,7 +206,7 @@ public sealed class ModbusProbeTests var before = fake.ProbeCount; await drv.ShutdownAsync(CancellationToken.None); - await Task.Delay(400); + await Task.Delay(400, TestContext.Current.CancellationToken); // A handful of in-flight ticks may complete after shutdown in a narrow race; the // contract is that the loop stops scheduling new ones. Tolerate ≤1 extra. diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusSubscriptionTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusSubscriptionTests.cs index e98bff14c..1812be1e9 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusSubscriptionTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusSubscriptionTests.cs @@ -86,7 +86,7 @@ public sealed class ModbusSubscriptionTests drv.OnDataChange += (_, e) => events.Enqueue(e); var handle = await drv.SubscribeAsync(["Level"], TimeSpan.FromMilliseconds(100), CancellationToken.None); - await Task.Delay(500); // ~5 poll cycles at 100ms, value stable the whole time + await Task.Delay(500, TestContext.Current.CancellationToken); // ~5 poll cycles at 100ms, value stable the whole time await drv.UnsubscribeAsync(handle, CancellationToken.None); events.Count.ShouldBe(1); // only the initial-data push, no change events after @@ -129,7 +129,7 @@ public sealed class ModbusSubscriptionTests var countAfterUnsub = events.Count; fake.HoldingRegisters[0] = 999; // would trigger a change if still polling - await Task.Delay(400); + await Task.Delay(400, TestContext.Current.CancellationToken); events.Count.ShouldBe(countAfterUnsub); } @@ -147,7 +147,7 @@ public sealed class ModbusSubscriptionTests drv.OnDataChange += (_, e) => events.Enqueue(e); var handle = await drv.SubscribeAsync(["Level"], TimeSpan.FromMilliseconds(10), CancellationToken.None); - await Task.Delay(300); + await Task.Delay(300, TestContext.Current.CancellationToken); await drv.UnsubscribeAsync(handle, CancellationToken.None); events.Count.ShouldBe(1); @@ -227,7 +227,7 @@ public sealed class ModbusSubscriptionTests { for (var i = 0; i < tagCount; i++) fake.HoldingRegisters[i] = (ushort)(fake.HoldingRegisters[i] + 5); - await Task.Delay(20); + await Task.Delay(20, TestContext.Current.CancellationToken); } foreach (var h in handles) diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverDiscoveryTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverDiscoveryTests.cs index f57d0c3b9..aeef6deb7 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverDiscoveryTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverDiscoveryTests.cs @@ -268,8 +268,8 @@ public sealed class MqttDriverDiscoveryTests await release.Task; }; - var initialize = Task.Run(() => driver.InitializeAsync("", CancellationToken.None)); - await entered.Task.WaitAsync(TimeSpan.FromSeconds(5)); + var initialize = Task.Run(() => driver.InitializeAsync("", CancellationToken.None), TestContext.Current.CancellationToken); + await entered.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); var dispose = driver.DisposeAsync().AsTask(); @@ -282,7 +282,7 @@ public sealed class MqttDriverDiscoveryTests release.SetResult(); await Should.ThrowAsync(() => initialize); // connect refused on the closed port - await dispose.WaitAsync(TimeSpan.FromSeconds(10)); + await dispose.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); dispose.IsCompletedSuccessfully.ShouldBeTrue(); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverSessionLifecycleTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverSessionLifecycleTests.cs index 8abf72aaa..84c7b5ef4 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverSessionLifecycleTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverSessionLifecycleTests.cs @@ -267,7 +267,7 @@ public sealed class MqttDriverSessionLifecycleTests await release.Task; }; - var initialize = Task.Run(() => driver.InitializeAsync(Json(options), TestContext.Current.CancellationToken)); + var initialize = Task.Run(() => driver.InitializeAsync(Json(options), TestContext.Current.CancellationToken), TestContext.Current.CancellationToken); await entered.Task.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken); // Times out on the gate (1 s) and tears down ungated. diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverWriteTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverWriteTests.cs index 78508e326..462aa4be0 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverWriteTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/MqttDriverWriteTests.cs @@ -41,7 +41,7 @@ public sealed class MqttDriverWriteTests public async Task An_unknown_reference_is_refused_in_its_own_slot() { var results = await PlainDriver(PlainTag(Path, "oven/set")) - .WriteAsync([new WriteRequest("Plant/Mqtt/dev1/NotATag", 1.0)], default); + .WriteAsync([new WriteRequest("Plant/Mqtt/dev1/NotATag", 1.0)], TestContext.Current.CancellationToken); results.Count.ShouldBe(1); results[0].StatusCode.ShouldBe(0x80340000u); // BadNodeIdUnknown @@ -54,7 +54,7 @@ public sealed class MqttDriverWriteTests // the operator simply never said where a write should go. The status has to say that, or the // only diagnosis available is "writes don't work". var results = await PlainDriver(PlainTag(ReadOnlyPath, writeTopic: null)) - .WriteAsync([new WriteRequest(ReadOnlyPath, 1.0)], default); + .WriteAsync([new WriteRequest(ReadOnlyPath, 1.0)], TestContext.Current.CancellationToken); results[0].StatusCode.ShouldBe(0x803B0000u); // BadNotWritable } @@ -66,7 +66,7 @@ public sealed class MqttDriverWriteTests // replay hazard WriteIdempotent exists to prevent — and this would be the driver deciding it on // the operator's behalf. var results = await PlainDriver(PlainTag(Path, "oven/set")) - .WriteAsync([new WriteRequest(Path, 42.5)], default); + .WriteAsync([new WriteRequest(Path, 42.5)], TestContext.Current.CancellationToken); results[0].StatusCode.ShouldBe(0x80050000u); // BadCommunicationError } @@ -78,13 +78,11 @@ public sealed class MqttDriverWriteTests // write in the same OPC UA request. var driver = PlainDriver(PlainTag(Path, "oven/set"), PlainTag(ReadOnlyPath, writeTopic: null)); - var results = await driver.WriteAsync( - [ + var results = await driver.WriteAsync([ new WriteRequest("Plant/Mqtt/dev1/NotATag", 1.0), new WriteRequest(ReadOnlyPath, 1.0), new WriteRequest(Path, 42.5), - ], - default); + ], TestContext.Current.CancellationToken); // Order-preserving, one status per request, each naming its own distinct cause. results.Count.ShouldBe(3); @@ -95,7 +93,7 @@ public sealed class MqttDriverWriteTests [Fact] public async Task An_empty_batch_is_answered_with_an_empty_result() - => (await PlainDriver().WriteAsync([], default)).ShouldBeEmpty(); + => (await PlainDriver().WriteAsync([], TestContext.Current.CancellationToken)).ShouldBeEmpty(); [Fact] public async Task WriteAsync_rejects_a_null_batch() @@ -109,7 +107,7 @@ public sealed class MqttDriverWriteTests { var builder = new WriteCapturingBuilder(); - await PlainDriver(PlainTag(Path, "oven/set")).DiscoverAsync(builder, default); + await PlainDriver(PlainTag(Path, "oven/set")).DiscoverAsync(builder, TestContext.Current.CancellationToken); builder.Variables.ShouldHaveSingleItem(); builder.Variables[0].SecurityClass.ShouldBe(SecurityClassification.Operate); @@ -125,7 +123,7 @@ public sealed class MqttDriverWriteTests // refuses every write would be the silent-no-op failure in a new costume. var builder = new WriteCapturingBuilder(); - await PlainDriver(PlainTag(ReadOnlyPath, writeTopic: null)).DiscoverAsync(builder, default); + await PlainDriver(PlainTag(ReadOnlyPath, writeTopic: null)).DiscoverAsync(builder, TestContext.Current.CancellationToken); builder.Variables[0].SecurityClass.ShouldBe(SecurityClassification.ViewOnly); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverReconnectTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverReconnectTests.cs index ce4d4db1a..4fa5f127b 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverReconnectTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverReconnectTests.cs @@ -476,7 +476,7 @@ public sealed class S7DriverReconnectTests await WaitUntilAsync(() => factory.Created.Count >= 2, TimeSpan.FromSeconds(5)); factory.Created.Count.ShouldBeGreaterThanOrEqualTo(2); var atFirstAttempt = factory.Created.Count; - await Task.Delay(TimeSpan.FromMilliseconds(900)); + await Task.Delay(TimeSpan.FromMilliseconds(900), TestContext.Current.CancellationToken); // Without the fix this is ~10+ (one 80 ms-cut attempt per tick); with it the window suppresses them. (factory.Created.Count - atFirstAttempt).ShouldBeLessThanOrEqualTo(1); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATCapabilityTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATCapabilityTests.cs index ff43a6a4f..fedb96b10 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATCapabilityTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATCapabilityTests.cs @@ -96,7 +96,7 @@ public sealed class TwinCATCapabilityTests await drv.ShutdownAsync(CancellationToken.None); var afterShutdown = events.Count; - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); events.Count.ShouldBe(afterShutdown); } @@ -185,7 +185,7 @@ public sealed class TwinCATCapabilityTests Probe = new TwinCATProbeOptions { Enabled = false }, }, "drv-1", factory); await drv.InitializeAsync("{}", CancellationToken.None); - await Task.Delay(200); + await Task.Delay(200, TestContext.Current.CancellationToken); drv.GetHostStatuses().Single().State.ShouldBe(HostState.Unknown); await drv.ShutdownAsync(CancellationToken.None); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDiagnosticsTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDiagnosticsTests.cs index 9fe134a6c..c3935b6e8 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDiagnosticsTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDiagnosticsTests.cs @@ -186,7 +186,7 @@ public sealed class TwinCATDiagnosticsTests IReadOnlyDictionary bag = new Dictionary(); for (var i = 0; i < 100 && bag.Count == 0; i++) { - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); bag = ((IDriverDiagnostics)drv).GetDiagnostics(); } bag["TwinCAT.OnlineChangeCnt"].ShouldBe("7"); @@ -218,8 +218,8 @@ public sealed class TwinCATDiagnosticsTests try { for (var i = 0; i < 100 && drv.GetHostStatuses().All(h => h.State != HostState.Running); i++) - await Task.Delay(20); - await Task.Delay(100); // several more probe ticks + await Task.Delay(20, TestContext.Current.CancellationToken); + await Task.Delay(100, TestContext.Current.CancellationToken); // several more probe ticks } finally { await drv.ShutdownAsync(CancellationToken.None); } diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDriverProbeTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDriverProbeTests.cs index 8d9a8c235..ec0ca8628 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDriverProbeTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATDriverProbeTests.cs @@ -187,7 +187,7 @@ public sealed class TwinCATDriverProbeTests catch (OperationCanceledException) { /* accept cancelled — expected on teardown */ } catch (ObjectDisposedException) { /* listener stopped — expected on teardown */ } catch (SocketException) { /* listener stopped — expected on teardown */ } - }); + }, TestContext.Current.CancellationToken); try { diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATReconnectReplayTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATReconnectReplayTests.cs index 337aad4bc..3dba610d5 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATReconnectReplayTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATReconnectReplayTests.cs @@ -314,7 +314,7 @@ public sealed class TwinCATReconnectReplayTests factory.Clients[0].SimulateWireDrop(); var readTask = Task.Run(() => drv.ReadAsync(["X"], CancellationToken.None)); await WaitForAsync(() => factory.Clients.Count >= 2, TimeSpan.FromSeconds(2)); - await Task.Delay(50); // let the replay reach the blocked AddNotification + await Task.Delay(50, TestContext.Current.CancellationToken); // let the replay reach the blocked AddNotification // Unsubscribe mid-replay (gate-free) — removes the registration from the device registry. await drv.UnsubscribeAsync(handle, TestContext.Current.CancellationToken); diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATSumChunkWarningTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATSumChunkWarningTests.cs index 948705b34..1c0c0bafc 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATSumChunkWarningTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATSumChunkWarningTests.cs @@ -56,7 +56,7 @@ public sealed class TwinCATSumChunkWarningTests while (!factory.Clients.Any(c => c.IsConnected) && DateTime.UtcNow < deadline) { await drv.ReadAsync(["A", "B"], CancellationToken.None); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); } factory.Clients.Any(c => c.IsConnected).ShouldBeTrue("the device must reconnect for the second half to mean anything"); await drv.ReadAsync(["A", "B"], CancellationToken.None);