using Shouldly; using Microsoft.Extensions.Logging.Abstractions; using Xunit; namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests; /// /// Tests for — the factory that lets the /// Server-side DriverFactoryBootstrap materialise a real /// from a DriverInstance row instead of falling back to a stub. /// public class OpcUaClientDriverFactoryTests { private const string SampleConfig = """{"EndpointUrl":"opc.tcp://host:4840","SecurityMode":"None","AutoAcceptCertificates":true}"""; /// Verifies the factory builds a driver carrying the right type + instance identity. [Fact] public void CreateInstance_builds_an_OpcUaClient_driver_with_the_right_identity() { var driver = OpcUaClientDriverFactoryExtensions.CreateInstance("drv-1", SampleConfig, NullLoggerFactory.Instance); driver.DriverType.ShouldBe("OpcUaClient"); driver.DriverInstanceId.ShouldBe("drv-1"); } /// Verifies the public driver-type-name constant matches the driver's DriverType. [Fact] public void DriverTypeName_is_OpcUaClient() => OpcUaClientDriverFactoryExtensions.DriverTypeName.ShouldBe("OpcUaClient"); /// Verifies a JSON literal that deserialises to null is rejected with a clear error. [Fact] public void CreateInstance_throws_on_null_json_deserialisation() => Should.Throw( () => OpcUaClientDriverFactoryExtensions.CreateInstance("drv-1", "null", NullLoggerFactory.Instance)); private const string RawTagsConfig = """ { "EndpointUrl": "opc.tcp://host:4840", "RawTags": [ { "rawPath": "Plant/Line1/Temp", "tagConfig": "{\"nodeId\":\"ns=2;s=Temperature\"}", "writeIdempotent": false }, { "rawPath": "Plant/Line1/Speed", "tagConfig": "{\"nodeId\":\"ns=2;s=Speed\"}", "writeIdempotent": true } ] } """; /// /// Verifies the v3 authored RawTags (RawPath + TagConfig blob + WriteIdempotent) bind /// through the DriverConfig deserialiser directly onto — /// the OpcUaClient driver has no separate DTO, so the factory's direct-into-options path must /// populate the RawPath resolution list. /// [Fact] public void CreateInstance_binds_rawtags_from_driverconfig() { var driver = OpcUaClientDriverFactoryExtensions.CreateInstance("drv-raw", RawTagsConfig, NullLoggerFactory.Instance); // The factory succeeds and identity is intact — the deserialiser tolerated + bound the RawTags array. driver.DriverType.ShouldBe("OpcUaClient"); driver.DriverInstanceId.ShouldBe("drv-raw"); // Assert the actual binding: deserialise the same DriverConfig into public options with the // factory's serialiser settings (case-insensitive + string enums) and confirm RawTags populated. var opts = System.Text.Json.JsonSerializer.Deserialize( RawTagsConfig, new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true, Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() }, }); opts.ShouldNotBeNull(); opts!.RawTags.Count.ShouldBe(2); opts.RawTags[0].RawPath.ShouldBe("Plant/Line1/Temp"); opts.RawTags[0].TagConfig.ShouldContain("ns=2;s=Temperature"); opts.RawTags[0].WriteIdempotent.ShouldBeFalse(); opts.RawTags[1].WriteIdempotent.ShouldBeTrue(); } }