[Harness] Remove Harness as a dependency (#8203)

This commit is contained in:
Přemek Vysoký 2020-03-27 17:41:31 +01:00 коммит произвёл GitHub
Родитель dddcba9dc4
Коммит 6209719f51
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 400 добавлений и 526 удалений

Просмотреть файл

@ -188,10 +188,6 @@ namespace Xharness {
var args = new MlaunchArguments (); var args = new MlaunchArguments ();
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
args.Add (new SdkRootArgument (harness.XcodeRoot));
}
for (int i = -1; i < harness.Verbosity; i++) for (int i = -1; i < harness.Verbosity; i++)
args.Add (new VerbosityArgument ()); 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 (); 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"); 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<ProcessExecutionResult> UninstallAsync () public async Task<ProcessExecutionResult> UninstallAsync ()
@ -217,17 +213,13 @@ namespace Xharness {
var args = new MlaunchArguments (); var args = new MlaunchArguments ();
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
args.Add (new SdkRootArgument (harness.XcodeRoot));
}
for (int i = -1; i < harness.Verbosity; i++) for (int i = -1; i < harness.Verbosity; i++)
args.Add (new VerbosityArgument ()); args.Add (new VerbosityArgument ());
args.Add (new UninstallAppFromDeviceArgument (AppInformation.BundleIdentifier)); args.Add (new UninstallAppFromDeviceArgument (AppInformation.BundleIdentifier));
args.Add (new DeviceNameArgument (companionDeviceName ?? deviceName)); 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); public TimeSpan GetNewTimeout () => TimeSpan.FromMinutes (harness.Timeout * timeoutMultiplier);
@ -241,10 +233,6 @@ namespace Xharness {
var args = new MlaunchArguments (); var args = new MlaunchArguments ();
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
args.Add (new SdkRootArgument (harness.XcodeRoot));
}
for (int i = -1; i < harness.Verbosity; i++) for (int i = -1; i < harness.Verbosity; i++)
args.Add (new VerbosityArgument ()); args.Add (new VerbosityArgument ());
@ -387,7 +375,7 @@ namespace Xharness {
MainLog.WriteLine ("Starting test run"); MainLog.WriteLine ("Starting test run");
await testReporter.CollectSimulatorResult ( 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 // cleanup after us
if (EnsureCleanSimulatorState) 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). // 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); var runLog = Log.CreateAggregatedLog (testReporter.CallbackLog, MainLog);
testReporter.TimeoutWatch.Start (); 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 { } finally {
deviceLogCapturer.StopCapture (); deviceLogCapturer.StopCapture ();
deviceSystemLog.Dispose (); deviceSystemLog.Dispose ();

Просмотреть файл

@ -5,6 +5,5 @@ using Xharness.Logging;
namespace Xharness.Collections{ namespace Xharness.Collections{
public interface ILoadAsync { public interface ILoadAsync {
Task LoadAsync (ILog log, bool include_locked, bool force); Task LoadAsync (ILog log, bool include_locked, bool force);
IHarness Harness { get; set; }
} }
} }

Просмотреть файл

@ -17,18 +17,14 @@ namespace Xharness
public class CrashSnapshotReporterFactory : ICrashSnapshotReporterFactory { public class CrashSnapshotReporterFactory : ICrashSnapshotReporterFactory {
readonly IProcessManager processManager; 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.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) => 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 { public interface ICrashSnapshotReporter {
@ -40,8 +36,6 @@ namespace Xharness
readonly IProcessManager processManager; readonly IProcessManager processManager;
readonly ILog log; readonly ILog log;
readonly ILogs logs; readonly ILogs logs;
readonly string xcodeRoot;
readonly string mlaunchPath;
readonly bool isDevice; readonly bool isDevice;
readonly string deviceName; readonly string deviceName;
readonly Func<string> tempFileProvider; readonly Func<string> tempFileProvider;
@ -52,8 +46,6 @@ namespace Xharness
public CrashSnapshotReporter (IProcessManager processManager, public CrashSnapshotReporter (IProcessManager processManager,
ILog log, ILog log,
ILogs logs, ILogs logs,
string xcodeRoot,
string mlaunchPath,
bool isDevice, bool isDevice,
string deviceName, string deviceName,
Func<string> tempFileProvider = null) Func<string> tempFileProvider = null)
@ -61,15 +53,13 @@ namespace Xharness
this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
this.log = log ?? throw new ArgumentNullException (nameof (log)); this.log = log ?? throw new ArgumentNullException (nameof (log));
this.logs = logs ?? throw new ArgumentNullException (nameof (logs)); 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.isDevice = isDevice;
this.deviceName = deviceName; this.deviceName = deviceName;
this.tempFileProvider = tempFileProvider ?? Path.GetTempFileName; 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)) 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)) if (!File.Exists (symbolicateCrashPath))
symbolicateCrashPath = null; symbolicateCrashPath = null;
} }
@ -135,14 +125,13 @@ namespace Xharness
var crashReportFile = logs.Create (name, $"Crash report: {name}", timestamp: false); var crashReportFile = logs.Create (name, $"Crash report: {name}", timestamp: false);
var args = new MlaunchArguments ( var args = new MlaunchArguments (
new DownloadCrashReportArgument (crashFile), new DownloadCrashReportArgument (crashFile),
new DownloadCrashReportToArgument (crashReportFile.FullPath), new DownloadCrashReportToArgument (crashReportFile.FullPath));
new SdkRootArgument (xcodeRoot));
if (!string.IsNullOrEmpty (deviceName)) { if (!string.IsNullOrEmpty (deviceName)) {
args.Add (new DeviceNameArgument(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) { if (result.Succeeded) {
log.WriteLine ("Downloaded crash report {0} to {1}", crashFile, crashReportFile.FullPath); log.WriteLine ("Downloaded crash report {0} to {1}", crashFile, crashReportFile.FullPath);
@ -162,7 +151,7 @@ namespace Xharness
var name = Path.GetFileName (report.FullPath); var name = Path.GetFileName (report.FullPath);
var symbolicated = logs.Create (Path.ChangeExtension (name, ".symbolicated.log"), $"Symbolicated crash report: {name}", timestamp: false); var symbolicated = logs.Create (Path.ChangeExtension (name, ".symbolicated.log"), $"Symbolicated crash report: {name}", timestamp: false);
var environment = new Dictionary<string, string> { { "DEVELOPER_DIR", Path.Combine (xcodeRoot, "Contents", "Developer") } }; var environment = new Dictionary<string, string> { { "DEVELOPER_DIR", Path.Combine (processManager.XcodeRoot, "Contents", "Developer") } };
var result = await processManager.ExecuteCommandAsync (symbolicateCrashPath, new [] { report.FullPath }, symbolicated, TimeSpan.FromMinutes (1), environment); var result = await processManager.ExecuteCommandAsync (symbolicateCrashPath, new [] { report.FullPath }, symbolicated, TimeSpan.FromMinutes (1), environment);
if (result.Succeeded) { if (result.Succeeded) {
log.WriteLine ("Symbolicated {0} successfully.", report.FullPath); log.WriteLine ("Symbolicated {0} successfully.", report.FullPath);
@ -184,15 +173,13 @@ namespace Xharness
} else { } else {
var tempFile = tempFileProvider (); var tempFile = tempFileProvider ();
try { try {
var args = new MlaunchArguments ( var args = new MlaunchArguments (new ListCrashReportsArgument (tempFile));
new ListCrashReportsArgument (tempFile),
new SdkRootArgument (xcodeRoot));
if (!string.IsNullOrEmpty (deviceName)) { if (!string.IsNullOrEmpty (deviceName)) {
args.Add (new DeviceNameArgument(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) if (result.Succeeded)
crashes.UnionWith (File.ReadAllLines (tempFile)); crashes.UnionWith (File.ReadAllLines (tempFile));
} finally { } finally {

Просмотреть файл

@ -14,19 +14,15 @@ namespace Xharness
public class DeviceLogCapturerFactory : IDeviceLogCapturerFactory { public class DeviceLogCapturerFactory : IDeviceLogCapturerFactory {
readonly IProcessManager processManager; 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.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) 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 mainLog;
readonly ILog deviceLog; readonly ILog deviceLog;
readonly string deviceName; 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.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
this.mainLog = mainLog ?? throw new ArgumentNullException (nameof (mainLog)); this.mainLog = mainLog ?? throw new ArgumentNullException (nameof (mainLog));
this.deviceLog = deviceLog ?? throw new ArgumentNullException (nameof (deviceLog)); this.deviceLog = deviceLog ?? throw new ArgumentNullException (nameof (deviceLog));
this.deviceName = deviceName ?? throw new ArgumentNullException (nameof (deviceName)); 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; Process process;
@ -60,17 +52,17 @@ namespace Xharness
{ {
streamEnds = new CountdownEvent (2); streamEnds = new CountdownEvent (2);
var sb = new List<string> { var args = new List<string> {
"--logdev", "--logdev",
"--sdkroot", "--sdkroot",
xcodeRoot, processManager.XcodeRoot,
"--devname", "--devname",
deviceName deviceName
}; };
process = new Process (); process = new Process ();
process.StartInfo.FileName = mlaunchPath; process.StartInfo.FileName = processManager.MlaunchPath;
process.StartInfo.Arguments = StringUtils.FormatArguments (sb); process.StartInfo.Arguments = StringUtils.FormatArguments (args);
process.StartInfo.UseShellExecute = false; process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardError = true;

Просмотреть файл

@ -17,15 +17,17 @@ namespace Xharness.Execution {
// interface that helps to manage the different processes in the app. // interface that helps to manage the different processes in the app.
public interface IProcessManager { public interface IProcessManager {
string XcodeRoot { get; }
string MlaunchPath { get; }
Version XcodeVersion { get; }
Task<ProcessExecutionResult> ExecuteCommandAsync (string filename, IList<string> args, ILog log, TimeSpan timeout, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null); Task<ProcessExecutionResult> ExecuteCommandAsync (string filename, IList<string> args, ILog log, TimeSpan timeout, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null);
Task<ProcessExecutionResult> ExecuteCommandAsync (string filename, MlaunchArguments args, ILog log, TimeSpan timeout, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null); Task<ProcessExecutionResult> ExecuteCommandAsync (MlaunchArguments args, ILog log, TimeSpan timeout, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null);
Task<ProcessExecutionResult> RunAsync (Process process, ILog log, CancellationToken? cancellationToken = null, bool? diagnostics = null); Task<ProcessExecutionResult> ExecuteXcodeCommandAsync (string executable, IList<string> args, ILog log, TimeSpan timeout);
Task<ProcessExecutionResult> RunAsync (Process process, ILog log, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null); Task<ProcessExecutionResult> RunAsync (Process process, ILog log, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null);
Task<ProcessExecutionResult> RunAsync (Process process, MlaunchArguments args, ILog log, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null); Task<ProcessExecutionResult> RunAsync (Process process, MlaunchArguments args, ILog log, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null);
Task<ProcessExecutionResult> RunAsync (Process process, ILog log, ILog stdoutLog, ILog stderrLog, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null); Task<ProcessExecutionResult> RunAsync (Process process, ILog log, ILog stdoutLog, ILog stderrLog, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null);
Task<bool> WaitForExitAsync (Process process, TimeSpan? timeout = null);
Task KillTreeAsync (Process process, ILog log, bool? diagnostics = true); Task KillTreeAsync (Process process, ILog log, bool? diagnostics = true);
Task KillTreeAsync (int pid, ILog log, bool? diagnostics = true); Task KillTreeAsync (int pid, ILog log, bool? diagnostics = true);
void GetChildrenPS (ILog log, List<int> list, int pid);
} }
} }

Просмотреть файл

@ -7,84 +7,101 @@ using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using Xharness.Execution.Mlaunch; using Xharness.Execution.Mlaunch;
using Xharness.Logging; using Xharness.Logging;
using Xharness.Utilities; using Xharness.Utilities;
namespace Xharness.Execution { namespace Xharness.Execution {
public class ProcessManager : IProcessManager { 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<ProcessExecutionResult> ExecuteCommandAsync (string filename, public async Task<ProcessExecutionResult> ExecuteCommandAsync (string filename,
IList<string> args, IList<string> args,
ILog log, ILog log,
TimeSpan timeout, TimeSpan timeout,
Dictionary<string, string> environment_variables = null, Dictionary<string, string> environmentVariables = null,
CancellationToken? cancellation_token = null) CancellationToken? cancellationToken = null)
{ {
using (var p = new Process ()) { using var p = new Process ();
p.StartInfo.FileName = filename; p.StartInfo.FileName = filename ?? throw new ArgumentNullException (nameof (filename));
p.StartInfo.Arguments = StringUtils.FormatArguments (args); p.StartInfo.Arguments = StringUtils.FormatArguments (args);
return await RunAsync (p, log, timeout, environment_variables, cancellation_token); return await RunAsync (p, log, timeout, environmentVariables, cancellationToken);
}
} }
public async Task<ProcessExecutionResult> ExecuteCommandAsync (string filename, public async Task<ProcessExecutionResult> ExecuteCommandAsync (MlaunchArguments args,
MlaunchArguments args,
ILog log, ILog log,
TimeSpan timeout, TimeSpan timeout,
Dictionary<string, string> environment_variables = null, Dictionary<string, string> environmentVariables = null,
CancellationToken? cancellation_token = null) CancellationToken? cancellationToken = null)
{ {
using (var p = new Process ()) { using var p = new Process ();
p.StartInfo.FileName = filename; return await RunAsync (p, args, log, timeout, environmentVariables, cancellationToken);
p.StartInfo.Arguments = args.AsCommandLine ();
return await RunAsync (p, log, timeout, environment_variables, cancellation_token);
} }
public Task<ProcessExecutionResult> ExecuteXcodeCommandAsync (string executable, IList<string> 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")] [DllImport ("/usr/lib/libc.dylib")]
internal static extern int kill (int pid, int sig); internal static extern int kill (int pid, int sig);
public static Task<bool> PollForExitAsync (int pid, TimeSpan timeout) public Task<ProcessExecutionResult> RunAsync (Process process,
ILog log,
TimeSpan? timeout = null,
Dictionary<string, string> environment_variables = null,
CancellationToken? cancellationToken = null,
bool? diagnostics = null)
{ {
var rv = new TaskCompletionSource<bool> (); return RunAsync (process, log, log, log, timeout, environment_variables, cancellationToken, diagnostics);
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); public Task<ProcessExecutionResult> RunAsync (Process process,
}); MlaunchArguments args,
return rv.Task; ILog log,
} TimeSpan? timeout = null,
Dictionary<string, string> environmentVariables = null,
public async Task<ProcessExecutionResult> RunAsync (Process process, ILog log, CancellationToken? cancellation_token = null, bool? diagnostics = null) CancellationToken? cancellationToken = null,
bool? diagnostics = null)
{ {
return await RunAsync (process, log, log, log, cancellation_token: cancellation_token, diagnostics: diagnostics); if (!args.Any (a => a is SdkRootArgument))
} args.Prepend (new SdkRootArgument (XcodeRoot));
public Task<ProcessExecutionResult> RunAsync (Process process, ILog log, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null) process.StartInfo.FileName = MlaunchPath;
{
return RunAsync (process, log, log, log, timeout, environment_variables, cancellation_token, diagnostics);
}
public Task<ProcessExecutionResult> RunAsync (Process process, MlaunchArguments args, ILog log, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null)
{
process.StartInfo.Arguments = args.AsCommandLine (); 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<ProcessExecutionResult> RunAsync (Process process, ILog log, ILog StdoutStream, ILog StderrStream, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null) public async Task<ProcessExecutionResult> RunAsync (Process process,
ILog log,
ILog stdout,
ILog stderr,
TimeSpan? timeout = null,
Dictionary<string, string> environment_variables = null,
CancellationToken? cancellationToken = null,
bool? diagnostics = null)
{ {
var stdout_completion = new TaskCompletionSource<bool> (); var stdout_completion = new TaskCompletionSource<bool> ();
var stderr_completion = new TaskCompletionSource<bool> (); var stderr_completion = new TaskCompletionSource<bool> ();
@ -105,9 +122,9 @@ namespace Xharness.Execution {
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
{ {
if (e.Data != null) { if (e.Data != null) {
lock (StdoutStream) { lock (stdout) {
StdoutStream.WriteLine (e.Data); stdout.WriteLine (e.Data);
StdoutStream.Flush (); stdout.Flush ();
} }
} else { } else {
stdout_completion.TrySetResult (true); stdout_completion.TrySetResult (true);
@ -117,9 +134,9 @@ namespace Xharness.Execution {
process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
{ {
if (e.Data != null) { if (e.Data != null) {
lock (StderrStream) { lock (stderr) {
StderrStream.WriteLine (e.Data); stderr.WriteLine (e.Data);
StderrStream.Flush (); stderr.Flush ();
} }
} else { } else {
stderr_completion.TrySetResult (true); stderr_completion.TrySetResult (true);
@ -148,7 +165,7 @@ namespace Xharness.Execution {
process.BeginErrorReadLine (); process.BeginErrorReadLine ();
process.BeginOutputReadLine (); process.BeginOutputReadLine ();
cancellation_token?.Register (() => { cancellationToken?.Register (() => {
var hasExited = false; var hasExited = false;
try { try {
hasExited = process.HasExited; hasExited = process.HasExited;
@ -159,7 +176,7 @@ namespace Xharness.Execution {
// processes behind). // processes behind).
} }
if (!hasExited) { if (!hasExited) {
StderrStream.WriteLine ($"Execution of {pid} was cancelled."); stderr.WriteLine ($"Execution of {pid} was cancelled.");
kill (pid, 9); kill (pid, 9);
} }
}); });
@ -168,7 +185,7 @@ namespace Xharness.Execution {
if (!await WaitForExitAsync (process, timeout.Value)) { if (!await WaitForExitAsync (process, timeout.Value)) {
await KillTreeAsync (process, log, diagnostics ?? true); await KillTreeAsync (process, log, diagnostics ?? true);
rv.TimedOut = true; rv.TimedOut = true;
lock (StderrStream) lock (stderr)
log.WriteLine ($"{pid} Execution timed out after {timeout.Value.TotalSeconds} seconds and the process was killed."); 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; return rv;
} }
public async Task<bool> WaitForExitAsync (Process process, TimeSpan? timeout = null)
{
if (process.HasExited)
return true;
var tcs = new TaskCompletionSource<bool> ();
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) public Task KillTreeAsync (Process process, ILog log, bool? diagnostics = true)
{ {
return KillTreeAsync (process.Id, log, diagnostics); return KillTreeAsync (process.Id, log, diagnostics);
@ -223,8 +208,8 @@ namespace Xharness.Execution {
public async Task KillTreeAsync (int pid, ILog log, bool? diagnostics = true) public async Task KillTreeAsync (int pid, ILog log, bool? diagnostics = true)
{ {
var pids = new List<int> (); var pids = GetChildrenPS (log, pid);
GetChildrenPS (log, pids, pid);
if (diagnostics == true) { if (diagnostics == true) {
log.WriteLine ($"Pids to kill: {string.Join (", ", pids.Select ((v) => v.ToString ()).ToArray ())}"); log.WriteLine ($"Pids to kill: {string.Join (", ", pids.Select ((v) => v.ToString ()).ToArray ())}");
using (var ps = new Process ()) { using (var ps = new Process ()) {
@ -271,9 +256,41 @@ namespace Xharness.Execution {
kill (pids [i], 9); kill (pids [i], 9);
} }
public void GetChildrenPS (ILog log, List<int> list, int pid) static async Task<bool> WaitForExitAsync (Process process, TimeSpan? timeout = null)
{ {
string stdout; if (process.HasExited)
return true;
var tcs = new TaskCompletionSource<bool> ();
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<int> GetChildrenPS (ILog log, int pid)
{
var list = new List<int> ();
using (Process ps = new Process ()) { using (Process ps = new Process ()) {
ps.StartInfo.FileName = "ps"; ps.StartInfo.FileName = "ps";
@ -281,20 +298,21 @@ namespace Xharness.Execution {
ps.StartInfo.UseShellExecute = false; ps.StartInfo.UseShellExecute = false;
ps.StartInfo.RedirectStandardOutput = true; ps.StartInfo.RedirectStandardOutput = true;
ps.Start (); ps.Start ();
stdout = ps.StandardOutput.ReadToEnd ();
string stdout = ps.StandardOutput.ReadToEnd ();
if (!ps.WaitForExit (1000)) { if (!ps.WaitForExit (1000)) {
log.WriteLine ("ps didn't finish in a reasonable amount of time (1 second)."); log.WriteLine ("ps didn't finish in a reasonable amount of time (1 second).");
return; return list;
} }
if (ps.ExitCode != 0) if (ps.ExitCode != 0)
return; return list;
stdout = stdout.Trim (); stdout = stdout.Trim ();
if (string.IsNullOrEmpty (stdout)) if (string.IsNullOrEmpty (stdout))
return; return list;
var dict = new Dictionary<int, List<int>> (); var dict = new Dictionary<int, List<int>> ();
foreach (string line in stdout.Split (new char [] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)) { 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 parent = l.Substring (0, space);
var process = l.Substring (space + 1); var process = l.Substring (space + 1);
int parent_id, process_id;
if (int.TryParse (parent, out parent_id) && int.TryParse (process, out process_id)) { if (int.TryParse (parent, out var parent_id) && int.TryParse (process, out var process_id)) {
List<int> children; if (!dict.TryGetValue (parent_id, out var children))
if (!dict.TryGetValue (parent_id, out children))
dict [parent_id] = children = new List<int> (); dict [parent_id] = children = new List<int> ();
children.Add (process_id); children.Add (process_id);
} }
} }
@ -319,15 +336,16 @@ namespace Xharness.Execution {
queue.Enqueue (pid); queue.Enqueue (pid);
do { do {
List<int> children;
var parent_id = queue.Dequeue (); var parent_id = queue.Dequeue ();
list.Add (parent_id); list.Add (parent_id);
if (dict.TryGetValue (parent_id, out children)) { if (dict.TryGetValue (parent_id, out var children)) {
foreach (var child in children) foreach (var child in children)
queue.Enqueue (child); queue.Enqueue (child);
} }
} while (queue.Count > 0); } while (queue.Count > 0);
} }
return list;
} }
} }
} }

Просмотреть файл

@ -6,8 +6,6 @@ using System.Linq;
using System.Net; using System.Net;
using System.Runtime.Serialization.Json; using System.Runtime.Serialization.Json;
using System.Xml; using System.Xml;
using System.Text;
using Xamarin;
using Xharness.Execution; using Xharness.Execution;
using Xharness.Logging; using Xharness.Logging;
@ -15,7 +13,6 @@ namespace Xharness
{ {
public static class GitHub public static class GitHub
{ {
static IProcessManager ProcessManager { get; set; } = new ProcessManager ();
static WebClient CreateClient () static WebClient CreateClient ()
{ {
var client = new WebClient (); var client = new WebClient ();
@ -56,11 +53,11 @@ namespace Xharness
} }
} }
public static IEnumerable<string> GetModifiedFiles (Harness harness, int pull_request) public static IEnumerable<string> GetModifiedFiles (IProcessManager processManager, Harness harness, int pull_request)
{ {
var path = Path.Combine (harness.LogDirectory, "pr" + pull_request + "-files.log"); var path = Path.Combine (harness.LogDirectory, "pr" + pull_request + "-files.log");
if (!File.Exists (path)) { if (!File.Exists (path)) {
var rv = GetModifiedFilesLocally (harness, pull_request); var rv = GetModifiedFilesLocally (processManager, harness, pull_request);
if (rv == null || rv.Count () == 0) { if (rv == null || rv.Count () == 0) {
rv = GetModifiedFilesRemotely (harness, pull_request); rv = GetModifiedFilesRemotely (harness, pull_request);
if (rv == null) if (rv == null)
@ -141,7 +138,7 @@ namespace Xharness
return File.ReadAllLines (path); return File.ReadAllLines (path);
} }
static IEnumerable<string> GetModifiedFilesLocally (Harness harness, int pull_request) static IEnumerable<string> GetModifiedFilesLocally (IProcessManager processManager, Harness harness, int pull_request)
{ {
var base_commit = $"origin/pr/{pull_request}/merge^"; var base_commit = $"origin/pr/{pull_request}/merge^";
var head_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.FileName = "git";
git.StartInfo.Arguments = $"diff-tree --no-commit-id --name-only -r {base_commit}..{head_commit}"; git.StartInfo.Arguments = $"diff-tree --no-commit-id --name-only -r {base_commit}..{head_commit}";
var output = new MemoryLog (); 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) if (rv.Succeeded)
return output.ToString ().Split (new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries); return output.ToString ().Split (new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

Просмотреть файл

@ -4,6 +4,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Xml; using System.Xml;
using Xharness.Collections; using Xharness.Collections;
using Xharness.Execution; using Xharness.Execution;
@ -18,24 +19,20 @@ namespace Xharness.Hardware {
} }
public class DeviceLoaderFactory : IDeviceLoaderFactory { public class DeviceLoaderFactory : IDeviceLoaderFactory {
readonly IHarness harness;
readonly IProcessManager processManager; 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)); 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 { public class Devices : IDeviceLoader {
readonly IProcessManager processManager; readonly IProcessManager processManager;
bool loaded; bool loaded;
public IHarness Harness { get; set; }
BlockingEnumerableCollection<IHardwareDevice> connected_devices = new BlockingEnumerableCollection<IHardwareDevice> (); BlockingEnumerableCollection<IHardwareDevice> connected_devices = new BlockingEnumerableCollection<IHardwareDevice> ();
public IEnumerable<IHardwareDevice> ConnectedDevices => connected_devices; public IEnumerable<IHardwareDevice> 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)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
} }
@ -76,18 +72,19 @@ namespace Xharness.Hardware {
var tmpfile = Path.GetTempFileName (); var tmpfile = Path.GetTempFileName ();
try { try {
using (var process = new Process ()) { using (var process = new Process ()) {
process.StartInfo.FileName = Harness.MlaunchPath;
var arguments = new MlaunchArguments ( var arguments = new MlaunchArguments (
new SdkRootArgument (Harness.XcodeRoot),
new ListDevicesArgument (tmpfile), new ListDevicesArgument (tmpfile),
new XmlOutputFormatArgument ()); new XmlOutputFormatArgument ());
if (extra_data) if (extra_data)
arguments.Add (new ListExtraDataArgument ()); 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); 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."); throw new Exception ("Failed to list devices.");
log.WriteLine ("Result:"); log.WriteLine ("Result:");
log.WriteLine (File.ReadAllText (tmpfile)); log.WriteLine (File.ReadAllText (tmpfile));

Просмотреть файл

@ -33,7 +33,6 @@ namespace Xharness.Hardware {
} }
public interface ISimulatorDevice : IDevice { public interface ISimulatorDevice : IDevice {
ITCCDatabase TCCDatabase { get; set; }
string SimRuntime { get; set; } string SimRuntime { get; set; }
string SimDeviceType { get; set; } string SimDeviceType { get; set; }
string DataPath { get; set; } string DataPath { get; set; }

Просмотреть файл

@ -9,10 +9,8 @@ using Xharness.Logging;
namespace Xharness.Hardware { namespace Xharness.Hardware {
public class SimulatorDevice : ISimulatorDevice { public class SimulatorDevice : ISimulatorDevice {
readonly IHarness harness;
readonly IProcessManager processManager; readonly IProcessManager processManager;
readonly ITCCDatabase tCCDatabase;
public ITCCDatabase TCCDatabase { get; set; } = new TCCDatabase ();
public string UDID { get; set; } public string UDID { get; set; }
public string Name { get; set; } public string Name { get; set; }
@ -23,10 +21,10 @@ namespace Xharness.Hardware {
public string SystemLog => Path.Combine (LogPath, "system.log"); 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.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); 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. // here we don't care if execution fails.
// erase the simulator (make sure the device isn't running first) // erase the simulator (make sure the device isn't running first)
await harness.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1)); await processManager.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 [] { "erase", UDID }, log, TimeSpan.FromMinutes (1));
// boot & shutdown to make sure it actually works // boot & shutdown to make sure it actually works
await harness.ExecuteXcodeCommandAsync ("simctl", new [] { "boot", UDID }, log, TimeSpan.FromMinutes (1)); await processManager.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 [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1));
} }
public async Task ShutdownAsync (ILog log) 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) public async Task KillEverythingAsync (ILog log)
@ -86,12 +84,12 @@ namespace Xharness.Hardware {
{ {
string simulator_app; string simulator_app;
if (IsWatchSimulator && harness.XcodeVersion.Major < 9) { if (IsWatchSimulator && processManager.XcodeVersion.Major < 9) {
simulator_app = Path.Combine (harness.XcodeRoot, "Contents", "Developer", "Applications", "Simulator (Watch).app"); simulator_app = Path.Combine (processManager.XcodeRoot, "Contents", "Developer", "Applications", "Simulator (Watch).app");
} else { } 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)) 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)); 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)) { if (File.Exists (TCC_db)) {
await TCCDatabase.AgreeToPromptsAsync (SimRuntime, TCC_db, log, bundle_identifiers); await tCCDatabase.AgreeToPromptsAsync (SimRuntime, TCC_db, log, bundle_identifiers);
} else { } else {
log.WriteLine ("No TCC.db found for the simulator {0} (SimRuntime={1} and SimDeviceType={1})", UDID, SimRuntime, SimDeviceType); log.WriteLine ("No TCC.db found for the simulator {0} (SimRuntime={1} and SimDeviceType={1})", UDID, SimRuntime, SimDeviceType);
} }

Просмотреть файл

@ -22,16 +22,14 @@ namespace Xharness.Hardware {
} }
public class SimulatorsLoaderFactory : ISimulatorsLoaderFactory { public class SimulatorsLoaderFactory : ISimulatorsLoaderFactory {
readonly IHarness harness;
readonly IProcessManager processManager; 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)); 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 { public class Simulators : ISimulatorsLoader {
@ -44,16 +42,13 @@ namespace Xharness.Hardware {
bool loaded; bool loaded;
public IHarness Harness { get; set; }
public IEnumerable<SimRuntime> SupportedRuntimes => supported_runtimes; public IEnumerable<SimRuntime> SupportedRuntimes => supported_runtimes;
public IEnumerable<SimDeviceType> SupportedDeviceTypes => supported_device_types; public IEnumerable<SimDeviceType> SupportedDeviceTypes => supported_device_types;
public IEnumerable<SimulatorDevice> AvailableDevices => available_devices; public IEnumerable<SimulatorDevice> AvailableDevices => available_devices;
public IEnumerable<SimDevicePair> AvailableDevicePairs => available_device_pairs; public IEnumerable<SimDevicePair> 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)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
} }
@ -76,18 +71,18 @@ namespace Xharness.Hardware {
var tmpfile = Path.GetTempFileName (); var tmpfile = Path.GetTempFileName ();
try { try {
using (var process = new Process ()) { using (var process = new Process ()) {
process.StartInfo.FileName = Harness.MlaunchPath;
var arguments = new MlaunchArguments ( var arguments = new MlaunchArguments (
new SdkRootArgument(Harness.XcodeRoot),
new ListSimulatorsArgument(tmpfile), new ListSimulatorsArgument(tmpfile),
new XmlOutputFormatArgument()); 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); 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."); throw new Exception ("Failed to list simulators.");
log.WriteLine ("Result:"); log.WriteLine ("Result:");
log.WriteLine (File.ReadAllText (tmpfile)); log.WriteLine (File.ReadAllText (tmpfile));
var simulator_data = new XmlDocument (); var simulator_data = new XmlDocument ();
@ -112,7 +107,7 @@ namespace Xharness.Hardware {
} }
foreach (XmlNode sim in simulator_data.SelectNodes ("/MTouch/Simulator/AvailableDevices/SimDevice")) { 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, Name = sim.Attributes ["Name"].Value,
UDID = sim.Attributes ["UDID"].Value, UDID = sim.Attributes ["UDID"].Value,
SimRuntime = sim.SelectSingleNode ("SimRuntime").InnerText, SimRuntime = sim.SelectSingleNode ("SimRuntime").InnerText,
@ -168,7 +163,7 @@ namespace Xharness.Hardware {
return devices; 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) { if (!rv.Succeeded) {
log.WriteLine ($"Could not create device for runtime={runtime} and device type={devicetype}."); log.WriteLine ($"Could not create device for runtime={runtime} and device type={devicetype}.");
return null; return null;
@ -207,8 +202,7 @@ namespace Xharness.Hardware {
log.Write (value); log.Write (value);
capturedLog.Append (value); capturedLog.Append (value);
}); });
var rv = await processManager.ExecuteXcodeCommandAsync ("simctl", new [] { "pair", device.UDID, companion_device.UDID }, pairLog, TimeSpan.FromMinutes (1));
var rv = await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "pair", device.UDID, companion_device.UDID }, pairLog, TimeSpan.FromMinutes (1));
if (!rv.Succeeded) { if (!rv.Succeeded) {
if (!create_device) { if (!create_device) {
var try_creating_device = false; var try_creating_device = false;

Просмотреть файл

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xharness.Execution; using Xharness.Execution;
using Xharness.Logging; using Xharness.Logging;
@ -9,7 +8,6 @@ using Xharness.Logging;
namespace Xharness.Hardware { namespace Xharness.Hardware {
public interface ITCCDatabase { public interface ITCCDatabase {
IProcessManager ProcessManager { get; set; }
Task AgreeToPromptsAsync (string simRuntime, string dataPath, ILog log, params string [] bundle_identifiers); Task AgreeToPromptsAsync (string simRuntime, string dataPath, ILog log, params string [] bundle_identifiers);
int GetTCCFormat (string simRuntime); int GetTCCFormat (string simRuntime);
} }
@ -19,7 +17,12 @@ namespace Xharness.Hardware {
static readonly string tvOSSimRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.tvOS-"; static readonly string tvOSSimRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.tvOS-";
static readonly string watchOSRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.watchOS-"; 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) { public int GetTCCFormat (string simRuntime) {
@ -109,7 +112,7 @@ namespace Xharness.Hardware {
} }
} }
args.Add (sql.ToString ()); 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) { if (!rv.Succeeded) {
failure = true; failure = true;
break; break;
@ -124,7 +127,7 @@ namespace Xharness.Hardware {
} }
log.WriteLine ("Current TCC database contents:"); 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));
} }
} }
} }

Просмотреть файл

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Xml; using System.Xml;
using Xharness.BCLTestImporter; using Xharness.BCLTestImporter;
using Xharness.Logging; using Xharness.Logging;
@ -51,66 +50,30 @@ namespace Xharness
public interface IHarness { public interface IHarness {
HarnessAction Action { get; } HarnessAction Action { get; }
bool DisableWatchOSOnWrench { get; }
string DOTNET { get; }
bool DryRun { get; }
bool ENABLE_XAMARIN { get; }
Dictionary<string, string> EnvironmentVariables { get; } Dictionary<string, string> EnvironmentVariables { get; }
ILog HarnessLog { get; set; } ILog HarnessLog { get; set; }
string GetStandardErrorTty ();
bool InCI { get; } 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<iOSTestProject> IOSTestProjects { get; }
string JENKINS_RESULTS_DIRECTORY { get; }
string JenkinsConfiguration { get; }
HashSet<string> Labels { get; }
double LaunchTimeout { get; } double LaunchTimeout { get; }
string LogDirectory { get; }
string MAC_DESTDIR { get; }
List<MacTestProject> 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; } double Timeout { get; }
string TodayContainerTemplate { get; }
string TodayExtensionTemplate { get; }
bool UseGroupedApps { get; }
int Verbosity { get; } int Verbosity { get; }
string WatchOSAppTemplate { get; }
string WatchOSContainerTemplate { get; }
string WatchOSExtensionTemplate { get; }
string XcodeRoot { get; }
Version XcodeVersion { get; }
XmlResultJargon XmlJargon { get; } XmlResultJargon XmlJargon { get; }
Task<ProcessExecutionResult> ExecuteXcodeCommandAsync (string executable, IList<string> args, ILog log, TimeSpan timeout);
bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device); bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device);
string GetStandardErrorTty ();
void Log (int min_level, string message, params object [] args); 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 { public class Harness : IHarness {
readonly TestTarget target; readonly TestTarget target;
readonly string buildConfiguration = "Debug"; readonly string buildConfiguration = "Debug";
IProcessManager processManager;
public HarnessAction Action { get; } public HarnessAction Action { get; }
public int Verbosity { get; } public int Verbosity { get; }
public ILog HarnessLog { get; set; } public ILog HarnessLog { get; set; }
public HashSet<string> Labels { get; } public HashSet<string> Labels { get; }
public XmlResultJargon XmlJargon { get; } public XmlResultJargon XmlJargon { get; }
public IProcessManager ProcessManager { get; }
public IResultParser ResultParser { get; } public IResultParser ResultParser { get; }
// This is the maccore/tests directory. // 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<iOSTestProject> IOSTestProjects { get; } public List<iOSTestProject> IOSTestProjects { get; }
public List<MacTestProject> MacTestProjects { get; } = new List<MacTestProject> (); public List<MacTestProject> MacTestProjects { get; } = new List<MacTestProject> ();
@ -164,19 +129,19 @@ namespace Xharness
public string TodayContainerTemplate { get; private set; } public string TodayContainerTemplate { get; private set; }
public string TodayExtensionTemplate { get; private set; } public string TodayExtensionTemplate { get; private set; }
public string BCLTodayExtensionTemplate { 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 MONO_PATH { get; } // 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 string TVOS_MONO_PATH { get; } // Use same name as in Makefiles, so that a grep finds it.
public bool INCLUDE_IOS { get; private set; } public bool INCLUDE_IOS { get; }
public bool INCLUDE_TVOS { get; private set; } public bool INCLUDE_TVOS { get; }
public bool INCLUDE_WATCH { get; private set; } public bool INCLUDE_WATCH { get; }
public bool INCLUDE_MAC { get; private set; } public bool INCLUDE_MAC { get; }
public string JENKINS_RESULTS_DIRECTORY { get; private set; } // Use same name as in Makefiles, so that a grep finds it. public string JENKINS_RESULTS_DIRECTORY { get; } // Use same name as in Makefiles, so that a grep finds it.
public string MAC_DESTDIR { get; private set; } public string MAC_DESTDIR { get; }
public string IOS_DESTDIR { get; private set; } public string IOS_DESTDIR { get; }
public string MONO_IOS_SDK_DESTDIR { get; private set; } public string MONO_IOS_SDK_DESTDIR { get; }
public string MONO_MAC_SDK_DESTDIR { get; private set; } public string MONO_MAC_SDK_DESTDIR { get; }
public bool ENABLE_XAMARIN { get; private set; } public bool ENABLE_XAMARIN { get; }
public string DOTNET { get; private set; } public string DOTNET { get; }
// Run // Run
@ -196,9 +161,8 @@ namespace Xharness
public string GetStandardErrorTty () => Helpers.GetTerminalName (2); 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)); ResultParser = resultParser ?? throw new ArgumentNullException (nameof (resultParser));
Action = action; Action = action;
@ -217,7 +181,6 @@ namespace Xharness
PeriodicCommand = configuration.PeriodicCommand; PeriodicCommand = configuration.PeriodicCommand;
PeriodicCommandArguments = configuration.PeriodicCommandArguments; PeriodicCommandArguments = configuration.PeriodicCommandArguments;
PeriodicCommandInterval = configuration.PeriodicCommandInterval; PeriodicCommandInterval = configuration.PeriodicCommandInterval;
SdkRoot = configuration.SdkRoot;
target = configuration.Target; target = configuration.Target;
Timeout = configuration.TimeoutInMinutes; Timeout = configuration.TimeoutInMinutes;
useSystemXamarinIOSMac = configuration.UseSystemXamarinIOSMac; useSystemXamarinIOSMac = configuration.UseSystemXamarinIOSMac;
@ -233,6 +196,29 @@ namespace Xharness
EnvironmentVariables = new Dictionary<string, string> (configuration.EnvironmentVariables); EnvironmentVariables = new Dictionary<string, string> (configuration.EnvironmentVariables);
LaunchTimeout = InCI ? 3 : 120; 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) public bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device)
@ -277,45 +263,6 @@ namespace Xharness
} while (true); } 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 AutoConfigureMac (bool generate_projects)
{ {
int rv = 0; int rv = 0;
@ -480,7 +427,7 @@ namespace Xharness
BCLTodayExtensionTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "bcl-test", "templates", "today")); BCLTodayExtensionTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "bcl-test", "templates", "today"));
} }
Dictionary<string, string> make_config = new Dictionary<string, string> (); // Dictionary<string, string> make_config = new Dictionary<string, string> ();
IEnumerable<string> FindConfigFiles (string name) IEnumerable<string> FindConfigFiles (string name)
{ {
var dir = Path.GetFullPath (RootDirectory); var dir = Path.GetFullPath (RootDirectory);
@ -492,20 +439,24 @@ namespace Xharness
} }
} }
void ParseConfigFiles () Dictionary<string, string> ParseConfigFiles ()
{ {
ParseConfigFiles (FindConfigFiles (useSystemXamarinIOSMac ? "test-system.config" : "test.config")); var configuration = new Dictionary<string, string> ();
ParseConfigFiles (FindConfigFiles ("Make.config.local")); foreach (var file in GetConfigFiles ()) {
ParseConfigFiles (FindConfigFiles ("Make.config")); ParseConfigFile (file, configuration);
} }
void ParseConfigFiles (IEnumerable<string> files) return configuration;
{
foreach (var file in files)
ParseConfigFile (file);
} }
void ParseConfigFile (string file) IEnumerable <string> GetConfigFiles ()
{
return FindConfigFiles (useSystemXamarinIOSMac ? "test-system.config" : "test.config")
.Concat (FindConfigFiles ("Make.config"))
.Concat (FindConfigFiles ("Make.config.local"));
}
void ParseConfigFile (string file, Dictionary<string, string> configuration)
{ {
if (string.IsNullOrEmpty (file)) if (string.IsNullOrEmpty (file))
return; return;
@ -514,9 +465,10 @@ namespace Xharness
var eq = line.IndexOf ('='); var eq = line.IndexOf ('=');
if (eq == -1) if (eq == -1)
continue; continue;
var key = line.Substring (0, eq); var key = line.Substring (0, eq);
if (!make_config.ContainsKey (key)) if (!configuration.ContainsKey (key))
make_config [key] = line.Substring (eq + 1); configuration [key] = line.Substring (eq + 1);
} }
} }
@ -604,22 +556,7 @@ namespace Xharness
HarnessLog = new ConsoleLog (); HarnessLog = new ConsoleLog ();
foreach (var project in IOSTestProjects) { foreach (var project in IOSTestProjects) {
var runner = new AppRunner (ProcessManager, var runner = CreateAppRunner (project);
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);
using (var install_log = new AppInstallMonitorLog (runner.MainLog)) { using (var install_log = new AppInstallMonitorLog (runner.MainLog)) {
var rv = runner.InstallAsync (install_log.CancellationToken).Result; var rv = runner.InstallAsync (install_log.CancellationToken).Result;
if (!rv.Succeeded) if (!rv.Succeeded)
@ -635,22 +572,7 @@ namespace Xharness
HarnessLog = new ConsoleLog (); HarnessLog = new ConsoleLog ();
foreach (var project in IOSTestProjects) { foreach (var project in IOSTestProjects) {
var runner = new AppRunner (ProcessManager, var runner = CreateAppRunner (project);
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 rv = runner.UninstallAsync ().Result; var rv = runner.UninstallAsync ().Result;
if (!rv.Succeeded) if (!rv.Succeeded)
return rv.ExitCode; return rv.ExitCode;
@ -664,22 +586,7 @@ namespace Xharness
HarnessLog = new ConsoleLog (); HarnessLog = new ConsoleLog ();
foreach (var project in IOSTestProjects) { foreach (var project in IOSTestProjects) {
var runner = new AppRunner (ProcessManager, var runner = CreateAppRunner (project);
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 rv = runner.RunAsync ().Result; var rv = runner.RunAsync ().Result;
if (rv != 0) if (rv != 0)
return rv; return rv;
@ -729,7 +636,6 @@ namespace Xharness
public int Execute () public int Execute ()
{ {
LoadConfig ();
switch (Action) { switch (Action) {
case HarnessAction.Configure: case HarnessAction.Configure:
return Configure (); return Configure ();
@ -753,7 +659,7 @@ namespace Xharness
AutoConfigureMac (false); AutoConfigureMac (false);
} }
var jenkins = new Jenkins.Jenkins (this, ProcessManager, ResultParser); var jenkins = new Jenkins.Jenkins (this, processManager, ResultParser);
return jenkins.Run (); return jenkins.Run ();
} }
@ -807,9 +713,23 @@ namespace Xharness
} }
} }
public Task<ProcessExecutionResult> ExecuteXcodeCommandAsync (string executable, IList<string> 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);
} }
} }
} }

Просмотреть файл

@ -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 // 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. // log all the required data.
public interface IAppRunner { public interface IAppRunner {
IProcessManager ProcessManager { get; }
AppBundleInformation AppInformation { get; } AppBundleInformation AppInformation { get; }
BuildToolTask BuildTask { get; } BuildToolTask BuildTask { get; }
TimeSpan GetNewTimeout (); TimeSpan GetNewTimeout ();
double LaunchTimeout { get; } double LaunchTimeout { get; }
IProcessManager ProcessManager { get; }
ILogs Logs { get; } ILogs Logs { get; }
ILog MainLog { get; } ILog MainLog { get; }
RunMode RunMode { get; } RunMode RunMode { get; }

Просмотреть файл

@ -103,15 +103,15 @@ namespace Xharness.Jenkins
this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager)); this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
this.resultParser = resultParser ?? throw new ArgumentNullException (nameof (resultParser)); this.resultParser = resultParser ?? throw new ArgumentNullException (nameof (resultParser));
Harness = harness ?? throw new ArgumentNullException (nameof (harness)); Harness = harness ?? throw new ArgumentNullException (nameof (harness));
simulators = new Simulators (harness, processManager); simulators = new Simulators (processManager);
devices = new Devices (harness, processManager); devices = new Devices (processManager);
} }
Task LoadAsync (ref ILog log, ILoadAsync loadable, string name) Task LoadAsync (ref ILog log, ILoadAsync loadable, string name)
{ {
loadable.Harness = Harness;
if (log == null) if (log == null)
log = Logs.Create ($"{name}-list-{Helpers.Timestamp}.log", $"{name} Listing"); log = Logs.Create ($"{name}-list-{Helpers.Timestamp}.log", $"{name} Listing");
log.Description = $"{name} Listing (in progress)"; log.Description = $"{name} Listing (in progress)";
var capturedLog = log; var capturedLog = log;
@ -481,7 +481,7 @@ namespace Xharness.Jenkins
clone.Xml.Save (clone.Path); clone.Xml.Save (clone.Path);
}); });
var build = new MSBuildTask { var build = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
TestProject = clone, TestProject = clone,
ProjectConfiguration = configuration, ProjectConfiguration = configuration,
@ -530,7 +530,7 @@ namespace Xharness.Jenkins
configurations = new string [] { "Debug" }; configurations = new string [] { "Debug" };
foreach (var config in configurations) { foreach (var config in configurations) {
foreach (var pair in ps) { foreach (var pair in ps) {
var derived = new MSBuildTask () { var derived = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
ProjectConfiguration = config, ProjectConfiguration = config,
ProjectPlatform = "iPhoneSimulator", ProjectPlatform = "iPhoneSimulator",
@ -584,7 +584,7 @@ namespace Xharness.Jenkins
projectTasks.Clear (); projectTasks.Clear ();
if (!project.SkipiOSVariation) { if (!project.SkipiOSVariation) {
var build64 = new MSBuildTask { var build64 = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
ProjectConfiguration = "Debug64", ProjectConfiguration = "Debug64",
ProjectPlatform = "iPhone", ProjectPlatform = "iPhone",
@ -594,7 +594,7 @@ namespace Xharness.Jenkins
build64.CloneTestProject (project); build64.CloneTestProject (project);
projectTasks.Add (new RunDeviceTask (devices, build64, processManager, devices.Connected64BitIOS.Where (d => d.IsSupported (project))) { Ignored = !IncludeiOS64 }); 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, Jenkins = this,
ProjectConfiguration = project.Name != "dont link" ? "Debug32" : "Release32", ProjectConfiguration = project.Name != "dont link" ? "Debug32" : "Release32",
ProjectPlatform = "iPhone", 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 }); projectTasks.Add (new RunDeviceTask (devices, build32, processManager, devices.Connected32BitIOS.Where (d => d.IsSupported (project))) { Ignored = !IncludeiOS32 });
var todayProject = project.AsTodayExtensionProject (); var todayProject = project.AsTodayExtensionProject ();
var buildToday = new MSBuildTask { var buildToday = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
ProjectConfiguration = "Debug64", ProjectConfiguration = "Debug64",
ProjectPlatform = "iPhone", ProjectPlatform = "iPhone",
@ -618,7 +618,7 @@ namespace Xharness.Jenkins
if (!project.SkiptvOSVariation) { if (!project.SkiptvOSVariation) {
var tvOSProject = project.AsTvOSProject (); var tvOSProject = project.AsTvOSProject ();
var buildTV = new MSBuildTask { var buildTV = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
ProjectConfiguration = "Debug", ProjectConfiguration = "Debug",
ProjectPlatform = "iPhone", ProjectPlatform = "iPhone",
@ -632,7 +632,7 @@ namespace Xharness.Jenkins
if (!project.SkipwatchOSVariation) { if (!project.SkipwatchOSVariation) {
var watchOSProject = project.AsWatchOSProject (); var watchOSProject = project.AsWatchOSProject ();
if (!project.SkipwatchOS32Variation) { if (!project.SkipwatchOS32Variation) {
var buildWatch32 = new MSBuildTask { var buildWatch32 = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
ProjectConfiguration = "Debug32", ProjectConfiguration = "Debug32",
ProjectPlatform = "iPhone", ProjectPlatform = "iPhone",
@ -644,7 +644,7 @@ namespace Xharness.Jenkins
} }
if (!project.SkipwatchOSARM64_32Variation) { if (!project.SkipwatchOSARM64_32Variation) {
var buildWatch64_32 = new MSBuildTask { var buildWatch64_32 = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
ProjectConfiguration = "Release64_32", // We don't support Debug for ARM64_32 yet. ProjectConfiguration = "Release64_32", // We don't support Debug for ARM64_32 yet.
ProjectPlatform = "iPhone", ProjectPlatform = "iPhone",
@ -720,7 +720,7 @@ namespace Xharness.Jenkins
void SelectTestsByModifiedFiles (int pull_request) 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); MainLog.WriteLine ("Found {0} modified file(s) in the pull request #{1}.", files.Count (), pull_request);
foreach (var f in files) foreach (var f in files)
@ -938,9 +938,9 @@ namespace Xharness.Jenkins
//Tasks.AddRange (await CreateRunSimulatorTasksAsync ()); //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, Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "Xamarin.iOS.Tasks.Tests.csproj"))), 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); Tasks.Add (nunitExecutioniOSMSBuild_net461);
var buildiOSMSBuild_netstandard2 = new MSBuildTask () { var buildiOSMSBuild_netstandard2 = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "Xamarin.iOS.Tasks.Tests.csproj"))), TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "Xamarin.iOS.Tasks.Tests.csproj"))),
SpecifyPlatform = false, SpecifyPlatform = false,
@ -988,7 +988,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (nunitExecutioniOSMSBuild_netstandard2); Tasks.Add (nunitExecutioniOSMSBuild_netstandard2);
var buildInstallSources = new MSBuildTask () var buildInstallSources = new MSBuildTask (processManager)
{ {
Jenkins = this, Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "InstallSourcesTests.csproj"))), 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 ()); throw new NotImplementedException (project.TargetFrameworkFlavors.ToString ());
} }
foreach (var config in configurations) { foreach (var config in configurations) {
MSBuildTask build = new MSBuildTask (); MSBuildTask build = new MSBuildTask (processManager);
build.Platform = platform; build.Platform = platform;
build.CloneTestProject (project); build.CloneTestProject (project);
build.Jenkins = this; build.Jenkins = this;
@ -1082,7 +1082,7 @@ namespace Xharness.Jenkins
} }
} }
var buildMTouch = new MakeTask () var buildMTouch = new MakeTask (processManager)
{ {
Jenkins = this, Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "mtouch", "mtouch.sln"))), TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "mtouch", "mtouch.sln"))),
@ -1104,7 +1104,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (nunitExecutionMTouch); Tasks.Add (nunitExecutionMTouch);
var buildGenerator = new MakeTask { var buildGenerator = new MakeTask (processManager) {
Jenkins = this, Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "src", "generator.sln"))), TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "src", "generator.sln"))),
SpecifyPlatform = false, SpecifyPlatform = false,
@ -1124,7 +1124,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (runGenerator); Tasks.Add (runGenerator);
var buildDotNetGenerator = new DotNetBuildTask { var buildDotNetGenerator = new DotNetBuildTask (processManager) {
Jenkins = this, Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "bgen", "bgen-tests.csproj"))), TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "bgen", "bgen-tests.csproj"))),
SpecifyPlatform = false, SpecifyPlatform = false,
@ -1140,7 +1140,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (runDotNetGenerator); Tasks.Add (runDotNetGenerator);
var run_mmp = new MakeTask var run_mmp = new MakeTask (processManager)
{ {
Jenkins = this, Jenkins = this,
Platform = TestPlatform.Mac, Platform = TestPlatform.Mac,
@ -1159,7 +1159,7 @@ namespace Xharness.Jenkins
run_mmp.Environment.Add ("BUILD_REVISION", "jenkins"); // This will print "@MonkeyWrench: AddFile: <log path>" lines, which we can use to get the log filenames. run_mmp.Environment.Add ("BUILD_REVISION", "jenkins"); // This will print "@MonkeyWrench: AddFile: <log path>" lines, which we can use to get the log filenames.
Tasks.Add (run_mmp); Tasks.Add (run_mmp);
var runMacBindingProject = new MakeTask var runMacBindingProject = new MakeTask (processManager)
{ {
Jenkins = this, Jenkins = this,
Platform = TestPlatform.Mac, Platform = TestPlatform.Mac,
@ -1171,7 +1171,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (runMacBindingProject); Tasks.Add (runMacBindingProject);
var buildXtroTests = new MakeTask { var buildXtroTests = new MakeTask (processManager) {
Jenkins = this, Jenkins = this,
Platform = TestPlatform.All, Platform = TestPlatform.All,
TestName = "Xtro", TestName = "Xtro",
@ -1189,7 +1189,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (runXtroReporter); Tasks.Add (runXtroReporter);
var buildCecilTests = new MakeTask { var buildCecilTests = new MakeTask (processManager) {
Jenkins = this, Jenkins = this,
Platform = TestPlatform.All, Platform = TestPlatform.All,
TestName = "Cecil", TestName = "Cecil",
@ -1209,7 +1209,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (runCecilTests); Tasks.Add (runCecilTests);
var runDocsTests = new MakeTask { var runDocsTests = new MakeTask (processManager) {
Jenkins = this, Jenkins = this,
Platform = TestPlatform.All, Platform = TestPlatform.All,
TestName = "Documentation", TestName = "Documentation",
@ -1220,7 +1220,7 @@ namespace Xharness.Jenkins
}; };
Tasks.Add (runDocsTests); Tasks.Add (runDocsTests);
var buildSampleTests = new MSBuildTask { var buildSampleTests = new MSBuildTask (processManager) {
Jenkins = this, Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "sampletester", "sampletester.sln"))), TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "sampletester", "sampletester.sln"))),
SpecifyPlatform = false, SpecifyPlatform = false,
@ -1253,7 +1253,7 @@ namespace Xharness.Jenkins
using (var process = new Process ()) { using (var process = new Process ()) {
process.StartInfo.FileName = Harness.PeriodicCommand; process.StartInfo.FileName = Harness.PeriodicCommand;
process.StartInfo.Arguments = Harness.PeriodicCommandArguments; 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) if (!rv.Succeeded)
periodic_loc.WriteLine ($"Periodic command failed with exit code {rv.ExitCode} (Timed out: {rv.TimedOut})"); 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. // We can populate and build test-libraries in parallel.
var populate = Task.Run (async () => { var populate = Task.Run (async () => {
var simulator = new SimulatorDevice (Harness, processManager); var simulator = new SimulatorDevice (processManager, new TCCDatabase (processManager));
await simulator.KillEverythingAsync (MainLog); await simulator.KillEverythingAsync (MainLog);
await PopulateTasksAsync (); await PopulateTasksAsync ();
populating = false; populating = false;
@ -1328,7 +1328,7 @@ namespace Xharness.Jenkins
var sb = new StringBuilder (); var sb = new StringBuilder ();
var callback_log = new CallbackLog ((v) => sb.Append (v)); var callback_log = new CallbackLog ((v) => sb.Append (v));
var log = Log.CreateAggregatedLog (callback_log, MainLog); 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; var per = v.Result;
if (!per.Succeeded) { if (!per.Succeeded) {
// Only show the log if something went wrong. // Only show the log if something went wrong.

Просмотреть файл

@ -4,6 +4,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml;
using Xharness.Execution;
using Xharness.Logging; using Xharness.Logging;
using Xharness.Utilities; using Xharness.Utilities;
@ -13,6 +14,10 @@ namespace Xharness.Jenkins.TestTasks
{ {
public string SolutionPath; public string SolutionPath;
protected BuildProjectTask (IProcessManager processManager) : base (processManager)
{
}
public bool RestoreNugets { public bool RestoreNugets {
get { get {
return TestProject.RestoreNugetsInProject || !string.IsNullOrEmpty (SolutionPath); return TestProject.RestoreNugetsInProject || !string.IsNullOrEmpty (SolutionPath);

Просмотреть файл

@ -6,9 +6,15 @@ namespace Xharness.Jenkins.TestTasks
{ {
public abstract class BuildToolTask : TestTask public abstract class BuildToolTask : TestTask
{ {
protected readonly IProcessManager ProcessManager;
public bool SpecifyPlatform = true; public bool SpecifyPlatform = true;
public bool SpecifyConfiguration = 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 { public override string Mode {
get { return Platform.ToString (); } get { return Platform.ToString (); }

Просмотреть файл

@ -1,10 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using Xharness.Execution;
namespace Xharness.Jenkins.TestTasks { namespace Xharness.Jenkins.TestTasks {
class DotNetBuildTask : MSBuildTask { class DotNetBuildTask : MSBuildTask {
public DotNetBuildTask () public DotNetBuildTask (IProcessManager processManager) : base (processManager)
{ {
SetDotNetEnvironmentVariables (Environment); SetDotNetEnvironmentVariables (Environment);
} }

Просмотреть файл

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml;
using Xharness.Execution;
using Xharness.Logging; using Xharness.Logging;
using Xharness.Utilities; using Xharness.Utilities;
@ -31,6 +32,10 @@ namespace Xharness.Jenkins.TestTasks
} }
} }
public MSBuildTask (IProcessManager processManager) : base (processManager)
{
}
protected override async Task ExecuteAsync () protected override async Task ExecuteAsync ()
{ {
using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) { using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) {

Просмотреть файл

@ -1,6 +1,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xharness.Execution;
using Xharness.Logging; using Xharness.Logging;
namespace Xharness.Jenkins.TestTasks namespace Xharness.Jenkins.TestTasks
@ -11,6 +12,10 @@ namespace Xharness.Jenkins.TestTasks
public string WorkingDirectory; public string WorkingDirectory;
public TimeSpan Timeout = TimeSpan.FromMinutes (5); public TimeSpan Timeout = TimeSpan.FromMinutes (5);
public MakeTask (IProcessManager processManager) : base (processManager)
{
}
protected override async Task ExecuteAsync () protected override async Task ExecuteAsync ()
{ {
using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) { using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) {

Просмотреть файл

@ -11,9 +11,9 @@ namespace Xharness.Jenkins.TestTasks
{ {
class RunDeviceTask : RunXITask<IHardwareDevice> class RunDeviceTask : RunXITask<IHardwareDevice>
{ {
readonly IProcessManager processManager = new ProcessManager ();
readonly IResultParser resultParser = new XmlResultParser (); readonly IResultParser resultParser = new XmlResultParser ();
readonly IDeviceLoader devices; readonly IDeviceLoader devices;
AppInstallMonitorLog install_log; AppInstallMonitorLog install_log;
public override string ProgressMessage { public override string ProgressMessage {
@ -81,14 +81,14 @@ namespace Xharness.Jenkins.TestTasks
CompanionDevice = devices.FindCompanionDevice (Jenkins.DeviceLoadLog, Device); CompanionDevice = devices.FindCompanionDevice (Jenkins.DeviceLoadLog, Device);
Jenkins.MainLog.WriteLine ("Acquired device '{0}' for '{1}'", Device.Name, ProjectFile); Jenkins.MainLog.WriteLine ("Acquired device '{0}' for '{1}'", Device.Name, ProjectFile);
runner = new AppRunner (processManager, runner = new AppRunner (ProcessManager,
new AppBundleInformationParser (), new AppBundleInformationParser (),
new SimulatorsLoaderFactory (Harness, processManager), new SimulatorsLoaderFactory (ProcessManager),
new SimpleListenerFactory (), new SimpleListenerFactory (),
new DeviceLoaderFactory (Harness, processManager), new DeviceLoaderFactory (ProcessManager),
new CrashSnapshotReporterFactory (ProcessManager, Harness.XcodeRoot, Harness.MlaunchPath), new CrashSnapshotReporterFactory (ProcessManager),
new CaptureLogFactory (), new CaptureLogFactory (),
new DeviceLogCapturerFactory (processManager, Harness.XcodeRoot, Harness.MlaunchPath), new DeviceLogCapturerFactory (ProcessManager),
new TestReporterFactory (), new TestReporterFactory (),
AppRunnerTarget, AppRunnerTarget,
Harness, Harness,
@ -148,14 +148,14 @@ namespace Xharness.Jenkins.TestTasks
// nor will it close & reopen the today app (but launching the main app // 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). // 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 AppBundleInformationParser (),
new SimulatorsLoaderFactory (Harness, processManager), new SimulatorsLoaderFactory (ProcessManager),
new SimpleListenerFactory (), new SimpleListenerFactory (),
new DeviceLoaderFactory (Harness, processManager), new DeviceLoaderFactory (ProcessManager),
new CrashSnapshotReporterFactory (ProcessManager, Harness.XcodeRoot, Harness.MlaunchPath), new CrashSnapshotReporterFactory (ProcessManager),
new CaptureLogFactory (), new CaptureLogFactory (),
new DeviceLogCapturerFactory (processManager, Harness.XcodeRoot, Harness.MlaunchPath), new DeviceLogCapturerFactory (ProcessManager),
new TestReporterFactory (), new TestReporterFactory (),
AppRunnerTarget, AppRunnerTarget,
Harness, Harness,

Просмотреть файл

@ -13,7 +13,6 @@ namespace Xharness.Jenkins.TestTasks
{ {
class RunSimulatorTask : RunXITask<ISimulatorDevice> class RunSimulatorTask : RunXITask<ISimulatorDevice>
{ {
readonly IProcessManager processManager = new ProcessManager ();
readonly ISimulatorsLoader simulators; readonly ISimulatorsLoader simulators;
public IAcquiredResource AcquiredResource; public IAcquiredResource AcquiredResource;
@ -77,14 +76,14 @@ namespace Xharness.Jenkins.TestTasks
await FindSimulatorAsync (); await FindSimulatorAsync ();
var clean_state = false;//Platform == TestPlatform.watchOS; var clean_state = false;//Platform == TestPlatform.watchOS;
runner = new AppRunner (processManager, runner = new AppRunner (ProcessManager,
new AppBundleInformationParser (), new AppBundleInformationParser (),
new SimulatorsLoaderFactory (Harness, processManager), new SimulatorsLoaderFactory (ProcessManager),
new SimpleListenerFactory (), new SimpleListenerFactory (),
new DeviceLoaderFactory (Harness, processManager), new DeviceLoaderFactory (ProcessManager),
new CrashSnapshotReporterFactory (ProcessManager, Harness.XcodeRoot, Harness.MlaunchPath), new CrashSnapshotReporterFactory (ProcessManager),
new CaptureLogFactory (), new CaptureLogFactory (),
new DeviceLogCapturerFactory (processManager, Harness.XcodeRoot, Harness.MlaunchPath), new DeviceLogCapturerFactory (ProcessManager),
new TestReporterFactory (), new TestReporterFactory (),
AppRunnerTarget, AppRunnerTarget,
Harness, Harness,

Просмотреть файл

@ -105,7 +105,7 @@ namespace Xharness {
// XS sets this, which breaks pretty much everything if it doesn't match what was passed to --sdkroot. // 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); 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 (); return harness.Execute ();
} }

Просмотреть файл

@ -40,7 +40,7 @@ namespace Xharness.Tests.Execution.Tests {
stdoutLog = new LogFile ("my stdout log", stdoutLogPath); stdoutLog = new LogFile ("my stdout log", stdoutLogPath);
stderrLog = new LogFile ("my stderr log", stderrLogPath); stderrLog = new LogFile ("my stderr log", stderrLogPath);
dummyProcess = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "DummyTestProcess.exe"); 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 = new Process ();
testProcess.StartInfo.FileName = "mono"; testProcess.StartInfo.FileName = "mono";
} }
@ -112,7 +112,7 @@ namespace Xharness.Tests.Execution.Tests {
{ {
var source = new CancellationTokenSource (); var source = new CancellationTokenSource ();
testProcess.StartInfo.Arguments = $"{dummyProcess} --exit-code={resultCode} --timeout={timeoutCount} --stdout=\"{stdoutMessage}\" --stderr=\"{stderrMessage}\""; 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) if (!timeout)
Assert.AreEqual (resultCode, result.ExitCode, "exit code"); Assert.AreEqual (resultCode, result.ExitCode, "exit code");
Assert.AreEqual (success, result.Succeeded, "success"); Assert.AreEqual (success, result.Succeeded, "success");

Просмотреть файл

@ -20,16 +20,14 @@ namespace Xharness.Tests.Hardware.Tests {
Devices devices; Devices devices;
string mlaunchPath; string mlaunchPath;
string sdkPath; string sdkPath;
Mock<IHarness> harness;
Mock<IProcessManager> processManager; Mock<IProcessManager> processManager;
Mock<ILog> executionLog; Mock<ILog> executionLog;
[SetUp] [SetUp]
public void SetUp () public void SetUp ()
{ {
harness = new Mock<IHarness> ();
processManager = new Mock<IProcessManager> (); processManager = new Mock<IProcessManager> ();
devices = new Devices (harness.Object, processManager.Object); devices = new Devices (processManager.Object);
executionLog = new Mock<ILog> (); executionLog = new Mock<ILog> ();
mlaunchPath = "/usr/bin/mlaunch"; // any will be ok, is mocked mlaunchPath = "/usr/bin/mlaunch"; // any will be ok, is mocked
sdkPath = "/Applications/Xcode.app"; sdkPath = "/Applications/Xcode.app";
@ -38,7 +36,6 @@ namespace Xharness.Tests.Hardware.Tests {
[TearDown] [TearDown]
public void TearDown () public void TearDown ()
{ {
harness = null;
processManager = null; processManager = null;
executionLog = null; executionLog = null;
devices = null; devices = null;
@ -50,10 +47,7 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
string processPath = null; string processPath = null;
MlaunchArguments passedArguments = 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 // 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<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>>(), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ())) processManager.Setup (p => p.RunAsync (It.IsAny<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>>(), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ()))
.Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary< string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { .Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary< string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => {
@ -87,10 +81,7 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
string processPath = null; string processPath = null;
MlaunchArguments passedArguments = 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 // 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<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>> (), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ())) processManager.Setup (p => p.RunAsync (It.IsAny<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>> (), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ()))
.Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary<string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { .Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary<string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => {

Просмотреть файл

@ -14,7 +14,6 @@ namespace Xharness.Tests.Hardware.Tests {
Mock<ILog> executionLog; Mock<ILog> executionLog;
Mock<IProcessManager> processManager; Mock<IProcessManager> processManager;
Mock<IHarness> harness;
SimulatorDevice simulator; SimulatorDevice simulator;
[SetUp] [SetUp]
@ -22,8 +21,7 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
executionLog = new Mock<ILog> (); executionLog = new Mock<ILog> ();
processManager = new Mock<IProcessManager> (); processManager = new Mock<IProcessManager> ();
harness = new Mock<IHarness> (); simulator = new SimulatorDevice (processManager.Object, new TCCDatabase (processManager.Object)) {
simulator = new SimulatorDevice (harness.Object, processManager.Object) {
UDID = Guid.NewGuid ().ToString () UDID = Guid.NewGuid ().ToString ()
}; };
} }
@ -57,10 +55,10 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
// just call and verify the correct args are pass // just call and verify the correct args are pass
await simulator.EraseAsync (executionLog.Object); await simulator.EraseAsync (executionLog.Object);
harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ())); processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ()));
harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "erase").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ())); processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "erase").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ()));
harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "boot").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ())); processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "boot").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ()));
harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ())); processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ()));
} }
@ -69,7 +67,7 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
await simulator.ShutdownAsync (executionLog.Object); await simulator.ShutdownAsync (executionLog.Object);
// just call and verify the correct args are pass // just call and verify the correct args are pass
harness.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ())); processManager.Verify (h => h.ExecuteXcodeCommandAsync (It.Is<string> (s => s == "simctl"), It.Is<string []> (args => args.Where (a => a == simulator.UDID || a == "shutdown").Count () == 2), It.IsAny<ILog> (), It.IsAny<TimeSpan> ()));
} }
[Test] [Test]
@ -81,7 +79,7 @@ namespace Xharness.Tests.Hardware.Tests {
return args.Where (a => toKill.Contains (a)).Count () == toKill.Count; return args.Where (a => toKill.Contains (a)).Count () == toKill.Count;
}; };
var simulator = new SimulatorDevice (Mock.Of<IHarness> (), processManager.Object); var simulator = new SimulatorDevice (processManager.Object, new TCCDatabase (processManager.Object));
await simulator.KillEverythingAsync (executionLog.Object); await simulator.KillEverythingAsync (executionLog.Object);
// verify that all the diff process have been killed making sure args are correct // verify that all the diff process have been killed making sure args are correct

Просмотреть файл

@ -19,7 +19,6 @@ namespace Xharness.Tests.Hardware.Tests {
string mlaunchPath; string mlaunchPath;
string sdkPath; string sdkPath;
Mock<IHarness> harness;
Mock<ILog> executionLog; Mock<ILog> executionLog;
Mock<IProcessManager> processManager; Mock<IProcessManager> processManager;
Simulators simulators; Simulators simulators;
@ -29,10 +28,9 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
mlaunchPath = "/usr/bin/mlaunch"; // any will be ok, is mocked mlaunchPath = "/usr/bin/mlaunch"; // any will be ok, is mocked
sdkPath = "/Applications/Xcode.app"; sdkPath = "/Applications/Xcode.app";
harness = new Mock<IHarness> ();
executionLog = new Mock<ILog> (); executionLog = new Mock<ILog> ();
processManager = new Mock<IProcessManager> (); processManager = new Mock<IProcessManager> ();
simulators = new Simulators (harness.Object, processManager.Object); simulators = new Simulators (processManager.Object);
} }
[TearDown] [TearDown]
@ -49,10 +47,7 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
string processPath = null; string processPath = null;
MlaunchArguments passedArguments = 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 // 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<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>> (), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ())) processManager.Setup (p => p.RunAsync (It.IsAny<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>> (), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ()))
.Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary<string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { .Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary<string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => {
@ -97,10 +92,7 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
string processPath = null; string processPath = null;
MlaunchArguments passedArguments = 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 // 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<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>> (), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ())) processManager.Setup (p => p.RunAsync (It.IsAny<Process> (), It.IsAny<MlaunchArguments> (), It.IsAny<ILog> (), It.IsAny<TimeSpan?> (), It.IsAny<Dictionary<string, string>> (), It.IsAny<CancellationToken?> (), It.IsAny<bool?> ()))
.Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary<string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { .Returns<Process, MlaunchArguments, ILog, TimeSpan?, Dictionary<string, string>, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => {
@ -141,11 +133,8 @@ namespace Xharness.Tests.Hardware.Tests {
{ {
string processPath = null; string processPath = null;
MlaunchArguments passedArguments = null; MlaunchArguments passedArguments = null;
// set the expectations of the mocks to get an error when
// executing the process processManager
harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath);
harness.Setup (h => h.XcodeRoot).Returns (sdkPath);
harness
.Setup (h => h.ExecuteXcodeCommandAsync ("simctl", It.Is<string []> (args => args[0] == "create"), executionLog.Object, TimeSpan.FromMinutes (1))) .Setup (h => h.ExecuteXcodeCommandAsync ("simctl", It.Is<string []> (args => args[0] == "create"), executionLog.Object, TimeSpan.FromMinutes (1)))
.ReturnsAsync (new ProcessExecutionResult () { ExitCode = 0 }); .ReturnsAsync (new ProcessExecutionResult () { ExitCode = 0 });

Просмотреть файл

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -25,9 +24,7 @@ namespace Xharness.Tests.Hardware.Tests {
public void SetUp () public void SetUp ()
{ {
processManager = new Mock<IProcessManager> (); processManager = new Mock<IProcessManager> ();
database = new TCCDatabase { database = new TCCDatabase (processManager.Object);
ProcessManager = processManager.Object,
};
executionLog = new Mock<ILog> (); executionLog = new Mock<ILog> ();
simRuntime = "com.apple.CoreSimulator.SimRuntime.iOS-12-1"; simRuntime = "com.apple.CoreSimulator.SimRuntime.iOS-12-1";
dataPath = "/path/to/my/data"; dataPath = "/path/to/my/data";

Просмотреть файл

@ -218,9 +218,7 @@ namespace Xharness.Tests {
[Test] [Test]
public async Task InstallOnDeviceTest () public async Task InstallOnDeviceTest ()
{ {
var harness = Mock.Of<IHarness> (x => x.XcodeRoot == "/path/to/xcode" var harness = Mock.Of<IHarness> (x => x.Verbosity == 2);
&& x.MlaunchPath == "/path/to/mlaunch"
&& x.Verbosity == 2);
var processResult = new ProcessExecutionResult () { ExitCode = 1, TimedOut = false }; var processResult = new ProcessExecutionResult () { ExitCode = 1, TimedOut = false };
processManager.SetReturnsDefault (Task.FromResult (processResult)); processManager.SetReturnsDefault (Task.FromResult (processResult));
@ -250,12 +248,9 @@ namespace Xharness.Tests {
// Verify // Verify
Assert.AreEqual (1, result.ExitCode); Assert.AreEqual (1, result.ExitCode);
var expectedArgs = $"--sdkroot /path/to/xcode -v -v -v " + var expectedArgs = $"-v -v -v --installdev {StringUtils.FormatArguments (appPath)} --devname \"Test iPad\"";
$"--installdev {StringUtils.FormatArguments (appPath)} " +
$"--devname \"Test iPad\"";
processManager.Verify (x => x.ExecuteCommandAsync ( processManager.Verify (x => x.ExecuteCommandAsync (
"/path/to/mlaunch",
It.Is<MlaunchArguments> (args => args.AsCommandLine() == expectedArgs), It.Is<MlaunchArguments> (args => args.AsCommandLine() == expectedArgs),
mainLog.Object, mainLog.Object,
TimeSpan.FromHours (1), TimeSpan.FromHours (1),
@ -266,9 +261,7 @@ namespace Xharness.Tests {
[Test] [Test]
public async Task UninstallFromDeviceTest () public async Task UninstallFromDeviceTest ()
{ {
var harness = Mock.Of<IHarness> (x => x.XcodeRoot == "/path/to/xcode" var harness = Mock.Of<IHarness> (x => x.Verbosity == 1);
&& x.MlaunchPath == "/path/to/mlaunch"
&& x.Verbosity == 1);
var processResult = new ProcessExecutionResult () { ExitCode = 3, TimedOut = false }; var processResult = new ProcessExecutionResult () { ExitCode = 3, TimedOut = false };
processManager.SetReturnsDefault (Task.FromResult (processResult)); processManager.SetReturnsDefault (Task.FromResult (processResult));
@ -297,12 +290,9 @@ namespace Xharness.Tests {
// Verify // Verify
Assert.AreEqual (3, result.ExitCode); Assert.AreEqual (3, result.ExitCode);
var expectedArgs = $"--sdkroot /path/to/xcode -v -v " + var expectedArgs = $"-v -v --uninstalldevbundleid {StringUtils.FormatArguments (appName)} --devname \"Test iPad\"";
$"--uninstalldevbundleid {StringUtils.FormatArguments (appName)} " +
$"--devname \"Test iPad\"";
processManager.Verify (x => x.ExecuteCommandAsync ( processManager.Verify (x => x.ExecuteCommandAsync (
"/path/to/mlaunch",
It.Is<MlaunchArguments> (args => args.AsCommandLine() == expectedArgs), It.Is<MlaunchArguments> (args => args.AsCommandLine() == expectedArgs),
mainLog.Object, mainLog.Object,
TimeSpan.FromMinutes (1), TimeSpan.FromMinutes (1),
@ -461,7 +451,6 @@ namespace Xharness.Tests {
processManager processManager
.Setup (x => x.ExecuteCommandAsync ( .Setup (x => x.ExecuteCommandAsync (
mlaunchPath,
It.Is<MlaunchArguments> (args => args.AsCommandLine() == expectedArgs), It.Is<MlaunchArguments> (args => args.AsCommandLine() == expectedArgs),
mainLog.Object, mainLog.Object,
TimeSpan.FromMinutes (harness.Timeout * 2), TimeSpan.FromMinutes (harness.Timeout * 2),
@ -612,7 +601,7 @@ namespace Xharness.Tests {
ips.Append (ipAddresses [i].ToString ()); 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 " + $"-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=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} " + $"-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1 -argument=-app-arg:-hostname:{ips} -setenv=NUNIT_HOSTNAME={ips} " +
@ -622,7 +611,6 @@ namespace Xharness.Tests {
processManager processManager
.Setup (x => x.ExecuteCommandAsync ( .Setup (x => x.ExecuteCommandAsync (
mlaunchPath,
It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs), It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs),
It.IsAny<ILog> (), It.IsAny<ILog> (),
TimeSpan.FromMinutes (harness.Timeout * 2), TimeSpan.FromMinutes (harness.Timeout * 2),
@ -633,18 +621,18 @@ namespace Xharness.Tests {
var xmlResultFile = Path.ChangeExtension (testResultFilePath, "xml"); var xmlResultFile = Path.ChangeExtension (testResultFilePath, "xml");
var testReporterFactory = new Mock<ITestReporterFactory> (); var testReporterFactory = new Mock<ITestReporterFactory> ();
var testReporter = new Mock<ITestReporter> (); var testReporter = new Mock<ITestReporter> ();
testReporterFactory.Setup (f => f.Create ( testReporterFactory
.Setup (f => f.Create (
It.IsAny<IAppRunner> (), It.IsAny<IAppRunner> (),
It.IsAny<string> (), "Test iPad",
It.IsAny<ISimpleListener> (), It.IsAny<ISimpleListener> (),
It.IsAny<ILog> (), mainLog.Object,
It.IsAny<ICrashSnapshotReporter> (), snapshotReporter.Object,
It.IsAny<IResultParser> ())).Returns (testReporter.Object); It.IsAny<IResultParser> ()))
.Returns (testReporter.Object);
testReporter.Setup (r => r.Timeout).Returns (TimeSpan.FromMinutes (harness.Timeout * 2)); 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.TimeoutWatch).Returns (new System.Diagnostics.Stopwatch ());
testReporter.Setup (r => r.ParseResult ()).Returns (() => { testReporter.Setup (r => r.ParseResult ()).Returns (() => Task.FromResult<(TestExecutingResult, string)> ((TestExecutingResult.Succeeded, null)));
return Task.FromResult<(TestExecutingResult, string)> ((TestExecutingResult.Succeeded, null));
});
testReporter.Setup (r => r.Success).Returns (true); testReporter.Setup (r => r.Success).Returns (true);
// Act // Act
@ -728,7 +716,7 @@ namespace Xharness.Tests {
ips.Append (ipAddresses [i].ToString ()); 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 " + $"-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=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} " + $"-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1 -argument=-app-arg:-hostname:{ips} -setenv=NUNIT_HOSTNAME={ips} " +
@ -738,7 +726,6 @@ namespace Xharness.Tests {
processManager processManager
.Setup (x => x.ExecuteCommandAsync ( .Setup (x => x.ExecuteCommandAsync (
mlaunchPath,
It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs), It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs),
It.IsAny<ILog> (), It.IsAny<ILog> (),
TimeSpan.FromMinutes (harness.Timeout * 2), TimeSpan.FromMinutes (harness.Timeout * 2),
@ -749,13 +736,15 @@ namespace Xharness.Tests {
var xmlResultFile = Path.ChangeExtension (testResultFilePath, "xml"); var xmlResultFile = Path.ChangeExtension (testResultFilePath, "xml");
var testReporterFactory = new Mock<ITestReporterFactory> (); var testReporterFactory = new Mock<ITestReporterFactory> ();
var testReporter = new Mock<ITestReporter> (); var testReporter = new Mock<ITestReporter> ();
testReporterFactory.Setup (f => f.Create ( testReporterFactory
.Setup (f => f.Create (
It.IsAny<IAppRunner> (), It.IsAny<IAppRunner> (),
It.IsAny<string> (), "Test iPad",
It.IsAny<ISimpleListener> (), It.IsAny<ISimpleListener> (),
It.IsAny<ILog> (), mainLog.Object,
It.IsAny<ICrashSnapshotReporter> (), snapshotReporter.Object,
It.IsAny<IResultParser> ())).Returns (testReporter.Object); It.IsAny<IResultParser> ()))
.Returns (testReporter.Object);
testReporter.Setup (r => r.Timeout).Returns (TimeSpan.FromMinutes (harness.Timeout * 2)); 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.TimeoutWatch).Returns (new System.Diagnostics.Stopwatch ());
testReporter.Setup (r => r.ParseResult ()).Returns (() => { testReporter.Setup (r => r.ParseResult ()).Returns (() => {
@ -802,11 +791,8 @@ namespace Xharness.Tests {
IHarness GetMockedHarness () IHarness GetMockedHarness ()
{ {
return Mock.Of<IHarness> (x => x.Action == HarnessAction.Run return Mock.Of<IHarness> (x => x.Action == HarnessAction.Run
&& x.XcodeRoot == xcodePath
&& x.MlaunchPath == mlaunchPath
&& x.Verbosity == 1 && x.Verbosity == 1
&& x.HarnessLog == mainLog.Object && x.HarnessLog == mainLog.Object
&& x.LogDirectory == logs.Object.Directory
&& x.InCI == false && x.InCI == false
&& x.EnvironmentVariables == new Dictionary<string, string> () { && x.EnvironmentVariables == new Dictionary<string, string> () {
{ "env1", "value1" }, { "env1", "value1" },

Просмотреть файл

@ -12,8 +12,8 @@ using Xharness.Utilities;
namespace Xharness.Tests { namespace Xharness.Tests {
[TestFixture] [TestFixture]
public class CrashSnapshotReporterTests { public class CrashReportSnapshotTests {
readonly string mlaunchPath = "./mlaunch";
string tempXcodeRoot; string tempXcodeRoot;
string symbolicatePath; string symbolicatePath;
@ -31,6 +31,9 @@ namespace Xharness.Tests {
tempXcodeRoot = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ()); tempXcodeRoot = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
symbolicatePath = Path.Combine (tempXcodeRoot, "Contents", "SharedFrameworks", "DTDeviceKitBase.framework", "Versions", "A", "Resources"); 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 // Create fake place for device logs
Directory.CreateDirectory (tempXcodeRoot); Directory.CreateDirectory (tempXcodeRoot);
@ -71,8 +74,6 @@ namespace Xharness.Tests {
var snapshotReport = new CrashSnapshotReporter (processManager.Object, var snapshotReport = new CrashSnapshotReporter (processManager.Object,
log.Object, log.Object,
logs.Object, logs.Object,
tempXcodeRoot,
mlaunchPath,
true, true,
deviceName, deviceName,
() => tempFilePath); () => tempFilePath);
@ -91,10 +92,9 @@ namespace Xharness.Tests {
// List of crash reports is retrieved // List of crash reports is retrieved
processManager.Verify ( processManager.Verify (
x => x.ExecuteCommandAsync ( x => x.ExecuteCommandAsync (
mlaunchPath,
It.Is<MlaunchArguments> (args => args.AsCommandLine () == It.Is<MlaunchArguments> (args => args.AsCommandLine () ==
StringUtils.FormatArguments ($"--list-crash-reports={tempFilePath}") + " " + StringUtils.FormatArguments (
$"--sdkroot {StringUtils.FormatArguments (tempXcodeRoot)} " + $"--list-crash-reports={tempFilePath}") + " " +
$"--devname {StringUtils.FormatArguments (deviceName)}"), $"--devname {StringUtils.FormatArguments (deviceName)}"),
log.Object, log.Object,
TimeSpan.FromMinutes (1), TimeSpan.FromMinutes (1),
@ -105,11 +105,10 @@ namespace Xharness.Tests {
// Device crash log is downloaded // Device crash log is downloaded
processManager.Verify ( processManager.Verify (
x => x.ExecuteCommandAsync ( x => x.ExecuteCommandAsync (
mlaunchPath,
It.Is<MlaunchArguments> (args => args.AsCommandLine () == It.Is<MlaunchArguments> (args => args.AsCommandLine () ==
StringUtils.FormatArguments ($"--download-crash-report={deviceName}") + " " + StringUtils.FormatArguments (
$"--download-crash-report={deviceName}") + " " +
StringUtils.FormatArguments ($"--download-crash-report-to={crashLogPath}") + " " + StringUtils.FormatArguments ($"--download-crash-report-to={crashLogPath}") + " " +
$"--sdkroot {StringUtils.FormatArguments (tempXcodeRoot)} " +
$"--devname {StringUtils.FormatArguments (deviceName)}"), $"--devname {StringUtils.FormatArguments (deviceName)}"),
log.Object, log.Object,
TimeSpan.FromMinutes (1), TimeSpan.FromMinutes (1),