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); } } }