Skip to content

Commit

Permalink
Add ProcessExtension to KillTree
Browse files Browse the repository at this point in the history
  • Loading branch information
ricaun committed Oct 1, 2024
1 parent a0e50f9 commit c38a26e
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add `EnvironmentSettings` to overwrite settings in the `TestAdapter`.
- Update `JsonService` implementation to use `Newtonsoft.Json` in the domain.
- Support `Cancel` to abort and `Kill` processes.
- Add `ProcessExtension` to `KillTree` for net framework.
### Tests
- Add `TestsRevitUI` to validate fake `RevitAPIUI` reference.

Expand Down
Binary file not shown.
138 changes: 138 additions & 0 deletions ricaun.RevitTest.TestAdapter/Extensions/ProcessExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#if NETFRAMEWORK
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace ricaun.RevitTest.TestAdapter.Extensions
{
internal static class ProcessExtension
{
/// <summary>
/// Kill
/// </summary>
/// <param name="process"></param>
/// <param name="entireProcessTree"></param>
public static void Kill(this Process process, bool entireProcessTree)
{
if (process is null) return;

if (!entireProcessTree)
{
process.Kill();
return;
}

process.KillTree();
}

#region KillTree
private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(30);

/// <summary>
/// KillTree
/// </summary>
/// <param name="process"></param>
/// <remarks>
/// https://github.com/dotnet/cli/blob/master/test/Microsoft.DotNet.Tools.Tests.Utilities/Extensions/ProcessExtensions.cs
/// </remarks>
internal static void KillTree(this Process process)
{
process.KillTree(_defaultTimeout);
}

private static void KillTree(this Process process, TimeSpan timeout)
{
string stdout;
if (_isWindows)
{
RunProcessAndWaitForExit(
"taskkill",
$"/T /F /PID {process.Id}",
timeout,
out stdout);
}
else
{
var children = new HashSet<int>();
GetAllChildIdsUnix(process.Id, children, timeout);
foreach (var childId in children)
{
KillProcessUnix(childId, timeout);
}
KillProcessUnix(process.Id, timeout);
}
}

private static void GetAllChildIdsUnix(int parentId, ISet<int> children, TimeSpan timeout)
{
string stdout;
var exitCode = RunProcessAndWaitForExit(
"pgrep",
$"-P {parentId}",
timeout,
out stdout);

if (exitCode == 0 && !string.IsNullOrEmpty(stdout))
{
using (var reader = new StringReader(stdout))
{
while (true)
{
var text = reader.ReadLine();
if (text == null)
{
return;
}

int id;
if (int.TryParse(text, out id))
{
children.Add(id);
// Recursively get the children
GetAllChildIdsUnix(id, children, timeout);
}
}
}
}
}

private static void KillProcessUnix(int processId, TimeSpan timeout)
{
string stdout;
RunProcessAndWaitForExit(
"kill",
$"-TERM {processId}",
timeout,
out stdout);
}

private static int RunProcessAndWaitForExit(string fileName, string arguments, TimeSpan timeout, out string stdout)
{
var startInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
RedirectStandardOutput = true,
UseShellExecute = false
};

var process = Process.Start(startInfo);

stdout = null;
if (process.WaitForExit((int)timeout.TotalMilliseconds))
{
stdout = process.StandardOutput.ReadToEnd();
}
else
{
process.Kill();
}

return process.ExitCode;
}
#endregion
}
}
#endif
Binary file not shown.
Binary file not shown.
5 changes: 1 addition & 4 deletions ricaun.RevitTest.TestAdapter/TestExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using ricaun.NUnit.Models;
using ricaun.RevitTest.TestAdapter.Extensions;
using ricaun.RevitTest.TestAdapter.Metadatas;
using ricaun.RevitTest.TestAdapter.Services;
using System;
Expand Down Expand Up @@ -91,11 +92,7 @@ public void Cancel()
{
foreach (var process in ricaun.RevitTest.Command.Process.ProcessStart.GetProcesses())
{
#if NET
process.Kill(true);
#else
process.Kill();
#endif
}
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,5 @@
<ItemGroup>
<None Include="Resources\icon.png" />
</ItemGroup>

</Project>

0 comments on commit c38a26e

Please sign in to comment.