From 6470ed6c2c04797f393ab0537d16df0b244e9073 Mon Sep 17 00:00:00 2001 From: Roman Marusyk Date: Thu, 24 Oct 2019 03:32:12 +0200 Subject: [PATCH] Recombine files ProcessTests.cs and ProcessTests.netcoreapp.cs (dotnet/corefx#42063) * Recombine files ProcessTests.cs and ProcessTests.netcoreapp.cs that aren't supported anymore * Add namespaces Commit migrated from https://github.com/dotnet/corefx/commit/bd18c12df9e5dd365a8b708cc2e7e0488b8177c1 --- .../tests/ProcessTests.cs | 350 ++++++++++++++++++++ .../tests/ProcessTests.netcoreapp.cs | 367 --------------------- .../tests/System.Diagnostics.Process.Tests.csproj | 1 - 3 files changed, 350 insertions(+), 368 deletions(-) delete mode 100644 src/libraries/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 86653fe..6515153 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -6,12 +6,14 @@ using System.Collections.Generic; using System.ComponentModel; using System.DirectoryServices.ActiveDirectory; using System.IO; +using System.IO.Pipes; using System.Linq; using System.Net; using System.Runtime.InteropServices; using System.Security; using System.Text; using System.Threading; +using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; using Microsoft.Win32.SafeHandles; using Xunit; @@ -1868,6 +1870,354 @@ namespace System.Diagnostics.Tests } } + [Fact] + public void Start_HasStandardInputEncodingNonRedirected_ThrowsInvalidOperationException() + { + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "FileName", + RedirectStandardInput = false, + StandardInputEncoding = Encoding.UTF8 + } + }; + + Assert.Throws(() => process.Start()); + } + + [Fact] + public void Start_StandardInputEncodingPropagatesToStreamWriter() + { + var process = CreateProcessPortable(RemotelyInvokable.Dummy); + process.StartInfo.RedirectStandardInput = true; + var encoding = new UTF32Encoding(bigEndian: false, byteOrderMark: true); + process.StartInfo.StandardInputEncoding = encoding; + process.Start(); + + Assert.Same(encoding, process.StandardInput.Encoding); + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void StartProcessWithArgumentList() + { + ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName()); + psi.ArgumentList.Add("arg1"); + psi.ArgumentList.Add("arg2"); + + Process testProcess = CreateProcess(); + testProcess.StartInfo = psi; + + try + { + testProcess.Start(); + Assert.Equal(string.Empty, testProcess.StartInfo.Arguments); + } + finally + { + testProcess.Kill(); + + Assert.True(testProcess.WaitForExit(WaitInMS)); + } + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void StartProcessWithSameArgumentList() + { + ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName()); + psi.ArgumentList.Add("arg1"); + psi.ArgumentList.Add("arg2"); + + Process testProcess = CreateProcess(); + Process secondTestProcess = CreateProcess(); + testProcess.StartInfo = psi; + try + { + testProcess.Start(); + Assert.Equal(string.Empty, testProcess.StartInfo.Arguments); + secondTestProcess.StartInfo = psi; + secondTestProcess.Start(); + Assert.Equal(string.Empty, secondTestProcess.StartInfo.Arguments); + } + finally + { + testProcess.Kill(); + + Assert.True(testProcess.WaitForExit(WaitInMS)); + + secondTestProcess.Kill(); + + Assert.True(testProcess.WaitForExit(WaitInMS)); + } + } + + [Fact] + public void BothArgumentCtorAndArgumentListSet() + { + ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName(), "arg3"); + psi.ArgumentList.Add("arg1"); + psi.ArgumentList.Add("arg2"); + + Process testProcess = CreateProcess(); + testProcess.StartInfo = psi; + Assert.Throws(() => testProcess.Start()); + } + + [Fact] + public void BothArgumentSetAndArgumentListSet() + { + ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName()); + psi.Arguments = "arg3"; + psi.ArgumentList.Add("arg1"); + psi.ArgumentList.Add("arg2"); + + Process testProcess = CreateProcess(); + testProcess.StartInfo = psi; + Assert.Throws(() => testProcess.Start()); + } + + [Fact] + public void Kill_EntireProcessTree_True_ProcessNotStarted_ThrowsInvalidOperationException() + { + var process = new Process(); + Assert.Throws(() => process.Kill(entireProcessTree: true)); + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] // Currently, remote processes are only supported on Windows. If that changes, adjust accordingly. + public void Kill_EntireProcessTree_True_CalledByNonLocalProcess_ThrowsInvalidOperationException() + { + Process currentProcess = Process.GetCurrentProcess(); + Process process; + + try + { + process = Process.GetProcessById(currentProcess.Id, "127.0.0.1"); + } + catch (InvalidOperationException) + { + // As we can't detect reliably if performance counters are enabled, + // we silently abort on InvalidOperationExceptions since this test + // can only run if the attempt to get the process succeeded. + return; + } + + Assert.Throws(() => process.Kill(entireProcessTree: true)); + } + + [Fact] + public void Kill_EntireProcessTree_True_CalledOnCallingProcess_ThrowsInvalidOperationException() + { + var process = Process.GetCurrentProcess(); + Assert.Throws(() => process.Kill(entireProcessTree: true)); + } + + [Fact] + public void Kill_EntireProcessTree_True_CalledOnTreeContainingCallingProcess_ThrowsInvalidOperationException() + { + Process containingProcess = CreateProcess(() => + { + Process parentProcess = CreateProcess(() => RunProcessAttemptingToKillEntireTreeOnParent()); + + parentProcess.Start(); + parentProcess.WaitForExit(); + + return parentProcess.ExitCode; + + }); + + containingProcess.Start(); + containingProcess.WaitForExit(); + + if (containingProcess.ExitCode != 10) + Assert.True(false, "attempt to terminate a process tree containing the calling process did not throw the expected exception"); + + int RunProcessAttemptingToKillEntireTreeOnParent() + { + Process process = CreateProcess(parentProcessIdString => + { + Process parentProcess = Process.GetProcessById(int.Parse(parentProcessIdString)); + + bool caught = false; + try + { + parentProcess.Kill(entireProcessTree: true); + } + catch (InvalidOperationException) + { + caught = true; + } + return caught ? 10 : 20; + }, Process.GetCurrentProcess().Id.ToString()); + + process.Start(); + process.WaitForExit(); + return process.ExitCode; + } + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Kill_ExitedChildProcess_DoesNotThrow(bool killTree) + { + Process process = CreateProcess(); + process.Start(); + + process.WaitForExit(); + + process.Kill(killTree); + } + + [Fact] + public async Task Kill_EntireProcessTree_False_OnlyRootProcessTerminated() + { + IReadOnlyList tree = CreateProcessTree(); + + try + { + Process parentProcess = tree.First(); + + parentProcess.Kill(entireProcessTree: false); + + await Helpers.RetryWithBackoff(() => + { + var actual = tree.Select(p => p.HasExited).ToList(); + Assert.Equal(new[] { true, false, false }, actual); + }); + } + finally + { + foreach (Process process in tree) + { + try + { + process.Kill(); + } + catch + { + // Test cleanup code, so ignore any exceptions. + } + } + } + } + + [Fact] + public async Task Kill_EntireProcessTree_True_EntireTreeTerminated() + { + IReadOnlyList tree = CreateProcessTree(); + + try + { + Process parentProcess = tree.First(); + + parentProcess.Kill(entireProcessTree: true); + + await Helpers.RetryWithBackoff(() => + { + var actual = tree.Select(p => p.HasExited).ToList(); + Assert.Equal(new[] { true, true, true }, actual); + }); + } + finally + { + foreach (Process process in tree) + { + try + { + process.Kill(); + } + catch + { + // Test cleanup code, so ignore any exceptions. + } + } + } + } + + private IReadOnlyList CreateProcessTree() + { + (Process Value, string Message) rootResult = ListenForAnonymousPipeMessage(rootPipeHandleString => + { + Process root = CreateProcess(rhs => + { + (Process Value, string Message) child1Result = ListenForAnonymousPipeMessage(child1PipeHandleString => + { + Process child1 = CreateProcess(c1hs => + { + Process child2 = CreateProcess(() => WaitForever()); + child2.Start(); + + SendMessage(child2.Id.ToString(), c1hs); + + return WaitForever(); + }, child1PipeHandleString, autoDispose: false); + + child1.Start(); + + return child1; + }); + + var child1ProcessId = child1Result.Value.Id; + var child2ProcessId = child1Result.Message; + SendMessage($"{child1ProcessId};{child2ProcessId}", rhs); + + return WaitForever(); + }, rootPipeHandleString, autoDispose: false); + + root.Start(); + + return root; + }); + + IEnumerable childProcesses = rootResult.Message + .Split(';') + .Select(x => int.Parse(x)) + .Select(pid => Process.GetProcessById(pid)); + + return new[] { rootResult.Value } + .Concat(childProcesses) + .ToList(); + + int WaitForever() + { + Thread.Sleep(Timeout.Infinite); + + // never reaches here -- but necessary to satisfy method's signature + return RemoteExecutor.SuccessExitCode; + } + + void SendMessage(string message, string handleAsString) + { + using (var client = new AnonymousPipeClientStream(PipeDirection.Out, handleAsString)) + { + using (var sw = new StreamWriter(client)) + { + sw.WriteLine(message); + } + } + } + + (T Value, string Message) ListenForAnonymousPipeMessage(Func action) + { + using (var pipeServer = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable)) + { + string handleAsString = pipeServer.GetClientHandleAsString(); + + T result = action(handleAsString); + + pipeServer.DisposeLocalCopyOfClientHandle(); + + using (var sr = new StreamReader(pipeServer)) + { + return (result, sr.ReadLine()); + } + } + } + } + private string GetCurrentProcessName() { return $"{Process.GetCurrentProcess().ProcessName}.exe"; diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs deleted file mode 100644 index bdd4449..0000000 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs +++ /dev/null @@ -1,367 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.IO; -using System.IO.Pipes; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.DotNet.RemoteExecutor; -using Xunit; - -namespace System.Diagnostics.Tests -{ - public partial class ProcessTests : ProcessTestBase - { - [Fact] - public void Start_HasStandardInputEncodingNonRedirected_ThrowsInvalidOperationException() - { - var process = new Process - { - StartInfo = new ProcessStartInfo - { - FileName = "FileName", - RedirectStandardInput = false, - StandardInputEncoding = Encoding.UTF8 - } - }; - - Assert.Throws(() => process.Start()); - } - - [Fact] - public void Start_StandardInputEncodingPropagatesToStreamWriter() - { - var process = CreateProcessPortable(RemotelyInvokable.Dummy); - process.StartInfo.RedirectStandardInput = true; - var encoding = new UTF32Encoding(bigEndian: false, byteOrderMark: true); - process.StartInfo.StandardInputEncoding = encoding; - process.Start(); - - Assert.Same(encoding, process.StandardInput.Encoding); - } - - [Fact] - [PlatformSpecific(TestPlatforms.Windows)] - public void StartProcessWithArgumentList() - { - ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName()); - psi.ArgumentList.Add("arg1"); - psi.ArgumentList.Add("arg2"); - - Process testProcess = CreateProcess(); - testProcess.StartInfo = psi; - - try - { - testProcess.Start(); - Assert.Equal(string.Empty, testProcess.StartInfo.Arguments); - } - finally - { - testProcess.Kill(); - - Assert.True(testProcess.WaitForExit(WaitInMS)); - } - } - - [Fact] - [PlatformSpecific(TestPlatforms.Windows)] - public void StartProcessWithSameArgumentList() - { - ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName()); - psi.ArgumentList.Add("arg1"); - psi.ArgumentList.Add("arg2"); - - Process testProcess = CreateProcess(); - Process secondTestProcess = CreateProcess(); - testProcess.StartInfo = psi; - try - { - testProcess.Start(); - Assert.Equal(string.Empty, testProcess.StartInfo.Arguments); - secondTestProcess.StartInfo = psi; - secondTestProcess.Start(); - Assert.Equal(string.Empty, secondTestProcess.StartInfo.Arguments); - } - finally - { - testProcess.Kill(); - - Assert.True(testProcess.WaitForExit(WaitInMS)); - - secondTestProcess.Kill(); - - Assert.True(testProcess.WaitForExit(WaitInMS)); - } - } - - [Fact] - public void BothArgumentCtorAndArgumentListSet() - { - ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName(), "arg3"); - psi.ArgumentList.Add("arg1"); - psi.ArgumentList.Add("arg2"); - - Process testProcess = CreateProcess(); - testProcess.StartInfo = psi; - Assert.Throws(() => testProcess.Start()); - } - - [Fact] - public void BothArgumentSetAndArgumentListSet() - { - ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName()); - psi.Arguments = "arg3"; - psi.ArgumentList.Add("arg1"); - psi.ArgumentList.Add("arg2"); - - Process testProcess = CreateProcess(); - testProcess.StartInfo = psi; - Assert.Throws(() => testProcess.Start()); - } - - [Fact] - public void Kill_EntireProcessTree_True_ProcessNotStarted_ThrowsInvalidOperationException() - { - var process = new Process(); - Assert.Throws(() => process.Kill(entireProcessTree: true)); - } - - [Fact] - [PlatformSpecific(TestPlatforms.Windows)] // Currently, remote processes are only supported on Windows. If that changes, adjust accordingly. - public void Kill_EntireProcessTree_True_CalledByNonLocalProcess_ThrowsInvalidOperationException() - { - Process currentProcess = Process.GetCurrentProcess(); - Process process; - - try - { - process = Process.GetProcessById(currentProcess.Id, "127.0.0.1"); - } - catch (InvalidOperationException) - { - // As we can't detect reliably if performance counters are enabled, - // we silently abort on InvalidOperationExceptions since this test - // can only run if the attempt to get the process succeeded. - return; - } - - Assert.Throws(() => process.Kill(entireProcessTree: true)); - } - - [Fact] - public void Kill_EntireProcessTree_True_CalledOnCallingProcess_ThrowsInvalidOperationException() - { - var process = Process.GetCurrentProcess(); - Assert.Throws(() => process.Kill(entireProcessTree: true)); - } - - [Fact] - public void Kill_EntireProcessTree_True_CalledOnTreeContainingCallingProcess_ThrowsInvalidOperationException() - { - Process containingProcess = CreateProcess(() => - { - Process parentProcess = CreateProcess(() => RunProcessAttemptingToKillEntireTreeOnParent()); - - parentProcess.Start(); - parentProcess.WaitForExit(); - - return parentProcess.ExitCode; - - }); - - containingProcess.Start(); - containingProcess.WaitForExit(); - - if (containingProcess.ExitCode != 10) - Assert.True(false, "attempt to terminate a process tree containing the calling process did not throw the expected exception"); - - int RunProcessAttemptingToKillEntireTreeOnParent() - { - Process process = CreateProcess(parentProcessIdString => - { - Process parentProcess = Process.GetProcessById(int.Parse(parentProcessIdString)); - - bool caught = false; - try - { - parentProcess.Kill(entireProcessTree: true); - } - catch (InvalidOperationException) - { - caught = true; - } - return caught ? 10 : 20; - }, Process.GetCurrentProcess().Id.ToString()); - - process.Start(); - process.WaitForExit(); - return process.ExitCode; - } - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void Kill_ExitedChildProcess_DoesNotThrow(bool killTree) - { - Process process = CreateProcess(); - process.Start(); - - process.WaitForExit(); - - process.Kill(killTree); - } - - [Fact] - public async Task Kill_EntireProcessTree_False_OnlyRootProcessTerminated() - { - IReadOnlyList tree = CreateProcessTree(); - - try - { - Process parentProcess = tree.First(); - - parentProcess.Kill(entireProcessTree: false); - - await Helpers.RetryWithBackoff(() => - { - var actual = tree.Select(p => p.HasExited).ToList(); - Assert.Equal(new[] { true, false, false }, actual); - }); - } - finally - { - foreach (Process process in tree) - { - try - { - process.Kill(); - } - catch - { - // Test cleanup code, so ignore any exceptions. - } - } - } - } - - [Fact] - public async Task Kill_EntireProcessTree_True_EntireTreeTerminated() - { - IReadOnlyList tree = CreateProcessTree(); - - try - { - Process parentProcess = tree.First(); - - parentProcess.Kill(entireProcessTree: true); - - await Helpers.RetryWithBackoff(() => - { - var actual = tree.Select(p => p.HasExited).ToList(); - Assert.Equal(new[] { true, true, true }, actual); - }); - } - finally - { - foreach (Process process in tree) - { - try - { - process.Kill(); - } - catch - { - // Test cleanup code, so ignore any exceptions. - } - } - } - } - - private IReadOnlyList CreateProcessTree() - { - (Process Value, string Message) rootResult = ListenForAnonymousPipeMessage(rootPipeHandleString => - { - Process root = CreateProcess(rhs => - { - (Process Value, string Message) child1Result = ListenForAnonymousPipeMessage(child1PipeHandleString => - { - Process child1 = CreateProcess(c1hs => - { - Process child2 = CreateProcess(() => WaitForever()); - child2.Start(); - - SendMessage(child2.Id.ToString(), c1hs); - - return WaitForever(); - }, child1PipeHandleString, autoDispose: false); - - child1.Start(); - - return child1; - }); - - var child1ProcessId = child1Result.Value.Id; - var child2ProcessId = child1Result.Message; - SendMessage($"{child1ProcessId};{child2ProcessId}", rhs); - - return WaitForever(); - }, rootPipeHandleString, autoDispose: false); - - root.Start(); - - return root; - }); - - IEnumerable childProcesses = rootResult.Message - .Split(';') - .Select(x => int.Parse(x)) - .Select(pid => Process.GetProcessById(pid)); - - return new[] { rootResult.Value } - .Concat(childProcesses) - .ToList(); - - int WaitForever() - { - Thread.Sleep(Timeout.Infinite); - - // never reaches here -- but necessary to satisfy method's signature - return RemoteExecutor.SuccessExitCode; - } - - void SendMessage(string message, string handleAsString) - { - using (var client = new AnonymousPipeClientStream(PipeDirection.Out, handleAsString)) - { - using (var sw = new StreamWriter(client)) - { - sw.WriteLine(message); - } - } - } - - (T Value, string Message) ListenForAnonymousPipeMessage(Func action) - { - using (var pipeServer = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable)) - { - string handleAsString = pipeServer.GetClientHandleAsString(); - - T result = action(handleAsString); - - pipeServer.DisposeLocalCopyOfClientHandle(); - - using (var sr = new StreamReader(pipeServer)) - { - return (result, sr.ReadLine()); - } - } - } - } - } -} diff --git a/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj b/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj index 2cbd7b3..ab30362 100644 --- a/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj +++ b/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj @@ -35,7 +35,6 @@ - -- 2.7.4