Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'test/ILLink.Tasks.IntegrationTests/CommandRunner.cs')
-rw-r--r--test/ILLink.Tasks.IntegrationTests/CommandRunner.cs191
1 files changed, 191 insertions, 0 deletions
diff --git a/test/ILLink.Tasks.IntegrationTests/CommandRunner.cs b/test/ILLink.Tasks.IntegrationTests/CommandRunner.cs
new file mode 100644
index 000000000..bc790c09a
--- /dev/null
+++ b/test/ILLink.Tasks.IntegrationTests/CommandRunner.cs
@@ -0,0 +1,191 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace ILLink.Tests
+{
+
+ public class CommandHelper
+ {
+ private ILogger logger;
+
+ public CommandHelper(ILogger logger)
+ {
+ this.logger = logger;
+ }
+
+ public int Dotnet(string args, string workingDir, string additionalPath = null)
+ {
+ return RunCommand(Path.GetFullPath(TestContext.DotnetToolPath), args,
+ workingDir, additionalPath, out string commandOutput);
+ }
+
+ public int RunCommand(string command, string args, int timeout = Int32.MaxValue)
+ {
+ return RunCommand(command, args, null, null, out string commandOutput, timeout);
+ }
+
+ public int RunCommand(string command, string args, string workingDir)
+ {
+ return RunCommand(command, args, workingDir, null, out string commandOutput);
+ }
+
+ public int RunCommand(string command, string args, string workingDir, string additionalPath,
+ out string commandOutput, int timeout = Int32.MaxValue, string terminatingOutput = null)
+ {
+ return (new CommandRunner(command, logger))
+ .WithArguments(args)
+ .WithWorkingDir(workingDir)
+ .WithAdditionalPath(additionalPath)
+ .WithTimeout(timeout)
+ .WithTerminatingOutput(terminatingOutput)
+ .Run(out commandOutput);
+ }
+ }
+
+ public class CommandRunner
+ {
+ private readonly ILogger logger;
+
+ private string command;
+ private string args;
+ private string workingDir;
+ private string additionalPath;
+ private int timeout = Int32.MaxValue;
+ private string terminatingOutput;
+
+ private void LogMessage (string message)
+ {
+ logger.LogMessage (message);
+ }
+
+ public CommandRunner(string command, ILogger logger) {
+ this.command = command;
+ this.logger = logger;
+ }
+
+ public CommandRunner WithArguments(string args) {
+ this.args = args;
+ return this;
+ }
+
+ public CommandRunner WithWorkingDir(string workingDir) {
+ this.workingDir = workingDir;
+ return this;
+ }
+
+ public CommandRunner WithAdditionalPath(string additionalPath) {
+ this.additionalPath = additionalPath;
+ return this;
+ }
+
+ public CommandRunner WithTimeout(int timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ public CommandRunner WithTerminatingOutput(string terminatingOutput) {
+ this.terminatingOutput = terminatingOutput;
+ return this;
+ }
+
+ public int Run()
+ {
+ return Run(out string commandOutputUnused);
+ }
+
+ public int Run(out string commandOutput)
+ {
+ if (String.IsNullOrEmpty(command)) {
+ throw new Exception("No command was specified specified.");
+ }
+ if (logger == null) {
+ throw new Exception("No logger present.");
+ }
+ var psi = new ProcessStartInfo
+ {
+ FileName = command,
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ };
+ LogMessage ($"caller working directory: {Environment.CurrentDirectory}");
+ if (!String.IsNullOrEmpty(args)) {
+ psi.Arguments = args;
+ LogMessage ($"{command} {args}");
+ } else {
+ LogMessage ($"{command}");
+ }
+ if (!String.IsNullOrEmpty(workingDir)) {
+ LogMessage ($"working directory: {workingDir}");
+ psi.WorkingDirectory = workingDir;
+ }
+ if (!String.IsNullOrEmpty(additionalPath)) {
+ string path = psi.Environment["PATH"];
+ psi.Environment["PATH"] = path + ";" + additionalPath;
+ }
+ var process = new Process();
+ process.StartInfo = psi;
+
+ // dotnet sets some environment variables that
+ // may cause problems in the child process.
+ psi.Environment.Remove("MSBuildExtensionsPath");
+ psi.Environment.Remove("MSBuildLoadMicrosoftTargetsReadOnly");
+ psi.Environment.Remove("MSBuildSDKsPath");
+ psi.Environment.Remove("VbcToolExe");
+ psi.Environment.Remove("CscToolExe");
+ psi.Environment.Remove("MSBUILD_EXE_PATH");
+
+ LogMessage ("environment:");
+ foreach (var item in psi.Environment) {
+ LogMessage ($"\t{item.Key}={item.Value}");
+ }
+
+ StringBuilder processOutput = new StringBuilder();
+ DataReceivedEventHandler handler = (sender, e) => {
+ processOutput.Append(e.Data);
+ processOutput.AppendLine();
+ };
+ StringBuilder processError = new StringBuilder();
+ DataReceivedEventHandler ehandler = (sender, e) => {
+ processError.Append(e.Data);
+ processError.AppendLine();
+ };
+ process.OutputDataReceived += handler;
+ process.ErrorDataReceived += ehandler;
+
+ // terminate process if output contains specified string
+ if (!String.IsNullOrEmpty(terminatingOutput)) {
+ DataReceivedEventHandler terminatingOutputHandler = (sender, e) => {
+ if (!String.IsNullOrEmpty(e.Data) && e.Data.Contains(terminatingOutput)) {
+ process.Kill();
+ }
+ };
+ process.OutputDataReceived += terminatingOutputHandler;
+ }
+
+ // start the process
+ process.Start();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ if (!process.WaitForExit(timeout)) {
+ LogMessage ($"killing process after {timeout} ms");
+ process.Kill();
+ }
+ // WaitForExit with timeout doesn't guarantee
+ // that the async output handlers have been
+ // called, so WaitForExit needs to be called
+ // afterwards.
+ process.WaitForExit();
+ string processOutputStr = processOutput.ToString();
+ string processErrorStr = processError.ToString();
+ LogMessage(processOutputStr);
+ LogMessage(processErrorStr);
+ commandOutput = processOutputStr;
+ return process.ExitCode;
+ }
+ }
+}