using System;
using System.Collections.Generic;
using Junction.Domain.Models;
using Junction.Protocols.OpcUa;
using Xunit;
namespace Junction.Tests.Unit
{
///
/// Config-validation tests for , mirroring
/// MtconnectDriverFactory tests: required/absolute/scheme checks, enum checks, the
/// UsernamePassword credential rule and case-insensitive key lookup.
///
public sealed class OpcuaDriverFactoryTests
{
private static readonly Guid MachineId = Guid.Parse("99999999-8888-7777-6666-555555555555");
private const string EndpointUrl = "opc.tcp://opcua-server.test:4840";
private static Machine MachineWithConfig(IReadOnlyDictionary? config) =>
new Machine(MachineId, "PLC-01", "opcua", config, TimeSpan.FromSeconds(5));
[Fact]
public void ProtocolId_IsOpcua()
{
Assert.Equal("opcua", new OpcuaDriverFactory().ProtocolId);
}
[Fact]
public void MissingEndpointUrl_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary()));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_ENDPOINTURL_MISSING");
}
[Fact]
public void NonAbsoluteEndpointUrl_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(
new Dictionary { ["EndpointUrl"] = "not a uri" }));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_ENDPOINTURL_INVALID");
}
[Fact]
public void WrongScheme_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(
new Dictionary { ["EndpointUrl"] = "http://opcua-server.test:4840" }));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_ENDPOINTURL_SCHEME");
}
[Fact]
public void ValidEndpointUrl_ReturnsOkDriverWithOpcuaProtocolId()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(
new Dictionary { ["EndpointUrl"] = EndpointUrl }));
Assert.True(result.IsSuccess);
Assert.NotNull(result.Value);
Assert.Equal("opcua", result.Value.ProtocolId);
}
[Fact]
public void EndpointUrlKeyIsCaseInsensitive()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(
new Dictionary { ["endpointurl"] = EndpointUrl }));
Assert.True(result.IsSuccess);
}
[Fact]
public void InvalidSecurityMode_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary
{
["EndpointUrl"] = EndpointUrl,
["SecurityMode"] = "Bogus",
}));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_SECURITYMODE_INVALID");
}
[Fact]
public void InvalidAuthMode_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary
{
["EndpointUrl"] = EndpointUrl,
["AuthMode"] = "Kerberos",
}));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_AUTHMODE_INVALID");
}
[Fact]
public void UsernamePasswordWithoutUsername_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary
{
["EndpointUrl"] = EndpointUrl,
["AuthMode"] = "UsernamePassword",
["Password"] = "secret",
}));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_USERNAME_MISSING");
}
[Fact]
public void UsernamePasswordWithoutPassword_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary
{
["EndpointUrl"] = EndpointUrl,
["AuthMode"] = "UsernamePassword",
["Username"] = "admin",
}));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_PASSWORD_MISSING");
}
[Fact]
public void UsernamePasswordWithCredentials_ReturnsOk()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary
{
["EndpointUrl"] = EndpointUrl,
["AuthMode"] = "UsernamePassword",
["Username"] = "admin",
["Password"] = "secret",
}));
Assert.True(result.IsSuccess);
}
[Fact]
public void InvalidTimeout_ReturnsFail()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary
{
["EndpointUrl"] = EndpointUrl,
["TimeoutSeconds"] = "-5",
}));
Assert.False(result.IsSuccess);
Assert.Contains(result.Errors, e => e.Code == "CONFIG_TIMEOUT_INVALID");
}
[Fact]
public void FullValidConfig_ReturnsOk()
{
var result = new OpcuaDriverFactory().Create(MachineWithConfig(new Dictionary
{
["EndpointUrl"] = EndpointUrl,
["SecurityMode"] = "SignAndEncrypt",
["SecurityPolicy"] = "Basic256Sha256",
["AuthMode"] = "Anonymous",
["NodeIds"] = "ns=2;s=Temp, ns=2;s=Speed",
["BrowseRoot"] = "i=85",
["TimeoutSeconds"] = "15",
}));
Assert.True(result.IsSuccess);
Assert.Equal("opcua", result.Value.ProtocolId);
}
}
}