Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helix Restore Issue Mitigation #41311

Merged
merged 27 commits into from
Apr 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
021516b
RunTests dotnet run --no-build
TanayParikh Apr 21, 2022
ee6202c
Remove duplicate run
TanayParikh Apr 21, 2022
674d5b9
Add to Build.props
TanayParikh Apr 21, 2022
85c3d69
Treat CA2007 as a warning in RunTests
TanayParikh Apr 21, 2022
133ce0b
NoWarn CA2007
TanayParikh Apr 21, 2022
4a6ba96
Ignore NU5104 for System.CommandLine prerelease package
TanayParikh Apr 21, 2022
69e1468
PR Feedback
TanayParikh Apr 21, 2022
3f97899
PR Feedback
TanayParikh Apr 22, 2022
f5d847e
Generate .config/dotnet-tools.json
dougbu Apr 27, 2022
56bacbe
Add tool packages to Helix correlation payloads
dougbu Apr 27, 2022
95a90e5
Do not restore tools from network
dougbu Apr 27, 2022
0f97390
Do not pass `dotnet-ef` version to `RunTests`
dougbu Apr 27, 2022
9a2900d
Remove DotNetToolsInstaller.csproj
dougbu Apr 27, 2022
787b743
Add `--playwright` option in `Runtests`
dougbu Apr 28, 2022
3664794
Use Arcade SDK in `RunTests` and `Publish` project
dougbu Apr 28, 2022
f550234
Correct minor problems in `RunTests` source
dougbu Apr 28, 2022
ac9b2f8
Use file-scoped namespaces in `RunTests` source
dougbu Apr 28, 2022
d9ef4d8
Use VS code fixes in `RunTests`
dougbu Apr 28, 2022
c12501c
Use published `RunTests` output on Helix agents
dougbu Apr 28, 2022
ddc91e0
Move `RunTests` under eng/tools/
dougbu Apr 28, 2022
9961ccb
Add `RunTests` to tools.slnf
dougbu Apr 28, 2022
5b14ca6
Rename `RunTests` project to `HelixTestRunner`
dougbu Apr 29, 2022
b3e15e0
!fixup! Define `$(ArtifactsBinDir)` in helix.proj
dougbu Apr 29, 2022
a788fd6
!fixup! Use `$(Configuration)` in helix.proj
dougbu Apr 29, 2022
9e45752
!fixup! Fix typo in property function
dougbu Apr 29, 2022
a22be2b
!fixup! Fix `dotnet` syntax in runtests.sh
dougbu Apr 29, 2022
9ffdffb
!fixup! Correct `%(HelixCorrelationPayload.Destination)`
dougbu Apr 30, 2022
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
Prev Previous commit
Next Next commit
Use file-scoped namespaces in RunTests source
  • Loading branch information
dougbu committed Apr 29, 2022
commit ac9b2f8a6cdd148232f5540b7b24973e3041c8fa
23 changes: 11 additions & 12 deletions eng/helix/content/RunTests/ProcessResult.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace RunTests
namespace RunTests;

public class ProcessResult
{
public class ProcessResult
public ProcessResult(string standardOutput, string standardError, int exitCode)
{
public ProcessResult(string standardOutput, string standardError, int exitCode)
{
StandardOutput = standardOutput;
StandardError = standardError;
ExitCode = exitCode;
}

public string StandardOutput { get; }
public string StandardError { get; }
public int ExitCode { get; }
StandardOutput = standardOutput;
StandardError = standardError;
ExitCode = exitCode;
}

public string StandardOutput { get; }
public string StandardError { get; }
public int ExitCode { get; }
}
281 changes: 140 additions & 141 deletions eng/helix/content/RunTests/ProcessUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,199 +12,198 @@

#nullable enable

namespace RunTests
namespace RunTests;

