[Harness] Add strongly typed mlaunch args and escape them (#8167)
Co-authored-by: Premek Vysoky <prvysoky@microsoft.com>
This commit is contained in:
Родитель
13e199a685
Коммит
d98c515a4c
|
@ -6,8 +6,9 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Execution.Mlaunch;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Jenkins.TestTasks;
|
||||
using Xharness.Listeners;
|
||||
using Xharness.Logging;
|
||||
|
@ -25,13 +26,10 @@ namespace Xharness {
|
|||
readonly IDeviceLogCapturerFactory deviceLogCapturerFactory;
|
||||
readonly ITestReporterFactory testReporterFactory;
|
||||
|
||||
readonly RunMode runMode;
|
||||
readonly bool isSimulator;
|
||||
readonly TestTarget target;
|
||||
readonly IHarness harness;
|
||||
readonly string variation;
|
||||
readonly double timeoutMultiplier;
|
||||
readonly string logDirectory;
|
||||
|
||||
string deviceName;
|
||||
string companionDeviceName;
|
||||
|
@ -107,7 +105,6 @@ namespace Xharness {
|
|||
this.companionDeviceName = companionDeviceName;
|
||||
this.ensureCleanSimulatorState = ensureCleanSimulatorState;
|
||||
this.simulators = simulators;
|
||||
this.variation = variation;
|
||||
this.BuildTask = buildTask;
|
||||
this.target = target;
|
||||
|
||||
|
@ -122,7 +119,7 @@ namespace Xharness {
|
|||
if (simulators != null)
|
||||
return true;
|
||||
|
||||
var sims = simulatorsLoaderFactory.CreateLoader();
|
||||
var sims = simulatorsLoaderFactory.CreateLoader ();
|
||||
await sims.LoadAsync (Logs.Create ($"simulator-list-{Helpers.Timestamp}.log", "Simulator list"), false, false);
|
||||
simulators = await sims.FindAsync (target, MainLog);
|
||||
|
||||
|
@ -139,8 +136,7 @@ namespace Xharness {
|
|||
return;
|
||||
|
||||
var devs = devicesLoaderFactory.CreateLoader ();
|
||||
Task.Run (async () =>
|
||||
{
|
||||
Task.Run (async () => {
|
||||
await devs.LoadAsync (MainLog, false, false);
|
||||
}).Wait ();
|
||||
|
||||
|
@ -165,8 +161,7 @@ namespace Xharness {
|
|||
throw new NoDeviceFoundException ($"Could not find any applicable devices with device class(es): {string.Join (", ", deviceClasses)}");
|
||||
} else if (selected.Count () > 1) {
|
||||
selected_data = selected
|
||||
.OrderBy ((dev) =>
|
||||
{
|
||||
.OrderBy ((dev) => {
|
||||
Version v;
|
||||
if (Version.TryParse (dev.ProductVersion, out v))
|
||||
return v;
|
||||
|
@ -193,21 +188,20 @@ namespace Xharness {
|
|||
|
||||
FindDevice ();
|
||||
|
||||
var args = new List<string> ();
|
||||
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
|
||||
args.Add ("--sdkroot");
|
||||
args.Add (harness.XcodeRoot);
|
||||
}
|
||||
for (int i = -1; i < harness.Verbosity; i++)
|
||||
args.Add ("-v");
|
||||
var args = new MlaunchArguments ();
|
||||
|
||||
args.Add ("--installdev");
|
||||
args.Add (AppInformation.AppPath);
|
||||
AddDeviceName (args, companionDeviceName ?? deviceName);
|
||||
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
|
||||
args.Add (new SdkRootArgument (harness.XcodeRoot));
|
||||
}
|
||||
|
||||
for (int i = -1; i < harness.Verbosity; i++)
|
||||
args.Add (new VerbosityArgument ());
|
||||
|
||||
args.Add (new InstallAppOnDeviceArgument (AppInformation.AppPath));
|
||||
args.Add (new DeviceNameArgument (companionDeviceName ?? deviceName));
|
||||
|
||||
if (RunMode == RunMode.WatchOS) {
|
||||
args.Add ("--device");
|
||||
args.Add ("ios,watchos");
|
||||
args.Add (new DeviceArgument ("ios,watchos"));
|
||||
}
|
||||
|
||||
var totalSize = Directory.GetFiles (AppInformation.AppPath, "*", SearchOption.AllDirectories).Select ((v) => new FileInfo (v).Length).Sum ();
|
||||
|
@ -223,17 +217,17 @@ namespace Xharness {
|
|||
|
||||
FindDevice ();
|
||||
|
||||
var args = new List<string> ();
|
||||
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
|
||||
args.Add ("--sdkroot");
|
||||
args.Add (harness.XcodeRoot);
|
||||
}
|
||||
for (int i = -1; i < harness.Verbosity; i++)
|
||||
args.Add ("-v");
|
||||
var args = new MlaunchArguments ();
|
||||
|
||||
args.Add ("--uninstalldevbundleid");
|
||||
args.Add (AppInformation.BundleIdentifier);
|
||||
AddDeviceName (args, companionDeviceName ?? deviceName);
|
||||
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
|
||||
args.Add (new SdkRootArgument (harness.XcodeRoot));
|
||||
}
|
||||
|
||||
for (int i = -1; i < harness.Verbosity; i++)
|
||||
args.Add (new VerbosityArgument ());
|
||||
|
||||
args.Add (new UninstallAppFromDeviceArgument (AppInformation.BundleIdentifier));
|
||||
args.Add (new DeviceNameArgument (companionDeviceName ?? deviceName));
|
||||
|
||||
return await ProcessManager.ExecuteCommandAsync (harness.MlaunchPath, args, MainLog, TimeSpan.FromMinutes (1));
|
||||
}
|
||||
|
@ -247,42 +241,42 @@ namespace Xharness {
|
|||
if (!isSimulator)
|
||||
FindDevice ();
|
||||
|
||||
var args = new List<string> ();
|
||||
var args = new MlaunchArguments ();
|
||||
|
||||
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
|
||||
args.Add ("--sdkroot");
|
||||
args.Add (harness.XcodeRoot);
|
||||
args.Add (new SdkRootArgument (harness.XcodeRoot));
|
||||
}
|
||||
|
||||
for (int i = -1; i < harness.Verbosity; i++)
|
||||
args.Add ("-v");
|
||||
args.Add ("-argument=-connection-mode");
|
||||
args.Add ("-argument=none"); // This will prevent the app from trying to connect to any IDEs
|
||||
args.Add ("-argument=-app-arg:-autostart");
|
||||
args.Add ("-setenv=NUNIT_AUTOSTART=true");
|
||||
args.Add ("-argument=-app-arg:-autoexit");
|
||||
args.Add ("-setenv=NUNIT_AUTOEXIT=true");
|
||||
args.Add ("-argument=-app-arg:-enablenetwork");
|
||||
args.Add ("-setenv=NUNIT_ENABLE_NETWORK=true");
|
||||
args.Add (new VerbosityArgument ());
|
||||
|
||||
args.Add (new SetAppArgumentArgument ("-connection-mode"));
|
||||
args.Add (new SetAppArgumentArgument ("none")); // This will prevent the app from trying to connect to any IDEs
|
||||
args.Add (new SetAppArgumentArgument ("-autostart", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_AUTOSTART", true));
|
||||
args.Add (new SetAppArgumentArgument ("-autoexit", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_AUTOEXIT", true));
|
||||
args.Add (new SetAppArgumentArgument ("-enablenetwork", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_ENABLE_NETWORK", true));
|
||||
// detect if we are using a jenkins bot.
|
||||
var useXmlOutput = harness.InCI;
|
||||
if (useXmlOutput) {
|
||||
args.Add ("-setenv=NUNIT_ENABLE_XML_OUTPUT=true");
|
||||
args.Add ("-setenv=NUNIT_ENABLE_XML_MODE=wrapped");
|
||||
args.Add ("-setenv=NUNIT_XML_VERSION=nunitv3");
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_ENABLE_XML_OUTPUT", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_ENABLE_XML_MODE", "wrapped"));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_XML_VERSION", "nunitv3"));
|
||||
}
|
||||
|
||||
if (harness.InCI) {
|
||||
// We use the 'BUILD_REVISION' variable to detect whether we're running CI or not.
|
||||
args.Add ($"-setenv=BUILD_REVISION=${Environment.GetEnvironmentVariable ("BUILD_REVISION")}");
|
||||
args.Add (new SetEnvVariableArgument ("BUILD_REVISION", "$" + Environment.GetEnvironmentVariable ("BUILD_REVISION")));
|
||||
}
|
||||
|
||||
if (!harness.GetIncludeSystemPermissionTests (TestPlatform.iOS, !isSimulator))
|
||||
args.Add ("-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1");
|
||||
args.Add (new SetEnvVariableArgument ("DISABLE_SYSTEM_PERMISSION_TESTS", 1));
|
||||
|
||||
if (isSimulator) {
|
||||
args.Add ("-argument=-app-arg:-hostname:127.0.0.1");
|
||||
args.Add ("-setenv=NUNIT_HOSTNAME=127.0.0.1");
|
||||
args.Add (new SetAppArgumentArgument ("-hostname:127.0.0.1", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_HOSTNAME", "127.0.0.1"));
|
||||
} else {
|
||||
var ips = new StringBuilder ();
|
||||
var ipAddresses = System.Net.Dns.GetHostEntry (System.Net.Dns.GetHostName ()).AddressList;
|
||||
|
@ -292,23 +286,24 @@ namespace Xharness {
|
|||
ips.Append (ipAddresses [i].ToString ());
|
||||
}
|
||||
|
||||
args.Add ($"-argument=-app-arg:-hostname:{ips}");
|
||||
args.Add ($"-setenv=NUNIT_HOSTNAME={ips}");
|
||||
var ipArg = ips.ToString ();
|
||||
args.Add (new SetAppArgumentArgument ($"-hostname:{ipArg}", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_HOSTNAME", ipArg));
|
||||
}
|
||||
|
||||
var listener_log = Logs.Create ($"test-{RunMode.ToString().ToLower()}-{Helpers.Timestamp}.log", LogType.TestLog.ToString (), timestamp: !useXmlOutput);
|
||||
var listener_log = Logs.Create ($"test-{RunMode.ToString ().ToLower ()}-{Helpers.Timestamp}.log", LogType.TestLog.ToString (), timestamp: !useXmlOutput);
|
||||
var (transport, listener, listenerTmpFile) = listenerFactory.Create (RunMode, MainLog, listener_log, isSimulator, true, useXmlOutput);
|
||||
|
||||
args.Add ($"-argument=-app-arg:-transport:{transport}");
|
||||
args.Add ($"-setenv=NUNIT_TRANSPORT={transport.ToString ().ToUpper ()}");
|
||||
|
||||
if (transport == ListenerTransport.File)
|
||||
args.Add ($"-setenv=NUNIT_LOG_FILE={listenerTmpFile}");
|
||||
|
||||
listener.Initialize ();
|
||||
|
||||
args.Add ($"-argument=-app-arg:-hostport:{listener.Port}");
|
||||
args.Add ($"-setenv=NUNIT_HOSTPORT={listener.Port}");
|
||||
args.Add (new SetAppArgumentArgument ($"-transport:{transport}", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_TRANSPORT", transport.ToString ().ToUpper ()));
|
||||
|
||||
if (transport == ListenerTransport.File)
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_LOG_FILE", listenerTmpFile));
|
||||
|
||||
args.Add (new SetAppArgumentArgument ($"-hostport:{listener.Port}", true));
|
||||
args.Add (new SetEnvVariableArgument ("NUNIT_HOSTPORT", listener.Port));
|
||||
|
||||
listener.StartAsync ();
|
||||
|
||||
|
@ -323,27 +318,26 @@ namespace Xharness {
|
|||
.ContinueWith (testReporter.LaunchCallback)
|
||||
.DoNotAwait ();
|
||||
|
||||
foreach (var kvp in harness.EnvironmentVariables)
|
||||
args.Add ($"-setenv={kvp.Key}={kvp.Value}");
|
||||
args.AddRange (harness.EnvironmentVariables.Select (kvp => new SetEnvVariableArgument (kvp.Key, kvp.Value)));
|
||||
|
||||
if (IsExtension) {
|
||||
switch (AppInformation.Extension) {
|
||||
case Extension.TodayExtension:
|
||||
args.Add (isSimulator ? "--launchsimbundleid" : "--launchdevbundleid");
|
||||
args.Add ("todayviewforextensions:" + AppInformation.BundleIdentifier);
|
||||
args.Add ("--observe-extension");
|
||||
args.Add (AppInformation.LaunchAppPath);
|
||||
args.Add (isSimulator
|
||||
? (MlaunchArgument) new LaunchSimulatorExtensionArgument (AppInformation.LaunchAppPath, AppInformation.BundleIdentifier)
|
||||
: new LaunchDeviceExtensionArgument (AppInformation.LaunchAppPath, AppInformation.BundleIdentifier));
|
||||
break;
|
||||
case Extension.WatchKit2:
|
||||
default:
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
} else {
|
||||
args.Add (isSimulator ? "--launchsim" : "--launchdev");
|
||||
args.Add (AppInformation.LaunchAppPath);
|
||||
args.Add (isSimulator
|
||||
? (MlaunchArgument) new LaunchSimulatorArgument (AppInformation.LaunchAppPath)
|
||||
: new LaunchDeviceArgument (AppInformation.LaunchAppPath));
|
||||
}
|
||||
if (!isSimulator)
|
||||
args.Add ("--disable-memory-limits");
|
||||
args.Add (new DisableMemoryLimitsArgument ());
|
||||
|
||||
if (isSimulator) {
|
||||
if (!await FindSimulatorAsync ())
|
||||
|
@ -352,13 +346,13 @@ namespace Xharness {
|
|||
if (RunMode != RunMode.WatchOS) {
|
||||
var stderr_tty = harness.GetStandardErrorTty ();
|
||||
if (!string.IsNullOrEmpty (stderr_tty)) {
|
||||
args.Add ($"--stdout={stderr_tty}");
|
||||
args.Add ($"--stderr={stderr_tty}");
|
||||
args.Add (new SetStdoutArgument (stderr_tty));
|
||||
args.Add (new SetStderrArgument (stderr_tty));
|
||||
} else {
|
||||
var stdout_log = Logs.CreateFile ($"stdout-{Helpers.Timestamp}.log", "Standard output");
|
||||
var stderr_log = Logs.CreateFile ($"stderr-{Helpers.Timestamp}.log", "Standard error");
|
||||
args.Add ($"--stdout={stdout_log}");
|
||||
args.Add ($"--stderr={stderr_log}");
|
||||
args.Add (new SetStdoutArgument (stdout_log));
|
||||
args.Add (new SetStderrArgument (stderr_log));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,7 +382,7 @@ namespace Xharness {
|
|||
await sim.PrepareSimulatorAsync (MainLog, AppInformation.BundleIdentifier);
|
||||
}
|
||||
|
||||
args.Add ($"--device=:v2:udid={simulator.UDID}");
|
||||
args.Add (new SimulatorUDIDArgument (simulator.UDID));
|
||||
|
||||
await crashReporter.StartCaptureAsync ();
|
||||
|
||||
|
@ -408,12 +402,12 @@ namespace Xharness {
|
|||
MainLog.WriteLine ("*** Executing {0}/{1} on device '{2}' ***", AppInformation.AppName, RunMode, deviceName);
|
||||
|
||||
if (RunMode == RunMode.WatchOS) {
|
||||
args.Add ("--attach-native-debugger"); // this prevents the watch from backgrounding the app.
|
||||
args.Add (new AttachNativeDebuggerArgument ()); // this prevents the watch from backgrounding the app.
|
||||
} else {
|
||||
args.Add ("--wait-for-exit");
|
||||
args.Add (new WaitForExitArgument ());
|
||||
}
|
||||
|
||||
AddDeviceName (args);
|
||||
args.Add (new DeviceNameArgument (deviceName));
|
||||
|
||||
var deviceSystemLog = Logs.Create ($"device-{deviceName}-{Helpers.Timestamp}.log", "Device log");
|
||||
var deviceLogCapturer = deviceLogCapturerFactory.Create (harness.HarnessLog, deviceSystemLog, deviceName);
|
||||
|
@ -447,18 +441,5 @@ namespace Xharness {
|
|||
(Result, FailureMessage) = await testReporter.ParseResult ();
|
||||
return testReporter.Success.Value ? 0 : 1;
|
||||
}
|
||||
|
||||
public void AddDeviceName (IList<string> args)
|
||||
{
|
||||
AddDeviceName (args, deviceName);
|
||||
}
|
||||
|
||||
public static void AddDeviceName (IList<string> args, string device_name)
|
||||
{
|
||||
if (!string.IsNullOrEmpty (device_name)) {
|
||||
args.Add ("--devname");
|
||||
args.Add (device_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,13 +60,16 @@ namespace Xharness
|
|||
{
|
||||
streamEnds = new CountdownEvent (2);
|
||||
|
||||
var sb = new List<string> {
|
||||
"--logdev",
|
||||
"--sdkroot",
|
||||
xcodeRoot,
|
||||
"--devname",
|
||||
deviceName
|
||||
};
|
||||
|
||||
process = new Process ();
|
||||
process.StartInfo.FileName = mlaunchPath;
|
||||
var sb = new List<string> ();
|
||||
sb.Add ("--logdev");
|
||||
sb.Add ("--sdkroot");
|
||||
sb.Add (xcodeRoot);
|
||||
AppRunner.AddDeviceName (sb, deviceName);
|
||||
process.StartInfo.Arguments = StringUtils.FormatArguments (sb);
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
namespace Xharness.Execution.Mlaunch {
|
||||
using System;
|
||||
|
||||
namespace Xharness.Execution.Mlaunch {
|
||||
|
||||
/// <summary>
|
||||
/// Specify the location of Apple SDKs, default to 'xcode-select' value.
|
||||
/// </summary>
|
||||
public sealed class SdkRootArgument : SingleValueArgument {
|
||||
public SdkRootArgument (string sdkPath) : base ("sdkroot", sdkPath)
|
||||
public SdkRootArgument (string sdkPath) : base ("sdkroot", sdkPath, false)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +20,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the syslog from the device to the console.
|
||||
/// </summary>
|
||||
public sealed class LogDevArgument : OptionArgument {
|
||||
public LogDevArgument () : base ("logdev")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List the available simulators. The output is xml, and written to the specified file.
|
||||
/// </summary>
|
||||
|
@ -37,10 +48,37 @@
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify which device (when many are present) the [install|lauch|kill|log]dev command applies
|
||||
/// Specifies the device type to launch the simulator as.
|
||||
/// </summary>
|
||||
public sealed class DeviceArgument : SingleValueArgument {
|
||||
public DeviceArgument (string deviceType) : base ("device", deviceType)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify which device (when many are present) the [install|lauch|kill|log]dev command applies.
|
||||
/// </summary>
|
||||
public sealed class DeviceNameArgument : SingleValueArgument {
|
||||
public DeviceNameArgument (string deviceName) : base ("devname", deviceName)
|
||||
public DeviceNameArgument (string deviceName) : base ("devname", deviceName, false)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Install the specified iOS app bundle on the device.
|
||||
/// </summary>
|
||||
public sealed class InstallAppOnDeviceArgument : SingleValueArgument {
|
||||
public InstallAppOnDeviceArgument (string appPath) : base ("installdev", appPath, false)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uninstall the specified bundle id from the device.
|
||||
/// </summary>
|
||||
public sealed class UninstallAppFromDeviceArgument : SingleValueArgument {
|
||||
public UninstallAppFromDeviceArgument (string appBundleId) : base ("uninstalldevbundleid", appBundleId, false)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -90,4 +128,162 @@
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attach native debugger.
|
||||
/// </summary>
|
||||
public sealed class AttachNativeDebuggerArgument : OptionArgument {
|
||||
public AttachNativeDebuggerArgument () : base ("attach-native-debugger")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to disable memory limits for launched apps.
|
||||
/// This is just an attempt, some or all usual limits may still be enforced.
|
||||
/// </summary>
|
||||
public sealed class DisableMemoryLimitsArgument : OptionArgument {
|
||||
public DisableMemoryLimitsArgument () : base ("disable-memory-limits")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WaitForExitArgument : OptionArgument {
|
||||
public WaitForExitArgument () : base ("wait-for-exit")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launch the app with this command line argument. This must be specified multiple times for multiple arguments.
|
||||
/// </summary>
|
||||
public sealed class SetAppArgumentArgument : MlaunchArgument {
|
||||
readonly string value;
|
||||
|
||||
public SetAppArgumentArgument (string value, bool isAppArg = false)
|
||||
{
|
||||
this.value = value ?? throw new ArgumentNullException (nameof (value));
|
||||
|
||||
if (isAppArg)
|
||||
this.value = "-app-arg:" + this.value;
|
||||
}
|
||||
|
||||
public override string AsCommandLineArgument () => "-argument=" + value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the environment variable in the application on startup.
|
||||
/// </summary>
|
||||
public sealed class SetEnvVariableArgument : MlaunchArgument {
|
||||
readonly string variableName;
|
||||
readonly string variableValue;
|
||||
|
||||
public SetEnvVariableArgument (string variableName, object variableValue)
|
||||
{
|
||||
this.variableName = variableName ?? throw new ArgumentNullException (nameof (variableName));
|
||||
this.variableValue = variableValue?.ToString () ?? throw new ArgumentNullException (nameof (variableValue));
|
||||
|
||||
if (variableValue is bool)
|
||||
this.variableValue = this.variableValue.ToLower ();
|
||||
}
|
||||
|
||||
public override string AsCommandLineArgument () => Escape ($"-setenv={variableName}={variableValue}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redirect the standard output for the simulated application to the specified file.
|
||||
/// </summary>
|
||||
public sealed class SetStdoutArgument : SingleValueArgument {
|
||||
public SetStdoutArgument (string targetFile) : base ("stdout", targetFile)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redirect the standard error for the simulated application to the specified file.
|
||||
/// </summary>
|
||||
public sealed class SetStderrArgument : SingleValueArgument {
|
||||
public SetStderrArgument (string targetFile) : base ("stderr", targetFile)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launch an app that is installed on device, specified by bundle identifier.
|
||||
/// </summary>
|
||||
public sealed class LaunchDeviceArgument : SingleValueArgument {
|
||||
public LaunchDeviceArgument (string launchAppPath) : base ("launchdev", launchAppPath, false)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launch the specified MonoTouch.app in the simulator.
|
||||
/// </summary>
|
||||
public sealed class LaunchSimulatorArgument : SingleValueArgument {
|
||||
public LaunchSimulatorArgument (string launchAppPath) : base ("launchsim", launchAppPath, false)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify which simulator to launch.
|
||||
/// </summary>
|
||||
public sealed class SimulatorUDIDArgument : MlaunchArgument {
|
||||
readonly string udid;
|
||||
|
||||
public SimulatorUDIDArgument (string udid)
|
||||
{
|
||||
this.udid = udid ?? throw new ArgumentNullException (nameof (udid));
|
||||
}
|
||||
|
||||
public override string AsCommandLineArgument () => $"--device=:v2:udid={udid}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launch an app that is installed on device, specified by bundle identifier.
|
||||
/// </summary>
|
||||
public sealed class LaunchSimulatorExtensionArgument : MlaunchArgument {
|
||||
readonly string launchAppPath;
|
||||
readonly string bundleId;
|
||||
|
||||
public LaunchSimulatorExtensionArgument (string launchAppPath, string bundleId)
|
||||
{
|
||||
this.launchAppPath = launchAppPath ?? throw new ArgumentNullException (nameof (launchAppPath));
|
||||
this.bundleId = bundleId ?? throw new ArgumentNullException (nameof (bundleId));
|
||||
}
|
||||
|
||||
public override string AsCommandLineArgument () => "--launchsimbundleid " +
|
||||
"todayviewforextensions:" + Escape (bundleId) + " " +
|
||||
"--observe-extension " + Escape (launchAppPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launch the specified bundle id in the simulator (which must already be installed).
|
||||
/// </summary>
|
||||
public sealed class LaunchDeviceExtensionArgument : MlaunchArgument {
|
||||
readonly string launchAppPath;
|
||||
readonly string bundleId;
|
||||
|
||||
public LaunchDeviceExtensionArgument (string launchAppPath, string bundleId)
|
||||
{
|
||||
this.launchAppPath = launchAppPath ?? throw new ArgumentNullException (nameof (launchAppPath));
|
||||
this.bundleId = bundleId ?? throw new ArgumentNullException (nameof (bundleId));
|
||||
}
|
||||
|
||||
public override string AsCommandLineArgument () => "--launchdevbundleid " +
|
||||
"todayviewforextensions:" + Escape (bundleId) + " " +
|
||||
"--observe-extension " + Escape (launchAppPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the verbosity level. Can be used repeatedly to lower the level.
|
||||
/// </summary>
|
||||
public sealed class VerbosityArgument : MlaunchArgument {
|
||||
public VerbosityArgument ()
|
||||
{
|
||||
}
|
||||
|
||||
public override string AsCommandLineArgument () => "-v";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Execution.Mlaunch {
|
||||
// mlaunch is really important and has a lot of arguments that are known but
|
||||
|
@ -9,23 +11,43 @@ namespace Xharness.Execution.Mlaunch {
|
|||
// needs a value does contain the value
|
||||
public abstract class MlaunchArgument {
|
||||
public abstract string AsCommandLineArgument ();
|
||||
|
||||
protected static string Escape (string value) => StringUtils.FormatArguments (value);
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
return obj is MlaunchArgument arg && arg.AsCommandLineArgument () == AsCommandLineArgument ();
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return AsCommandLineArgument ().GetHashCode ();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class SingleValueArgument : MlaunchArgument {
|
||||
private readonly string argumentName;
|
||||
private readonly string argumentValue;
|
||||
readonly string argumentName;
|
||||
readonly string argumentValue;
|
||||
readonly bool useEqualSign;
|
||||
|
||||
protected SingleValueArgument (string argumentName, string argumentValue)
|
||||
protected SingleValueArgument (string argumentName, string argumentValue, bool useEqualSign = true)
|
||||
{
|
||||
this.argumentName = argumentName ?? throw new ArgumentNullException (nameof (argumentName));
|
||||
this.argumentValue = argumentValue ?? throw new ArgumentNullException (nameof (argumentValue));
|
||||
this.useEqualSign = useEqualSign;
|
||||
}
|
||||
|
||||
public override string AsCommandLineArgument () => $"--{argumentName}={argumentValue}";
|
||||
public override string AsCommandLineArgument ()
|
||||
{
|
||||
if (useEqualSign)
|
||||
return Escape ($"--{argumentName}={argumentValue}");
|
||||
else
|
||||
return $"--{argumentName} {Escape (argumentValue)}";
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class OptionArgument : MlaunchArgument {
|
||||
private readonly string argumentName;
|
||||
readonly string argumentName;
|
||||
|
||||
protected OptionArgument (string argumentName)
|
||||
{
|
||||
|
@ -35,7 +57,7 @@ namespace Xharness.Execution.Mlaunch {
|
|||
public override string AsCommandLineArgument () => $"--{argumentName}";
|
||||
}
|
||||
|
||||
public class MlaunchArguments {
|
||||
public class MlaunchArguments : IEnumerable<MlaunchArgument> {
|
||||
readonly List<MlaunchArgument> arguments = new List<MlaunchArgument> ();
|
||||
|
||||
public MlaunchArguments (params MlaunchArgument [] args)
|
||||
|
@ -44,8 +66,25 @@ namespace Xharness.Execution.Mlaunch {
|
|||
}
|
||||
|
||||
public void Add (MlaunchArgument arg) => arguments.Add (arg);
|
||||
public void AddRange (params MlaunchArgument [] args) => arguments.AddRange (args);
|
||||
|
||||
public void AddRange (IEnumerable<MlaunchArgument> args) => arguments.AddRange (args);
|
||||
|
||||
public string AsCommandLine () => string.Join (" ", arguments.Select (a => a.AsCommandLineArgument ()));
|
||||
public IEnumerable<MlaunchArgument> GetArguments () => arguments;
|
||||
|
||||
public IEnumerator<MlaunchArgument> GetEnumerator () => arguments.GetEnumerator ();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator () => arguments.GetEnumerator ();
|
||||
|
||||
public override string ToString () => AsCommandLine ();
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
return obj is MlaunchArguments arg && arg.AsCommandLine () == AsCommandLine ();
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return AsCommandLine ().GetHashCode ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Xharness.Utilities
|
|||
return string.Join (" ", QuoteForProcess (arguments));
|
||||
}
|
||||
|
||||
static string [] QuoteForProcess (params string [] array)
|
||||
static string [] QuoteForProcess (params string [] array)
|
||||
{
|
||||
if (array == null || array.Length == 0)
|
||||
return array;
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using Xharness.Execution.Mlaunch;
|
||||
|
||||
namespace Xharness.Tests.Execution.Tests {
|
||||
|
||||
[TestFixture]
|
||||
public class MlaunchArgumentsTest {
|
||||
|
||||
public class CommandLineDataTestSource {
|
||||
public static IEnumerable CommandLineArgs {
|
||||
get {
|
||||
string listDevFile = "/my/listdev.txt";
|
||||
string listSimFile = "/my/listsim.txt";
|
||||
string xmlOutputType = "XML";
|
||||
|
||||
yield return new TestCaseData (arg: new MlaunchArgument [] { new ListDevicesArgument (listDevFile) })
|
||||
.Returns ($"--listdev={listDevFile}");
|
||||
|
||||
yield return new TestCaseData (arg: new MlaunchArgument [] { new ListSimulatorsArgument (listSimFile) })
|
||||
.Returns ($"--listsim={listSimFile}");
|
||||
|
||||
yield return new TestCaseData (arg: new MlaunchArgument [] { new XmlOutputFormatArgument () })
|
||||
.Returns ($"--output-format={xmlOutputType}");
|
||||
|
||||
yield return new TestCaseData (arg: new MlaunchArgument [] { new ListExtraDataArgument () })
|
||||
.Returns ("--list-extra-data");
|
||||
|
||||
yield return new TestCaseData (arg: new MlaunchArgument [] { new ListDevicesArgument (listDevFile), new ListSimulatorsArgument (listSimFile) })
|
||||
.Returns ($"--listdev={listDevFile} --listsim={listSimFile}");
|
||||
|
||||
yield return new TestCaseData (arg: new MlaunchArgument [] { new ListDevicesArgument (listDevFile), new ListExtraDataArgument () })
|
||||
.Returns ($"--listdev={listDevFile} --list-extra-data");
|
||||
|
||||
yield return new TestCaseData (arg: new MlaunchArgument [] { new ListDevicesArgument (listDevFile), new XmlOutputFormatArgument (), new ListExtraDataArgument () })
|
||||
.Returns ($"--listdev={listDevFile} --output-format={xmlOutputType} --list-extra-data");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource (typeof (CommandLineDataTestSource), "CommandLineArgs")]
|
||||
public string AsCommandLineTest (MlaunchArgument [] args)
|
||||
{
|
||||
return new MlaunchArguments (args).AsCommandLine ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Xharness.Execution.Mlaunch;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Tests.Execution.Tests {
|
||||
|
||||
[TestFixture]
|
||||
public class MlaunchArgumentsTests {
|
||||
|
||||
public class CommandLineDataTestSource {
|
||||
public static IEnumerable CommandLineArgs {
|
||||
get {
|
||||
string listDevFile = "/my/listdev.txt";
|
||||
string listSimFile = "/my/listsim.txt";
|
||||
string xmlOutputType = "XML";
|
||||
|
||||
yield return new TestCaseData (arg:
|
||||
new MlaunchArgument [] {
|
||||
new ListDevicesArgument (listDevFile)
|
||||
})
|
||||
.Returns ($"--listdev={listDevFile}");
|
||||
|
||||
yield return new TestCaseData (arg:
|
||||
new MlaunchArgument [] {
|
||||
new ListSimulatorsArgument (listSimFile)
|
||||
})
|
||||
.Returns ($"--listsim={listSimFile}");
|
||||
|
||||
yield return new TestCaseData (arg:
|
||||
new MlaunchArgument [] {
|
||||
new XmlOutputFormatArgument ()
|
||||
})
|
||||
.Returns ($"--output-format={xmlOutputType}");
|
||||
|
||||
yield return new TestCaseData (arg:
|
||||
new MlaunchArgument [] {
|
||||
new ListExtraDataArgument ()
|
||||
})
|
||||
.Returns ("--list-extra-data");
|
||||
|
||||
yield return new TestCaseData (arg:
|
||||
new MlaunchArgument [] {
|
||||
new DownloadCrashReportToArgument ("/path/with spaces.txt"),
|
||||
new DeviceNameArgument ("Test iPad")
|
||||
})
|
||||
.Returns ($"\"--download-crash-report-to=/path/with spaces.txt\" --devname \"Test iPad\"");
|
||||
|
||||
yield return new TestCaseData (arg:
|
||||
new MlaunchArgument [] {
|
||||
new SetEnvVariableArgument ("SOME_PARAM", "true"),
|
||||
new SetEnvVariableArgument ("NUNIT_LOG_FILE", "/another space/path.txt")
|
||||
})
|
||||
.Returns ($"-setenv=SOME_PARAM=true \"-setenv=NUNIT_LOG_FILE=/another space/path.txt\"");
|
||||
|
||||
yield return new TestCaseData (arg:
|
||||
new MlaunchArgument [] {
|
||||
new ListDevicesArgument (listDevFile),
|
||||
new XmlOutputFormatArgument (),
|
||||
new ListExtraDataArgument ()
|
||||
})
|
||||
.Returns ($"--listdev={listDevFile} --output-format={xmlOutputType} --list-extra-data");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource (typeof (CommandLineDataTestSource), "CommandLineArgs")]
|
||||
public string AsCommandLineTest (MlaunchArgument [] args)
|
||||
{
|
||||
return new MlaunchArguments (args).AsCommandLine ();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MlaunchArgumentAndProcessManagerTest ()
|
||||
{
|
||||
var oldArgs = new List<string> () {
|
||||
"--download-crash-report-to=/path/with spaces.txt",
|
||||
"--sdkroot",
|
||||
"/path to xcode/spaces",
|
||||
"--devname",
|
||||
"Premek's iPhone",
|
||||
};
|
||||
|
||||
var newArgs = new MlaunchArguments () {
|
||||
new DownloadCrashReportToArgument ("/path/with spaces.txt"),
|
||||
new SdkRootArgument ("/path to xcode/spaces"),
|
||||
new DeviceNameArgument ("Premek's iPhone"),
|
||||
};
|
||||
|
||||
var oldWayOfPassingArgs = StringUtils.FormatArguments (oldArgs);
|
||||
var newWayOfPassingArgs = newArgs.AsCommandLine ();
|
||||
|
||||
Assert.AreEqual (oldWayOfPassingArgs, newWayOfPassingArgs, "Something changed when moving to MlaunchArguments");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MlaunchArgumentEqualityTest ()
|
||||
{
|
||||
var arg1 = new DownloadCrashReportToArgument ("/path/with spaces.txt");
|
||||
var arg2 = new DownloadCrashReportToArgument ("/path/with spaces.txt");
|
||||
var arg3 = new DownloadCrashReportToArgument ("/path/with.txt");
|
||||
|
||||
Assert.AreEqual (arg1, arg2, "equality is broken");
|
||||
Assert.AreNotEqual (arg1, arg3, "equality is broken");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MlaunchArgumentsEqualityTest ()
|
||||
{
|
||||
var args1 = new MlaunchArgument [] {
|
||||
new ListDevicesArgument ("foo"),
|
||||
new ListSimulatorsArgument ("bar")
|
||||
};
|
||||
var args2 = new MlaunchArgument [] {
|
||||
new ListDevicesArgument ("foo"),
|
||||
new ListSimulatorsArgument ("bar")
|
||||
};
|
||||
var args3 = new MlaunchArgument [] {
|
||||
new ListDevicesArgument ("foo"),
|
||||
new ListSimulatorsArgument ("xyz")
|
||||
};
|
||||
|
||||
Assert.AreEqual (args1, args2, "equality is broken");
|
||||
Assert.AreNotEqual (args1, args3, "equality is broken");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,14 +70,14 @@ namespace Xharness.Tests.Hardware.Tests {
|
|||
await devices.LoadAsync (executionLog.Object);
|
||||
});
|
||||
|
||||
MlaunchArgument sdkRootArg = passedArguments.GetArguments ().Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
MlaunchArgument sdkRootArg = passedArguments.Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (sdkRootArg, "sdk arg missing");
|
||||
AssertArgumentValue (sdkRootArg, sdkPath, "sdk arg wrong");
|
||||
|
||||
MlaunchArgument listDevArg = passedArguments.GetArguments ().Where (a => a is ListDevicesArgument).FirstOrDefault();
|
||||
MlaunchArgument listDevArg = passedArguments.Where (a => a is ListDevicesArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (listDevArg, "list devices arg missing");
|
||||
|
||||
MlaunchArgument outputFormatArg = passedArguments.GetArguments ().Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
MlaunchArgument outputFormatArg = passedArguments.Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (outputFormatArg, "output format arg missing");
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ namespace Xharness.Tests.Hardware.Tests {
|
|||
passedArguments = args;
|
||||
|
||||
// we get the temp file that was passed as the args, and write our sample xml, which will be parsed to get the devices :)
|
||||
var tempPath = args.GetArguments ().Where (a => a is ListDevicesArgument).First ().AsCommandLineArgument ();
|
||||
var tempPath = args.Where (a => a is ListDevicesArgument).First ().AsCommandLineArgument ();
|
||||
tempPath = tempPath.Substring(tempPath.IndexOf('=') + 1);
|
||||
|
||||
var name = GetType ().Assembly.GetManifestResourceNames ().Where (a => a.EndsWith ("devices.xml", StringComparison.Ordinal)).FirstOrDefault ();
|
||||
|
@ -117,18 +117,18 @@ namespace Xharness.Tests.Hardware.Tests {
|
|||
// validate the execution of mlaunch
|
||||
Assert.AreEqual (mlaunchPath, processPath, "process path");
|
||||
|
||||
MlaunchArgument sdkRootArg = passedArguments.GetArguments ().Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
MlaunchArgument sdkRootArg = passedArguments.Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (sdkRootArg, "sdk arg missing");
|
||||
AssertArgumentValue (sdkRootArg, sdkPath, "sdk arg wrong");
|
||||
|
||||
MlaunchArgument listDevArg = passedArguments.GetArguments ().Where (a => a is ListDevicesArgument).FirstOrDefault();
|
||||
MlaunchArgument listDevArg = passedArguments.Where (a => a is ListDevicesArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (listDevArg, "list devices arg missing");
|
||||
|
||||
MlaunchArgument outputFormatArg = passedArguments.GetArguments ().Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
MlaunchArgument outputFormatArg = passedArguments.Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (outputFormatArg, "output format arg missing");
|
||||
|
||||
if (extraData) {
|
||||
MlaunchArgument listExtraDataArg = passedArguments.GetArguments ().Where (a => a is ListExtraDataArgument).FirstOrDefault();
|
||||
MlaunchArgument listExtraDataArg = passedArguments.Where (a => a is ListExtraDataArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (listExtraDataArg, "list extra data arg missing");
|
||||
}
|
||||
|
||||
|
|
|
@ -71,14 +71,14 @@ namespace Xharness.Tests.Hardware.Tests {
|
|||
});
|
||||
|
||||
// validate the execution of mlaunch
|
||||
MlaunchArgument sdkRootArg = passedArguments.GetArguments ().Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
MlaunchArgument sdkRootArg = passedArguments.Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (sdkRootArg, "sdk arg missing");
|
||||
AssertArgumentValue (sdkRootArg, sdkPath, "sdk arg wrong");
|
||||
|
||||
MlaunchArgument listSimArg = passedArguments.GetArguments ().Where (a => a is ListSimulatorsArgument).FirstOrDefault();
|
||||
MlaunchArgument listSimArg = passedArguments.Where (a => a is ListSimulatorsArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (listSimArg, "list devices arg missing");
|
||||
|
||||
MlaunchArgument outputFormatArg = passedArguments.GetArguments ().Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
MlaunchArgument outputFormatArg = passedArguments.Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (outputFormatArg, "output format arg missing");
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ namespace Xharness.Tests.Hardware.Tests {
|
|||
passedArguments = args;
|
||||
|
||||
// we get the temp file that was passed as the args, and write our sample xml, which will be parsed to get the devices :)
|
||||
var tempPath = args.GetArguments ().Where (a => a is ListSimulatorsArgument).First ().AsCommandLineArgument ();
|
||||
var tempPath = args.Where (a => a is ListSimulatorsArgument).First ().AsCommandLineArgument ();
|
||||
tempPath = tempPath.Substring(tempPath.IndexOf('=') + 1);
|
||||
|
||||
CopySampleData (tempPath);
|
||||
|
@ -121,14 +121,14 @@ namespace Xharness.Tests.Hardware.Tests {
|
|||
// validate the execution of mlaunch
|
||||
Assert.AreEqual (mlaunchPath, processPath, "process path");
|
||||
|
||||
MlaunchArgument sdkRootArg = passedArguments.GetArguments ().Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
MlaunchArgument sdkRootArg = passedArguments.Where (a => a is SdkRootArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (sdkRootArg, "sdk arg missing");
|
||||
AssertArgumentValue (sdkRootArg, sdkPath, "sdk arg wrong");
|
||||
|
||||
MlaunchArgument listSimArg = passedArguments.GetArguments ().Where (a => a is ListSimulatorsArgument).FirstOrDefault();
|
||||
MlaunchArgument listSimArg = passedArguments.Where (a => a is ListSimulatorsArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (listSimArg, "list devices arg missing");
|
||||
|
||||
MlaunchArgument outputFormatArg = passedArguments.GetArguments ().Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
MlaunchArgument outputFormatArg = passedArguments.Where (a => a is XmlOutputFormatArgument).FirstOrDefault();
|
||||
Assert.IsNotNull (outputFormatArg, "output format arg missing");
|
||||
|
||||
Assert.AreEqual (75, simulators.AvailableDevices.Count());
|
||||
|
@ -158,7 +158,7 @@ namespace Xharness.Tests.Hardware.Tests {
|
|||
passedArguments = args;
|
||||
|
||||
// we get the temp file that was passed as the args, and write our sample xml, which will be parsed to get the devices :)
|
||||
var tempPath = args.GetArguments ().Where (a => a is ListSimulatorsArgument).First ().AsCommandLineArgument ();
|
||||
var tempPath = args.Where (a => a is ListSimulatorsArgument).First ().AsCommandLineArgument ();
|
||||
tempPath = tempPath.Substring(tempPath.IndexOf('=') + 1);
|
||||
|
||||
CopySampleData (tempPath);
|
||||
|
|
|
@ -9,9 +9,11 @@ using System.Threading.Tasks;
|
|||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Execution.Mlaunch;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Listeners;
|
||||
using Xharness.Logging;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Tests {
|
||||
[TestFixture]
|
||||
|
@ -223,6 +225,9 @@ namespace Xharness.Tests {
|
|||
var processResult = new ProcessExecutionResult () { ExitCode = 1, TimedOut = false };
|
||||
processManager.SetReturnsDefault (Task.FromResult (processResult));
|
||||
|
||||
devices.Setup (x => x.ConnectedDevices).Returns (mockDevices);
|
||||
|
||||
// Act
|
||||
var appRunner = new AppRunner (processManager.Object,
|
||||
appBundleInformationParser,
|
||||
simulatorsFactory,
|
||||
|
@ -239,28 +244,19 @@ namespace Xharness.Tests {
|
|||
projectFilePath: projectFilePath,
|
||||
buildConfiguration: "Debug");
|
||||
|
||||
devices.Setup (x => x.ConnectedDevices).Returns (mockDevices);
|
||||
|
||||
// Act
|
||||
CancellationToken cancellationToken = new CancellationToken ();
|
||||
var result = await appRunner.InstallAsync (cancellationToken);
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual (1, result.ExitCode);
|
||||
|
||||
var expectedArgs = $"--sdkroot /path/to/xcode -v -v -v " +
|
||||
$"--installdev {StringUtils.FormatArguments (appPath)} " +
|
||||
$"--devname \"Test iPad\"";
|
||||
|
||||
processManager.Verify (x => x.ExecuteCommandAsync (
|
||||
"/path/to/mlaunch",
|
||||
new List<string> () {
|
||||
"--sdkroot",
|
||||
"/path/to/xcode",
|
||||
"-v",
|
||||
"-v",
|
||||
"-v",
|
||||
"--installdev",
|
||||
appPath,
|
||||
"--devname",
|
||||
"Test iPad"
|
||||
},
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs),
|
||||
mainLog.Object,
|
||||
TimeSpan.FromHours (1),
|
||||
null,
|
||||
|
@ -277,6 +273,9 @@ namespace Xharness.Tests {
|
|||
var processResult = new ProcessExecutionResult () { ExitCode = 3, TimedOut = false };
|
||||
processManager.SetReturnsDefault (Task.FromResult (processResult));
|
||||
|
||||
devices.Setup (x => x.ConnectedDevices).Returns (mockDevices.Reverse ());
|
||||
|
||||
// Act
|
||||
var appRunner = new AppRunner (processManager.Object,
|
||||
appBundleInformationParser,
|
||||
simulatorsFactory,
|
||||
|
@ -293,24 +292,18 @@ namespace Xharness.Tests {
|
|||
projectFilePath: Path.Combine (sampleProjectPath, "SystemXunit.csproj"),
|
||||
buildConfiguration: "Debug");
|
||||
|
||||
devices.Setup (x => x.ConnectedDevices).Returns (mockDevices.Reverse ());
|
||||
|
||||
var result = await appRunner.UninstallAsync ();
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual (3, result.ExitCode);
|
||||
|
||||
var expectedArgs = $"--sdkroot /path/to/xcode -v -v " +
|
||||
$"--uninstalldevbundleid {StringUtils.FormatArguments (appName)} " +
|
||||
$"--devname \"Test iPad\"";
|
||||
|
||||
processManager.Verify (x => x.ExecuteCommandAsync (
|
||||
"/path/to/mlaunch",
|
||||
new List<string> () {
|
||||
"--sdkroot",
|
||||
"/path/to/xcode",
|
||||
"-v",
|
||||
"-v",
|
||||
"--uninstalldevbundleid",
|
||||
appName,
|
||||
"--devname",
|
||||
"Test iPad"
|
||||
},
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs),
|
||||
mainLog.Object,
|
||||
TimeSpan.FromMinutes (1),
|
||||
null,
|
||||
|
@ -458,19 +451,20 @@ namespace Xharness.Tests {
|
|||
It.IsAny<string> ()))
|
||||
.Returns (captureLog.Object);
|
||||
|
||||
var expectedArgs = $"--sdkroot {xcodePath} -v -v -argument=-connection-mode -argument=none " +
|
||||
$"-argument=-app-arg:-autostart -setenv=NUNIT_AUTOSTART=true -argument=-app-arg:-autoexit " +
|
||||
$"-setenv=NUNIT_AUTOEXIT=true -argument=-app-arg:-enablenetwork -setenv=NUNIT_ENABLE_NETWORK=true " +
|
||||
var expectedArgs = $"--sdkroot {StringUtils.FormatArguments (xcodePath)} -v -v " +
|
||||
$"-argument=-connection-mode -argument=none -argument=-app-arg:-autostart " +
|
||||
$"-setenv=NUNIT_AUTOSTART=true -argument=-app-arg:-autoexit -setenv=NUNIT_AUTOEXIT=true " +
|
||||
$"-argument=-app-arg:-enablenetwork -setenv=NUNIT_ENABLE_NETWORK=true " +
|
||||
$"-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1 -argument=-app-arg:-hostname:127.0.0.1 " +
|
||||
$"-setenv=NUNIT_HOSTNAME=127.0.0.1 -argument=-app-arg:-transport:Tcp -setenv=NUNIT_TRANSPORT=TCP " +
|
||||
$"-argument=-app-arg:-hostport:{simpleListener.Object.Port} -setenv=NUNIT_HOSTPORT={simpleListener.Object.Port} " +
|
||||
$"-setenv=env1=value1 -setenv=env2=value2 --launchsim {appPath} --stdout=tty1 --stderr=tty1 " +
|
||||
$"--device=:v2:udid={simulator.Object.UDID}";
|
||||
$"-setenv=env1=value1 -setenv=env2=value2 --launchsim {StringUtils.FormatArguments (appPath)} " +
|
||||
$"--stdout=tty1 --stderr=tty1 --device=:v2:udid={simulator.Object.UDID}";
|
||||
|
||||
processManager
|
||||
.Setup (x => x.ExecuteCommandAsync (
|
||||
mlaunchPath,
|
||||
It.Is<IList<string>> (args => string.Join (" ", args) == expectedArgs),
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs),
|
||||
mainLog.Object,
|
||||
TimeSpan.FromMinutes (harness.Timeout * 2),
|
||||
null,
|
||||
|
@ -620,18 +614,18 @@ namespace Xharness.Tests {
|
|||
ips.Append (ipAddresses [i].ToString ());
|
||||
}
|
||||
|
||||
var expectedArgs = $"--sdkroot {xcodePath} -v -v -argument=-connection-mode -argument=none " +
|
||||
var expectedArgs = $"--sdkroot {StringUtils.FormatArguments (xcodePath)} -v -v -argument=-connection-mode -argument=none " +
|
||||
$"-argument=-app-arg:-autostart -setenv=NUNIT_AUTOSTART=true -argument=-app-arg:-autoexit " +
|
||||
$"-setenv=NUNIT_AUTOEXIT=true -argument=-app-arg:-enablenetwork -setenv=NUNIT_ENABLE_NETWORK=true " +
|
||||
$"-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1 -argument=-app-arg:-hostname:{ips} -setenv=NUNIT_HOSTNAME={ips} " +
|
||||
$"-argument=-app-arg:-transport:Tcp -setenv=NUNIT_TRANSPORT=TCP -argument=-app-arg:-hostport:{simpleListener.Object.Port} " +
|
||||
$"-setenv=NUNIT_HOSTPORT={simpleListener.Object.Port} -setenv=env1=value1 -setenv=env2=value2 " +
|
||||
$"--launchdev {appPath} --disable-memory-limits --wait-for-exit --devname Test iPad";
|
||||
$"--launchdev {StringUtils.FormatArguments (appPath)} --disable-memory-limits --wait-for-exit --devname \"Test iPad\"";
|
||||
|
||||
processManager
|
||||
.Setup (x => x.ExecuteCommandAsync (
|
||||
mlaunchPath,
|
||||
It.Is<IList<string>> (args => string.Join (" ", args) == expectedArgs),
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs),
|
||||
It.IsAny<ILog> (),
|
||||
TimeSpan.FromMinutes (harness.Timeout * 2),
|
||||
null,
|
||||
|
@ -736,18 +730,18 @@ namespace Xharness.Tests {
|
|||
ips.Append (ipAddresses [i].ToString ());
|
||||
}
|
||||
|
||||
var expectedArgs = $"--sdkroot {xcodePath} -v -v -argument=-connection-mode -argument=none " +
|
||||
var expectedArgs = $"--sdkroot {StringUtils.FormatArguments (xcodePath)} -v -v -argument=-connection-mode -argument=none " +
|
||||
$"-argument=-app-arg:-autostart -setenv=NUNIT_AUTOSTART=true -argument=-app-arg:-autoexit " +
|
||||
$"-setenv=NUNIT_AUTOEXIT=true -argument=-app-arg:-enablenetwork -setenv=NUNIT_ENABLE_NETWORK=true " +
|
||||
$"-setenv=DISABLE_SYSTEM_PERMISSION_TESTS=1 -argument=-app-arg:-hostname:{ips} -setenv=NUNIT_HOSTNAME={ips} " +
|
||||
$"-argument=-app-arg:-transport:Tcp -setenv=NUNIT_TRANSPORT=TCP -argument=-app-arg:-hostport:{simpleListener.Object.Port} " +
|
||||
$"-setenv=NUNIT_HOSTPORT={simpleListener.Object.Port} -setenv=env1=value1 -setenv=env2=value2 " +
|
||||
$"--launchdev {appPath} --disable-memory-limits --wait-for-exit --devname Test iPad";
|
||||
$"--launchdev {StringUtils.FormatArguments (appPath)} --disable-memory-limits --wait-for-exit --devname \"Test iPad\"";
|
||||
|
||||
processManager
|
||||
.Setup (x => x.ExecuteCommandAsync (
|
||||
mlaunchPath,
|
||||
It.Is<IList<string>> (args => string.Join (" ", args) == expectedArgs),
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () == expectedArgs),
|
||||
It.IsAny<ILog> (),
|
||||
TimeSpan.FromMinutes (harness.Timeout * 2),
|
||||
null,
|
||||
|
|
|
@ -8,10 +8,11 @@ using NUnit.Framework;
|
|||
using Xharness.Execution;
|
||||
using Xharness.Execution.Mlaunch;
|
||||
using Xharness.Logging;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Tests {
|
||||
[TestFixture]
|
||||
public class CrashReportSnapshotTests {
|
||||
public class CrashSnapshotReporterTests {
|
||||
readonly string mlaunchPath = "./mlaunch";
|
||||
string tempXcodeRoot;
|
||||
string symbolicatePath;
|
||||
|
@ -27,7 +28,7 @@ namespace Xharness.Tests {
|
|||
log = new Mock<ILog> ();
|
||||
logs = new Mock<ILogs> ();
|
||||
|
||||
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");
|
||||
|
||||
// Create fake place for device logs
|
||||
|
@ -39,7 +40,8 @@ namespace Xharness.Tests {
|
|||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown () {
|
||||
public void TearDown ()
|
||||
{
|
||||
Directory.Delete (tempXcodeRoot, true);
|
||||
}
|
||||
|
||||
|
@ -50,7 +52,7 @@ namespace Xharness.Tests {
|
|||
|
||||
const string deviceName = "Sample-iPhone";
|
||||
const string crashLogPath = "/path/to/crash.log";
|
||||
const string symbolicateLogPath = "/path/to/" + deviceName+ ".symbolicated.log";
|
||||
const string symbolicateLogPath = "/path/to/" + deviceName + ".symbolicated.log";
|
||||
|
||||
var crashReport = Mock.Of<ILogFile> (x => x.Path == crashLogPath);
|
||||
var symbolicateReport = Mock.Of<ILogFile> (x => x.Path == symbolicateLogPath);
|
||||
|
@ -63,38 +65,7 @@ namespace Xharness.Tests {
|
|||
logs.Setup (x => x.Create ("crash.symbolicated.log", "Symbolicated crash report: crash.log", It.IsAny<bool> ()))
|
||||
.Returns (symbolicateReport);
|
||||
|
||||
// List of crash reports is retrieved
|
||||
processManager
|
||||
.Setup (x => x.ExecuteCommandAsync (
|
||||
mlaunchPath,
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () == $"--list-crash-reports={tempFilePath} --sdkroot={tempXcodeRoot} --devname={deviceName}"),
|
||||
log.Object,
|
||||
TimeSpan.FromMinutes (1),
|
||||
null,
|
||||
null))
|
||||
.ReturnsAsync (new ProcessExecutionResult () { ExitCode = 0 });
|
||||
|
||||
// Device crash log is downloaded
|
||||
processManager
|
||||
.Setup (x => x.ExecuteCommandAsync (
|
||||
mlaunchPath,
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () == $"--download-crash-report={deviceName} --download-crash-report-to={crashLogPath} --sdkroot={tempXcodeRoot} --devname={deviceName}"),
|
||||
log.Object,
|
||||
TimeSpan.FromMinutes (1),
|
||||
null,
|
||||
null))
|
||||
.ReturnsAsync (new ProcessExecutionResult () { ExitCode = 0 });
|
||||
|
||||
// Symbolicate is ran
|
||||
processManager
|
||||
.Setup (x => x.ExecuteCommandAsync (
|
||||
Path.Combine (symbolicatePath, "symbolicatecrash"),
|
||||
It.Is<IList<string>> (args => args.First () == crashLogPath),
|
||||
symbolicateReport,
|
||||
TimeSpan.FromMinutes (1),
|
||||
It.IsAny <Dictionary<string, string>>(),
|
||||
null))
|
||||
.ReturnsAsync (new ProcessExecutionResult () { ExitCode = 0 });
|
||||
processManager.SetReturnsDefault (Task.FromResult (new ProcessExecutionResult () { ExitCode = 0 }));
|
||||
|
||||
// Act
|
||||
var snapshotReport = new CrashSnapshotReporter (processManager.Object,
|
||||
|
@ -114,9 +85,48 @@ namespace Xharness.Tests {
|
|||
|
||||
await snapshotReport.EndCaptureAsync (TimeSpan.FromSeconds (10));
|
||||
|
||||
// Verify all calls above
|
||||
processManager.VerifyAll ();
|
||||
// Verify
|
||||
logs.VerifyAll ();
|
||||
|
||||
// List of crash reports is retrieved
|
||||
processManager.Verify (
|
||||
x => x.ExecuteCommandAsync (
|
||||
mlaunchPath,
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () ==
|
||||
StringUtils.FormatArguments ($"--list-crash-reports={tempFilePath}") + " " +
|
||||
$"--sdkroot {StringUtils.FormatArguments (tempXcodeRoot)} " +
|
||||
$"--devname {StringUtils.FormatArguments (deviceName)}"),
|
||||
log.Object,
|
||||
TimeSpan.FromMinutes (1),
|
||||
null,
|
||||
null),
|
||||
Times.Exactly (2));
|
||||
|
||||
// Device crash log is downloaded
|
||||
processManager.Verify (
|
||||
x => x.ExecuteCommandAsync (
|
||||
mlaunchPath,
|
||||
It.Is<MlaunchArguments> (args => args.AsCommandLine () ==
|
||||
StringUtils.FormatArguments ($"--download-crash-report={deviceName}") + " " +
|
||||
StringUtils.FormatArguments ($"--download-crash-report-to={crashLogPath}") + " " +
|
||||
$"--sdkroot {StringUtils.FormatArguments (tempXcodeRoot)} " +
|
||||
$"--devname {StringUtils.FormatArguments (deviceName)}"),
|
||||
log.Object,
|
||||
TimeSpan.FromMinutes (1),
|
||||
null,
|
||||
null),
|
||||
Times.Once);
|
||||
|
||||
// Symbolicate is ran
|
||||
processManager.Verify (
|
||||
x => x.ExecuteCommandAsync (
|
||||
Path.Combine (symbolicatePath, "symbolicatecrash"),
|
||||
It.Is<IList<string>> (args => args.First () == crashLogPath),
|
||||
symbolicateReport,
|
||||
TimeSpan.FromMinutes (1),
|
||||
It.IsAny<Dictionary<string, string>> (),
|
||||
null),
|
||||
Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@
|
|||
<Compile Include="BCLTestImporter\Tests\TestProjectDefinitionTest.cs" />
|
||||
<Compile Include="Tests\AppBundleInformationParserTests.cs" />
|
||||
<Compile Include="Tests\AppRunnerTests.cs" />
|
||||
<Compile Include="Tests\CrashReportSnapshotTests.cs" />
|
||||
<Compile Include="Tests\CrashSnapshotReporterTests.cs" />
|
||||
<Compile Include="Tests\XmlResultParserTests.cs" />
|
||||
<Compile Include="Logging\Tests\LogsTest.cs" />
|
||||
<Compile Include="Logging\Tests\LogFileTest.cs" />
|
||||
|
@ -71,7 +71,7 @@
|
|||
<Compile Include="Listeners\Tests\SimpleFileListenerTest.cs" />
|
||||
<Compile Include="Listeners\Tests\SimpleTcpListenerTest.cs" />
|
||||
<Compile Include="Execution\Tests\ProcessManagerTests.cs" />
|
||||
<Compile Include="Execution\Tests\MlaunchArgumentsTest.cs" />
|
||||
<Compile Include="Execution\Tests\MlaunchArgumentsTests.cs" />
|
||||
<Compile Include="Hardware\Tests\DeviceTest.cs" />
|
||||
<Compile Include="Hardware\Tests\DevicesTest.cs" />
|
||||
<Compile Include="Hardware\Tests\TCCDatabaseTests.cs" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче