256 lines
8.2 KiB
C#
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();
|
|
}
|
|
}
|