From 565b77e6cf5d28d85a8ea0d5a8d8b66190df37cd Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 11 Jun 2026 09:16:51 -0400 Subject: [PATCH] fix(galaxy): unify IsConnected with _connected guard; AttachForTests marks connected (review) --- .../Runtime/GalaxyMxSession.cs | 9 ++++-- .../Runtime/GalaxyMxSessionReconnectTests.cs | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Runtime/GalaxyMxSession.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Runtime/GalaxyMxSession.cs index d48d3528..4758b7db 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Runtime/GalaxyMxSession.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Runtime/GalaxyMxSession.cs @@ -40,8 +40,12 @@ public sealed class GalaxyMxSession : IAsyncDisposable _logger = logger ?? NullLogger.Instance; } - /// Gets a value indicating whether the session is connected. - public bool IsConnected => _session is not null; + /// + /// Gets a value indicating whether a session is currently established. Set true on a + /// successful connect/attach and false after teardown/dispose — tracks the same + /// _connected flag that guards on, so the two never disagree. + /// + public bool IsConnected => _connected; /// /// Server-side handle returned by MXAccess Register. Zero before @@ -122,6 +126,7 @@ public sealed class GalaxyMxSession : IAsyncDisposable ObjectDisposedException.ThrowIf(_disposed, this); _session = session ?? throw new ArgumentNullException(nameof(session)); _serverHandle = serverHandle; + _connected = true; // an attached session means connected — keeps IsConnected + the ConnectAsync no-op guard consistent. } /// diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionReconnectTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionReconnectTests.cs index b1e689eb..2eab49fe 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionReconnectTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/Runtime/GalaxyMxSessionReconnectTests.cs @@ -98,9 +98,38 @@ public sealed class GalaxyMxSessionReconnectTests await Should.ThrowAsync( async () => await session.ConnectAsync(null!, CancellationToken.None)); openCount.ShouldBe(1); + session.IsConnected.ShouldBeFalse(); // _connected must NOT be latched by the failed attempt. // The failed first attempt must not have latched _connected — the retry reaches the body. await session.ConnectAsync(null!, CancellationToken.None); openCount.ShouldBe(2); } + + /// + /// tracks the _connected guard across the + /// full lifecycle: false when fresh, true after connect, still true after a recreate, and + /// false again after dispose. + /// + [Fact] + public async Task IsConnected_reflects_connect_recreate_and_dispose() + { + var session = NewSession(); + var openCount = 0; + session.OpenAndRegisterOverrideForTests = _ => + { + openCount++; + return Task.CompletedTask; + }; + + session.IsConnected.ShouldBeFalse(); + + await session.ConnectAsync(null!, CancellationToken.None); + session.IsConnected.ShouldBeTrue(); + + await session.RecreateAsync(null!, CancellationToken.None); + session.IsConnected.ShouldBeTrue(); + + await session.DisposeAsync(); + session.IsConnected.ShouldBeFalse(); + } }