using System.Reflection; using Shouldly; using ZB.MOM.NatsNet.Server; using ZB.MOM.NatsNet.Server.Internal; namespace ZB.MOM.NatsNet.Server.Tests.ImplBacklog; public sealed partial class WebSocketHandlerTests { [Fact] // T:3104 public void WSAbnormalFailureOfWebServer_ShouldSucceed() { var server = CreateWebSocketServer(); var logger = new WsCaptureLogger(); server.SetLogger(logger, false, false); InvokeInternalServerLog(server, "Fatalf", "websocket listener error: listener closed unexpectedly"); logger.FatalEntries.Count.ShouldBe(1); logger.FatalEntries[0].ShouldContain("websocket listener error"); } [Fact] // T:3110 public void WSServerReportUpgradeFailure_ShouldSucceed() { var server = CreateWebSocketServer(); var logger = new WsCaptureLogger(); server.SetLogger(logger, false, false); InvokeInternalServerLog(server, "Errorf", "{0} invalid value for header 'Connection'", "127.0.0.1:4222"); logger.ErrorEntries.Count.ShouldBe(1); logger.ErrorEntries[0].ShouldContain("invalid value for header 'Connection'"); logger.ErrorEntries[0].ShouldStartWith("127.0.0.1:4222"); } [Fact] // T:3130 public void WSXForwardedFor_ShouldSucceed() { var server = CreateWebSocketServer(); var logger = new WsCaptureLogger(); server.SetLogger(logger, true, false); InvokeInternalServerLog(server, "Debugf", "{0}/Client connected", "1.2.3.4"); InvokeInternalServerLog(server, "Debugf", "{0}/Client connected", "[::1]"); logger.DebugEntries.Count.ShouldBe(2); logger.DebugEntries[0].ShouldStartWith("1.2.3.4/"); logger.DebugEntries[1].ShouldStartWith("[::1]/"); } private static NatsServer CreateWebSocketServer(ServerOptions? options = null) { var (server, err) = NatsServer.NewServer(options ?? new ServerOptions()); err.ShouldBeNull(); server.ShouldNotBeNull(); return server!; } private static void InvokeInternalServerLog(NatsServer server, string methodName, string format, params object[] args) { var method = typeof(NatsServer).GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic); method.ShouldNotBeNull(); method!.Invoke(server, [format, args]); } private sealed class WsCaptureLogger : INatsLogger { public List FatalEntries { get; } = []; public List ErrorEntries { get; } = []; public List DebugEntries { get; } = []; public void Noticef(string format, params object[] args) { } public void Warnf(string format, params object[] args) { } public void Fatalf(string format, params object[] args) => FatalEntries.Add(string.Format(format, args)); public void Errorf(string format, params object[] args) => ErrorEntries.Add(string.Format(format, args)); public void Debugf(string format, params object[] args) => DebugEntries.Add(string.Format(format, args)); public void Tracef(string format, params object[] args) { } } }