feat(batch4-task2): implement core logger wiring features
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
using Shouldly;
|
||||
using System.Reflection;
|
||||
using ZB.MOM.NatsNet.Server;
|
||||
using ZB.MOM.NatsNet.Server.Internal;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server.Tests.Internal;
|
||||
@@ -135,4 +137,130 @@ public class ServerLoggerTests
|
||||
_ = name; // used for test display only
|
||||
ServerLogging.RemoveAuthTokenFromTrace(input).ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetLogger_SetLoggerV2AndConfigureLogger_ShouldApplyExpectedSemantics()
|
||||
{
|
||||
var (server, err) = NatsServer.NewServer(new ServerOptions());
|
||||
err.ShouldBeNull();
|
||||
server.ShouldNotBeNull();
|
||||
|
||||
var setLogger = GetRequiredServerMethod("SetLogger", typeof(INatsLogger), typeof(bool), typeof(bool));
|
||||
var setLoggerV2 = GetRequiredServerMethod("SetLoggerV2", typeof(INatsLogger), typeof(bool), typeof(bool), typeof(bool));
|
||||
var configureLogger = GetRequiredServerMethod("ConfigureLogger");
|
||||
var executeLogCall = GetRequiredServerMethod("ExecuteLogCall", typeof(Action<INatsLogger>));
|
||||
|
||||
var first = new CapturingLogger();
|
||||
setLogger.Invoke(server, [first, true, true]);
|
||||
|
||||
GetPrivateIntField(server!, "_debugEnabled").ShouldBe(1);
|
||||
GetPrivateIntField(server!, "_traceEnabled").ShouldBe(1);
|
||||
GetPrivateIntField(server!, "_traceSysAcc").ShouldBe(0);
|
||||
|
||||
var second = new CapturingLogger();
|
||||
setLoggerV2.Invoke(server, [second, false, false, true]);
|
||||
|
||||
first.Disposed.ShouldBeTrue();
|
||||
GetPrivateIntField(server!, "_debugEnabled").ShouldBe(0);
|
||||
GetPrivateIntField(server!, "_traceEnabled").ShouldBe(0);
|
||||
GetPrivateIntField(server!, "_traceSysAcc").ShouldBe(1);
|
||||
|
||||
var noLogOptions = server!.Options;
|
||||
noLogOptions.NoLog = true;
|
||||
configureLogger.Invoke(server, null);
|
||||
|
||||
InvokeNoticef(server, "no-log should keep existing logger");
|
||||
second.Messages.ShouldContain(msg => msg.Contains("no-log should keep existing logger", StringComparison.Ordinal));
|
||||
|
||||
var calls = 0;
|
||||
executeLogCall.Invoke(server, [(Action<INatsLogger>)(_ => calls++)]);
|
||||
calls.ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReOpenLogFile_ByLoggerMode_ShouldMatchExpectedBehavior()
|
||||
{
|
||||
var (server, err) = NatsServer.NewServer(new ServerOptions());
|
||||
err.ShouldBeNull();
|
||||
server.ShouldNotBeNull();
|
||||
|
||||
var setLogger = GetRequiredServerMethod("SetLogger", typeof(INatsLogger), typeof(bool), typeof(bool));
|
||||
var configureLogger = GetRequiredServerMethod("ConfigureLogger");
|
||||
var reOpenLogFile = GetRequiredServerMethod("ReOpenLogFile");
|
||||
var executeLogCall = GetRequiredServerMethod("ExecuteLogCall", typeof(Action<INatsLogger>));
|
||||
|
||||
// Nil logger path: executeLogCall should no-op.
|
||||
var called = false;
|
||||
executeLogCall.Invoke(server, [(Action<INatsLogger>)(_ => called = true)]);
|
||||
called.ShouldBeFalse();
|
||||
|
||||
// Non-file logger path.
|
||||
var memoryLogger = new CapturingLogger();
|
||||
setLogger.Invoke(server, [memoryLogger, false, false]);
|
||||
reOpenLogFile.Invoke(server, null);
|
||||
memoryLogger.Messages.ShouldContain(m => m.Contains("not a file logger", StringComparison.Ordinal));
|
||||
|
||||
// File logger path.
|
||||
var logFile = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid():N}.log");
|
||||
var opts = server!.Options;
|
||||
opts.LogFile = logFile;
|
||||
opts.NoLog = false;
|
||||
opts.Debug = false;
|
||||
opts.Trace = false;
|
||||
opts.Logtime = false;
|
||||
|
||||
configureLogger.Invoke(server, null);
|
||||
InvokeNoticef(server, "message-before-reopen");
|
||||
reOpenLogFile.Invoke(server, null);
|
||||
InvokeNoticef(server, "message-after-reopen");
|
||||
|
||||
File.Exists(logFile).ShouldBeTrue();
|
||||
var content = File.ReadAllText(logFile);
|
||||
content.ShouldContain("File log re-opened");
|
||||
content.ShouldContain("message-after-reopen");
|
||||
}
|
||||
|
||||
private static int GetPrivateIntField(object target, string fieldName)
|
||||
{
|
||||
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
field.ShouldNotBeNull();
|
||||
return (int)field!.GetValue(target)!;
|
||||
}
|
||||
|
||||
private static MethodInfo GetRequiredServerMethod(string name, params Type[] parameterTypes)
|
||||
{
|
||||
var method = typeof(NatsServer).GetMethod(
|
||||
name,
|
||||
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
|
||||
binder: null,
|
||||
types: parameterTypes,
|
||||
modifiers: null);
|
||||
|
||||
method.ShouldNotBeNull($"{name} should exist on NatsServer");
|
||||
return method!;
|
||||
}
|
||||
|
||||
private static void InvokeNoticef(NatsServer server, string message)
|
||||
{
|
||||
var noticeMethod = typeof(NatsServer).GetMethod(
|
||||
"Noticef",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
noticeMethod.ShouldNotBeNull();
|
||||
noticeMethod!.Invoke(server, ["{0}", new object?[] { message }]);
|
||||
}
|
||||
|
||||
private sealed class CapturingLogger : INatsLogger, IDisposable
|
||||
{
|
||||
public List<string> Messages { get; } = [];
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
public void Noticef(string format, params object[] args) => Messages.Add(string.Format(format, args));
|
||||
public void Warnf(string format, params object[] args) => Messages.Add(string.Format(format, args));
|
||||
public void Fatalf(string format, params object[] args) => Messages.Add(string.Format(format, args));
|
||||
public void Errorf(string format, params object[] args) => Messages.Add(string.Format(format, args));
|
||||
public void Debugf(string format, params object[] args) => Messages.Add(string.Format(format, args));
|
||||
public void Tracef(string format, params object[] args) => Messages.Add(string.Format(format, args));
|
||||
|
||||
public void Dispose() => Disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user