From 5e3fb4229d6a89a69a842d782d0d4af93de5edc3 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 12 Nov 2026 11:00:59 -0500 Subject: [PATCH] test(redundancy): exercise SessionClosing in the #884 ServiceLevel claim test The claim test disposed its sessions, which may leave them to time out rather than raise SessionClosing, so only the SessionCreated half of the SDK's session-headroom overwrite was proven. Sessions now close explicitly, a later level (230, inside the SDK's >= 200 overwrite band for every case, where the old level-10 left the 200 case at 190 and so unexercised) is read back on a surviving session after another one closes on its own. Probed without the claim: the close-only read fails (255) in all three cases. Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi --- .../ServiceLevelBindingReplayTests.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ServiceLevelBindingReplayTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ServiceLevelBindingReplayTests.cs index 74beac046..0a5704574 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ServiceLevelBindingReplayTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ServiceLevelBindingReplayTests.cs @@ -106,15 +106,27 @@ public sealed class ServiceLevelBindingReplayTests publisher.Publish(level); var url = $"opc.tcp://localhost:{port}/OtOpcUa"; + // SessionCreated: the first session opening. using (var first = await OpenAsync(url, clientPki, ct)) + { (await ReadServiceLevelAsync(first, ct)).ShouldBe(level, "the first session opening must not displace the published level"); + // An explicit CloseSession so the server raises SessionClosing (Dispose alone may leave the session to time out). + await first.CloseAsync(5_000, true, ct); + } using var second = await OpenAsync(url, clientPki, ct); (await ReadServiceLevelAsync(second, ct)).ShouldBe(level, "a session closing then another opening must not displace it"); - publisher.Publish((byte)(level - 10)); - using var third = await OpenAsync(url, clientPki, ct); - (await ReadServiceLevelAsync(third, ct)).ShouldBe((byte)(level - 10), "a level published while a session is open must survive the next one"); + // A level published while a session is open (230 keeps every case inside the SDK's >= 200 overwrite band) + // must survive another session opening AND, read on the surviving session, that session closing on its own. + const byte later = 230; + publisher.Publish(later); + using (var third = await OpenAsync(url, clientPki, ct)) + { + (await ReadServiceLevelAsync(third, ct)).ShouldBe(later, "a level published while a session is open must survive the next one"); + await third.CloseAsync(5_000, true, ct); + } + (await ReadServiceLevelAsync(second, ct)).ShouldBe(later, "a session closing on its own must not displace it"); } finally {