public static class ProcessUtil
{
public static class ProcessUtil
[DllImport("libc", SetLastError = true, EntryPoint = "kill")]
private static extern int sys_kill(int pid, int sig);

public static Task CaptureDumpAsync()
{
[DllImport("libc", SetLastError = true, EntryPoint = "kill")]
private static extern int sys_kill(int pid, int sig);
var dumpDirectoryPath = Environment.GetEnvironmentVariable("HELIX_DUMP_FOLDER");

public static Task CaptureDumpAsync()
if (dumpDirectoryPath == null)
{
var dumpDirectoryPath = Environment.GetEnvironmentVariable("HELIX_DUMP_FOLDER");
return Task.CompletedTask;
}

if (dumpDirectoryPath == null)
{
return Task.CompletedTask;
}
var process = Process.GetCurrentProcess();
var dumpFilePath = Path.Combine(dumpDirectoryPath, $"{process.ProcessName}-{process.Id}.dmp");

var process = Process.GetCurrentProcess();
var dumpFilePath = Path.Combine(dumpDirectoryPath, $"{process.ProcessName}-{process.Id}.dmp");
return CaptureDumpAsync(process.Id, dumpFilePath);
}

return CaptureDumpAsync(process.Id, dumpFilePath);
}
public static Task CaptureDumpAsync(int pid)
{
var dumpDirectoryPath = Environment.GetEnvironmentVariable("HELIX_DUMP_FOLDER");

public static Task CaptureDumpAsync(int pid)
if (dumpDirectoryPath == null)
{
var dumpDirectoryPath = Environment.GetEnvironmentVariable("HELIX_DUMP_FOLDER");
return Task.CompletedTask;
}

if (dumpDirectoryPath == null)
{
return Task.CompletedTask;
}
var process = Process.GetProcessById(pid);
var dumpFilePath = Path.Combine(dumpDirectoryPath, $"{process.ProcessName}.{process.Id}.dmp");

var process = Process.GetProcessById(pid);
var dumpFilePath = Path.Combine(dumpDirectoryPath, $"{process.ProcessName}.{process.Id}.dmp");
return CaptureDumpAsync(process.Id, dumpFilePath);
}

return CaptureDumpAsync(process.Id, dumpFilePath);
public static Task CaptureDumpAsync(int pid, string dumpFilePath)
{
// Skip this on OSX, we know it's unsupported right now
if (OperatingSystem.IsMacOS())
{
// Can we capture stacks or do a gcdump instead?
return Task.CompletedTask;
}

public static Task CaptureDumpAsync(int pid, string dumpFilePath)
if (!File.Exists($"{Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT")}/dotnet-dump") &&
!File.Exists($"{Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT")}/dotnet-dump.exe"))
{
// Skip this on OSX, we know it's unsupported right now
if (OperatingSystem.IsMacOS())
{
// Can we capture stacks or do a gcdump instead?
return Task.CompletedTask;
}

if (!File.Exists($"{Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT")}/dotnet-dump") &&
!File.Exists($"{Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT")}/dotnet-dump.exe"))
{
return Task.CompletedTask;
}

return RunAsync($"{Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT")}/dotnet-dump", $"collect -p {pid} -o \"{dumpFilePath}\"");
return Task.CompletedTask;
}

public static async Task<ProcessResult> RunAsync(
string filename,
string arguments,
string? workingDirectory = null,
string? dumpDirectoryPath = null,
bool throwOnError = true,
IDictionary<string, string?>? environmentVariables = null,
Action<string>? outputDataReceived = null,
Action<string>? errorDataReceived = null,
Action<int>? onStart = null,
CancellationToken cancellationToken = default)
return RunAsync($"{Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT")}/dotnet-dump", $"collect -p {pid} -o \"{dumpFilePath}\"");
}

public static async Task<ProcessResult> RunAsync(
string filename,
string arguments,
string? workingDirectory = null,
string? dumpDirectoryPath = null,
bool throwOnError = true,
IDictionary<string, string?>? environmentVariables = null,
Action<string>? outputDataReceived = null,
Action<string>? errorDataReceived = null,
Action<int>? onStart = null,
CancellationToken cancellationToken = default)
{
Console.WriteLine($"Running '{filename} {arguments}'");
using var process = new Process()
{
Console.WriteLine($"Running '{filename} {arguments}'");
using var process = new Process()
{
StartInfo =
{
FileName = filename,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
},
EnableRaisingEvents = true
};

if (workingDirectory != null)
StartInfo =
{
process.StartInfo.WorkingDirectory = workingDirectory;
}
FileName = filename,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
},
EnableRaisingEvents = true
};

if (workingDirectory != null)
{
process.StartInfo.WorkingDirectory = workingDirectory;
}

dumpDirectoryPath ??= Environment.GetEnvironmentVariable("HELIX_DUMP_FOLDER");
dumpDirectoryPath ??= Environment.GetEnvironmentVariable("HELIX_DUMP_FOLDER");

if (dumpDirectoryPath != null)
{
process.StartInfo.EnvironmentVariables["COMPlus_DbgEnableMiniDump"] = "1";
process.StartInfo.EnvironmentVariables["COMPlus_DbgMiniDumpName"] = Path.Combine(dumpDirectoryPath, $"{Path.GetFileName(filename)}.%d.dmp");
}
if (dumpDirectoryPath != null)
{
process.StartInfo.EnvironmentVariables["COMPlus_DbgEnableMiniDump"] = "1";
process.StartInfo.EnvironmentVariables["COMPlus_DbgMiniDumpName"] = Path.Combine(dumpDirectoryPath, $"{Path.GetFileName(filename)}.%d.dmp");
}

if (environmentVariables != null)
if (environmentVariables != null)
{
foreach (var kvp in environmentVariables)
{
foreach (var kvp in environmentVariables)
{
process.StartInfo.Environment.Add(kvp);
}
process.StartInfo.Environment.Add(kvp);
}
}

