Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit b5aa230

Browse files
committed
Merge pull request #2633 from stephentoub/process_wait_tests
Add tests for Process.WaitForExit
2 parents aa15229 + 525cb9c commit b5aa230

File tree

5 files changed

+132
-3
lines changed

5 files changed

+132
-3
lines changed

src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private void CloseCore()
6262
/// <summary>
6363
/// Instructs the Process component to wait the specified number of milliseconds for the associated process to exit.
6464
/// </summary>
65-
public bool WaitForExitCore(int milliseconds)
65+
private bool WaitForExitCore(int milliseconds)
6666
{
6767
bool exited = GetWaitState().WaitForExit(milliseconds);
6868
Debug.Assert(exited || milliseconds != Timeout.Infinite);

src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitState.Unix.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,4 +512,4 @@ internal bool WaitForExit(int millisecondsTimeout)
512512
}
513513

514514
}
515-
}
515+
}

src/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests/ProcessTestBase.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ protected Process CreateProcessInfinite()
3131
protected Process CreateProcess(string optionalArgument = ""/*String.Empty is not a constant*/)
3232
{
3333
Process p = new Process();
34-
_processes.Add(p);
34+
lock (_processes)
35+
{
36+
_processes.Add(p);
37+
}
3538

3639
p.StartInfo.FileName = CoreRunName;
3740
p.StartInfo.Arguments = string.IsNullOrWhiteSpace(optionalArgument) ?
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
8+
namespace System.Diagnostics.ProcessTests
9+
{
10+
public class ProcessWaitingTests : ProcessTestBase
11+
{
12+
[Fact]
13+
public void MultipleProcesses_StartAllKillAllWaitAll()
14+
{
15+
const int Iters = 50;
16+
Process[] processes = Enumerable.Range(0, Iters).Select(_ => CreateProcessInfinite()).ToArray();
17+
18+
foreach (Process p in processes) p.Start();
19+
foreach (Process p in processes) p.Kill();
20+
foreach (Process p in processes) Assert.True(p.WaitForExit(WaitInMS));
21+
}
22+
23+
[Fact]
24+
public void MultipleProcesses_SerialStartKillWait()
25+
{
26+
const int Iters = 50;
27+
for (int i = 0; i < Iters; i++)
28+
{
29+
Process p = CreateProcessInfinite();
30+
p.Start();
31+
p.Kill();
32+
p.WaitForExit(WaitInMS);
33+
}
34+
}
35+
36+
[Fact]
37+
public void MultipleProcesses_ParallelStartKillWait()
38+
{
39+
const int Tasks = 4, ItersPerTask = 50;
40+
Action work = () =>
41+
{
42+
for (int i = 0; i < ItersPerTask; i++)
43+
{
44+
Process p = CreateProcessInfinite();
45+
p.Start();
46+
p.Kill();
47+
p.WaitForExit(WaitInMS);
48+
}
49+
};
50+
Task.WaitAll(Enumerable.Range(0, Tasks).Select(_ => Task.Run(work)).ToArray());
51+
}
52+
53+
[Theory]
54+
[InlineData(0)] // poll
55+
[InlineData(10)] // real timeout
56+
public void CurrentProcess_WaitNeverCompletes(int milliseconds)
57+
{
58+
Assert.False(Process.GetCurrentProcess().WaitForExit(milliseconds));
59+
}
60+
61+
[Fact]
62+
public void SingleProcess_TryWaitMultipleTimesBeforeCompleting()
63+
{
64+
Process p = CreateProcessInfinite();
65+
p.Start();
66+
67+
// Verify we can try to wait for the process to exit multiple times
68+
Assert.False(p.WaitForExit(0));
69+
Assert.False(p.WaitForExit(0));
70+
71+
// Then wait until it exits and concurrently kill it.
72+
// There's a race condition here, in that we really want to test
73+
// killing it while we're waiting, but we could end up killing it
74+
// before hand, in which case we're simply not testing exactly
75+
// what we wanted to test, but everything should still work.
76+
Task.Delay(10).ContinueWith(_ => p.Kill());
77+
Assert.True(p.WaitForExit(WaitInMS));
78+
Assert.True(p.WaitForExit(0));
79+
}
80+
81+
[Theory]
82+
[InlineData(false)]
83+
[InlineData(true)]
84+
public async Task SingleProcess_WaitAfterExited(bool addHandlerBeforeStart)
85+
{
86+
Process p = CreateProcessInfinite();
87+
p.EnableRaisingEvents = true;
88+
89+
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
90+
if (addHandlerBeforeStart)
91+
{
92+
p.Exited += delegate { tcs.SetResult(true); };
93+
}
94+
p.Start();
95+
if (!addHandlerBeforeStart)
96+
{
97+
p.Exited += delegate { tcs.SetResult(true); };
98+
}
99+
100+
p.Kill();
101+
await tcs.Task;
102+
103+
Assert.True(p.WaitForExit(0));
104+
}
105+
106+
[Fact]
107+
public void SingleProcess_CopiesShareExitInformation()
108+
{
109+
Process p = CreateProcessInfinite();
110+
p.Start();
111+
112+
Process[] copies = Enumerable.Range(0, 3).Select(_ => Process.GetProcessById(p.Id)).ToArray();
113+
114+
Assert.False(p.WaitForExit(0));
115+
p.Kill();
116+
Assert.True(p.WaitForExit(WaitInMS));
117+
118+
foreach (Process copy in copies)
119+
{
120+
Assert.True(copy.WaitForExit(0));
121+
}
122+
}
123+
124+
}
125+
}

src/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests/System.Diagnostics.Process.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<Compile Include="ProcessModuleTests.cs" />
2626
<Compile Include="ProcessStartInfoTests.cs" />
2727
<Compile Include="Interop.cs" />
28+
<Compile Include="ProcessWaitingTests.cs" />
2829
<Compile Include="ProcessTests.cs" />
2930
<Compile Include="ProcessStandardConsoleTests.cs" />
3031
<Compile Include="ProcessStreamReadTests.cs" />

0 commit comments

Comments
 (0)