From 6209719f51535c593ee1ac6fe21a1a032cc9461b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emek=20Vysok=C3=BD?= Date: Fri, 27 Mar 2020 17:41:31 +0100 Subject: [PATCH] [Harness] Remove Harness as a dependency (#8203) --- tests/xharness/AppRunner.cs | 20 +- tests/xharness/Collections/ILoadAsync.cs | 1 - tests/xharness/CrashSnapshotReporter.cs | 31 +-- tests/xharness/DeviceLogCapturer.cs | 22 +- tests/xharness/Execution/IProcessManager.cs | 10 +- tests/xharness/Execution/ProcessManager.cs | 222 ++++++++-------- tests/xharness/GitHub.cs | 11 +- tests/xharness/Hardware/Devices.cs | 21 +- tests/xharness/Hardware/ISimulatorDevice.cs | 1 - tests/xharness/Hardware/SimulatorDevice.cs | 28 +-- tests/xharness/Hardware/Simulators.cs | 28 +-- tests/xharness/Hardware/TCCDatabase.cs | 13 +- tests/xharness/Harness.cs | 238 ++++++------------ tests/xharness/IAppRunner.cs | 2 +- tests/xharness/Jenkins/Jenkins.cs | 58 ++--- .../Jenkins/TestTasks/BuildProjectTask.cs | 5 + .../Jenkins/TestTasks/BuildToolTask.cs | 8 +- .../Jenkins/TestTasks/DotNetBuildTask.cs | 4 +- .../xharness/Jenkins/TestTasks/MSBuildTask.cs | 5 + tests/xharness/Jenkins/TestTasks/MakeTask.cs | 5 + .../Jenkins/TestTasks/RunDeviceTask.cs | 22 +- .../Jenkins/TestTasks/RunSimulatorTask.cs | 11 +- tests/xharness/Program.cs | 2 +- .../Execution/Tests/ProcessManagerTests.cs | 4 +- .../Hardware/Tests/DevicesTest.cs | 15 +- .../Hardware/Tests/SimulatorDeviceTest.cs | 16 +- .../Hardware/Tests/SimulatorsTest.cs | 23 +- .../Hardware/Tests/TCCDatabaseTests.cs | 5 +- .../Xharness.Tests/Tests/AppRunnerTests.cs | 70 +++--- .../Tests/CrashSnapshotReporterTests.cs | 25 +- 30 files changed, 400 insertions(+), 526 deletions(-) diff --git a/tests/xharness/AppRunner.cs b/tests/xharness/AppRunner.cs index 8ef574f104..7f427ddee1 100644 --- a/tests/xharness/AppRunner.cs +++ b/tests/xharness/AppRunner.cs @@ -188,10 +188,6 @@ namespace Xharness { var args = new MlaunchArguments (); - if (!string.IsNullOrEmpty (harness.XcodeRoot)) { - args.Add (new SdkRootArgument (harness.XcodeRoot)); - } - for (int i = -1; i < harness.Verbosity; i++) args.Add (new VerbosityArgument ()); @@ -205,7 +201,7 @@ namespace Xharness { var totalSize = Directory.GetFiles (AppInformation.AppPath, "*", SearchOption.AllDirectories).Select ((v) => new FileInfo (v).Length).Sum (); MainLog.WriteLine ($"Installing '{AppInformation.AppPath}' to '{companionDeviceName ?? deviceName}'. Size: {totalSize} bytes = {totalSize / 1024.0 / 1024.0:N2} MB"); - return await ProcessManager.ExecuteCommandAsync (harness.MlaunchPath, args, MainLog, TimeSpan.FromHours (1), cancellation_token: cancellation_token); + return await ProcessManager.ExecuteCommandAsync (args, MainLog, TimeSpan.FromHours (1), cancellation_token: cancellation_token); } public async Task UninstallAsync () @@ -217,17 +213,13 @@ namespace Xharness { var args = new MlaunchArguments (); - if (!string.IsNullOrEmpty (harness.XcodeRoot)) { - args.Add (new SdkRootArgument (harness.XcodeRoot)); - } - for (int i = -1; i < harness.Verbosity; i++) args.Add (new VerbosityArgument ()); args.Add (new UninstallAppFromDeviceArgument (AppInformation.BundleIdentifier)); args.Add (new DeviceNameArgument (companionDeviceName ?? deviceName)); - return await ProcessManager.ExecuteCommandAsync (harness.MlaunchPath, args, MainLog, TimeSpan.FromMinutes (1)); + return await ProcessManager.ExecuteCommandAsync (args, MainLog, TimeSpan.FromMinutes (1)); } public TimeSpan GetNewTimeout () => TimeSpan.FromMinutes (harness.Timeout * timeoutMultiplier); @@ -241,10 +233,6 @@ namespace Xharness { var args = new MlaunchArguments (); - if (!string.IsNullOrEmpty (harness.XcodeRoot)) { - args.Add (new SdkRootArgument (harness.XcodeRoot)); - } - for (int i = -1; i < harness.Verbosity; i++) args.Add (new VerbosityArgument ()); @@ -387,7 +375,7 @@ namespace Xharness { MainLog.WriteLine ("Starting test run"); await testReporter.CollectSimulatorResult ( - ProcessManager.ExecuteCommandAsync (harness.MlaunchPath, args, run_log, testReporter.Timeout, cancellation_token: testReporter.CancellationToken)); + ProcessManager.ExecuteCommandAsync (args, run_log, testReporter.Timeout, cancellation_token: testReporter.CancellationToken)); // cleanup after us if (EnsureCleanSimulatorState) @@ -419,7 +407,7 @@ namespace Xharness { // We need to check for MT1111 (which means that mlaunch won't wait for the app to exit). var runLog = Log.CreateAggregatedLog (testReporter.CallbackLog, MainLog); testReporter.TimeoutWatch.Start (); - await testReporter.CollectDeviceResult (ProcessManager.ExecuteCommandAsync (harness.MlaunchPath, args, runLog, testReporter.Timeout, cancellation_token: testReporter.CancellationToken)); + await testReporter.CollectDeviceResult (ProcessManager.ExecuteCommandAsync (args, runLog, testReporter.Timeout, cancellation_token: testReporter.CancellationToken)); } finally { deviceLogCapturer.StopCapture (); deviceSystemLog.Dispose (); diff --git a/tests/xharness/Collections/ILoadAsync.cs b/tests/xharness/Collections/ILoadAsync.cs index c64e1b06d2..6f72aabaf5 100644 --- a/tests/xharness/Collections/ILoadAsync.cs +++ b/tests/xharness/Collections/ILoadAsync.cs @@ -5,6 +5,5 @@ using Xharness.Logging; namespace Xharness.Collections{ public interface ILoadAsync { Task LoadAsync (ILog log, bool include_locked, bool force); - IHarness Harness { get; set; } } } diff --git a/tests/xharness/CrashSnapshotReporter.cs b/tests/xharness/CrashSnapshotReporter.cs index eb935fe352..72606e2431 100644 --- a/tests/xharness/CrashSnapshotReporter.cs +++ b/tests/xharness/CrashSnapshotReporter.cs @@ -17,18 +17,14 @@ namespace Xharness public class CrashSnapshotReporterFactory : ICrashSnapshotReporterFactory { readonly IProcessManager processManager; - readonly string xcodeRoot; - readonly string mlaunchPath; - public CrashSnapshotReporterFactory (IProcessManager processManager, string xcodeRoot, string mlaunchPath) + public CrashSnapshotReporterFactory (IProcessManager processManager) { this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); - this.xcodeRoot = xcodeRoot ?? throw new ArgumentNullException (nameof (xcodeRoot)); - this.mlaunchPath = mlaunchPath ?? throw new ArgumentNullException (nameof (mlaunchPath)); } public ICrashSnapshotReporter Create (ILog log, ILogs logs, bool isDevice, string deviceName) => - new CrashSnapshotReporter (processManager, log, logs, xcodeRoot, mlaunchPath, isDevice, deviceName); + new CrashSnapshotReporter (processManager, log, logs, isDevice, deviceName); } public interface ICrashSnapshotReporter { @@ -40,8 +36,6 @@ namespace Xharness readonly IProcessManager processManager; readonly ILog log; readonly ILogs logs; - readonly string xcodeRoot; - readonly string mlaunchPath; readonly bool isDevice; readonly string deviceName; readonly Func tempFileProvider; @@ -52,8 +46,6 @@ namespace Xharness public CrashSnapshotReporter (IProcessManager processManager, ILog log, ILogs logs, - string xcodeRoot, - string mlaunchPath, bool isDevice, string deviceName, Func tempFileProvider = null) @@ -61,15 +53,13 @@ namespace Xharness this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); this.log = log ?? throw new ArgumentNullException (nameof (log)); this.logs = logs ?? throw new ArgumentNullException (nameof (logs)); - this.xcodeRoot = xcodeRoot ?? throw new ArgumentNullException (nameof (xcodeRoot)); - this.mlaunchPath = mlaunchPath ?? throw new ArgumentNullException (nameof (mlaunchPath)); this.isDevice = isDevice; this.deviceName = deviceName; this.tempFileProvider = tempFileProvider ?? Path.GetTempFileName; - symbolicateCrashPath = Path.Combine (xcodeRoot, "Contents", "SharedFrameworks", "DTDeviceKitBase.framework", "Versions", "A", "Resources", "symbolicatecrash"); + symbolicateCrashPath = Path.Combine (processManager.XcodeRoot, "Contents", "SharedFrameworks", "DTDeviceKitBase.framework", "Versions", "A", "Resources", "symbolicatecrash"); if (!File.Exists (symbolicateCrashPath)) - symbolicateCrashPath = Path.Combine (xcodeRoot, "Contents", "SharedFrameworks", "DVTFoundation.framework", "Versions", "A", "Resources", "symbolicatecrash"); + symbolicateCrashPath = Path.Combine (processManager.XcodeRoot, "Contents", "SharedFrameworks", "DVTFoundation.framework", "Versions", "A", "Resources", "symbolicatecrash"); if (!File.Exists (symbolicateCrashPath)) symbolicateCrashPath = null; } @@ -135,14 +125,13 @@ namespace Xharness var crashReportFile = logs.Create (name, $"Crash report: {name}", timestamp: false); var args = new MlaunchArguments ( new DownloadCrashReportArgument (crashFile), - new DownloadCrashReportToArgument (crashReportFile.FullPath), - new SdkRootArgument (xcodeRoot)); + new DownloadCrashReportToArgument (crashReportFile.FullPath)); if (!string.IsNullOrEmpty (deviceName)) { args.Add (new DeviceNameArgument(deviceName)); } - var result = await processManager.ExecuteCommandAsync (mlaunchPath, args, log, TimeSpan.FromMinutes (1)); + var result = await processManager.ExecuteCommandAsync (args, log, TimeSpan.FromMinutes (1)); if (result.Succeeded) { log.WriteLine ("Downloaded crash report {0} to {1}", crashFile, crashReportFile.FullPath); @@ -162,7 +151,7 @@ namespace Xharness var name = Path.GetFileName (report.FullPath); var symbolicated = logs.Create (Path.ChangeExtension (name, ".symbolicated.log"), $"Symbolicated crash report: {name}", timestamp: false); - var environment = new Dictionary { { "DEVELOPER_DIR", Path.Combine (xcodeRoot, "Contents", "Developer") } }; + var environment = new Dictionary { { "DEVELOPER_DIR", Path.Combine (processManager.XcodeRoot, "Contents", "Developer") } }; var result = await processManager.ExecuteCommandAsync (symbolicateCrashPath, new [] { report.FullPath }, symbolicated, TimeSpan.FromMinutes (1), environment); if (result.Succeeded) { log.WriteLine ("Symbolicated {0} successfully.", report.FullPath); @@ -184,15 +173,13 @@ namespace Xharness } else { var tempFile = tempFileProvider (); try { - var args = new MlaunchArguments ( - new ListCrashReportsArgument (tempFile), - new SdkRootArgument (xcodeRoot)); + var args = new MlaunchArguments (new ListCrashReportsArgument (tempFile)); if (!string.IsNullOrEmpty (deviceName)) { args.Add (new DeviceNameArgument(deviceName)); } - var result = await processManager.ExecuteCommandAsync (mlaunchPath, args, log, TimeSpan.FromMinutes (1)); + var result = await processManager.ExecuteCommandAsync (args, log, TimeSpan.FromMinutes (1)); if (result.Succeeded) crashes.UnionWith (File.ReadAllLines (tempFile)); } finally { diff --git a/tests/xharness/DeviceLogCapturer.cs b/tests/xharness/DeviceLogCapturer.cs index 4579a8da58..daedce85ec 100644 --- a/tests/xharness/DeviceLogCapturer.cs +++ b/tests/xharness/DeviceLogCapturer.cs @@ -14,19 +14,15 @@ namespace Xharness public class DeviceLogCapturerFactory : IDeviceLogCapturerFactory { readonly IProcessManager processManager; - readonly string xcodeRoot; - readonly string mlaunchPath; - public DeviceLogCapturerFactory (IProcessManager processManager, string xcodeRoot, string mlaunchPath) + public DeviceLogCapturerFactory (IProcessManager processManager) { this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); - this.xcodeRoot = xcodeRoot ?? throw new ArgumentNullException (nameof (xcodeRoot)); - this.mlaunchPath = mlaunchPath ?? throw new ArgumentNullException (nameof (mlaunchPath)); } public IDeviceLogCapturer Create (ILog mainLog, ILog deviceLog, string deviceName) { - return new DeviceLogCapturer (processManager, mainLog, deviceLog, deviceName, xcodeRoot, mlaunchPath); + return new DeviceLogCapturer (processManager, mainLog, deviceLog, deviceName); } } @@ -40,17 +36,13 @@ namespace Xharness readonly ILog mainLog; readonly ILog deviceLog; readonly string deviceName; - readonly string xcodeRoot; - readonly string mlaunchPath; - public DeviceLogCapturer (IProcessManager processManager, ILog mainLog, ILog deviceLog, string deviceName, string xcodeRoot, string mlaunchPath) + public DeviceLogCapturer (IProcessManager processManager, ILog mainLog, ILog deviceLog, string deviceName) { this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); this.mainLog = mainLog ?? throw new ArgumentNullException (nameof (mainLog)); this.deviceLog = deviceLog ?? throw new ArgumentNullException (nameof (deviceLog)); this.deviceName = deviceName ?? throw new ArgumentNullException (nameof (deviceName)); - this.xcodeRoot = xcodeRoot ?? throw new ArgumentNullException (nameof (xcodeRoot)); - this.mlaunchPath = mlaunchPath ?? throw new ArgumentNullException (nameof (mlaunchPath)); } Process process; @@ -60,17 +52,17 @@ namespace Xharness { streamEnds = new CountdownEvent (2); - var sb = new List { + var args = new List { "--logdev", "--sdkroot", - xcodeRoot, + processManager.XcodeRoot, "--devname", deviceName }; process = new Process (); - process.StartInfo.FileName = mlaunchPath; - process.StartInfo.Arguments = StringUtils.FormatArguments (sb); + process.StartInfo.FileName = processManager.MlaunchPath; + process.StartInfo.Arguments = StringUtils.FormatArguments (args); process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; diff --git a/tests/xharness/Execution/IProcessManager.cs b/tests/xharness/Execution/IProcessManager.cs index 936805224a..f5f129b5a3 100644 --- a/tests/xharness/Execution/IProcessManager.cs +++ b/tests/xharness/Execution/IProcessManager.cs @@ -17,15 +17,17 @@ namespace Xharness.Execution { // interface that helps to manage the different processes in the app. public interface IProcessManager { + string XcodeRoot { get; } + string MlaunchPath { get; } + Version XcodeVersion { get; } + Task ExecuteCommandAsync (string filename, IList args, ILog log, TimeSpan timeout, Dictionary environment_variables = null, CancellationToken? cancellation_token = null); - Task ExecuteCommandAsync (string filename, MlaunchArguments args, ILog log, TimeSpan timeout, Dictionary environment_variables = null, CancellationToken? cancellation_token = null); - Task RunAsync (Process process, ILog log, CancellationToken? cancellationToken = null, bool? diagnostics = null); + Task ExecuteCommandAsync (MlaunchArguments args, ILog log, TimeSpan timeout, Dictionary environment_variables = null, CancellationToken? cancellation_token = null); + Task ExecuteXcodeCommandAsync (string executable, IList args, ILog log, TimeSpan timeout); Task RunAsync (Process process, ILog log, TimeSpan? timeout = null, Dictionary environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null); Task RunAsync (Process process, MlaunchArguments args, ILog log, TimeSpan? timeout = null, Dictionary environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null); Task RunAsync (Process process, ILog log, ILog stdoutLog, ILog stderrLog, TimeSpan? timeout = null, Dictionary environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null); - Task WaitForExitAsync (Process process, TimeSpan? timeout = null); Task KillTreeAsync (Process process, ILog log, bool? diagnostics = true); Task KillTreeAsync (int pid, ILog log, bool? diagnostics = true); - void GetChildrenPS (ILog log, List list, int pid); } } diff --git a/tests/xharness/Execution/ProcessManager.cs b/tests/xharness/Execution/ProcessManager.cs index 34f4a7ee62..773f9e014d 100644 --- a/tests/xharness/Execution/ProcessManager.cs +++ b/tests/xharness/Execution/ProcessManager.cs @@ -7,84 +7,101 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Xml; using Xharness.Execution.Mlaunch; using Xharness.Logging; using Xharness.Utilities; namespace Xharness.Execution { public class ProcessManager : IProcessManager { - public ProcessManager () + public string XcodeRoot { get; } + public string MlaunchPath { get; } + + Version xcode_version; + public Version XcodeVersion { + get { + if (xcode_version == null) { + var doc = new XmlDocument (); + doc.Load (Path.Combine (XcodeRoot, "Contents", "version.plist")); + xcode_version = Version.Parse (doc.SelectSingleNode ("//key[text() = 'CFBundleShortVersionString']/following-sibling::string").InnerText); + } + return xcode_version; + } + } + + public ProcessManager (string xcodeRoot, string mlaunchPath) { + XcodeRoot = xcodeRoot ?? throw new ArgumentNullException (nameof (xcodeRoot)); + MlaunchPath = mlaunchPath ?? throw new ArgumentNullException (nameof (mlaunchPath)); } public async Task ExecuteCommandAsync (string filename, IList args, ILog log, TimeSpan timeout, - Dictionary environment_variables = null, - CancellationToken? cancellation_token = null) + Dictionary environmentVariables = null, + CancellationToken? cancellationToken = null) { - using (var p = new Process ()) { - p.StartInfo.FileName = filename; - p.StartInfo.Arguments = StringUtils.FormatArguments (args); - return await RunAsync (p, log, timeout, environment_variables, cancellation_token); - } + using var p = new Process (); + p.StartInfo.FileName = filename ?? throw new ArgumentNullException (nameof (filename)); + p.StartInfo.Arguments = StringUtils.FormatArguments (args); + return await RunAsync (p, log, timeout, environmentVariables, cancellationToken); } - public async Task ExecuteCommandAsync (string filename, - MlaunchArguments args, + public async Task ExecuteCommandAsync (MlaunchArguments args, ILog log, TimeSpan timeout, - Dictionary environment_variables = null, - CancellationToken? cancellation_token = null) + Dictionary environmentVariables = null, + CancellationToken? cancellationToken = null) { - using (var p = new Process ()) { - p.StartInfo.FileName = filename; - p.StartInfo.Arguments = args.AsCommandLine (); - return await RunAsync (p, log, timeout, environment_variables, cancellation_token); - } + using var p = new Process (); + return await RunAsync (p, args, log, timeout, environmentVariables, cancellationToken); + } + + public Task ExecuteXcodeCommandAsync (string executable, IList args, ILog log, TimeSpan timeout) + { + string filename = Path.Combine (XcodeRoot, "Contents", "Developer", "usr", "bin", executable); + return ExecuteCommandAsync (filename, args, log, timeout: timeout); } [DllImport ("/usr/lib/libc.dylib")] internal static extern int kill (int pid, int sig); - public static Task PollForExitAsync (int pid, TimeSpan timeout) + public Task RunAsync (Process process, + ILog log, + TimeSpan? timeout = null, + Dictionary environment_variables = null, + CancellationToken? cancellationToken = null, + bool? diagnostics = null) { - var rv = new TaskCompletionSource (); - var watch = new Stopwatch (); - watch.Start (); - Task.Run (async () => { - while (watch.ElapsedMilliseconds < timeout.TotalMilliseconds) { - if (kill (pid, 0) != 0) { - // pid is not valid anymore, program exited - rv.SetResult (true); - return; - } - await Task.Delay (TimeSpan.FromMilliseconds (100)); - } - - rv.SetResult (false); - }); - return rv.Task; + return RunAsync (process, log, log, log, timeout, environment_variables, cancellationToken, diagnostics); } - public async Task RunAsync (Process process, ILog log, CancellationToken? cancellation_token = null, bool? diagnostics = null) - { - return await RunAsync (process, log, log, log, cancellation_token: cancellation_token, diagnostics: diagnostics); - } - - public Task RunAsync (Process process, ILog log, TimeSpan? timeout = null, Dictionary environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null) - { - return RunAsync (process, log, log, log, timeout, environment_variables, cancellation_token, diagnostics); - } - - public Task RunAsync (Process process, MlaunchArguments args, ILog log, TimeSpan? timeout = null, Dictionary environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null) + public Task RunAsync (Process process, + MlaunchArguments args, + ILog log, + TimeSpan? timeout = null, + Dictionary environmentVariables = null, + CancellationToken? cancellationToken = null, + bool? diagnostics = null) { + if (!args.Any (a => a is SdkRootArgument)) + args.Prepend (new SdkRootArgument (XcodeRoot)); + + process.StartInfo.FileName = MlaunchPath; process.StartInfo.Arguments = args.AsCommandLine (); - return RunAsync (process, log, timeout, environment_variables, cancellation_token, diagnostics); + + return RunAsync (process, log, timeout, environmentVariables, cancellationToken, diagnostics); } - public async Task RunAsync (Process process, ILog log, ILog StdoutStream, ILog StderrStream, TimeSpan? timeout = null, Dictionary environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null) + public async Task RunAsync (Process process, + ILog log, + ILog stdout, + ILog stderr, + TimeSpan? timeout = null, + Dictionary environment_variables = null, + CancellationToken? cancellationToken = null, + bool? diagnostics = null) { var stdout_completion = new TaskCompletionSource (); var stderr_completion = new TaskCompletionSource (); @@ -105,9 +122,9 @@ namespace Xharness.Execution { process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => { if (e.Data != null) { - lock (StdoutStream) { - StdoutStream.WriteLine (e.Data); - StdoutStream.Flush (); + lock (stdout) { + stdout.WriteLine (e.Data); + stdout.Flush (); } } else { stdout_completion.TrySetResult (true); @@ -117,9 +134,9 @@ namespace Xharness.Execution { process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => { if (e.Data != null) { - lock (StderrStream) { - StderrStream.WriteLine (e.Data); - StderrStream.Flush (); + lock (stderr) { + stderr.WriteLine (e.Data); + stderr.Flush (); } } else { stderr_completion.TrySetResult (true); @@ -148,7 +165,7 @@ namespace Xharness.Execution { process.BeginErrorReadLine (); process.BeginOutputReadLine (); - cancellation_token?.Register (() => { + cancellationToken?.Register (() => { var hasExited = false; try { hasExited = process.HasExited; @@ -159,7 +176,7 @@ namespace Xharness.Execution { // processes behind). } if (!hasExited) { - StderrStream.WriteLine ($"Execution of {pid} was cancelled."); + stderr.WriteLine ($"Execution of {pid} was cancelled."); kill (pid, 9); } }); @@ -168,7 +185,7 @@ namespace Xharness.Execution { if (!await WaitForExitAsync (process, timeout.Value)) { await KillTreeAsync (process, log, diagnostics ?? true); rv.TimedOut = true; - lock (StderrStream) + lock (stderr) log.WriteLine ($"{pid} Execution timed out after {timeout.Value.TotalSeconds} seconds and the process was killed."); } } @@ -184,38 +201,6 @@ namespace Xharness.Execution { return rv; } - public async Task WaitForExitAsync (Process process, TimeSpan? timeout = null) - { - if (process.HasExited) - return true; - - var tcs = new TaskCompletionSource (); - - void ProcessExited (object sender, EventArgs ea) - { - process.Exited -= ProcessExited; - tcs.TrySetResult (true); - } - - process.Exited += ProcessExited; - process.EnableRaisingEvents = true; - - // Check if process exited again, in case it exited after we checked - // the last time, but before we attached the event handler. - if (process.HasExited) { - process.Exited -= ProcessExited; - tcs.TrySetResult (true); - return true; - } - - if (timeout.HasValue) { - return await tcs.Task.TimeoutAfter (timeout.Value); - } else { - await tcs.Task; - return true; - } - } - public Task KillTreeAsync (Process process, ILog log, bool? diagnostics = true) { return KillTreeAsync (process.Id, log, diagnostics); @@ -223,8 +208,8 @@ namespace Xharness.Execution { public async Task KillTreeAsync (int pid, ILog log, bool? diagnostics = true) { - var pids = new List (); - GetChildrenPS (log, pids, pid); + var pids = GetChildrenPS (log, pid); + if (diagnostics == true) { log.WriteLine ($"Pids to kill: {string.Join (", ", pids.Select ((v) => v.ToString ()).ToArray ())}"); using (var ps = new Process ()) { @@ -271,9 +256,41 @@ namespace Xharness.Execution { kill (pids [i], 9); } - public void GetChildrenPS (ILog log, List list, int pid) + static async Task WaitForExitAsync (Process process, TimeSpan? timeout = null) { - string stdout; + if (process.HasExited) + return true; + + var tcs = new TaskCompletionSource (); + + void ProcessExited (object sender, EventArgs ea) + { + process.Exited -= ProcessExited; + tcs.TrySetResult (true); + } + + process.Exited += ProcessExited; + process.EnableRaisingEvents = true; + + // Check if process exited again, in case it exited after we checked + // the last time, but before we attached the event handler. + if (process.HasExited) { + process.Exited -= ProcessExited; + tcs.TrySetResult (true); + return true; + } + + if (timeout.HasValue) { + return await tcs.Task.TimeoutAfter (timeout.Value); + } else { + await tcs.Task; + return true; + } + } + + static List GetChildrenPS (ILog log, int pid) + { + var list = new List (); using (Process ps = new Process ()) { ps.StartInfo.FileName = "ps"; @@ -281,20 +298,21 @@ namespace Xharness.Execution { ps.StartInfo.UseShellExecute = false; ps.StartInfo.RedirectStandardOutput = true; ps.Start (); - stdout = ps.StandardOutput.ReadToEnd (); + + string stdout = ps.StandardOutput.ReadToEnd (); if (!ps.WaitForExit (1000)) { log.WriteLine ("ps didn't finish in a reasonable amount of time (1 second)."); - return; + return list; } if (ps.ExitCode != 0) - return; + return list; stdout = stdout.Trim (); if (string.IsNullOrEmpty (stdout)) - return; + return list; var dict = new Dictionary> (); foreach (string line in stdout.Split (new char [] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)) { @@ -305,12 +323,11 @@ namespace Xharness.Execution { var parent = l.Substring (0, space); var process = l.Substring (space + 1); - int parent_id, process_id; - if (int.TryParse (parent, out parent_id) && int.TryParse (process, out process_id)) { - List children; - if (!dict.TryGetValue (parent_id, out children)) + if (int.TryParse (parent, out var parent_id) && int.TryParse (process, out var process_id)) { + if (!dict.TryGetValue (parent_id, out var children)) dict [parent_id] = children = new List (); + children.Add (process_id); } } @@ -319,15 +336,16 @@ namespace Xharness.Execution { queue.Enqueue (pid); do { - List children; var parent_id = queue.Dequeue (); list.Add (parent_id); - if (dict.TryGetValue (parent_id, out children)) { + if (dict.TryGetValue (parent_id, out var children)) { foreach (var child in children) queue.Enqueue (child); } } while (queue.Count > 0); } + + return list; } } } diff --git a/tests/xharness/GitHub.cs b/tests/xharness/GitHub.cs index 239181aed8..e4b1090f78 100644 --- a/tests/xharness/GitHub.cs +++ b/tests/xharness/GitHub.cs @@ -6,8 +6,6 @@ using System.Linq; using System.Net; using System.Runtime.Serialization.Json; using System.Xml; -using System.Text; -using Xamarin; using Xharness.Execution; using Xharness.Logging; @@ -15,7 +13,6 @@ namespace Xharness { public static class GitHub { - static IProcessManager ProcessManager { get; set; } = new ProcessManager (); static WebClient CreateClient () { var client = new WebClient (); @@ -56,11 +53,11 @@ namespace Xharness } } - public static IEnumerable GetModifiedFiles (Harness harness, int pull_request) + public static IEnumerable GetModifiedFiles (IProcessManager processManager, Harness harness, int pull_request) { var path = Path.Combine (harness.LogDirectory, "pr" + pull_request + "-files.log"); if (!File.Exists (path)) { - var rv = GetModifiedFilesLocally (harness, pull_request); + var rv = GetModifiedFilesLocally (processManager, harness, pull_request); if (rv == null || rv.Count () == 0) { rv = GetModifiedFilesRemotely (harness, pull_request); if (rv == null) @@ -141,7 +138,7 @@ namespace Xharness return File.ReadAllLines (path); } - static IEnumerable GetModifiedFilesLocally (Harness harness, int pull_request) + static IEnumerable GetModifiedFilesLocally (IProcessManager processManager, Harness harness, int pull_request) { var base_commit = $"origin/pr/{pull_request}/merge^"; var head_commit = $"origin/pr/{pull_request}/merge"; @@ -155,7 +152,7 @@ namespace Xharness git.StartInfo.FileName = "git"; git.StartInfo.Arguments = $"diff-tree --no-commit-id --name-only -r {base_commit}..{head_commit}"; var output = new MemoryLog (); - var rv = ProcessManager.RunAsync (git, harness.HarnessLog, output, output).Result; + var rv = processManager.RunAsync (git, harness.HarnessLog, stdoutLog: output, stderrLog: output).Result; if (rv.Succeeded) return output.ToString ().Split (new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries); diff --git a/tests/xharness/Hardware/Devices.cs b/tests/xharness/Hardware/Devices.cs index ec34edd24b..5e87320620 100644 --- a/tests/xharness/Hardware/Devices.cs +++ b/tests/xharness/Hardware/Devices.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; +using System.Web.UI.WebControls; using System.Xml; using Xharness.Collections; using Xharness.Execution; @@ -18,24 +19,20 @@ namespace Xharness.Hardware { } public class DeviceLoaderFactory : IDeviceLoaderFactory { - readonly IHarness harness; readonly IProcessManager processManager; - public DeviceLoaderFactory (IHarness harness, IProcessManager processManager) + public DeviceLoaderFactory (IProcessManager processManager) { - this.harness = harness ?? throw new ArgumentNullException (nameof (harness)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); } - public IDeviceLoader CreateLoader () => new Devices (harness, processManager); + public IDeviceLoader CreateLoader () => new Devices (processManager); } public class Devices : IDeviceLoader { readonly IProcessManager processManager; bool loaded; - public IHarness Harness { get; set; } - BlockingEnumerableCollection connected_devices = new BlockingEnumerableCollection (); public IEnumerable ConnectedDevices => connected_devices; @@ -51,9 +48,8 @@ namespace Xharness.Hardware { } } - public Devices (IHarness harness, IProcessManager processManager) + public Devices (IProcessManager processManager) { - Harness = harness ?? throw new ArgumentNullException (nameof (harness)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); } @@ -76,18 +72,19 @@ namespace Xharness.Hardware { var tmpfile = Path.GetTempFileName (); try { using (var process = new Process ()) { - process.StartInfo.FileName = Harness.MlaunchPath; var arguments = new MlaunchArguments ( - new SdkRootArgument (Harness.XcodeRoot), new ListDevicesArgument (tmpfile), new XmlOutputFormatArgument ()); if (extra_data) arguments.Add (new ListExtraDataArgument ()); + var task = processManager.ExecuteCommandAsync (arguments, log, timeout: TimeSpan.FromSeconds (120)); log.WriteLine ("Launching {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - var rv = await processManager.RunAsync (process, arguments, log, timeout: TimeSpan.FromSeconds (120)); - if (!rv.Succeeded) + + var result = await task; + + if (!result.Succeeded) throw new Exception ("Failed to list devices."); log.WriteLine ("Result:"); log.WriteLine (File.ReadAllText (tmpfile)); diff --git a/tests/xharness/Hardware/ISimulatorDevice.cs b/tests/xharness/Hardware/ISimulatorDevice.cs index 543180ea18..8a4db7e672 100644 --- a/tests/xharness/Hardware/ISimulatorDevice.cs +++ b/tests/xharness/Hardware/ISimulatorDevice.cs @@ -33,7 +33,6 @@ namespace Xharness.Hardware { } public interface ISimulatorDevice : IDevice { - ITCCDatabase TCCDatabase { get; set; } string SimRuntime { get; set; } string SimDeviceType { get; set; } string DataPath { get; set; } diff --git a/tests/xharness/Hardware/SimulatorDevice.cs b/tests/xharness/Hardware/SimulatorDevice.cs index e957b785b6..41f95a1c7c 100644 --- a/tests/xharness/Hardware/SimulatorDevice.cs +++ b/tests/xharness/Hardware/SimulatorDevice.cs @@ -9,10 +9,8 @@ using Xharness.Logging; namespace Xharness.Hardware { public class SimulatorDevice : ISimulatorDevice { - readonly IHarness harness; readonly IProcessManager processManager; - - public ITCCDatabase TCCDatabase { get; set; } = new TCCDatabase (); + readonly ITCCDatabase tCCDatabase; public string UDID { get; set; } public string Name { get; set; } @@ -23,10 +21,10 @@ namespace Xharness.Hardware { public string SystemLog => Path.Combine (LogPath, "system.log"); - public SimulatorDevice (IHarness harness, IProcessManager processManager) + public SimulatorDevice (IProcessManager processManager, ITCCDatabase tccDatabase) { - this.harness = harness ?? throw new ArgumentNullException (nameof (harness)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); + this.tCCDatabase = tccDatabase ?? throw new ArgumentNullException (nameof (tccDatabase)); } public bool IsWatchSimulator => SimRuntime.StartsWith ("com.apple.CoreSimulator.SimRuntime.watchOS", StringComparison.Ordinal); @@ -43,17 +41,17 @@ namespace Xharness.Hardware { { // here we don't care if execution fails. // erase the simulator (make sure the device isn't running first) - await harness.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1)); - await harness.ExecuteXcodeCommandAsync ("simctl", new [] { "erase", UDID }, log, TimeSpan.FromMinutes (1)); + await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1)); + await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "erase", UDID }, log, TimeSpan.FromMinutes (1)); // boot & shutdown to make sure it actually works - await harness.ExecuteXcodeCommandAsync ("simctl", new [] { "boot", UDID }, log, TimeSpan.FromMinutes (1)); - await harness.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1)); + await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "boot", UDID }, log, TimeSpan.FromMinutes (1)); + await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1)); } public async Task ShutdownAsync (ILog log) { - await harness.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1)); + await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1)); } public async Task KillEverythingAsync (ILog log) @@ -86,12 +84,12 @@ namespace Xharness.Hardware { { string simulator_app; - if (IsWatchSimulator && harness.XcodeVersion.Major < 9) { - simulator_app = Path.Combine (harness.XcodeRoot, "Contents", "Developer", "Applications", "Simulator (Watch).app"); + if (IsWatchSimulator && processManager.XcodeVersion.Major < 9) { + simulator_app = Path.Combine (processManager.XcodeRoot, "Contents", "Developer", "Applications", "Simulator (Watch).app"); } else { - simulator_app = Path.Combine (harness.XcodeRoot, "Contents", "Developer", "Applications", "Simulator.app"); + simulator_app = Path.Combine (processManager.XcodeRoot, "Contents", "Developer", "Applications", "Simulator.app"); if (!Directory.Exists (simulator_app)) - simulator_app = Path.Combine (harness.XcodeRoot, "Contents", "Developer", "Applications", "iOS Simulator.app"); + simulator_app = Path.Combine (processManager.XcodeRoot, "Contents", "Developer", "Applications", "iOS Simulator.app"); } await processManager.ExecuteCommandAsync ("open", new [] { "-a", simulator_app, "--args", "-CurrentDeviceUDID", UDID }, log, TimeSpan.FromSeconds (15)); @@ -121,7 +119,7 @@ namespace Xharness.Hardware { } if (File.Exists (TCC_db)) { - await TCCDatabase.AgreeToPromptsAsync (SimRuntime, TCC_db, log, bundle_identifiers); + await tCCDatabase.AgreeToPromptsAsync (SimRuntime, TCC_db, log, bundle_identifiers); } else { log.WriteLine ("No TCC.db found for the simulator {0} (SimRuntime={1} and SimDeviceType={1})", UDID, SimRuntime, SimDeviceType); } diff --git a/tests/xharness/Hardware/Simulators.cs b/tests/xharness/Hardware/Simulators.cs index 89d23b1480..20ae066192 100644 --- a/tests/xharness/Hardware/Simulators.cs +++ b/tests/xharness/Hardware/Simulators.cs @@ -22,16 +22,14 @@ namespace Xharness.Hardware { } public class SimulatorsLoaderFactory : ISimulatorsLoaderFactory { - readonly IHarness harness; readonly IProcessManager processManager; - public SimulatorsLoaderFactory (IHarness harness, IProcessManager processManager) + public SimulatorsLoaderFactory (IProcessManager processManager) { - this.harness = harness ?? throw new ArgumentNullException (nameof (harness)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); } - public ISimulatorsLoader CreateLoader () => new Simulators (harness, processManager); + public ISimulatorsLoader CreateLoader () => new Simulators (processManager); } public class Simulators : ISimulatorsLoader { @@ -43,17 +41,14 @@ namespace Xharness.Hardware { readonly IProcessManager processManager; bool loaded; - - public IHarness Harness { get; set; } public IEnumerable SupportedRuntimes => supported_runtimes; public IEnumerable SupportedDeviceTypes => supported_device_types; public IEnumerable AvailableDevices => available_devices; public IEnumerable AvailableDevicePairs => available_device_pairs; - public Simulators (IHarness harness, IProcessManager processManager) + public Simulators (IProcessManager processManager) { - Harness = harness ?? throw new ArgumentNullException (nameof (harness)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); } @@ -76,18 +71,18 @@ namespace Xharness.Hardware { var tmpfile = Path.GetTempFileName (); try { using (var process = new Process ()) { - process.StartInfo.FileName = Harness.MlaunchPath; var arguments = new MlaunchArguments ( - new SdkRootArgument(Harness.XcodeRoot), new ListSimulatorsArgument(tmpfile), new XmlOutputFormatArgument()); - process.StartInfo.Arguments = arguments.AsCommandLine (); + var task = processManager.ExecuteCommandAsync (arguments, log, timeout: TimeSpan.FromSeconds (30)); log.WriteLine ("Launching {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - var rv = await processManager.RunAsync (process, arguments, log, timeout: TimeSpan.FromSeconds (30)); - if (!rv.Succeeded) + var result = await task; + + if (!result.Succeeded) throw new Exception ("Failed to list simulators."); + log.WriteLine ("Result:"); log.WriteLine (File.ReadAllText (tmpfile)); var simulator_data = new XmlDocument (); @@ -112,7 +107,7 @@ namespace Xharness.Hardware { } foreach (XmlNode sim in simulator_data.SelectNodes ("/MTouch/Simulator/AvailableDevices/SimDevice")) { - available_devices.Add (new SimulatorDevice (Harness, processManager) { + available_devices.Add (new SimulatorDevice (processManager, new TCCDatabase (processManager)) { Name = sim.Attributes ["Name"].Value, UDID = sim.Attributes ["UDID"].Value, SimRuntime = sim.SelectSingleNode ("SimRuntime").InnerText, @@ -168,7 +163,7 @@ namespace Xharness.Hardware { return devices; } - var rv = await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "create", CreateName (devicetype, runtime), devicetype, runtime }, log, TimeSpan.FromMinutes (1)); + var rv = await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "create", CreateName (devicetype, runtime), devicetype, runtime }, log, TimeSpan.FromMinutes (1)); if (!rv.Succeeded) { log.WriteLine ($"Could not create device for runtime={runtime} and device type={devicetype}."); return null; @@ -207,8 +202,7 @@ namespace Xharness.Hardware { log.Write (value); capturedLog.Append (value); }); - - var rv = await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "pair", device.UDID, companion_device.UDID }, pairLog, TimeSpan.FromMinutes (1)); + var rv = await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "pair", device.UDID, companion_device.UDID }, pairLog, TimeSpan.FromMinutes (1)); if (!rv.Succeeded) { if (!create_device) { var try_creating_device = false; diff --git a/tests/xharness/Hardware/TCCDatabase.cs b/tests/xharness/Hardware/TCCDatabase.cs index 871e780569..d1070710a0 100644 --- a/tests/xharness/Hardware/TCCDatabase.cs +++ b/tests/xharness/Hardware/TCCDatabase.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Threading.Tasks; using Xharness.Execution; using Xharness.Logging; @@ -9,7 +8,6 @@ using Xharness.Logging; namespace Xharness.Hardware { public interface ITCCDatabase { - IProcessManager ProcessManager { get; set; } Task AgreeToPromptsAsync (string simRuntime, string dataPath, ILog log, params string [] bundle_identifiers); int GetTCCFormat (string simRuntime); } @@ -19,7 +17,12 @@ namespace Xharness.Hardware { static readonly string tvOSSimRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.tvOS-"; static readonly string watchOSRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.watchOS-"; - public IProcessManager ProcessManager { get; set; } = new ProcessManager (); + readonly IProcessManager processManager; + + public TCCDatabase (IProcessManager processManager) + { + this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); + } public int GetTCCFormat (string simRuntime) { @@ -109,7 +112,7 @@ namespace Xharness.Hardware { } } args.Add (sql.ToString ()); - var rv = await ProcessManager.ExecuteCommandAsync ("sqlite3", args, log, TimeSpan.FromSeconds (5)); + var rv = await processManager.ExecuteCommandAsync ("sqlite3", args, log, TimeSpan.FromSeconds (5)); if (!rv.Succeeded) { failure = true; break; @@ -124,7 +127,7 @@ namespace Xharness.Hardware { } log.WriteLine ("Current TCC database contents:"); - await ProcessManager.ExecuteCommandAsync ("sqlite3", new [] { TCCDb, ".dump" }, log, TimeSpan.FromSeconds (5)); + await processManager.ExecuteCommandAsync ("sqlite3", new [] { TCCDb, ".dump" }, log, TimeSpan.FromSeconds (5)); } } } diff --git a/tests/xharness/Harness.cs b/tests/xharness/Harness.cs index 3026f5694f..6a623777ac 100644 --- a/tests/xharness/Harness.cs +++ b/tests/xharness/Harness.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading.Tasks; using System.Xml; using Xharness.BCLTestImporter; using Xharness.Logging; @@ -51,66 +50,30 @@ namespace Xharness public interface IHarness { HarnessAction Action { get; } - bool DisableWatchOSOnWrench { get; } - string DOTNET { get; } - bool DryRun { get; } - bool ENABLE_XAMARIN { get; } Dictionary EnvironmentVariables { get; } ILog HarnessLog { get; set; } - string GetStandardErrorTty (); bool InCI { get; } - bool INCLUDE_IOS { get; } - bool INCLUDE_MAC { get; } - bool INCLUDE_TVOS { get; } - bool INCLUDE_WATCH { get; } - bool? IncludeSystemPermissionTests { get; set; } - string IOS_DESTDIR { get; } - List IOSTestProjects { get; } - string JENKINS_RESULTS_DIRECTORY { get; } - string JenkinsConfiguration { get; } - HashSet Labels { get; } double LaunchTimeout { get; } - string LogDirectory { get; } - string MAC_DESTDIR { get; } - List MacTestProjects { get; } - string MarkdownSummaryPath { get; } - string MlaunchPath { get; } - string MONO_IOS_SDK_DESTDIR { get; } - string MONO_MAC_SDK_DESTDIR { get; } - string MONO_PATH { get; } - string PeriodicCommand { get; } - string PeriodicCommandArguments { get; } - TimeSpan PeriodicCommandInterval { get; } - IProcessManager ProcessManager { get; } double Timeout { get; } - string TodayContainerTemplate { get; } - string TodayExtensionTemplate { get; } - bool UseGroupedApps { get; } int Verbosity { get; } - string WatchOSAppTemplate { get; } - string WatchOSContainerTemplate { get; } - string WatchOSExtensionTemplate { get; } - string XcodeRoot { get; } - Version XcodeVersion { get; } XmlResultJargon XmlJargon { get; } - Task ExecuteXcodeCommandAsync (string executable, IList args, ILog log, TimeSpan timeout); + bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device); + string GetStandardErrorTty (); void Log (int min_level, string message, params object [] args); - void Log (string message); - void Log (string message, params object [] args); - void Save (StringWriter doc, string path); } public class Harness : IHarness { readonly TestTarget target; readonly string buildConfiguration = "Debug"; + IProcessManager processManager; + public HarnessAction Action { get; } public int Verbosity { get; } public ILog HarnessLog { get; set; } public HashSet Labels { get; } public XmlResultJargon XmlJargon { get; } - public IProcessManager ProcessManager { get; } public IResultParser ResultParser { get; } // This is the maccore/tests directory. @@ -150,6 +113,8 @@ namespace Xharness } } + string MlaunchPath => Path.Combine (IOS_DESTDIR, "Library", "Frameworks", "Xamarin.iOS.framework", "Versions", "Current", "bin", "mlaunch"); + public List IOSTestProjects { get; } public List MacTestProjects { get; } = new List (); @@ -164,19 +129,19 @@ namespace Xharness public string TodayContainerTemplate { get; private set; } public string TodayExtensionTemplate { get; private set; } public string BCLTodayExtensionTemplate { get; private set; } - public string MONO_PATH { get; private set; } // Use same name as in Makefiles, so that a grep finds it. - public string TVOS_MONO_PATH { get; private set; } // Use same name as in Makefiles, so that a grep finds it. - public bool INCLUDE_IOS { get; private set; } - public bool INCLUDE_TVOS { get; private set; } - public bool INCLUDE_WATCH { get; private set; } - public bool INCLUDE_MAC { get; private set; } - public string JENKINS_RESULTS_DIRECTORY { get; private set; } // Use same name as in Makefiles, so that a grep finds it. - public string MAC_DESTDIR { get; private set; } - public string IOS_DESTDIR { get; private set; } - public string MONO_IOS_SDK_DESTDIR { get; private set; } - public string MONO_MAC_SDK_DESTDIR { get; private set; } - public bool ENABLE_XAMARIN { get; private set; } - public string DOTNET { get; private set; } + public string MONO_PATH { get; } // Use same name as in Makefiles, so that a grep finds it. + public string TVOS_MONO_PATH { get; } // Use same name as in Makefiles, so that a grep finds it. + public bool INCLUDE_IOS { get; } + public bool INCLUDE_TVOS { get; } + public bool INCLUDE_WATCH { get; } + public bool INCLUDE_MAC { get; } + public string JENKINS_RESULTS_DIRECTORY { get; } // Use same name as in Makefiles, so that a grep finds it. + public string MAC_DESTDIR { get; } + public string IOS_DESTDIR { get; } + public string MONO_IOS_SDK_DESTDIR { get; } + public string MONO_MAC_SDK_DESTDIR { get; } + public bool ENABLE_XAMARIN { get; } + public string DOTNET { get; } // Run @@ -196,9 +161,8 @@ namespace Xharness public string GetStandardErrorTty () => Helpers.GetTerminalName (2); - public Harness (IProcessManager processManager, IResultParser resultParser, HarnessAction action, HarnessConfiguration configuration) + public Harness (IResultParser resultParser, HarnessAction action, HarnessConfiguration configuration) { - ProcessManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); ResultParser = resultParser ?? throw new ArgumentNullException (nameof (resultParser)); Action = action; @@ -217,7 +181,6 @@ namespace Xharness PeriodicCommand = configuration.PeriodicCommand; PeriodicCommandArguments = configuration.PeriodicCommandArguments; PeriodicCommandInterval = configuration.PeriodicCommandInterval; - SdkRoot = configuration.SdkRoot; target = configuration.Target; Timeout = configuration.TimeoutInMinutes; useSystemXamarinIOSMac = configuration.UseSystemXamarinIOSMac; @@ -233,6 +196,29 @@ namespace Xharness EnvironmentVariables = new Dictionary (configuration.EnvironmentVariables); LaunchTimeout = InCI ? 3 : 120; + + var config = ParseConfigFiles (); + var src_root = Path.GetDirectoryName (Path.GetFullPath (RootDirectory)); + + MONO_PATH = Path.GetFullPath (Path.Combine (src_root, "external", "mono")); + TVOS_MONO_PATH = MONO_PATH; + INCLUDE_IOS = config.ContainsKey ("INCLUDE_IOS") && !string.IsNullOrEmpty (config ["INCLUDE_IOS"]); + INCLUDE_TVOS = config.ContainsKey ("INCLUDE_TVOS") && !string.IsNullOrEmpty (config ["INCLUDE_TVOS"]); + JENKINS_RESULTS_DIRECTORY = config ["JENKINS_RESULTS_DIRECTORY"]; + INCLUDE_WATCH = config.ContainsKey ("INCLUDE_WATCH") && !string.IsNullOrEmpty (config ["INCLUDE_WATCH"]); + INCLUDE_MAC = config.ContainsKey ("INCLUDE_MAC") && !string.IsNullOrEmpty (config ["INCLUDE_MAC"]); + MAC_DESTDIR = config ["MAC_DESTDIR"]; + + IOS_DESTDIR = config ["IOS_DESTDIR"]; + MONO_IOS_SDK_DESTDIR = config ["MONO_IOS_SDK_DESTDIR"]; + MONO_MAC_SDK_DESTDIR = config ["MONO_MAC_SDK_DESTDIR"]; + ENABLE_XAMARIN = config.ContainsKey ("ENABLE_XAMARIN") && !string.IsNullOrEmpty (config ["ENABLE_XAMARIN"]); + DOTNET = config ["DOTNET"]; + + if (string.IsNullOrEmpty (SdkRoot)) + SdkRoot = config ["XCODE_DEVELOPER_ROOT"] ?? configuration.SdkRoot; + + processManager = new ProcessManager (XcodeRoot, MlaunchPath); } public bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device) @@ -277,45 +263,6 @@ namespace Xharness } while (true); } - Version xcode_version; - public Version XcodeVersion { - get { - if (xcode_version == null) { - var doc = new XmlDocument (); - doc.Load (Path.Combine (XcodeRoot, "Contents", "version.plist")); - xcode_version = Version.Parse (doc.SelectSingleNode ("//key[text() = 'CFBundleShortVersionString']/following-sibling::string").InnerText); - } - return xcode_version; - } - } - - public string MlaunchPath { - get { - return Path.Combine (IOS_DESTDIR, "Library", "Frameworks", "Xamarin.iOS.framework", "Versions", "Current", "bin", "mlaunch"); - } - } - - void LoadConfig () - { - ParseConfigFiles (); - var src_root = Path.GetDirectoryName (Path.GetFullPath (RootDirectory)); - MONO_PATH = Path.GetFullPath (Path.Combine (src_root, "external", "mono")); - TVOS_MONO_PATH = MONO_PATH; - INCLUDE_IOS = make_config.ContainsKey ("INCLUDE_IOS") && !string.IsNullOrEmpty (make_config ["INCLUDE_IOS"]); - INCLUDE_TVOS = make_config.ContainsKey ("INCLUDE_TVOS") && !string.IsNullOrEmpty (make_config ["INCLUDE_TVOS"]); - JENKINS_RESULTS_DIRECTORY = make_config ["JENKINS_RESULTS_DIRECTORY"]; - INCLUDE_WATCH = make_config.ContainsKey ("INCLUDE_WATCH") && !string.IsNullOrEmpty (make_config ["INCLUDE_WATCH"]); - INCLUDE_MAC = make_config.ContainsKey ("INCLUDE_MAC") && !string.IsNullOrEmpty (make_config ["INCLUDE_MAC"]); - MAC_DESTDIR = make_config ["MAC_DESTDIR"]; - IOS_DESTDIR = make_config ["IOS_DESTDIR"]; - if (string.IsNullOrEmpty (SdkRoot)) - SdkRoot = make_config ["XCODE_DEVELOPER_ROOT"]; - MONO_IOS_SDK_DESTDIR = make_config ["MONO_IOS_SDK_DESTDIR"]; - MONO_MAC_SDK_DESTDIR = make_config ["MONO_MAC_SDK_DESTDIR"]; - ENABLE_XAMARIN = make_config.ContainsKey ("ENABLE_XAMARIN") && !string.IsNullOrEmpty (make_config ["ENABLE_XAMARIN"]); - DOTNET = make_config ["DOTNET"]; - } - int AutoConfigureMac (bool generate_projects) { int rv = 0; @@ -480,7 +427,7 @@ namespace Xharness BCLTodayExtensionTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "bcl-test", "templates", "today")); } - Dictionary make_config = new Dictionary (); + // Dictionary make_config = new Dictionary (); IEnumerable FindConfigFiles (string name) { var dir = Path.GetFullPath (RootDirectory); @@ -492,20 +439,24 @@ namespace Xharness } } - void ParseConfigFiles () + Dictionary ParseConfigFiles () { - ParseConfigFiles (FindConfigFiles (useSystemXamarinIOSMac ? "test-system.config" : "test.config")); - ParseConfigFiles (FindConfigFiles ("Make.config.local")); - ParseConfigFiles (FindConfigFiles ("Make.config")); + var configuration = new Dictionary (); + foreach (var file in GetConfigFiles ()) { + ParseConfigFile (file, configuration); + } + + return configuration; } - void ParseConfigFiles (IEnumerable files) + IEnumerable GetConfigFiles () { - foreach (var file in files) - ParseConfigFile (file); + return FindConfigFiles (useSystemXamarinIOSMac ? "test-system.config" : "test.config") + .Concat (FindConfigFiles ("Make.config")) + .Concat (FindConfigFiles ("Make.config.local")); } - void ParseConfigFile (string file) + void ParseConfigFile (string file, Dictionary configuration) { if (string.IsNullOrEmpty (file)) return; @@ -514,9 +465,10 @@ namespace Xharness var eq = line.IndexOf ('='); if (eq == -1) continue; + var key = line.Substring (0, eq); - if (!make_config.ContainsKey (key)) - make_config [key] = line.Substring (eq + 1); + if (!configuration.ContainsKey (key)) + configuration [key] = line.Substring (eq + 1); } } @@ -604,22 +556,7 @@ namespace Xharness HarnessLog = new ConsoleLog (); foreach (var project in IOSTestProjects) { - var runner = new AppRunner (ProcessManager, - new AppBundleInformationParser (), - new SimulatorsLoaderFactory (this, ProcessManager), - new SimpleListenerFactory (), - new DeviceLoaderFactory (this, ProcessManager), - new CrashSnapshotReporterFactory (ProcessManager, XcodeRoot, MlaunchPath), - new CaptureLogFactory (), - new DeviceLogCapturerFactory (ProcessManager, XcodeRoot, MlaunchPath), - new TestReporterFactory (), - target, - this, - HarnessLog, - new Logs (LogDirectory), - project.Path, - buildConfiguration); - + var runner = CreateAppRunner (project); using (var install_log = new AppInstallMonitorLog (runner.MainLog)) { var rv = runner.InstallAsync (install_log.CancellationToken).Result; if (!rv.Succeeded) @@ -635,22 +572,7 @@ namespace Xharness HarnessLog = new ConsoleLog (); foreach (var project in IOSTestProjects) { - var runner = new AppRunner (ProcessManager, - new AppBundleInformationParser (), - new SimulatorsLoaderFactory (this, ProcessManager), - new SimpleListenerFactory (), - new DeviceLoaderFactory (this, ProcessManager), - new CrashSnapshotReporterFactory (ProcessManager, XcodeRoot, MlaunchPath), - new CaptureLogFactory (), - new DeviceLogCapturerFactory (ProcessManager, XcodeRoot, MlaunchPath), - new TestReporterFactory (), - target, - this, - HarnessLog, - new Logs (LogDirectory), - project.Path, - buildConfiguration); - + var runner = CreateAppRunner (project); var rv = runner.UninstallAsync ().Result; if (!rv.Succeeded) return rv.ExitCode; @@ -664,22 +586,7 @@ namespace Xharness HarnessLog = new ConsoleLog (); foreach (var project in IOSTestProjects) { - var runner = new AppRunner (ProcessManager, - new AppBundleInformationParser (), - new SimulatorsLoaderFactory (this, ProcessManager), - new SimpleListenerFactory (), - new DeviceLoaderFactory (this, ProcessManager), - new CrashSnapshotReporterFactory (ProcessManager, XcodeRoot, MlaunchPath), - new CaptureLogFactory (), - new DeviceLogCapturerFactory (ProcessManager, XcodeRoot, MlaunchPath), - new TestReporterFactory (), - target, - this, - HarnessLog, - new Logs (LogDirectory), - project.Path, - buildConfiguration); - + var runner = CreateAppRunner (project); var rv = runner.RunAsync ().Result; if (rv != 0) return rv; @@ -729,7 +636,6 @@ namespace Xharness public int Execute () { - LoadConfig (); switch (Action) { case HarnessAction.Configure: return Configure (); @@ -753,7 +659,7 @@ namespace Xharness AutoConfigureMac (false); } - var jenkins = new Jenkins.Jenkins (this, ProcessManager, ResultParser); + var jenkins = new Jenkins.Jenkins (this, processManager, ResultParser); return jenkins.Run (); } @@ -807,9 +713,23 @@ namespace Xharness } } - public Task ExecuteXcodeCommandAsync (string executable, IList args, ILog log, TimeSpan timeout) + private AppRunner CreateAppRunner (TestProject project) { - return ProcessManager.ExecuteCommandAsync (Path.Combine (XcodeRoot, "Contents", "Developer", "usr", "bin", executable), args, log, timeout: timeout); + return new AppRunner (processManager, + new AppBundleInformationParser (), + new SimulatorsLoaderFactory (processManager), + new SimpleListenerFactory (), + new DeviceLoaderFactory (processManager), + new CrashSnapshotReporterFactory (processManager), + new CaptureLogFactory (), + new DeviceLogCapturerFactory (processManager), + new TestReporterFactory (), + target, + this, + HarnessLog, + new Logs (LogDirectory), + project.Path, + buildConfiguration); } } } diff --git a/tests/xharness/IAppRunner.cs b/tests/xharness/IAppRunner.cs index c77e9205f2..8dc0007e5a 100644 --- a/tests/xharness/IAppRunner.cs +++ b/tests/xharness/IAppRunner.cs @@ -7,11 +7,11 @@ namespace Xharness { // common interface that contains the basic info needed by the test result to be able to parse the results and // log all the required data. public interface IAppRunner { + IProcessManager ProcessManager { get; } AppBundleInformation AppInformation { get; } BuildToolTask BuildTask { get; } TimeSpan GetNewTimeout (); double LaunchTimeout { get; } - IProcessManager ProcessManager { get; } ILogs Logs { get; } ILog MainLog { get; } RunMode RunMode { get; } diff --git a/tests/xharness/Jenkins/Jenkins.cs b/tests/xharness/Jenkins/Jenkins.cs index 5e6ba01bf2..b5af36697c 100644 --- a/tests/xharness/Jenkins/Jenkins.cs +++ b/tests/xharness/Jenkins/Jenkins.cs @@ -103,15 +103,15 @@ namespace Xharness.Jenkins this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); this.resultParser = resultParser ?? throw new ArgumentNullException (nameof (resultParser)); Harness = harness ?? throw new ArgumentNullException (nameof (harness)); - simulators = new Simulators (harness, processManager); - devices = new Devices (harness, processManager); + simulators = new Simulators (processManager); + devices = new Devices (processManager); } Task LoadAsync (ref ILog log, ILoadAsync loadable, string name) { - loadable.Harness = Harness; if (log == null) log = Logs.Create ($"{name}-list-{Helpers.Timestamp}.log", $"{name} Listing"); + log.Description = $"{name} Listing (in progress)"; var capturedLog = log; @@ -481,7 +481,7 @@ namespace Xharness.Jenkins clone.Xml.Save (clone.Path); }); - var build = new MSBuildTask { + var build = new MSBuildTask (processManager) { Jenkins = this, TestProject = clone, ProjectConfiguration = configuration, @@ -530,7 +530,7 @@ namespace Xharness.Jenkins configurations = new string [] { "Debug" }; foreach (var config in configurations) { foreach (var pair in ps) { - var derived = new MSBuildTask () { + var derived = new MSBuildTask (processManager) { Jenkins = this, ProjectConfiguration = config, ProjectPlatform = "iPhoneSimulator", @@ -584,7 +584,7 @@ namespace Xharness.Jenkins projectTasks.Clear (); if (!project.SkipiOSVariation) { - var build64 = new MSBuildTask { + var build64 = new MSBuildTask (processManager) { Jenkins = this, ProjectConfiguration = "Debug64", ProjectPlatform = "iPhone", @@ -594,7 +594,7 @@ namespace Xharness.Jenkins build64.CloneTestProject (project); projectTasks.Add (new RunDeviceTask (devices, build64, processManager, devices.Connected64BitIOS.Where (d => d.IsSupported (project))) { Ignored = !IncludeiOS64 }); - var build32 = new MSBuildTask { + var build32 = new MSBuildTask (processManager) { Jenkins = this, ProjectConfiguration = project.Name != "dont link" ? "Debug32" : "Release32", ProjectPlatform = "iPhone", @@ -605,7 +605,7 @@ namespace Xharness.Jenkins projectTasks.Add (new RunDeviceTask (devices, build32, processManager, devices.Connected32BitIOS.Where (d => d.IsSupported (project))) { Ignored = !IncludeiOS32 }); var todayProject = project.AsTodayExtensionProject (); - var buildToday = new MSBuildTask { + var buildToday = new MSBuildTask (processManager) { Jenkins = this, ProjectConfiguration = "Debug64", ProjectPlatform = "iPhone", @@ -618,7 +618,7 @@ namespace Xharness.Jenkins if (!project.SkiptvOSVariation) { var tvOSProject = project.AsTvOSProject (); - var buildTV = new MSBuildTask { + var buildTV = new MSBuildTask (processManager) { Jenkins = this, ProjectConfiguration = "Debug", ProjectPlatform = "iPhone", @@ -632,7 +632,7 @@ namespace Xharness.Jenkins if (!project.SkipwatchOSVariation) { var watchOSProject = project.AsWatchOSProject (); if (!project.SkipwatchOS32Variation) { - var buildWatch32 = new MSBuildTask { + var buildWatch32 = new MSBuildTask (processManager) { Jenkins = this, ProjectConfiguration = "Debug32", ProjectPlatform = "iPhone", @@ -644,7 +644,7 @@ namespace Xharness.Jenkins } if (!project.SkipwatchOSARM64_32Variation) { - var buildWatch64_32 = new MSBuildTask { + var buildWatch64_32 = new MSBuildTask (processManager) { Jenkins = this, ProjectConfiguration = "Release64_32", // We don't support Debug for ARM64_32 yet. ProjectPlatform = "iPhone", @@ -720,7 +720,7 @@ namespace Xharness.Jenkins void SelectTestsByModifiedFiles (int pull_request) { - var files = GitHub.GetModifiedFiles (Harness, pull_request); + var files = GitHub.GetModifiedFiles (processManager, Harness, pull_request); MainLog.WriteLine ("Found {0} modified file(s) in the pull request #{1}.", files.Count (), pull_request); foreach (var f in files) @@ -938,9 +938,9 @@ namespace Xharness.Jenkins //Tasks.AddRange (await CreateRunSimulatorTasksAsync ()); - var crashReportSnapshotFactory = new CrashSnapshotReporterFactory (processManager, Harness.XcodeRoot, Harness.MlaunchPath); + var crashReportSnapshotFactory = new CrashSnapshotReporterFactory (processManager); - var buildiOSMSBuild_net461 = new MSBuildTask () + var buildiOSMSBuild_net461 = new MSBuildTask (processManager) { Jenkins = this, TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "Xamarin.iOS.Tasks.Tests.csproj"))), @@ -965,7 +965,7 @@ namespace Xharness.Jenkins }; Tasks.Add (nunitExecutioniOSMSBuild_net461); - var buildiOSMSBuild_netstandard2 = new MSBuildTask () { + var buildiOSMSBuild_netstandard2 = new MSBuildTask (processManager) { Jenkins = this, TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "Xamarin.iOS.Tasks.Tests.csproj"))), SpecifyPlatform = false, @@ -988,7 +988,7 @@ namespace Xharness.Jenkins }; Tasks.Add (nunitExecutioniOSMSBuild_netstandard2); - var buildInstallSources = new MSBuildTask () + var buildInstallSources = new MSBuildTask (processManager) { Jenkins = this, TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "InstallSourcesTests.csproj"))), @@ -1039,7 +1039,7 @@ namespace Xharness.Jenkins throw new NotImplementedException (project.TargetFrameworkFlavors.ToString ()); } foreach (var config in configurations) { - MSBuildTask build = new MSBuildTask (); + MSBuildTask build = new MSBuildTask (processManager); build.Platform = platform; build.CloneTestProject (project); build.Jenkins = this; @@ -1082,7 +1082,7 @@ namespace Xharness.Jenkins } } - var buildMTouch = new MakeTask () + var buildMTouch = new MakeTask (processManager) { Jenkins = this, TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "mtouch", "mtouch.sln"))), @@ -1104,7 +1104,7 @@ namespace Xharness.Jenkins }; Tasks.Add (nunitExecutionMTouch); - var buildGenerator = new MakeTask { + var buildGenerator = new MakeTask (processManager) { Jenkins = this, TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "src", "generator.sln"))), SpecifyPlatform = false, @@ -1124,7 +1124,7 @@ namespace Xharness.Jenkins }; Tasks.Add (runGenerator); - var buildDotNetGenerator = new DotNetBuildTask { + var buildDotNetGenerator = new DotNetBuildTask (processManager) { Jenkins = this, TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "bgen", "bgen-tests.csproj"))), SpecifyPlatform = false, @@ -1140,7 +1140,7 @@ namespace Xharness.Jenkins }; Tasks.Add (runDotNetGenerator); - var run_mmp = new MakeTask + var run_mmp = new MakeTask (processManager) { Jenkins = this, Platform = TestPlatform.Mac, @@ -1159,7 +1159,7 @@ namespace Xharness.Jenkins run_mmp.Environment.Add ("BUILD_REVISION", "jenkins"); // This will print "@MonkeyWrench: AddFile: " lines, which we can use to get the log filenames. Tasks.Add (run_mmp); - var runMacBindingProject = new MakeTask + var runMacBindingProject = new MakeTask (processManager) { Jenkins = this, Platform = TestPlatform.Mac, @@ -1171,7 +1171,7 @@ namespace Xharness.Jenkins }; Tasks.Add (runMacBindingProject); - var buildXtroTests = new MakeTask { + var buildXtroTests = new MakeTask (processManager) { Jenkins = this, Platform = TestPlatform.All, TestName = "Xtro", @@ -1189,7 +1189,7 @@ namespace Xharness.Jenkins }; Tasks.Add (runXtroReporter); - var buildCecilTests = new MakeTask { + var buildCecilTests = new MakeTask (processManager) { Jenkins = this, Platform = TestPlatform.All, TestName = "Cecil", @@ -1209,7 +1209,7 @@ namespace Xharness.Jenkins }; Tasks.Add (runCecilTests); - var runDocsTests = new MakeTask { + var runDocsTests = new MakeTask (processManager) { Jenkins = this, Platform = TestPlatform.All, TestName = "Documentation", @@ -1220,7 +1220,7 @@ namespace Xharness.Jenkins }; Tasks.Add (runDocsTests); - var buildSampleTests = new MSBuildTask { + var buildSampleTests = new MSBuildTask (processManager) { Jenkins = this, TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "sampletester", "sampletester.sln"))), SpecifyPlatform = false, @@ -1253,7 +1253,7 @@ namespace Xharness.Jenkins using (var process = new Process ()) { process.StartInfo.FileName = Harness.PeriodicCommand; process.StartInfo.Arguments = Harness.PeriodicCommandArguments; - var rv = await Harness.ProcessManager.RunAsync (process, periodic_loc, timeout: Harness.PeriodicCommandInterval); + var rv = await processManager.RunAsync (process, periodic_loc, timeout: Harness.PeriodicCommandInterval); if (!rv.Succeeded) periodic_loc.WriteLine ($"Periodic command failed with exit code {rv.ExitCode} (Timed out: {rv.TimedOut})"); } @@ -1293,7 +1293,7 @@ namespace Xharness.Jenkins // We can populate and build test-libraries in parallel. var populate = Task.Run (async () => { - var simulator = new SimulatorDevice (Harness, processManager); + var simulator = new SimulatorDevice (processManager, new TCCDatabase (processManager)); await simulator.KillEverythingAsync (MainLog); await PopulateTasksAsync (); populating = false; @@ -1328,7 +1328,7 @@ namespace Xharness.Jenkins var sb = new StringBuilder (); var callback_log = new CallbackLog ((v) => sb.Append (v)); var log = Log.CreateAggregatedLog (callback_log, MainLog); - return Harness.ProcessManager.ExecuteCommandAsync ("make", new [] { "all", $"-j{Environment.ProcessorCount}", "-C", Path.Combine (Harness.RootDirectory, "test-libraries") }, log, TimeSpan.FromMinutes (10)).ContinueWith ((v) => { + return processManager.ExecuteCommandAsync ("make", new [] { "all", $"-j{Environment.ProcessorCount}", "-C", Path.Combine (Harness.RootDirectory, "test-libraries") }, log, TimeSpan.FromMinutes (10)).ContinueWith ((v) => { var per = v.Result; if (!per.Succeeded) { // Only show the log if something went wrong. diff --git a/tests/xharness/Jenkins/TestTasks/BuildProjectTask.cs b/tests/xharness/Jenkins/TestTasks/BuildProjectTask.cs index 6e376f9da3..366a049c33 100644 --- a/tests/xharness/Jenkins/TestTasks/BuildProjectTask.cs +++ b/tests/xharness/Jenkins/TestTasks/BuildProjectTask.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Threading.Tasks; using System.Xml; +using Xharness.Execution; using Xharness.Logging; using Xharness.Utilities; @@ -13,6 +14,10 @@ namespace Xharness.Jenkins.TestTasks { public string SolutionPath; + protected BuildProjectTask (IProcessManager processManager) : base (processManager) + { + } + public bool RestoreNugets { get { return TestProject.RestoreNugetsInProject || !string.IsNullOrEmpty (SolutionPath); diff --git a/tests/xharness/Jenkins/TestTasks/BuildToolTask.cs b/tests/xharness/Jenkins/TestTasks/BuildToolTask.cs index 38e6bb41b9..88c7bc27da 100644 --- a/tests/xharness/Jenkins/TestTasks/BuildToolTask.cs +++ b/tests/xharness/Jenkins/TestTasks/BuildToolTask.cs @@ -6,9 +6,15 @@ namespace Xharness.Jenkins.TestTasks { public abstract class BuildToolTask : TestTask { + protected readonly IProcessManager ProcessManager; + public bool SpecifyPlatform = true; public bool SpecifyConfiguration = true; - public IProcessManager ProcessManager { get; set; } = new ProcessManager (); + + protected BuildToolTask (IProcessManager processManager) + { + ProcessManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); + } public override string Mode { get { return Platform.ToString (); } diff --git a/tests/xharness/Jenkins/TestTasks/DotNetBuildTask.cs b/tests/xharness/Jenkins/TestTasks/DotNetBuildTask.cs index 3a59966be3..b0e0417baf 100644 --- a/tests/xharness/Jenkins/TestTasks/DotNetBuildTask.cs +++ b/tests/xharness/Jenkins/TestTasks/DotNetBuildTask.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; -using System.Diagnostics; +using Xharness.Execution; namespace Xharness.Jenkins.TestTasks { class DotNetBuildTask : MSBuildTask { - public DotNetBuildTask () + public DotNetBuildTask (IProcessManager processManager) : base (processManager) { SetDotNetEnvironmentVariables (Environment); } diff --git a/tests/xharness/Jenkins/TestTasks/MSBuildTask.cs b/tests/xharness/Jenkins/TestTasks/MSBuildTask.cs index 5216ccb507..51136ee3e4 100644 --- a/tests/xharness/Jenkins/TestTasks/MSBuildTask.cs +++ b/tests/xharness/Jenkins/TestTasks/MSBuildTask.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using System.Xml; +using Xharness.Execution; using Xharness.Logging; using Xharness.Utilities; @@ -31,6 +32,10 @@ namespace Xharness.Jenkins.TestTasks } } + public MSBuildTask (IProcessManager processManager) : base (processManager) + { + } + protected override async Task ExecuteAsync () { using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) { diff --git a/tests/xharness/Jenkins/TestTasks/MakeTask.cs b/tests/xharness/Jenkins/TestTasks/MakeTask.cs index e508fd48d8..e639dd4f7c 100644 --- a/tests/xharness/Jenkins/TestTasks/MakeTask.cs +++ b/tests/xharness/Jenkins/TestTasks/MakeTask.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Threading.Tasks; +using Xharness.Execution; using Xharness.Logging; namespace Xharness.Jenkins.TestTasks @@ -11,6 +12,10 @@ namespace Xharness.Jenkins.TestTasks public string WorkingDirectory; public TimeSpan Timeout = TimeSpan.FromMinutes (5); + public MakeTask (IProcessManager processManager) : base (processManager) + { + } + protected override async Task ExecuteAsync () { using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) { diff --git a/tests/xharness/Jenkins/TestTasks/RunDeviceTask.cs b/tests/xharness/Jenkins/TestTasks/RunDeviceTask.cs index 6a1c9c5ebf..ebc37ad6a2 100644 --- a/tests/xharness/Jenkins/TestTasks/RunDeviceTask.cs +++ b/tests/xharness/Jenkins/TestTasks/RunDeviceTask.cs @@ -11,9 +11,9 @@ namespace Xharness.Jenkins.TestTasks { class RunDeviceTask : RunXITask { - readonly IProcessManager processManager = new ProcessManager (); readonly IResultParser resultParser = new XmlResultParser (); readonly IDeviceLoader devices; + AppInstallMonitorLog install_log; public override string ProgressMessage { @@ -81,14 +81,14 @@ namespace Xharness.Jenkins.TestTasks CompanionDevice = devices.FindCompanionDevice (Jenkins.DeviceLoadLog, Device); Jenkins.MainLog.WriteLine ("Acquired device '{0}' for '{1}'", Device.Name, ProjectFile); - runner = new AppRunner (processManager, + runner = new AppRunner (ProcessManager, new AppBundleInformationParser (), - new SimulatorsLoaderFactory (Harness, processManager), + new SimulatorsLoaderFactory (ProcessManager), new SimpleListenerFactory (), - new DeviceLoaderFactory (Harness, processManager), - new CrashSnapshotReporterFactory (ProcessManager, Harness.XcodeRoot, Harness.MlaunchPath), + new DeviceLoaderFactory (ProcessManager), + new CrashSnapshotReporterFactory (ProcessManager), new CaptureLogFactory (), - new DeviceLogCapturerFactory (processManager, Harness.XcodeRoot, Harness.MlaunchPath), + new DeviceLogCapturerFactory (ProcessManager), new TestReporterFactory (), AppRunnerTarget, Harness, @@ -148,14 +148,14 @@ namespace Xharness.Jenkins.TestTasks // nor will it close & reopen the today app (but launching the main app // will do both of these things, preparing the device for launching the today extension). - AppRunner todayRunner = new AppRunner (processManager, + AppRunner todayRunner = new AppRunner (ProcessManager, new AppBundleInformationParser (), - new SimulatorsLoaderFactory (Harness, processManager), + new SimulatorsLoaderFactory (ProcessManager), new SimpleListenerFactory (), - new DeviceLoaderFactory (Harness, processManager), - new CrashSnapshotReporterFactory (ProcessManager, Harness.XcodeRoot, Harness.MlaunchPath), + new DeviceLoaderFactory (ProcessManager), + new CrashSnapshotReporterFactory (ProcessManager), new CaptureLogFactory (), - new DeviceLogCapturerFactory (processManager, Harness.XcodeRoot, Harness.MlaunchPath), + new DeviceLogCapturerFactory (ProcessManager), new TestReporterFactory (), AppRunnerTarget, Harness, diff --git a/tests/xharness/Jenkins/TestTasks/RunSimulatorTask.cs b/tests/xharness/Jenkins/TestTasks/RunSimulatorTask.cs index c05441e05f..19892b6f8b 100644 --- a/tests/xharness/Jenkins/TestTasks/RunSimulatorTask.cs +++ b/tests/xharness/Jenkins/TestTasks/RunSimulatorTask.cs @@ -13,7 +13,6 @@ namespace Xharness.Jenkins.TestTasks { class RunSimulatorTask : RunXITask { - readonly IProcessManager processManager = new ProcessManager (); readonly ISimulatorsLoader simulators; public IAcquiredResource AcquiredResource; @@ -77,14 +76,14 @@ namespace Xharness.Jenkins.TestTasks await FindSimulatorAsync (); var clean_state = false;//Platform == TestPlatform.watchOS; - runner = new AppRunner (processManager, + runner = new AppRunner (ProcessManager, new AppBundleInformationParser (), - new SimulatorsLoaderFactory (Harness, processManager), + new SimulatorsLoaderFactory (ProcessManager), new SimpleListenerFactory (), - new DeviceLoaderFactory (Harness, processManager), - new CrashSnapshotReporterFactory (ProcessManager, Harness.XcodeRoot, Harness.MlaunchPath), + new DeviceLoaderFactory (ProcessManager), + new CrashSnapshotReporterFactory (ProcessManager), new CaptureLogFactory (), - new DeviceLogCapturerFactory (processManager, Harness.XcodeRoot, Harness.MlaunchPath), + new DeviceLogCapturerFactory (ProcessManager), new TestReporterFactory (), AppRunnerTarget, Harness, diff --git a/tests/xharness/Program.cs b/tests/xharness/Program.cs index d9fbc3694d..bdbf076529 100644 --- a/tests/xharness/Program.cs +++ b/tests/xharness/Program.cs @@ -105,7 +105,7 @@ namespace Xharness { // XS sets this, which breaks pretty much everything if it doesn't match what was passed to --sdkroot. Environment.SetEnvironmentVariable ("XCODE_DEVELOPER_DIR_PATH", null); - var harness = new Harness (new ProcessManager(), new XmlResultParser (), action, configuration); + var harness = new Harness (new XmlResultParser (), action, configuration); return harness.Execute (); } diff --git a/tests/xharness/Xharness.Tests/Execution/Tests/ProcessManagerTests.cs b/tests/xharness/Xharness.Tests/Execution/Tests/ProcessManagerTests.cs index 0abd0034ea..cf38e98dab 100644 --- a/tests/xharness/Xharness.Tests/Execution/Tests/ProcessManagerTests.cs +++ b/tests/xharness/Xharness.Tests/Execution/Tests/ProcessManagerTests.cs @@ -40,7 +40,7 @@ namespace Xharness.Tests.Execution.Tests { stdoutLog = new LogFile ("my stdout log", stdoutLogPath); stderrLog = new LogFile ("my stderr log", stderrLogPath); dummyProcess = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "DummyTestProcess.exe"); - manager = new ProcessManager (); + manager = new ProcessManager ("/path/to/xcode", "/path/to/mlaunch"); testProcess = new Process (); testProcess.StartInfo.FileName = "mono"; } @@ -112,7 +112,7 @@ namespace Xharness.Tests.Execution.Tests { { var source = new CancellationTokenSource (); testProcess.StartInfo.Arguments = $"{dummyProcess} --exit-code={resultCode} --timeout={timeoutCount} --stdout=\"{stdoutMessage}\" --stderr=\"{stderrMessage}\""; - var result = await manager.RunAsync (testProcess, executionLog, source.Token); + var result = await manager.RunAsync (testProcess, executionLog, executionLog, executionLog, cancellationToken: source.Token); if (!timeout) Assert.AreEqual (resultCode, result.ExitCode, "exit code"); Assert.AreEqual (success, result.Succeeded, "success"); diff --git a/tests/xharness/Xharness.Tests/Hardware/Tests/DevicesTest.cs b/tests/xharness/Xharness.Tests/Hardware/Tests/DevicesTest.cs index 95d052f5f3..e7f1a5417d 100644 --- a/tests/xharness/Xharness.Tests/Hardware/Tests/DevicesTest.cs +++ b/tests/xharness/Xharness.Tests/Hardware/Tests/DevicesTest.cs @@ -20,16 +20,14 @@ namespace Xharness.Tests.Hardware.Tests { Devices devices; string mlaunchPath; string sdkPath; - Mock harness; Mock processManager; Mock executionLog; [SetUp] public void SetUp () { - harness = new Mock (); processManager = new Mock (); - devices = new Devices (harness.Object, processManager.Object); + devices = new Devices (processManager.Object); executionLog = new Mock (); mlaunchPath = "/usr/bin/mlaunch"; // any will be ok, is mocked sdkPath = "/Applications/Xcode.app"; @@ -38,7 +36,6 @@ namespace Xharness.Tests.Hardware.Tests { [TearDown] public void TearDown () { - harness = null; processManager = null; executionLog = null; devices = null; @@ -50,10 +47,7 @@ namespace Xharness.Tests.Hardware.Tests { { string processPath = null; MlaunchArguments passedArguments = null; - // set the expectations of the mocks to get an error when - // executing the process - harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath); - harness.Setup (h => h.XcodeRoot).Returns (sdkPath); + // moq It.Is is not working as nicelly as we would like it, we capture data and use asserts processManager.Setup (p => p.RunAsync (It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny>(), It.IsAny (), It.IsAny ())) .Returns, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { @@ -87,10 +81,7 @@ namespace Xharness.Tests.Hardware.Tests { { string processPath = null; MlaunchArguments passedArguments = null; - // set the expectations of the mocks to get an error when - // executing the process - harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath); - harness.Setup (h => h.XcodeRoot).Returns (sdkPath); + // moq It.Is is not working as nicelly as we would like it, we capture data and use asserts processManager.Setup (p => p.RunAsync (It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny> (), It.IsAny (), It.IsAny ())) .Returns, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { diff --git a/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorDeviceTest.cs b/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorDeviceTest.cs index d29b78f69a..f0ad213651 100644 --- a/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorDeviceTest.cs +++ b/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorDeviceTest.cs @@ -14,7 +14,6 @@ namespace Xharness.Tests.Hardware.Tests { Mock executionLog; Mock processManager; - Mock harness; SimulatorDevice simulator; [SetUp] @@ -22,8 +21,7 @@ namespace Xharness.Tests.Hardware.Tests { { executionLog = new Mock (); processManager = new Mock (); - harness = new Mock (); - simulator = new SimulatorDevice (harness.Object, processManager.Object) { + simulator = new SimulatorDevice (processManager.Object, new TCCDatabase (processManager.Object)) { UDID = Guid.NewGuid ().ToString () }; } @@ -57,10 +55,10 @@ namespace Xharness.Tests.Hardware.Tests { { // just call and verify the correct args are pass await simulator.EraseAsync (executionLog.Object); - harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny (), It.IsAny ())); - harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "erase").Count () == 2), It.IsAny (), It.IsAny ())); - harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "boot").Count () == 2), It.IsAny (), It.IsAny ())); - harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny (), It.IsAny ())); + processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny (), It.IsAny ())); + processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "erase").Count () == 2), It.IsAny (), It.IsAny ())); + processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "boot").Count () == 2), It.IsAny (), It.IsAny ())); + processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny (), It.IsAny ())); } @@ -69,7 +67,7 @@ namespace Xharness.Tests.Hardware.Tests { { await simulator.ShutdownAsync (executionLog.Object); // just call and verify the correct args are pass - harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny (), It.IsAny ())); + processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is (s => s == "simctl"), It.Is (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny (), It.IsAny ())); } [Test] @@ -81,7 +79,7 @@ namespace Xharness.Tests.Hardware.Tests { return args.Where (a => toKill.Contains (a)).Count () == toKill.Count; }; - var simulator = new SimulatorDevice (Mock.Of (), processManager.Object); + var simulator = new SimulatorDevice (processManager.Object, new TCCDatabase (processManager.Object)); await simulator.KillEverythingAsync (executionLog.Object); // verify that all the diff process have been killed making sure args are correct diff --git a/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorsTest.cs b/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorsTest.cs index a9b6291741..3b0b7d6fa3 100644 --- a/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorsTest.cs +++ b/tests/xharness/Xharness.Tests/Hardware/Tests/SimulatorsTest.cs @@ -19,7 +19,6 @@ namespace Xharness.Tests.Hardware.Tests { string mlaunchPath; string sdkPath; - Mock harness; Mock executionLog; Mock processManager; Simulators simulators; @@ -29,10 +28,9 @@ namespace Xharness.Tests.Hardware.Tests { { mlaunchPath = "/usr/bin/mlaunch"; // any will be ok, is mocked sdkPath = "/Applications/Xcode.app"; - harness = new Mock (); executionLog = new Mock (); processManager = new Mock (); - simulators = new Simulators (harness.Object, processManager.Object); + simulators = new Simulators (processManager.Object); } [TearDown] @@ -49,10 +47,7 @@ namespace Xharness.Tests.Hardware.Tests { { string processPath = null; MlaunchArguments passedArguments = null; - // set the expectations of the mocks to get an error when - // executing the process - harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath); - harness.Setup (h => h.XcodeRoot).Returns (sdkPath); + // moq It.Is is not working as nicelly as we would like it, we capture data and use asserts processManager.Setup (p => p.RunAsync (It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny> (), It.IsAny (), It.IsAny ())) .Returns, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { @@ -97,10 +92,7 @@ namespace Xharness.Tests.Hardware.Tests { { string processPath = null; MlaunchArguments passedArguments = null; - // set the expectations of the mocks to get an error when - // executing the process - harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath); - harness.Setup (h => h.XcodeRoot).Returns (sdkPath); + // moq It.Is is not working as nicelly as we would like it, we capture data and use asserts processManager.Setup (p => p.RunAsync (It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny> (), It.IsAny (), It.IsAny ())) .Returns, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { @@ -141,12 +133,9 @@ namespace Xharness.Tests.Hardware.Tests { { string processPath = null; MlaunchArguments passedArguments = null; - // set the expectations of the mocks to get an error when - // executing the process - harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath); - harness.Setup (h => h.XcodeRoot).Returns (sdkPath); - harness - .Setup (h => h.ExecuteXcodeCommandAsync ("simctl", It.Is (args => args [0] == "create"), executionLog.Object, TimeSpan.FromMinutes (1))) + + processManager + .Setup (h => h.ExecuteXcodeCommandAsync ("simctl", It.Is (args => args[0] == "create"), executionLog.Object, TimeSpan.FromMinutes (1))) .ReturnsAsync (new ProcessExecutionResult () { ExitCode = 0 }); // moq It.Is is not working as nicelly as we would like it, we capture data and use asserts diff --git a/tests/xharness/Xharness.Tests/Hardware/Tests/TCCDatabaseTests.cs b/tests/xharness/Xharness.Tests/Hardware/Tests/TCCDatabaseTests.cs index 8a1ba9062d..bd9b60b3c0 100644 --- a/tests/xharness/Xharness.Tests/Hardware/Tests/TCCDatabaseTests.cs +++ b/tests/xharness/Xharness.Tests/Hardware/Tests/TCCDatabaseTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -25,9 +24,7 @@ namespace Xharness.Tests.Hardware.Tests { public void SetUp () { processManager = new Mock (); - database = new TCCDatabase { - ProcessManager = processManager.Object, - }; + database = new TCCDatabase (processManager.Object); executionLog = new Mock (); simRuntime = "com.apple.CoreSimulator.SimRuntime.iOS-12-1"; dataPath = "/path/to/my/data"; diff --git a/tests/xharness/Xharness.Tests/Tests/AppRunnerTests.cs b/tests/xharness/Xharness.Tests/Tests/AppRunnerTests.cs index 279284aaa4..f037b06473 100644 --- a/tests/xharness/Xharness.Tests/Tests/AppRunnerTests.cs +++ b/tests/xharness/Xharness.Tests/Tests/AppRunnerTests.cs @@ -218,9 +218,7 @@ namespace Xharness.Tests { [Test] public async Task InstallOnDeviceTest () { - var harness = Mock.Of (x => x.XcodeRoot == "/path/to/xcode" - && x.MlaunchPath == "/path/to/mlaunch" - && x.Verbosity == 2); + var harness = Mock.Of (x => x.Verbosity == 2); var processResult = new ProcessExecutionResult () { ExitCode = 1, TimedOut = false }; processManager.SetReturnsDefault (Task.FromResult (processResult)); @@ -250,13 +248,10 @@ namespace Xharness.Tests { // Verify Assert.AreEqual (1, result.ExitCode); - var expectedArgs = $"--sdkroot /path/to/xcode -v -v -v " + - $"--installdev {StringUtils.FormatArguments (appPath)} " + - $"--devname \"Test iPad\""; + var expectedArgs = $"-v -v -v --installdev {StringUtils.FormatArguments (appPath)} --devname \"Test iPad\""; processManager.Verify (x => x.ExecuteCommandAsync ( - "/path/to/mlaunch", - It.Is (args => args.AsCommandLine () == expectedArgs), + It.Is (args => args.AsCommandLine() == expectedArgs), mainLog.Object, TimeSpan.FromHours (1), null, @@ -266,9 +261,7 @@ namespace Xharness.Tests { [Test] public async Task UninstallFromDeviceTest () { - var harness = Mock.Of (x => x.XcodeRoot == "/path/to/xcode" - && x.MlaunchPath == "/path/to/mlaunch" - && x.Verbosity == 1); + var harness = Mock.Of (x => x.Verbosity == 1); var processResult = new ProcessExecutionResult () { ExitCode = 3, TimedOut = false }; processManager.SetReturnsDefault (Task.FromResult (processResult)); @@ -297,13 +290,10 @@ namespace Xharness.Tests { // Verify Assert.AreEqual (3, result.ExitCode); - var expectedArgs = $"--sdkroot /path/to/xcode -v -v " + - $"--uninstalldevbundleid {StringUtils.FormatArguments (appName)} " + - $"--devname \"Test iPad\""; + var expectedArgs = $"-v -v --uninstalldevbundleid {StringUtils.FormatArguments (appName)} --devname \"Test iPad\""; processManager.Verify (x => x.ExecuteCommandAsync ( - "/path/to/mlaunch", - It.Is (args => args.AsCommandLine () == expectedArgs), + It.Is (args => args.AsCommandLine() == expectedArgs), mainLog.Object, TimeSpan.FromMinutes (1), null, @@ -461,8 +451,7 @@ namespace Xharness.Tests { processManager .Setup (x => x.ExecuteCommandAsync ( - mlaunchPath, - It.Is (args => args.AsCommandLine () == expectedArgs), + It.Is (args => args.AsCommandLine() == expectedArgs), mainLog.Object, TimeSpan.FromMinutes (harness.Timeout * 2), null, @@ -612,7 +601,7 @@ namespace Xharness.Tests { ips.Append (ipAddresses [i].ToString ()); } - var expectedArgs = $"--sdkroot {StringUtils.FormatArguments (xcodePath)} -v -v -argument=-connection-mode -argument=none " + + var expectedArgs = $"-v -v -argument=-connection-mode -argument=none " + $"-argument=-app-arg:-autostart -setenv=NUNIT_AUTOSTART=true -argument=-app-arg:-autoexit " + $"-setenv=NUNIT_AUTOEXIT=true -argument=-app-arg:-enablenetwork -setenv=NUNIT_ENABLE_NETWORK=true " + $"-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1 -argument=-app-arg:-hostname:{ips} -setenv=NUNIT_HOSTNAME={ips} " + @@ -622,7 +611,6 @@ namespace Xharness.Tests { processManager .Setup (x => x.ExecuteCommandAsync ( - mlaunchPath, It.Is (args => args.AsCommandLine () == expectedArgs), It.IsAny (), TimeSpan.FromMinutes (harness.Timeout * 2), @@ -633,18 +621,18 @@ namespace Xharness.Tests { var xmlResultFile = Path.ChangeExtension (testResultFilePath, "xml"); var testReporterFactory = new Mock (); var testReporter = new Mock (); - testReporterFactory.Setup (f => f.Create ( - It.IsAny (), - It.IsAny (), - It.IsAny (), - It.IsAny (), - It.IsAny (), - It.IsAny ())).Returns (testReporter.Object); + testReporterFactory + .Setup (f => f.Create ( + It.IsAny (), + "Test iPad", + It.IsAny (), + mainLog.Object, + snapshotReporter.Object, + It.IsAny ())) + .Returns (testReporter.Object); testReporter.Setup (r => r.Timeout).Returns (TimeSpan.FromMinutes (harness.Timeout * 2)); testReporter.Setup (r => r.TimeoutWatch).Returns (new System.Diagnostics.Stopwatch ()); - testReporter.Setup (r => r.ParseResult ()).Returns (() => { - return Task.FromResult<(TestExecutingResult, string)> ((TestExecutingResult.Succeeded, null)); - }); + testReporter.Setup (r => r.ParseResult ()).Returns (() => Task.FromResult<(TestExecutingResult, string)> ((TestExecutingResult.Succeeded, null))); testReporter.Setup (r => r.Success).Returns (true); // Act @@ -728,7 +716,7 @@ namespace Xharness.Tests { ips.Append (ipAddresses [i].ToString ()); } - var expectedArgs = $"--sdkroot {StringUtils.FormatArguments (xcodePath)} -v -v -argument=-connection-mode -argument=none " + + var expectedArgs = $"-v -v -argument=-connection-mode -argument=none " + $"-argument=-app-arg:-autostart -setenv=NUNIT_AUTOSTART=true -argument=-app-arg:-autoexit " + $"-setenv=NUNIT_AUTOEXIT=true -argument=-app-arg:-enablenetwork -setenv=NUNIT_ENABLE_NETWORK=true " + $"-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1 -argument=-app-arg:-hostname:{ips} -setenv=NUNIT_HOSTNAME={ips} " + @@ -738,7 +726,6 @@ namespace Xharness.Tests { processManager .Setup (x => x.ExecuteCommandAsync ( - mlaunchPath, It.Is (args => args.AsCommandLine () == expectedArgs), It.IsAny (), TimeSpan.FromMinutes (harness.Timeout * 2), @@ -749,13 +736,15 @@ namespace Xharness.Tests { var xmlResultFile = Path.ChangeExtension (testResultFilePath, "xml"); var testReporterFactory = new Mock (); var testReporter = new Mock (); - testReporterFactory.Setup (f => f.Create ( - It.IsAny (), - It.IsAny (), - It.IsAny (), - It.IsAny (), - It.IsAny (), - It.IsAny ())).Returns (testReporter.Object); + testReporterFactory + .Setup (f => f.Create ( + It.IsAny (), + "Test iPad", + It.IsAny (), + mainLog.Object, + snapshotReporter.Object, + It.IsAny ())) + .Returns (testReporter.Object); testReporter.Setup (r => r.Timeout).Returns (TimeSpan.FromMinutes (harness.Timeout * 2)); testReporter.Setup (r => r.TimeoutWatch).Returns (new System.Diagnostics.Stopwatch ()); testReporter.Setup (r => r.ParseResult ()).Returns (() => { @@ -802,11 +791,8 @@ namespace Xharness.Tests { IHarness GetMockedHarness () { return Mock.Of (x => x.Action == HarnessAction.Run - && x.XcodeRoot == xcodePath - && x.MlaunchPath == mlaunchPath && x.Verbosity == 1 && x.HarnessLog == mainLog.Object - && x.LogDirectory == logs.Object.Directory && x.InCI == false && x.EnvironmentVariables == new Dictionary () { { "env1", "value1" }, diff --git a/tests/xharness/Xharness.Tests/Tests/CrashSnapshotReporterTests.cs b/tests/xharness/Xharness.Tests/Tests/CrashSnapshotReporterTests.cs index 2f45f1faf5..39d23804a9 100644 --- a/tests/xharness/Xharness.Tests/Tests/CrashSnapshotReporterTests.cs +++ b/tests/xharness/Xharness.Tests/Tests/CrashSnapshotReporterTests.cs @@ -12,8 +12,8 @@ using Xharness.Utilities; namespace Xharness.Tests { [TestFixture] - public class CrashSnapshotReporterTests { - readonly string mlaunchPath = "./mlaunch"; + public class CrashReportSnapshotTests { + string tempXcodeRoot; string symbolicatePath; @@ -30,6 +30,9 @@ namespace Xharness.Tests { tempXcodeRoot = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ()); symbolicatePath = Path.Combine (tempXcodeRoot, "Contents", "SharedFrameworks", "DTDeviceKitBase.framework", "Versions", "A", "Resources"); + + processManager.SetupGet (x => x.XcodeRoot).Returns (tempXcodeRoot); + processManager.SetupGet (x => x.MlaunchPath).Returns ("/var/bin/mlaunch"); // Create fake place for device logs Directory.CreateDirectory (tempXcodeRoot); @@ -71,8 +74,6 @@ namespace Xharness.Tests { var snapshotReport = new CrashSnapshotReporter (processManager.Object, log.Object, logs.Object, - tempXcodeRoot, - mlaunchPath, true, deviceName, () => tempFilePath); @@ -91,11 +92,10 @@ namespace Xharness.Tests { // List of crash reports is retrieved processManager.Verify ( x => x.ExecuteCommandAsync ( - mlaunchPath, It.Is (args => args.AsCommandLine () == - StringUtils.FormatArguments ($"--list-crash-reports={tempFilePath}") + " " + - $"--sdkroot {StringUtils.FormatArguments (tempXcodeRoot)} " + - $"--devname {StringUtils.FormatArguments (deviceName)}"), + StringUtils.FormatArguments ( + $"--list-crash-reports={tempFilePath}") + " " + + $"--devname {StringUtils.FormatArguments (deviceName)}"), log.Object, TimeSpan.FromMinutes (1), null, @@ -105,12 +105,11 @@ namespace Xharness.Tests { // Device crash log is downloaded processManager.Verify ( x => x.ExecuteCommandAsync ( - mlaunchPath, It.Is (args => args.AsCommandLine () == - StringUtils.FormatArguments ($"--download-crash-report={deviceName}") + " " + - StringUtils.FormatArguments ($"--download-crash-report-to={crashLogPath}") + " " + - $"--sdkroot {StringUtils.FormatArguments (tempXcodeRoot)} " + - $"--devname {StringUtils.FormatArguments (deviceName)}"), + StringUtils.FormatArguments ( + $"--download-crash-report={deviceName}") + " " + + StringUtils.FormatArguments ($"--download-crash-report-to={crashLogPath}") + " " + + $"--devname {StringUtils.FormatArguments (deviceName)}"), log.Object, TimeSpan.FromMinutes (1), null,