using System.Diagnostics; using System.Threading.Tasks; using Shouldly; using Xunit; using ZB.MOM.WW.LmxOpcUa.Host.Domain; namespace ZB.MOM.WW.LmxOpcUa.Tests.Helpers { /// /// Verifies the reusable OPC UA server fixture used by integration and wiring tests. /// public class OpcUaServerFixtureTests { /// /// Confirms that the standard fake-backed fixture starts the bridge and tears it down cleanly. /// [Fact] public async Task WithFakes_StartsAndStops() { var fixture = OpcUaServerFixture.WithFakes(); await fixture.InitializeAsync(); fixture.Service.ShouldNotBeNull(); fixture.Service.MxClient.ShouldNotBeNull(); fixture.Service.MxClient!.State.ShouldBe(ConnectionState.Connected); fixture.Service.GalaxyStatsInstance.ShouldNotBeNull(); fixture.Service.GalaxyStatsInstance!.GalaxyName.ShouldBe("TestGalaxy"); fixture.OpcUaPort.ShouldBeGreaterThan(16000); fixture.EndpointUrl.ShouldContain(fixture.OpcUaPort.ToString()); await fixture.DisposeAsync(); } /// /// Confirms that the fake-client fixture bypasses COM wiring and uses the provided fake runtime client. /// [Fact] public async Task WithFakeMxAccessClient_SkipsCom() { var mxClient = new FakeMxAccessClient(); var fixture = OpcUaServerFixture.WithFakeMxAccessClient(mxClient); await fixture.InitializeAsync(); fixture.Service.MxClient.ShouldBe(mxClient); mxClient.State.ShouldBe(ConnectionState.Connected); await fixture.DisposeAsync(); } /// /// Confirms that separate fixture instances automatically allocate unique OPC UA ports. /// [Fact] public async Task MultipleFixtures_GetUniquePortsAutomatically() { var fixture1 = OpcUaServerFixture.WithFakeMxAccessClient(); var fixture2 = OpcUaServerFixture.WithFakeMxAccessClient(); fixture1.OpcUaPort.ShouldNotBe(fixture2.OpcUaPort); // Both can start without port conflicts await fixture1.InitializeAsync(); await fixture2.InitializeAsync(); fixture1.Service.ShouldNotBeNull(); fixture2.Service.ShouldNotBeNull(); await fixture1.DisposeAsync(); await fixture2.DisposeAsync(); } /// /// Confirms that fixture shutdown completes quickly enough for the integration test suite. /// [Fact] public async Task Shutdown_CompletesWithin30Seconds() { var fixture = OpcUaServerFixture.WithFakes(); await fixture.InitializeAsync(); var sw = Stopwatch.StartNew(); await fixture.DisposeAsync(); sw.Stop(); sw.Elapsed.TotalSeconds.ShouldBeLessThan(30); } /// /// Confirms that runtime callbacks arriving after shutdown are ignored cleanly. /// [Fact] public async Task Stop_UnhooksNodeManagerFromMxAccessCallbacks() { var mxClient = new FakeMxAccessClient(); var fixture = OpcUaServerFixture.WithFakeMxAccessClient(mxClient); await fixture.InitializeAsync(); await fixture.DisposeAsync(); Should.NotThrow(() => mxClient.SimulateDataChange("TestMachine_001.MachineID", Vtq.Good(42))); } /// /// Confirms that the fake-backed fixture builds the seeded address space and Galaxy statistics. /// [Fact] public async Task WithFakes_BuildsAddressSpace() { var fixture = OpcUaServerFixture.WithFakes(); await fixture.InitializeAsync(); fixture.Service.GalaxyStatsInstance!.ObjectCount.ShouldBe(5); fixture.Service.GalaxyStatsInstance.AttributeCount.ShouldBe(6); fixture.Service.GalaxyStatsInstance.DbConnected.ShouldBe(true); await fixture.DisposeAsync(); } } }