7e91c37a52
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
54 lines
2.5 KiB
C#
54 lines
2.5 KiB
C#
using System.Net;
|
|
using System.Net.Sockets;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.IntegrationTests;
|
|
|
|
/// <summary>
|
|
/// Reachability gate for the shared opc-plc fixture (<c>OPCUA_SIM_ENDPOINT</c>, default
|
|
/// <c>opc.tcp://10.100.0.35:50000</c>). A small copy of the probe in
|
|
/// <c>Driver.OpcUaClient.IntegrationTests/OpcPlcFixture</c> rather than a cross-project reference —
|
|
/// that project drags the whole driver in. Tests call <see cref="SkipUnlessReachable"/> first, so a
|
|
/// machine without the simulator reports Skipped instead of a connect failure.
|
|
/// </summary>
|
|
internal static class OpcPlcProbe
|
|
{
|
|
private const string EndpointEnvVar = "OPCUA_SIM_ENDPOINT";
|
|
private const string DefaultEndpoint = "opc.tcp://10.100.0.35:50000";
|
|
|
|
/// <summary>The simulator endpoint the tests should connect to.</summary>
|
|
public static string Endpoint =>
|
|
Environment.GetEnvironmentVariable(EndpointEnvVar) is { Length: > 0 } e ? e : DefaultEndpoint;
|
|
|
|
private static readonly Lazy<string?> Reason = new(Probe);
|
|
|
|
/// <summary>Skips the calling test when opc-plc does not accept a TCP connection (probed once per run).</summary>
|
|
public static void SkipUnlessReachable()
|
|
{
|
|
if (Reason.Value is { } reason) Xunit.Assert.Skip(reason);
|
|
}
|
|
|
|
private static string? Probe()
|
|
{
|
|
var body = Endpoint.StartsWith("opc.tcp://", StringComparison.OrdinalIgnoreCase)
|
|
? Endpoint["opc.tcp://".Length..]
|
|
: Endpoint;
|
|
var slash = body.IndexOf('/');
|
|
if (slash >= 0) body = body[..slash];
|
|
var colon = body.LastIndexOf(':');
|
|
var host = colon >= 0 ? body[..colon] : body;
|
|
var port = colon >= 0 && int.TryParse(body[(colon + 1)..], out var p) ? p : 4840;
|
|
try
|
|
{
|
|
using var client = new TcpClient(AddressFamily.InterNetwork);
|
|
var addr = Dns.GetHostAddresses(host).FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork)
|
|
?? IPAddress.Loopback;
|
|
if (client.ConnectAsync(addr, port).Wait(TimeSpan.FromSeconds(2)) && client.Connected) return null;
|
|
return $"opc-plc simulator at {host}:{port} did not accept a TCP connection within 2s. Start it or override {EndpointEnvVar}.";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return $"opc-plc simulator at {host}:{port} unreachable: {ex.GetType().Name}: {ex.Message}. Start it or override {EndpointEnvVar}.";
|
|
}
|
|
}
|
|
}
|