From 3122728593f88c0551313e86472b1d1fd771aa85 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 15 Aug 2026 18:16:59 -0400 Subject: [PATCH] test(runtime): serialize meter-asserting publish-actor suites (cross-collection counter pollution) --- .../OpcUa/OpcUaPublishActorApplyFailureTests.cs | 10 ++++++++++ .../OpcUa/OpcUaPublishActorRebuildTests.cs | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorApplyFailureTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorApplyFailureTests.cs index af17654b..f113ea06 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorApplyFailureTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorApplyFailureTests.cs @@ -23,6 +23,16 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.OpcUa; /// otopcua.opcua.apply.failed meter and log at Error — instead of the optimistic Info line. The /// happy path must stay Info-only (zero increments). /// +/// +/// Shares the opcua-publish-meters collection with OpcUaPublishActorRebuildTests so the two +/// classes NEVER run in parallel. The zero-increment assertions below (recorder.Total.ShouldBe(0)) +/// read a process-wide filtered only on the instrument NAME, and +/// otopcua.opcua.apply.failed carries no tag identifying the emitting actor instance (only +/// kind=rebuild|nodes) — so the assertion cannot be scoped to this test's own actor. The sibling +/// class's degraded-apply tests deliberately increment the same counter, which intermittently made these +/// zero assertions fail when the two classes ran concurrently in different xUnit collections. +/// +[Collection("opcua-publish-meters")] public sealed class OpcUaPublishActorApplyFailureTests : RuntimeActorTestBase { /// A rebuild whose sink throws increments otopcua.opcua.apply.failed (kind=rebuild). R2-07 — a diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs index 63a2cd17..5851527b 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs @@ -16,6 +16,18 @@ using ZB.MOM.WW.OtOpcUa.Runtime.Tests.Harness; namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.OpcUa; +/// +/// Shares the opcua-publish-meters collection with +/// so the two classes NEVER run in parallel. MeterRecorder is a process-wide +/// filtered only on the instrument NAME, and +/// otopcua.opcua.apply.failed carries no tag identifying which actor instance emitted it (only +/// kind=rebuild|nodes) — so it cannot be scoped to one test. The degraded-apply tests here +/// ( and +/// ) deliberately increment that counter, +/// which intermittently broke the sibling class's Total.ShouldBe(0) happy-path assertions when the +/// two classes ran concurrently in different collections. Serialising them is the fix. +/// +[Collection("opcua-publish-meters")] public sealed class OpcUaPublishActorRebuildTests : RuntimeActorTestBase { /// R2-07 — RebuildAddressSpace with dbFactory loads the artifact, composes, and applies. Two