Adds alarm_ack.md documenting the two-way acknowledge flow (OPC UA client writes AckMsg, Galaxy confirms via Acked data change). Includes external code review fixes for subscriptions and node manager, and removes stale plan files now superseded by component documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
120 lines
4.2 KiB
C#
120 lines
4.2 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Verifies the reusable OPC UA server fixture used by integration and wiring tests.
|
|
/// </summary>
|
|
public class OpcUaServerFixtureTests
|
|
{
|
|
/// <summary>
|
|
/// Confirms that the standard fake-backed fixture starts the bridge and tears it down cleanly.
|
|
/// </summary>
|
|
[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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Confirms that the fake-client fixture bypasses COM wiring and uses the provided fake runtime client.
|
|
/// </summary>
|
|
[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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Confirms that separate fixture instances automatically allocate unique OPC UA ports.
|
|
/// </summary>
|
|
[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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Confirms that fixture shutdown completes quickly enough for the integration test suite.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Confirms that runtime callbacks arriving after shutdown are ignored cleanly.
|
|
/// </summary>
|
|
[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)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Confirms that the fake-backed fixture builds the seeded address space and Galaxy statistics.
|
|
/// </summary>
|
|
[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();
|
|
}
|
|
}
|
|
}
|