Files
natsnet/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/SignalHandlerTests.cs

256 lines
8.2 KiB
C#

// Copyright 2012-2026 The NATS Authors
// Licensed under the Apache License, Version 2.0
using System.Runtime.InteropServices;
using Shouldly;
using ZB.MOM.NatsNet.Server.Internal;
namespace ZB.MOM.NatsNet.Server.Tests.Internal;
/// <summary>
/// Tests for SignalHandler — mirrors server/signal_test.go.
/// </summary>
public sealed class SignalHandlerTests : IDisposable
{
public SignalHandlerTests()
{
SignalHandler.ResetTestHooks();
SignalHandler.SetProcessName("nats-server");
}
public void Dispose()
{
SignalHandler.ResetTestHooks();
SignalHandler.SetProcessName("nats-server");
}
[Fact] // T:3158
public void CommandToUnixSignal_ShouldMapCorrectly()
{
SignalHandler.CommandToUnixSignal(ServerCommand.Stop).ShouldBe(UnixSignal.SigKill);
SignalHandler.CommandToUnixSignal(ServerCommand.Quit).ShouldBe(UnixSignal.SigInt);
SignalHandler.CommandToUnixSignal(ServerCommand.Reopen).ShouldBe(UnixSignal.SigUsr1);
SignalHandler.CommandToUnixSignal(ServerCommand.Reload).ShouldBe(UnixSignal.SigHup);
SignalHandler.CommandToUnixSignal(ServerCommand.Term).ShouldBe(UnixSignal.SigTerm);
SignalHandler.CommandToUnixSignal(ServerCommand.LameDuckMode).ShouldBe(UnixSignal.SigUsr2);
}
[Fact] // T:3155
public void SetProcessName_ShouldNotThrow()
{
Should.NotThrow(() => SignalHandler.SetProcessName("test-server"));
}
[Fact] // T:3149
public void IsWindowsService_ShouldReturnFalse()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
SignalHandler.IsWindowsService().ShouldBeFalse();
}
[Fact] // T:3148
public void Run_ShouldInvokeStartAction()
{
var called = false;
SignalHandler.Run(() => called = true);
called.ShouldBeTrue();
}
[Fact] // T:3157
public void ProcessSignal_InvalidPid_ShouldReturnError()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "not-a-pid");
err.ShouldNotBeNull();
}
[Fact] // T:2919
public void ProcessSignalInvalidCommand_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
var err = SignalHandler.ProcessSignal((ServerCommand)99, "123");
err.ShouldNotBeNull();
err!.Message.ShouldContain("unknown signal");
}
[Fact] // T:2920
public void ProcessSignalInvalidPid_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "abc");
err.ShouldNotBeNull();
err!.Message.ShouldBe("invalid pid: abc");
}
[Fact] // T:2913
public void ProcessSignalMultipleProcesses_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
SignalHandler.ResolvePidsHandler = () => [123, 456];
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "");
err.ShouldNotBeNull();
err!.Message.ShouldBe("multiple nats-server processes running:\n123\n456");
}
[Fact] // T:2914
public void ProcessSignalMultipleProcessesGlob_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
SignalHandler.ResolvePidsHandler = () => [123, 456];
SignalHandler.SendSignalHandler = static (_, _) => new InvalidOperationException("mock");
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "*");
err.ShouldNotBeNull();
var lines = err!.Message.Split('\n');
lines.Length.ShouldBe(3);
lines[0].ShouldBe(string.Empty);
lines[1].ShouldStartWith("signal \"stop\" 123:");
lines[2].ShouldStartWith("signal \"stop\" 456:");
}
[Fact] // T:2915
public void ProcessSignalMultipleProcessesGlobPartial_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
SignalHandler.ResolvePidsHandler = () => [123, 124, 456];
SignalHandler.SendSignalHandler = static (_, _) => new InvalidOperationException("mock");
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "12*");
err.ShouldNotBeNull();
var lines = err!.Message.Split('\n');
lines.Length.ShouldBe(3);
lines[0].ShouldBe(string.Empty);
lines[1].ShouldStartWith("signal \"stop\" 123:");
lines[2].ShouldStartWith("signal \"stop\" 124:");
}
[Fact] // T:2916
public void ProcessSignalPgrepError_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
SignalHandler.ResolvePidsHandler = static () => throw new InvalidOperationException("unable to resolve pid, try providing one");
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "");
err.ShouldNotBeNull();
err!.Message.ShouldBe("unable to resolve pid, try providing one");
}
[Fact] // T:2917
public void ProcessSignalPgrepMangled_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
SignalHandler.ResolvePidsHandler = static () => throw new InvalidOperationException("unable to resolve pid, try providing one");
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "");
err.ShouldNotBeNull();
err!.Message.ShouldBe("unable to resolve pid, try providing one");
}
[Fact] // T:2918
public void ProcessSignalResolveSingleProcess_ShouldSucceed()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
var called = false;
SignalHandler.ResolvePidsHandler = () => [123];
SignalHandler.SendSignalHandler = (pid, signal) =>
{
called = true;
pid.ShouldBe(123);
signal.ShouldBe(UnixSignal.SigKill);
return null;
};
var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "");
err.ShouldBeNull();
called.ShouldBeTrue();
}
[Fact] // T:2921
public void ProcessSignalQuitProcess_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.Quit, UnixSignal.SigInt, "123");
}
[Fact] // T:2922
public void ProcessSignalTermProcess_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.Term, UnixSignal.SigTerm, "123");
}
[Fact] // T:2923
public void ProcessSignalReopenProcess_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.Reopen, UnixSignal.SigUsr1, "123");
}
[Fact] // T:2924
public void ProcessSignalReloadProcess_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.Reload, UnixSignal.SigHup, "123");
}
[Fact] // T:2925
public void ProcessSignalLameDuckMode_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.LameDuckMode, UnixSignal.SigUsr2, "123");
}
[Fact] // T:2926
public void ProcessSignalTermDuringLameDuckMode_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.Term, UnixSignal.SigTerm, "123");
}
[Fact] // T:2927
public void SignalInterruptHasSuccessfulExit_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.Quit, UnixSignal.SigInt, "123");
}
[Fact] // T:2928
public void SignalTermHasSuccessfulExit_ShouldSucceed()
{
ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand.Term, UnixSignal.SigTerm, "123");
}
private static void ProcessSignalCommand_ShouldUseExpectedSignal(ServerCommand command, UnixSignal expectedSignal, string pid)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
var called = false;
SignalHandler.SendSignalHandler = (resolvedPid, signal) =>
{
called = true;
resolvedPid.ShouldBe(123);
signal.ShouldBe(expectedSignal);
return null;
};
var err = SignalHandler.ProcessSignal(command, pid);
err.ShouldBeNull();
called.ShouldBeTrue();
}
}