Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 47 additions & 16 deletions src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
Expand Down Expand Up @@ -192,16 +193,26 @@ public void SignalHandler_CanDisposeInHandler(PosixSignal signal)
const string PosixSignalRegistrationCreatedMessage = "PosixSignalRegistration created.";
const string PosixSignalHandlerStartedMessage = "PosixSignalRegistration handler started.";
const string PosixSignalHandlerDisposedMessage = "PosixSignalRegistration disposed.";
const int UnterminatedExitCode = -1;
const int UnterminatedExitCode = 1;

var remoteInvokeOptions = new RemoteInvokeOptions { CheckExitCode = false };
// Process operations timeout cascading:
// WaitInMS * 1: Remote process wait for first signal that unregisters the exercised signal handler
// WaitInMS * 2: Remote process may additionally wait for a second signal that should terminate it
// WaitInMS * 3: RemoteExecutor timeout, leaving slack for process startup, signal delivery, and teardown

var remoteInvokeOptions = new RemoteInvokeOptions { CheckExitCode = false, TimeOut = WaitInMS * 3 };
remoteInvokeOptions.StartInfo.RedirectStandardOutput = true;
if (OperatingSystem.IsWindows())
{
remoteInvokeOptions.StartInfo.CreateNewProcessGroup = true;
remoteInvokeOptions.CheckExitCode = true;
remoteInvokeOptions.ExpectedExitCode = unchecked((int)0xC000013A); // STATUS_CONTROL_C_EXIT
}

using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(
bool remoteHandleDisposeAttempted = false;
ExceptionDispatchInfo testException = null;
ExceptionDispatchInfo disposeException = null;
RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(
(signalStr) =>
{
PosixSignal expectedSignal = Enum.Parse<PosixSignal>(signalStr);
Expand Down Expand Up @@ -238,7 +249,6 @@ public void SignalHandler_CanDisposeInHandler(PosixSignal signal)
arg: $"{signal}",
remoteInvokeOptions);


try
{
AssertRemoteProcessStandardOutputLine(remoteHandle, PosixSignalRegistrationCreatedMessage, WaitInMS);
Expand All @@ -260,25 +270,46 @@ public void SignalHandler_CanDisposeInHandler(PosixSignal signal)
SendSignal(signal, remoteHandle.Process);
}

Assert.True(remoteHandle.Process.WaitForExit(WaitInMS));
Assert.True(remoteHandle.Process.StandardOutput.EndOfStream);

if (OperatingSystem.IsWindows())
// For Windows, we prefer more feature rich termination and status checking in remoteHandle.Dispose()
// However on other platforms, exit code is platform dependent, so we check manually.
if (!OperatingSystem.IsWindows())
{
Assert.Equal(unchecked((int)0xC000013A), remoteHandle.Process.ExitCode); // STATUS_CONTROL_C_EXIT
}
else
{
// Signal numbers are platform dependent, so we can't check exact exit code
Assert.True(remoteHandle.Process.WaitForExit(WaitInMS));

Assert.NotEqual(0, remoteHandle.Process.ExitCode);
Assert.NotEqual(UnterminatedExitCode, remoteHandle.Process.ExitCode);
Assert.NotEqual(RemoteExecutor.SuccessExitCode, remoteHandle.Process.ExitCode);
Comment thread
mrek-msft marked this conversation as resolved.
}

remoteHandleDisposeAttempted = true;
remoteHandle.Dispose();
}
catch (Exception ex)
{
testException = ExceptionDispatchInfo.Capture(ex);
}
finally
{
// If sending the signal fails or process did not exit on its own, we want to kill the process ASAP
// to prevent RemoteExecutor's timeout from hiding it.
remoteHandle.Process.Kill();
if (!remoteHandleDisposeAttempted)
{
try
{
remoteHandle.Dispose();
}
catch (Exception ex)
{
disposeException = ExceptionDispatchInfo.Capture(ex);
}
}
}
// test exception is more important, exception at dispose could be consequence of it
if (testException is not null)
{
testException.Throw();
}
if (disposeException is not null)
{
disposeException.Throw();
}
}

Expand Down
Loading