Files
natsdotnet/tests/NATS.Server.Tests/Configuration/LoggingReloadTests.cs
Joseph Doherty 4c53159de8 feat: add runtime logging level changes (Gap 14.5)
Adds LoggingChangeResult and ApplyLoggingChanges to ConfigReloader, deriving
an effective log level from Debug/Trace flags (Trace > Debug > Information) and
reporting flag-level and level-string changes for hot-reload notification.
2026-02-25 11:48:29 -05:00

170 lines
5.6 KiB
C#

// 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");
}
}