feat(batch18): implement group-a server core helpers

This commit is contained in:
Joseph Doherty
2026-02-28 19:17:53 -05:00
parent e16d7ffab3
commit f8d384711d
7 changed files with 308 additions and 10 deletions

View File

@@ -1,5 +1,8 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using Shouldly;
using ZB.MOM.NatsNet.Server;
using ZB.MOM.NatsNet.Server.Internal;
@@ -10,6 +13,99 @@ namespace ZB.MOM.NatsNet.Server.Tests.ImplBacklog;
public sealed class MonitoringHandlerTests
{
[Fact]
public void GetMonitoringTLSConfig_WithServerTlsConfig_DisablesClientCertificateRequirementOnClone()
{
var (certFile, keyFile, tempDir, _) = CreatePemCertificate(DateTimeOffset.UtcNow.AddMinutes(10));
var (tlsOpts, parseErr) = ServerOptions.ParseTLS(
new Dictionary<string, object?>
{
["cert_file"] = certFile,
["key_file"] = keyFile,
["verify"] = true,
},
isClientCtx: false);
parseErr.ShouldBeNull();
tlsOpts.ShouldNotBeNull();
var (tlsConfig, tlsErr) = ServerOptions.GenTLSConfig(tlsOpts!);
tlsErr.ShouldBeNull();
tlsConfig.ShouldNotBeNull();
var opts = new ServerOptions { TlsConfig = tlsConfig };
var (server, error) = NatsServer.NewServer(opts);
error.ShouldBeNull();
server.ShouldNotBeNull();
var monitoringTls = server!.GetMonitoringTLSConfig();
monitoringTls.ShouldNotBeNull();
monitoringTls!.ClientCertificateRequired.ShouldBeFalse();
monitoringTls.CertificateRevocationCheckMode.ShouldBe(opts.TlsConfig!.CertificateRevocationCheckMode);
opts.TlsConfig!.ClientCertificateRequired.ShouldBeTrue();
Directory.Delete(tempDir, recursive: true);
}
[Fact]
public void HTTPHandler_WhenMonitoringListenerStops_TransitionsToNull()
{
var opts = new ServerOptions
{
HttpHost = "127.0.0.1",
HttpPort = -1,
};
var (server, error) = NatsServer.NewServer(opts);
error.ShouldBeNull();
server.ShouldNotBeNull();
server!.HTTPHandler().ShouldBeNull();
var startError = server.StartMonitoring();
startError.ShouldBeNull();
server.HTTPHandler().ShouldNotBeNull();
var listenerField = typeof(NatsServer).GetField("_http", BindingFlags.Instance | BindingFlags.NonPublic);
listenerField.ShouldNotBeNull();
var listener = listenerField!.GetValue(server).ShouldBeOfType<TcpListener>();
listener.Stop();
var transitioned = SpinWait.SpinUntil(() => server.HTTPHandler() == null, TimeSpan.FromSeconds(5));
transitioned.ShouldBeTrue();
server.HTTPHandler().ShouldBeNull();
}
[Fact]
public async Task LogRejectedTLSConns_WhenRateCounterHasBlockedConnections_EmitsWarning()
{
var opts = new ServerOptions { TlsRateLimit = 1 };
var (server, error) = NatsServer.NewServer(opts);
error.ShouldBeNull();
server.ShouldNotBeNull();
var logger = new MonitoringCaptureLogger();
server!.SetLogger(logger, debugFlag: false, traceFlag: false);
var rateCounterField = typeof(NatsServer).GetField("_connRateCounter", BindingFlags.Instance | BindingFlags.NonPublic);
rateCounterField.ShouldNotBeNull();
var rateCounter = rateCounterField!.GetValue(server).ShouldBeOfType<RateCounter>();
rateCounter.Allow();
rateCounter.Allow();
using var cts = new CancellationTokenSource();
var loop = server.LogRejectedTLSConns(cts.Token, TimeSpan.FromMilliseconds(10));
var warned = SpinWait.SpinUntil(
() => logger.WarningEntries.Any(w => w.Contains("Rejected", StringComparison.OrdinalIgnoreCase)),
TimeSpan.FromSeconds(2));
cts.Cancel();
await loop;
warned.ShouldBeTrue();
}
[Fact] // T:2108
public void MonitorConnzClosedConnsBadTLSClient_ShouldSucceed()
{
@@ -228,6 +324,18 @@ public sealed class MonitoringHandlerTests
return (certFile, keyFile, tempDir, notAfter);
}
private sealed class MonitoringCaptureLogger : INatsLogger
{
public List<string> WarningEntries { get; } = [];
public void Noticef(string format, params object[] args) { }
public void Warnf(string format, params object[] args) => WarningEntries.Add(string.Format(format, args));
public void Fatalf(string format, params object[] args) { }
public void Errorf(string format, params object[] args) { }
public void Debugf(string format, params object[] args) { }
public void Tracef(string format, params object[] args) { }
}
[Fact] // T:2065
public void MonitorNoPort_ShouldSucceed()
{