using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Shouldly; using Xunit; namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests; [Trait("Category", "Unit")] public sealed class OpcUaClientCertAuthTests { [Fact] public void BuildCertificateIdentity_rejects_missing_path() { var opts = new OpcUaClientDriverOptions { AuthType = OpcUaAuthType.Certificate }; Should.Throw(() => OpcUaClientDriver.BuildCertificateIdentity(opts)) .Message.ShouldContain("UserCertificatePath"); } [Fact] public void BuildCertificateIdentity_rejects_nonexistent_file() { var opts = new OpcUaClientDriverOptions { AuthType = OpcUaAuthType.Certificate, UserCertificatePath = Path.Combine(Path.GetTempPath(), $"does-not-exist-{Guid.NewGuid():N}.pfx"), }; Should.Throw(() => OpcUaClientDriver.BuildCertificateIdentity(opts)); } [Fact] public void BuildCertificateIdentity_loads_a_valid_PFX_with_private_key() { // Generate a self-signed cert on the fly so the test doesn't ship a static PFX. // The driver doesn't care about the issuer — just needs a cert with a private key. using var rsa = RSA.Create(2048); var req = new CertificateRequest("CN=OpcUaClientCertAuthTests", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); var cert = req.CreateSelfSigned(DateTimeOffset.UtcNow.AddMinutes(-5), DateTimeOffset.UtcNow.AddHours(1)); var tmpPath = Path.Combine(Path.GetTempPath(), $"opcua-cert-test-{Guid.NewGuid():N}.pfx"); File.WriteAllBytes(tmpPath, cert.Export(X509ContentType.Pfx, "testpw")); try { var opts = new OpcUaClientDriverOptions { AuthType = OpcUaAuthType.Certificate, UserCertificatePath = tmpPath, UserCertificatePassword = "testpw", }; var identity = OpcUaClientDriver.BuildCertificateIdentity(opts); identity.ShouldNotBeNull(); identity.TokenType.ShouldBe(Opc.Ua.UserTokenType.Certificate); } finally { try { File.Delete(tmpPath); } catch { /* best-effort */ } } } }