diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventDeliveryPerfTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventDeliveryPerfTests.cs index b101f5de6..b81ac7f0a 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventDeliveryPerfTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventDeliveryPerfTests.cs @@ -35,6 +35,9 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests; /// compiles against the pre-#855 tree for a before/after comparison. /// [Trait("Category", "Perf")] +// Shares a collection with the other user of OtOpcUaSdkServer.RingEventQueues (a process-wide switch the perf +// harness flips), so the wiring assertion never observes it switched off (#870 review). +[Collection(RingEventQueueSwitchCollection.Name)] public sealed class FolderEventDeliveryPerfTests { private const string OptInVariable = "OTOPCUA_EVENT_PERF"; diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/RingEventQueueWiringTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/RingEventQueueWiringTests.cs index f654cc186..2174f71e7 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/RingEventQueueWiringTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/RingEventQueueWiringTests.cs @@ -9,6 +9,9 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests; /// item's queue is a ; the SDK's always asks /// the server's factory), and data-change queues are still the SDK's own. /// +// Shares a collection with the other user of OtOpcUaSdkServer.RingEventQueues (a process-wide switch the perf +// harness flips), so the wiring assertion never observes it switched off (#870 review). +[Collection(RingEventQueueSwitchCollection.Name)] public sealed class RingEventQueueWiringTests { [Fact] @@ -23,3 +26,11 @@ public sealed class RingEventQueueWiringTests factory.CreateDataChangeQueue(false, 2).ShouldBeOfType(); } } + +/// Serialises the tests that read or flip OtOpcUaSdkServer.RingEventQueues. +[CollectionDefinition(Name)] +public sealed class RingEventQueueSwitchCollection +{ + /// The collection name. + public const string Name = "RingEventQueueSwitch"; +} diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/RingEventMonitoredItemQueueParityTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/RingEventMonitoredItemQueueParityTests.cs index b2d264ccf..677b1f573 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/RingEventMonitoredItemQueueParityTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/RingEventMonitoredItemQueueParityTests.cs @@ -143,6 +143,26 @@ public sealed class RingEventMonitoredItemQueueParityTests Both(q => q.IsEventContainedInQueue(Targets[1]), sdk, ring, "absent").ShouldBeFalse(); } + /// Upper boundary of the window: the entry exactly 1000th from newest is still found; 1001st is not. + [Fact] + public void Duplicate_check_includes_the_1000th_newest_entry() + { + var sdk = new EventMonitoredItemQueue(false, 1, Telemetry); + var ring = new RingEventMonitoredItemQueue(1); + sdk.SetQueueSize(3000, true); + ring.SetQueueSize(3000, true); + var outside = new Target(); + var boundary = new Target(); + void Add(EventFieldList e) { sdk.Enqueue(e); ring.Enqueue(e); } + Add(new EventFieldList { Handle = outside }); + Add(new EventFieldList { Handle = boundary }); + for (var i = 0; i < 999; i++) Add(new EventFieldList { Handle = Targets[0] }); + + // 1001 entries: `boundary` is the 1000th newest (inside), `outside` the 1001st. + Both(q => q.IsEventContainedInQueue(boundary), sdk, ring, "boundary").ShouldBeTrue(); + Both(q => q.IsEventContainedInQueue(outside), sdk, ring, "outside").ShouldBeFalse(); + } + /// Random interleavings of every queue operation, at small sizes (wrap-around, grow, shrink, size 0). [Theory] [MemberData(nameof(Seeds))]