From 923bc737a37a4382e787be49dac14b340d6c72f3 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 10 Nov 2026 14:27:36 -0500 Subject: [PATCH] test: initialize immutable historian TLS fixture options --- .../historiangw-131/consumer-1.0.0.patch | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/scripts/validation/historiangw-131/consumer-1.0.0.patch b/scripts/validation/historiangw-131/consumer-1.0.0.patch index b22cd7a6..1e855bb0 100644 --- a/scripts/validation/historiangw-131/consumer-1.0.0.patch +++ b/scripts/validation/historiangw-131/consumer-1.0.0.patch @@ -81,8 +81,9 @@ diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/Hist new file mode 100644 --- /dev/null +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayTlsPolicyWireTests.cs -@@ -0,0 +1,126 @@ +@@ -0,0 +1,142 @@ +using System.Net; ++using System.Security.Authentication; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using Grpc.Core; @@ -101,7 +102,7 @@ new file mode 100644 +namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests; + +/// historiangw#131: verify the mapped TLS posture through an actual local gRPC connection. -+public sealed class HistorianGatewayTlsPolicyWireTests ++public sealed class HistorianGatewayTlsPolicyWireTests(ITestOutputHelper output) +{ + private static CancellationToken Ct => TestContext.Current.CancellationToken; + @@ -111,8 +112,10 @@ new file mode 100644 + await using var server = await Server.StartAsync(tls: true); + using var adapter = HistorianGatewayClientAdapter.Create(server.Options(), NullLoggerFactory.Instance); + -+ await Should.ThrowAsync( ++ var error = await Should.ThrowAsync( + () => adapter.TagExistsAsync("T", Ct).WaitAsync(TimeSpan.FromSeconds(15), Ct)); ++ output.WriteLine($"TLS rejection: {error}"); ++ ContainsTlsAuthenticationFailure(error).ShouldBeTrue("the failure must be TLS authentication, not an arbitrary connection failure"); + server.MetadataCalls.ShouldBe(0); + } + @@ -120,8 +123,7 @@ new file mode 100644 + public async Task Explicit_tls_opt_out_reaches_the_same_self_signed_server_shape() + { + await using var server = await Server.StartAsync(tls: true); -+ var options = server.Options(); -+ options.AllowUntrustedServerCertificate = true; ++ var options = server.Options(allowUntrusted: true); + using var adapter = HistorianGatewayClientAdapter.Create(options, NullLoggerFactory.Instance); + + (await adapter.TagExistsAsync("T", Ct).WaitAsync(TimeSpan.FromSeconds(15), Ct)).ShouldBeTrue(); @@ -132,15 +134,28 @@ new file mode 100644 + public async Task Plaintext_ignores_stale_tls_opt_out_and_ca_settings_and_reaches_the_rpc() + { + await using var server = await Server.StartAsync(tls: false); -+ var options = server.Options(); -+ options.AllowUntrustedServerCertificate = true; -+ options.CaCertificatePath = "/nonexistent/historiangw-131-stale-ca.pem"; ++ var options = server.Options(allowUntrusted: true, caPath: "/nonexistent/historiangw-131-stale-ca.pem"); + using var adapter = HistorianGatewayClientAdapter.Create(options, NullLoggerFactory.Instance); + + (await adapter.TagExistsAsync("T", Ct).WaitAsync(TimeSpan.FromSeconds(15), Ct)).ShouldBeTrue(); + server.MetadataCalls.ShouldBe(1); + } + ++ private static bool ContainsTlsAuthenticationFailure(Exception error) ++ { ++ var pending = new Stack(); ++ var seen = new HashSet(ReferenceEqualityComparer.Instance); ++ pending.Push(error); ++ while (pending.TryPop(out var current)) ++ { ++ if (!seen.Add(current)) continue; ++ if (current is AuthenticationException) return true; ++ if (current.InnerException is { } inner) pending.Push(inner); ++ if (current is RpcException { Status.DebugException: { } debug }) pending.Push(debug); ++ } ++ return false; ++ } ++ + private sealed class TagsService : HistorianTags.HistorianTagsBase + { + public int Calls; @@ -156,10 +171,11 @@ new file mode 100644 + RSA? key, X509Certificate2? certificate) : IAsyncDisposable + { + public int MetadataCalls => Volatile.Read(ref service.Calls); -+ public ServerHistorianOptions Options() => new() ++ public ServerHistorianOptions Options(bool allowUntrusted = false, string? caPath = null) => new() + { + Endpoint = endpoint, ApiKey = "histgw_131_test", UseTls = certificate is not null, + CallTimeout = TimeSpan.FromSeconds(2), ++ AllowUntrustedServerCertificate = allowUntrusted, CaCertificatePath = caPath, + }; + + public static async Task StartAsync(bool tls)