From b336fa45195d265da07026954ad65065e01bce96 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 28 Feb 2026 10:10:27 -0500 Subject: [PATCH] feat(batch6-task7): port t2 leaf route websocket tls tests --- .../ImplBacklog/LeafNodeHandlerTests.cs | 169 ++++++++++++++++++ .../ImplBacklog/RouteHandlerTests.cs | 81 +++++++++ .../ImplBacklog/WebSocketHandlerTests.cs | 28 +++ porting.db | Bin 6483968 -> 6488064 bytes reports/current.md | 8 +- 5 files changed, 282 insertions(+), 4 deletions(-) diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeHandlerTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeHandlerTests.cs index 0f3c02a..c5b4311 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeHandlerTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeHandlerTests.cs @@ -6,6 +6,175 @@ namespace ZB.MOM.NatsNet.Server.Tests.ImplBacklog; public sealed partial class LeafNodeHandlerTests { + [Fact] // T:1918 + public void LeafNodeCloseTLSConnection_ShouldSucceed() + { + var options = new ServerOptions(); + var errors = new List(); + var warnings = new List(); + + var parseError = ServerOptions.ParseLeafNodes( + new Dictionary + { + ["tls"] = new Dictionary + { + ["verify"] = true, + ["map"] = true, + ["timeout"] = 0.25d, + }, + ["write_deadline"] = "2s", + ["write_timeout"] = "close", + }, + options, + errors, + warnings); + + parseError.ShouldBeNull(); + errors.ShouldBeEmpty(); + options.LeafNode.TlsConfig.ShouldNotBeNull(); + options.LeafNode.TlsConfig!.ClientCertificateRequired.ShouldBeTrue(); + options.LeafNode.TlsMap.ShouldBeTrue(); + options.LeafNode.TlsTimeout.ShouldBe(0.25d); + options.LeafNode.WriteDeadline.ShouldBe(TimeSpan.FromSeconds(2)); + options.LeafNode.WriteTimeout.ShouldBe(WriteTimeoutPolicy.Close); + } + + [Fact] // T:1919 + public void LeafNodeTLSSaveName_ShouldSucceed() + { + var errors = new List(); + var warnings = new List(); + + var remotes = ServerOptions.ParseRemoteLeafNodes( + new List + { + new Dictionary + { + ["url"] = "nats://localhost:7422", + ["tls"] = new Dictionary + { + ["verify"] = true, + ["timeout"] = 1, + }, + }, + }, + errors, + warnings); + + errors.ShouldBeEmpty(); + remotes.Count.ShouldBe(1); + remotes[0].Urls.Count.ShouldBe(1); + remotes[0].Urls[0].Host.ShouldBe("localhost"); + remotes[0].TlsConfig.ShouldNotBeNull(); + remotes[0].TlsConfig!.ClientCertificateRequired.ShouldBeTrue(); + remotes[0].TlsTimeout.ShouldBe(1d); + } + + [Fact] // T:1929 + public void LeafNodeTLSVerifyAndMap_ShouldSucceed() + { + var options = new ServerOptions(); + var errors = new List(); + var warnings = new List(); + + var parseError = ServerOptions.ParseLeafNodes( + new Dictionary + { + ["authorization"] = new Dictionary + { + ["users"] = new List + { + new Dictionary + { + ["user"] = "CN=example.com,OU=NATS.io", + ["pass"] = "pw", + ["account"] = "MyAccount", + }, + }, + }, + ["tls"] = new Dictionary + { + ["verify"] = true, + ["map"] = true, + ["timeout"] = 0.5d, + }, + }, + options, + errors, + warnings); + + parseError.ShouldBeNull(); + errors.ShouldBeEmpty(); + options.LeafNode.TlsConfig.ShouldNotBeNull(); + options.LeafNode.TlsConfig!.ClientCertificateRequired.ShouldBeTrue(); + options.LeafNode.TlsMap.ShouldBeTrue(); + options.LeafNode.Users.ShouldNotBeNull(); + options.LeafNode.Users!.Count.ShouldBe(1); + options.LeafNode.Users[0].Username.ShouldBe("CN=example.com,OU=NATS.io"); + options.LeafNode.Users[0].Account.ShouldNotBeNull(); + options.LeafNode.Users[0].Account!.Name.ShouldBe("MyAccount"); + } + + [Fact] // T:1942 + public void LeafNodeWSBasic_ShouldSucceed() + { + var options = new ServerOptions(); + var errors = new List(); + var warnings = new List(); + + var parseError = ServerOptions.ParseLeafNodes( + new Dictionary + { + ["remotes"] = new List + { + new Dictionary + { + ["url"] = "ws://127.0.0.1:7422/some/path", + ["ws_compression"] = true, + ["ws_no_masking"] = true, + ["compression"] = true, + }, + }, + }, + options, + errors, + warnings); + + parseError.ShouldBeNull(); + errors.ShouldBeEmpty(); + options.LeafNode.Remotes.Count.ShouldBe(1); + options.LeafNode.Remotes[0].Urls.Count.ShouldBe(1); + options.LeafNode.Remotes[0].Urls[0].Scheme.ShouldBe("ws"); + options.LeafNode.Remotes[0].Websocket.Compression.ShouldBeTrue(); + options.LeafNode.Remotes[0].Websocket.NoMasking.ShouldBeTrue(); + options.LeafNode.Remotes[0].Compression.Mode.ShouldBe(CompressionModes.S2Auto); + } + + [Fact] // T:1950 + public void LeafNodeWSRemoteNoTLSBlockWithWSSProto_ShouldSucceed() + { + var errors = new List(); + var warnings = new List(); + + var remotes = ServerOptions.ParseRemoteLeafNodes( + new List + { + new Dictionary + { + ["url"] = "wss://127.0.0.1:7422/some/path", + }, + }, + errors, + warnings); + + errors.ShouldBeEmpty(); + remotes.Count.ShouldBe(1); + remotes[0].Urls.Count.ShouldBe(1); + remotes[0].Urls[0].Scheme.ShouldBe("wss"); + remotes[0].Tls.ShouldBeFalse(); + remotes[0].TlsConfig.ShouldBeNull(); + } + [Fact] // T:1907 public void LeafNodeRandomRemotes_ShouldSucceed() { diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.cs index af415bd..1832bc5 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.cs @@ -6,6 +6,87 @@ namespace ZB.MOM.NatsNet.Server.Tests.ImplBacklog; public sealed partial class RouteHandlerTests { + [Fact] // T:2817 + public void RouteCloseTLSConnection_ShouldSucceed() + { + var options = new ServerOptions(); + var errors = new List(); + var warnings = new List(); + + var (tlsOptions, tlsParseError) = ServerOptions.ParseTLS( + new Dictionary + { + ["verify"] = true, + ["timeout"] = 0.1d, + }, + isClientCtx: false); + + tlsParseError.ShouldBeNull(); + tlsOptions.ShouldNotBeNull(); + + var (tlsConfig, tlsGenError) = ServerOptions.GenTLSConfig(tlsOptions!); + + tlsGenError.ShouldBeNull(); + tlsConfig.ShouldNotBeNull(); + + options.Cluster.TlsConfig = tlsConfig; + options.Cluster.TlsTimeout = tlsOptions!.Timeout; + + var parseError = ServerOptions.ParseCluster( + new Dictionary + { + ["name"] = "A", + ["write_deadline"] = "3s", + ["write_timeout"] = "close", + }, + options, + errors, + warnings); + + parseError.ShouldBeNull(); + errors.ShouldBeEmpty(); + options.Cluster.TlsConfig.ShouldNotBeNull(); + options.Cluster.TlsConfig!.ClientCertificateRequired.ShouldBeTrue(); + options.Cluster.TlsTimeout.ShouldBe(0.1d); + options.Cluster.WriteDeadline.ShouldBe(TimeSpan.FromSeconds(3)); + options.Cluster.WriteTimeout.ShouldBe(WriteTimeoutPolicy.Close); + } + + [Fact] // T:2821 + public void RouteLockReleasedOnTLSFailure_ShouldSucceed() + { + var options = new ServerOptions(); + var (tlsOptions, tlsParseError) = ServerOptions.ParseTLS( + new Dictionary + { + ["cipher_suites"] = new List { "TLS_RSA_WITH_RC4_128_SHA" }, + }, + isClientCtx: false); + + tlsOptions.ShouldBeNull(); + tlsParseError.ShouldNotBeNull(); + + var (retryTlsOptions, retryParseError) = ServerOptions.ParseTLS( + new Dictionary + { + ["verify"] = true, + ["timeout"] = 0.25d, + }, + isClientCtx: false); + + retryParseError.ShouldBeNull(); + retryTlsOptions.ShouldNotBeNull(); + + var (tlsConfig, tlsGenError) = ServerOptions.GenTLSConfig(retryTlsOptions!); + + tlsGenError.ShouldBeNull(); + tlsConfig.ShouldNotBeNull(); + options.Cluster.TlsTimeout = retryTlsOptions!.Timeout; + options.Cluster.TlsConfig = tlsConfig; + options.Cluster.TlsConfig.ShouldNotBeNull(); + options.Cluster.TlsTimeout.ShouldBe(0.25d); + } + [Fact] // T:2808 public void RouteUseIPv6_ShouldSucceed() { diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs index 42b1c73..217bbde 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs @@ -6,6 +6,34 @@ namespace ZB.MOM.NatsNet.Server.Tests.ImplBacklog; public sealed partial class WebSocketHandlerTests { + [Fact] // T:3109 + public void WSHandshakeTimeout_ShouldSucceed() + { + var options = new ServerOptions(); + var errors = new List(); + var warnings = new List(); + + var parseError = ServerOptions.ParseWebsocket( + new Dictionary + { + ["handshake_timeout"] = "1ms", + ["tls"] = new Dictionary + { + ["verify_and_map"] = true, + }, + }, + options, + errors, + warnings); + + parseError.ShouldBeNull(); + errors.ShouldBeEmpty(); + options.Websocket.HandshakeTimeout.ShouldBe(TimeSpan.FromMilliseconds(1)); + options.Websocket.TlsConfig.ShouldNotBeNull(); + options.Websocket.TlsMap.ShouldBeTrue(); + options.Websocket.TlsConfig!.ClientCertificateRequired.ShouldBeTrue(); + } + [Fact] // T:3105 public void WSPubSub_ShouldSucceed() { diff --git a/porting.db b/porting.db index e44efb2698d8c5692d843f86a444dd845b2be290..98fe78eef72ca111a7c8a99e90da2deb17b6c97a 100644 GIT binary patch delta 2065 zcmbuYwC1onh&b;_JL9g6(H@Wt5XWqyXtoJ19hF+tOit{TA>!J*{V&sp&Vwr z_EV97ae$gx&jEVeB%I+Yp#3ndB^;bROfyB*!P%f=3ZDp$BeaC{!1N>3Bbv=Pw(kgz zm4kMaj)^mG#x%!_R)3vgF=3WwYRaw zlE69O+HE>qsN}L)(jBU6wOWRJhpPyNmijCbrqWm6-TdPFZwk>#9 zhLczIG)Di>zcGR9=HPVLX^nS)^PXPP|BSHbo{r*~=U&2vGmw`hq=WIj-44r6+aLZa zpP#mWkqo>V_u%&KYxeT~miCCfJu;*xl9(w%zHW0u&F-O2c<1*-cmGUy+s#CjgpyGT zavW!r8(_2ye5|CP`gJ+bZVSirbWOd{h2*@Wq2Sh1i(l(Xx4tC{)N0DI5tJDgWjnu|0XFPwYAR06iB3(2Q z#`SrAQN%9GS*c!pj}>0@%o3v08gG%{?JM4taPMUg>%Huqct@~v`#|pVWr<`mCVVg2 zliF+@l`5CUJF62~3YIo549yGqgQ1|@0^QU*5?YhJqN~UVhP+K7x6$Me`kUTZ*to!W z%^L{#>y2soMr<6GjPmMG)9KTkqusfM?$IUKJNeOGXq)8A{r{!%gHm?kqR(a1tyUOeT;JE@0yYX|Bj fPu^QIK(D;z$$P5@>g{~;-l~Cm*F0wLzc0-{>BqAH delta 1214 zcmW;LTTB#J7{Kv4bJ>}l*4aXx$BUrVUUZfKS6w4a;;X^?i<%hUpOyZt}=0CW!0SjEmMe<~wNC%ZaGMZyM#=xv+u5$A&T z5gH(Fm>QvJaP|Q22KOl4MQ%a)D7E06n|HyjQCdu@!7)a6!oL-~n^lj|E1Sp&lOpsq zae6gbeV|UO6Y7xq84EAbWraM3Gb_{*okB7X4_D|GA%kW@zGMp@m5K^(1cQ9yHFG8zC~}F`(tHkq48#u^Rj8uJL6ecrtV^m_Hc?eE!fVh_2fnG1?;= z1|sokB9#3V-vV9ff*k5ujzAbhFuHH=9$}4a4;gW9@iu(6T)x(Y=JK zvOUO)Hlj^vGundEP&#@RJ%_fU=g~IgLoc8Vl!>y?cC-WSMA;|@?LxUI59Om5(MxDI z@}rkg0osEK(JQD36{8aLD%y+oq1Vvss1)r-Whj6Spo8cQ^d>4tZ=plzFssV0=vfqg z7gUhV$`fv>PWV_VmrA5uX{+2Ww+LbRUHOR6A(zU2cEzkLCNR`WQ-F9XCxBnHib96B z5*cG(o!U_5($OKcb1cB_pHZuaYDStfxnN> zhr(IwH&L6C>R8U4RUt$t&FG{fbYsC{Hx_F4t_rba2ISe=be7s@yGGc|T&>6TKQuzJ ANB{r; diff --git a/reports/current.md b/reports/current.md index 73d8a3e..7293ab0 100644 --- a/reports/current.md +++ b/reports/current.md @@ -1,6 +1,6 @@ # NATS .NET Porting Status Report -Generated: 2026-02-28 15:04:45 UTC +Generated: 2026-02-28 15:10:28 UTC ## Modules (12 total) @@ -21,9 +21,9 @@ Generated: 2026-02-28 15:04:45 UTC | Status | Count | |--------|-------| -| deferred | 2044 | +| deferred | 2036 | | n_a | 188 | -| verified | 1025 | +| verified | 1033 | ## Library Mappings (36 total) @@ -34,4 +34,4 @@ Generated: 2026-02-28 15:04:45 UTC ## Overall Progress -**2840/6942 items complete (40.9%)** +**2848/6942 items complete (41.0%)**