var outputBuilder = new StringBuilder();
process.OutputDataReceived += (_, e) =>
var outputBuilder = new StringBuilder();
process.OutputDataReceived += (_, e) =>
{
if (e.Data != null)
{
if (e.Data != null)
if (outputDataReceived != null)
{
if (outputDataReceived != null)
{
outputDataReceived.Invoke(e.Data);
}
else
{
outputBuilder.AppendLine(e.Data);
}
outputDataReceived.Invoke(e.Data);
}
};

var errorBuilder = new StringBuilder();
process.ErrorDataReceived += (_, e) =>
{
if (e.Data != null)
else
{
if (errorDataReceived != null)
{
errorDataReceived.Invoke(e.Data);
}
else
{
errorBuilder.AppendLine(e.Data);
}
outputBuilder.AppendLine(e.Data);
}
};

var processLifetimeTask = new TaskCompletionSource<ProcessResult>();
}
};

process.Exited += (_, e) =>
var errorBuilder = new StringBuilder();
process.ErrorDataReceived += (_, e) =>
{
if (e.Data != null)
{
Console.WriteLine($"'{process.StartInfo.FileName} {process.StartInfo.Arguments}' completed with exit code '{process.ExitCode}'");
if (throwOnError && process.ExitCode != 0)
if (errorDataReceived != null)
{
processLifetimeTask.TrySetException(new InvalidOperationException($"Command {filename} {arguments} returned exit code {process.ExitCode} output: {outputBuilder.ToString()}"));
errorDataReceived.Invoke(e.Data);
}
else
{
processLifetimeTask.TrySetResult(new ProcessResult(outputBuilder.ToString(), errorBuilder.ToString(), process.ExitCode));
errorBuilder.AppendLine(e.Data);
}
};
}
};

process.Start();
onStart?.Invoke(process.Id);
var processLifetimeTask = new TaskCompletionSource<ProcessResult>();

process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.Exited += (_, e) =>
{
Console.WriteLine($"'{process.StartInfo.FileName} {process.StartInfo.Arguments}' completed with exit code '{process.ExitCode}'");
if (throwOnError && process.ExitCode != 0)
{
processLifetimeTask.TrySetException(new InvalidOperationException($"Command {filename} {arguments} returned exit code {process.ExitCode} output: {outputBuilder.ToString()}"));
}
else
{
processLifetimeTask.TrySetResult(new ProcessResult(outputBuilder.ToString(), errorBuilder.ToString(), process.ExitCode));
}
};

var canceledTcs = new TaskCompletionSource<object?>();
await using var _ = cancellationToken.Register(() => canceledTcs.TrySetResult(null));
process.Start();
onStart?.Invoke(process.Id);

var result = await Task.WhenAny(processLifetimeTask.Task, canceledTcs.Task);
process.BeginOutputReadLine();
process.BeginErrorReadLine();

if (result == canceledTcs.Task)
var canceledTcs = new TaskCompletionSource<object?>();
await using var _ = cancellationToken.Register(() => canceledTcs.TrySetResult(null));

var result = await Task.WhenAny(processLifetimeTask.Task, canceledTcs.Task);

if (result == canceledTcs.Task)
{
if (dumpDirectoryPath != null)
{
if (dumpDirectoryPath != null)
{
var dumpFilePath = Path.Combine(dumpDirectoryPath, $"{Path.GetFileName(filename)}.{process.Id}.dmp");
// Capture a process dump if the dumpDirectory is set
await CaptureDumpAsync(process.Id, dumpFilePath);
}
var dumpFilePath = Path.Combine(dumpDirectoryPath, $"{Path.GetFileName(filename)}.{process.Id}.dmp");
// Capture a process dump if the dumpDirectory is set
await CaptureDumpAsync(process.Id, dumpFilePath);
}

if (!OperatingSystem.IsWindows())
{
sys_kill(process.Id, sig: 2); // SIGINT
if (!OperatingSystem.IsWindows())
{
sys_kill(process.Id, sig: 2); // SIGINT

var cancel = new CancellationTokenSource();
var cancel = new CancellationTokenSource();

await Task.WhenAny(processLifetimeTask.Task, Task.Delay(TimeSpan.FromSeconds(5), cancel.Token));
await Task.WhenAny(processLifetimeTask.Task, Task.Delay(TimeSpan.FromSeconds(5), cancel.Token));

cancel.Cancel();
}
cancel.Cancel();
}

if (!process.HasExited)
{
process.CloseMainWindow();

if (!process.HasExited)
{
process.CloseMainWindow();

if (!process.HasExited)
{
process.Kill();
}
process.Kill();
}
}

return await processLifetimeTask.Task;
}

return await processLifetimeTask.Task;
}
}
Loading