66 lines
2.9 KiB
C#
66 lines
2.9 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.IntegrationTests;
|
|
|
|
/// <summary>
|
|
/// Reverse-connect smoke (PR-11). Asserts the driver binds a listener at the
|
|
/// configured URL and accepts an inbound dial from <c>opc-plc-rc</c> (the
|
|
/// reverse-connect variant of Microsoft Industrial IoT's OPC UA simulator).
|
|
/// The session that comes up should be functionally identical to a dialled
|
|
/// session — same Read / Subscribe surface — but the transport direction is
|
|
/// server → client instead of client → server.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <b>Build-only by default</b>: the test is gated on <c>OPCUA_RC_SIM</c>
|
|
/// + the docker-compose <c>opc-plc-rc</c> service. CI runs that don't
|
|
/// spin up the dialer skip with a clear message; the build still has to
|
|
/// compile so wire-level regressions in the reverse-connect code path are
|
|
/// caught even when the dialer isn't around.
|
|
/// </para>
|
|
/// </remarks>
|
|
[Collection(OpcPlcReverseConnectCollection.Name)]
|
|
[Trait("Category", "Integration")]
|
|
[Trait("Simulator", "opc-plc-rc")]
|
|
public sealed class OpcUaClientReverseConnectSmokeTests(OpcPlcReverseConnectFixture rc)
|
|
{
|
|
[Fact]
|
|
public async Task Driver_accepts_reverse_connect_from_opc_plc_rc_simulator()
|
|
{
|
|
if (rc.SkipReason is not null) Assert.Skip(rc.SkipReason);
|
|
|
|
var options = new OpcUaClientDriverOptions
|
|
{
|
|
// Conventional EndpointUrl still required — the driver derives the
|
|
// EndpointDescription from it for the session-create call. The actual
|
|
// dial direction is flipped by ReverseConnect.Enabled below.
|
|
EndpointUrl = "opc.tcp://opc-plc-rc:50001",
|
|
SecurityPolicy = OpcUaSecurityPolicy.None,
|
|
SecurityMode = OpcUaSecurityMode.None,
|
|
AuthType = OpcUaAuthType.Anonymous,
|
|
AutoAcceptCertificates = true,
|
|
Timeout = TimeSpan.FromSeconds(15),
|
|
SessionTimeout = TimeSpan.FromSeconds(60),
|
|
ReverseConnect = new ReverseConnectOptions(
|
|
Enabled: true,
|
|
ListenerUrl: rc.ListenerUrl,
|
|
// null = accept any upstream — only one is dialling this listener in
|
|
// the smoke test, so there's no demux to worry about.
|
|
ExpectedServerUri: null),
|
|
};
|
|
|
|
await using var drv = new OpcUaClientDriver(options, "opcua-rc-smoke");
|
|
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken);
|
|
|
|
// The session is up via reverse path — assert a steady-state read works.
|
|
var snapshots = await drv.ReadAsync(
|
|
[OpcPlcProfile.StepUp], TestContext.Current.CancellationToken);
|
|
|
|
snapshots.Count.ShouldBe(1);
|
|
snapshots[0].StatusCode.ShouldBe(0u,
|
|
"reverse-connect session must round-trip a Read identically to a dialled session");
|
|
}
|
|
}
|