diff --git a/tests/NATS.Server.Tests/Configuration/LoggingReloadTests.cs b/tests/NATS.Server.Tests/Configuration/LoggingReloadTests.cs new file mode 100644 index 0000000..6d3a270 --- /dev/null +++ b/tests/NATS.Server.Tests/Configuration/LoggingReloadTests.cs @@ -0,0 +1,169 @@ +// Tests for ConfigReloader.ApplyLoggingChanges. +// Go reference: golang/nats-server/server/reload.go — traceOption.Apply, debugOption.Apply. + +using NATS.Server; +using NATS.Server.Configuration; +using Shouldly; + +namespace NATS.Server.Tests.Configuration; + +public class LoggingReloadTests +{ + // ─── helpers ──────────────────────────────────────────────────── + + private static NatsOptions BaseOpts() => new NatsOptions(); + + // ─── tests ────────────────────────────────────────────────────── + + [Fact] + public void No_changes_returns_no_changes() + { + // Go reference: reload.go traceOption.Apply — no-op when flags unchanged + var old = BaseOpts(); + var updated = BaseOpts(); + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.HasChanges.ShouldBeFalse(); + result.LevelChanged.ShouldBeFalse(); + result.TraceChanged.ShouldBeFalse(); + result.DebugChanged.ShouldBeFalse(); + } + + [Fact] + public void Level_changed_detected() + { + // Go reference: reload.go debugOption.Apply — enabling debug changes effective level + var old = BaseOpts(); // Debug=false, Trace=false → "Information" + var updated = BaseOpts(); + updated.Debug = true; // Debug=true → "Debug" + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.HasChanges.ShouldBeTrue(); + result.LevelChanged.ShouldBeTrue(); + } + + [Fact] + public void Trace_enabled_detected() + { + // Go reference: reload.go traceOption.Apply — enabling trace flag + var old = BaseOpts(); + var updated = BaseOpts(); + updated.Trace = true; + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.HasChanges.ShouldBeTrue(); + result.TraceChanged.ShouldBeTrue(); + } + + [Fact] + public void Trace_disabled_detected() + { + // Go reference: reload.go traceOption.Apply — disabling trace flag + var old = BaseOpts(); + old.Trace = true; + var updated = BaseOpts(); // Trace=false + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.HasChanges.ShouldBeTrue(); + result.TraceChanged.ShouldBeTrue(); + } + + [Fact] + public void Debug_enabled_detected() + { + // Go reference: reload.go debugOption.Apply — enabling debug flag + var old = BaseOpts(); + var updated = BaseOpts(); + updated.Debug = true; + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.HasChanges.ShouldBeTrue(); + result.DebugChanged.ShouldBeTrue(); + } + + [Fact] + public void Debug_disabled_detected() + { + // Go reference: reload.go debugOption.Apply — disabling debug flag + var old = BaseOpts(); + old.Debug = true; + var updated = BaseOpts(); // Debug=false + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.HasChanges.ShouldBeTrue(); + result.DebugChanged.ShouldBeTrue(); + } + + [Fact] + public void OldLevel_and_NewLevel_set() + { + // Go reference: reload.go — level transition is reported with explicit before/after values + var old = BaseOpts(); // Information + var updated = BaseOpts(); + updated.Trace = true; // Trace takes precedence + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.LevelChanged.ShouldBeTrue(); + result.OldLevel.ShouldBe("Information"); + result.NewLevel.ShouldBe("Trace"); + } + + [Fact] + public void Case_insensitive_level_comparison() + { + // Same effective level produced regardless of flag combination that yields the same tier + // Debug=true on both sides → "Debug" == "Debug", no level change + var old = BaseOpts(); + old.Debug = true; + var updated = BaseOpts(); + updated.Debug = true; + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.LevelChanged.ShouldBeFalse(); + result.HasChanges.ShouldBeFalse(); + } + + [Fact] + public void Null_level_defaults_to_Information() + { + // Go reference: reload.go — absent log level is treated as Information + // When neither Debug nor Trace is set the effective level is "Information" + var old = BaseOpts(); + var updated = BaseOpts(); + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + // No change, and effective level should be "Information" for both sides + result.LevelChanged.ShouldBeFalse(); + result.OldLevel.ShouldBeNull(); // only populated when a level change is detected + result.NewLevel.ShouldBeNull(); + } + + [Fact] + public void Multiple_changes_detected() + { + // Go reference: reload.go — independent trace and debug options both apply + var old = BaseOpts(); + old.Debug = true; + + var updated = BaseOpts(); + updated.Trace = true; // Debug removed, Trace added — both flags changed + + var result = ConfigReloader.ApplyLoggingChanges(old, updated); + + result.HasChanges.ShouldBeTrue(); + result.TraceChanged.ShouldBeTrue(); + result.DebugChanged.ShouldBeTrue(); + result.LevelChanged.ShouldBeTrue(); + result.OldLevel.ShouldBe("Debug"); + result.NewLevel.ShouldBe("Trace"); + } +}