* Revert "[Harness] Refactor simulators and devices listing. (#8064)" This reverts commite53b686ef6
. * Revert "[Harness] Move utilities out from Harness.cs, refactor AppRunner fields (#8074)" This reverts commit78dd3b861c
.
This commit is contained in:
Родитель
9b82c1c311
Коммит
f2063efefb
|
@ -1,111 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness {
|
||||
// Monitor the output from 'mlaunch --installdev' and cancel the installation if there's no output for 1 minute.
|
||||
class AppInstallMonitorLog : Log {
|
||||
public override string FullPath => copy_to.FullPath;
|
||||
|
||||
readonly ILog copy_to;
|
||||
readonly CancellationTokenSource cancellation_source;
|
||||
|
||||
public bool CopyingApp;
|
||||
public bool CopyingWatchApp;
|
||||
public TimeSpan AppCopyDuration;
|
||||
public TimeSpan WatchAppCopyDuration;
|
||||
public Stopwatch AppCopyStart = new Stopwatch ();
|
||||
public Stopwatch WatchAppCopyStart = new Stopwatch ();
|
||||
public int AppPercentComplete;
|
||||
public int WatchAppPercentComplete;
|
||||
public long AppBytes;
|
||||
public long WatchAppBytes;
|
||||
public long AppTotalBytes;
|
||||
public long WatchAppTotalBytes;
|
||||
|
||||
public CancellationToken CancellationToken {
|
||||
get {
|
||||
return cancellation_source.Token;
|
||||
}
|
||||
}
|
||||
|
||||
public AppInstallMonitorLog (ILog copy_to)
|
||||
: base (copy_to.Logs, $"Watch transfer log for {copy_to.Description}")
|
||||
{
|
||||
this.copy_to = copy_to;
|
||||
cancellation_source = new CancellationTokenSource ();
|
||||
cancellation_source.Token.Register (() => {
|
||||
copy_to.WriteLine ("App installation cancelled: it timed out after no output for 1 minute.");
|
||||
});
|
||||
}
|
||||
|
||||
public override Encoding Encoding => copy_to.Encoding;
|
||||
public override void Flush ()
|
||||
{
|
||||
copy_to.Flush ();
|
||||
}
|
||||
|
||||
public override StreamReader GetReader ()
|
||||
{
|
||||
return copy_to.GetReader ();
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
base.Dispose (disposing);
|
||||
copy_to.Dispose ();
|
||||
cancellation_source.Dispose ();
|
||||
}
|
||||
|
||||
void ResetTimer ()
|
||||
{
|
||||
cancellation_source.CancelAfter (TimeSpan.FromMinutes (1));
|
||||
}
|
||||
|
||||
public override void WriteLine (string value)
|
||||
{
|
||||
var v = value.Trim ();
|
||||
if (v.StartsWith ("Installing application bundle", StringComparison.Ordinal)) {
|
||||
if (!CopyingApp) {
|
||||
CopyingApp = true;
|
||||
AppCopyStart.Start ();
|
||||
} else if (!CopyingWatchApp) {
|
||||
CopyingApp = false;
|
||||
CopyingWatchApp = true;
|
||||
AppCopyStart.Stop ();
|
||||
WatchAppCopyStart.Start ();
|
||||
}
|
||||
} else if (v.StartsWith ("PercentComplete: ", StringComparison.Ordinal) && int.TryParse (v.Substring ("PercentComplete: ".Length).Trim (), out var percent)) {
|
||||
if (CopyingApp)
|
||||
AppPercentComplete = percent;
|
||||
else if (CopyingWatchApp)
|
||||
WatchAppPercentComplete = percent;
|
||||
} else if (v.StartsWith ("NumBytes: ", StringComparison.Ordinal) && int.TryParse (v.Substring ("NumBytes: ".Length).Trim (), out var num_bytes)) {
|
||||
if (CopyingApp) {
|
||||
AppBytes = num_bytes;
|
||||
AppCopyDuration = AppCopyStart.Elapsed;
|
||||
} else if (CopyingWatchApp) {
|
||||
WatchAppBytes = num_bytes;
|
||||
WatchAppCopyDuration = WatchAppCopyStart.Elapsed;
|
||||
}
|
||||
} else if (v.StartsWith ("TotalBytes: ", StringComparison.Ordinal) && int.TryParse (v.Substring ("TotalBytes: ".Length).Trim (), out var total_bytes)) {
|
||||
if (CopyingApp)
|
||||
AppTotalBytes = total_bytes;
|
||||
else if (CopyingWatchApp)
|
||||
WatchAppTotalBytes = total_bytes;
|
||||
}
|
||||
|
||||
ResetTimer ();
|
||||
|
||||
copy_to.WriteLine (value);
|
||||
}
|
||||
|
||||
public override void Write (byte [] buffer, int offset, int count)
|
||||
{
|
||||
copy_to.Write (buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,15 +8,14 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Xamarin;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Jenkins.TestTasks;
|
||||
using Xharness.Listeners;
|
||||
using Xharness.Logging;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness {
|
||||
namespace Xharness
|
||||
{
|
||||
public enum AppRunnerTarget
|
||||
{
|
||||
None,
|
||||
|
@ -38,15 +37,6 @@ namespace Xharness {
|
|||
|
||||
class AppRunner
|
||||
{
|
||||
string appPath;
|
||||
string launchAppPath;
|
||||
string platform;
|
||||
Extension? extension;
|
||||
bool isSimulator;
|
||||
string configuration;
|
||||
string mode;
|
||||
bool initialized;
|
||||
|
||||
public Harness Harness;
|
||||
public string ProjectFile;
|
||||
public string AppPath;
|
||||
|
@ -55,75 +45,111 @@ namespace Xharness {
|
|||
public ISimpleListenerFactory ListenerFactory = new SimpleListenerFactory ();
|
||||
|
||||
public TestExecutingResult Result { get; private set; }
|
||||
|
||||
public string FailureMessage { get; private set; }
|
||||
|
||||
public string DeviceName { get; set; }
|
||||
string appName;
|
||||
string appPath;
|
||||
string launchAppPath;
|
||||
string bundle_identifier;
|
||||
string platform;
|
||||
Extension? extension;
|
||||
bool isSimulator;
|
||||
|
||||
public string CompanionDeviceName { get; set; }
|
||||
string device_name;
|
||||
string companion_device_name;
|
||||
|
||||
public bool IsExtension => extension.HasValue;
|
||||
string configuration;
|
||||
public string Configuration {
|
||||
get { return configuration ?? Harness.Configuration; }
|
||||
set { configuration = value; }
|
||||
}
|
||||
|
||||
public string AppName { get; private set; }
|
||||
public string DeviceName {
|
||||
get { return device_name; }
|
||||
set { device_name = value; }
|
||||
}
|
||||
|
||||
public string CompanionDeviceName {
|
||||
get { return companion_device_name; }
|
||||
set { companion_device_name = value; }
|
||||
}
|
||||
|
||||
public bool isExtension {
|
||||
get {
|
||||
return extension.HasValue;
|
||||
}
|
||||
}
|
||||
|
||||
public string AppName => appName;
|
||||
|
||||
public double TimeoutMultiplier { get; set; } = 1;
|
||||
|
||||
ILogs logs;
|
||||
public ILogs Logs => logs ?? (logs = new Logs (LogDirectory));
|
||||
|
||||
public ILog MainLog { get; set; }
|
||||
|
||||
public ISimulatorDevice [] Simulators { get; set; }
|
||||
ISimulatorDevice simulator => Simulators [0];
|
||||
|
||||
public string BundleIdentifier { get; private set; }
|
||||
|
||||
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
|
||||
// For watch apps we end up with 2 simulators, the watch simulator (the main one), and the iphone simulator (the companion one).
|
||||
SimDevice[] simulators;
|
||||
SimDevice simulator { get { return simulators [0]; } }
|
||||
SimDevice companion_simulator { get { return simulators.Length == 2 ? simulators [1] : null; } }
|
||||
|
||||
AppRunnerTarget target;
|
||||
public AppRunnerTarget Target {
|
||||
get => target == AppRunnerTarget.None ? Harness.Target : target;
|
||||
set => target = value;
|
||||
get { return target == AppRunnerTarget.None ? Harness.Target : target; }
|
||||
set { target = value; }
|
||||
}
|
||||
|
||||
string log_directory;
|
||||
public string LogDirectory {
|
||||
get => log_directory ?? Harness.LogDirectory;
|
||||
set => log_directory = value;
|
||||
get { return log_directory ?? Harness.LogDirectory; }
|
||||
set { log_directory = value; }
|
||||
}
|
||||
|
||||
bool ensure_clean_simulator_state = true;
|
||||
public bool EnsureCleanSimulatorState {
|
||||
get => ensure_clean_simulator_state && string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("SKIP_SIMULATOR_SETUP"));
|
||||
set => ensure_clean_simulator_state = value;
|
||||
ILogs logs;
|
||||
public ILogs Logs {
|
||||
get {
|
||||
return logs ?? (logs = new Logs (LogDirectory));
|
||||
}
|
||||
}
|
||||
|
||||
public string Configuration {
|
||||
get => configuration ?? Harness.Configuration;
|
||||
set => configuration = value;
|
||||
ILog main_log;
|
||||
public ILog MainLog {
|
||||
get { return main_log; }
|
||||
set { main_log = value; }
|
||||
}
|
||||
|
||||
public SimDevice [] Simulators {
|
||||
get { return simulators; }
|
||||
set { simulators = value; }
|
||||
}
|
||||
|
||||
public string BundleIdentifier {
|
||||
get {
|
||||
return bundle_identifier;
|
||||
}
|
||||
}
|
||||
|
||||
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
|
||||
|
||||
string mode;
|
||||
|
||||
async Task<bool> FindSimulatorAsync ()
|
||||
{
|
||||
if (Simulators != null)
|
||||
if (simulators != null)
|
||||
return true;
|
||||
|
||||
var sims = new Simulators () {
|
||||
Harness = Harness,
|
||||
};
|
||||
await sims.LoadAsync (Logs.Create ($"simulator-list-{Harness.Timestamp}.log", "Simulator list"));
|
||||
Simulators = await sims.FindAsync (Target, MainLog);
|
||||
simulators = await sims.FindAsync (Target, main_log);
|
||||
|
||||
return Simulators != null;
|
||||
return simulators != null;
|
||||
}
|
||||
|
||||
void FindDevice ()
|
||||
{
|
||||
if (DeviceName != null)
|
||||
if (device_name != null)
|
||||
return;
|
||||
|
||||
DeviceName = Environment.GetEnvironmentVariable ("DEVICE_NAME");
|
||||
if (!string.IsNullOrEmpty (DeviceName))
|
||||
device_name = Environment.GetEnvironmentVariable ("DEVICE_NAME");
|
||||
if (!string.IsNullOrEmpty (device_name))
|
||||
return;
|
||||
|
||||
var devs = new Devices () {
|
||||
|
@ -131,7 +157,7 @@ namespace Xharness {
|
|||
};
|
||||
Task.Run (async () =>
|
||||
{
|
||||
await devs.LoadAsync (MainLog);
|
||||
await devs.LoadAsync (main_log);
|
||||
}).Wait ();
|
||||
|
||||
string [] deviceClasses;
|
||||
|
@ -150,28 +176,30 @@ namespace Xharness {
|
|||
}
|
||||
|
||||
var selected = devs.ConnectedDevices.Where ((v) => deviceClasses.Contains (v.DeviceClass) && v.IsUsableForDebugging != false);
|
||||
IHardwareDevice selected_data;
|
||||
Device selected_data;
|
||||
if (selected.Count () == 0) {
|
||||
throw new Exception ($"Could not find any applicable devices with device class(es): {string.Join (", ", deviceClasses)}");
|
||||
} else if (selected.Count () > 1) {
|
||||
selected_data = selected
|
||||
.OrderBy ((dev) =>
|
||||
{
|
||||
if (Version.TryParse (dev.ProductVersion, out Version v))
|
||||
Version v;
|
||||
if (Version.TryParse (dev.ProductVersion, out v))
|
||||
return v;
|
||||
return new Version ();
|
||||
})
|
||||
.First ();
|
||||
MainLog.WriteLine ("Found {0} devices for device class(es) '{1}': '{2}'. Selected: '{3}' (because it has the lowest version).", selected.Count (), string.Join ("', '", deviceClasses), string.Join ("', '", selected.Select ((v) => v.Name).ToArray ()), selected_data.Name);
|
||||
main_log.WriteLine ("Found {0} devices for device class(es) '{1}': '{2}'. Selected: '{3}' (because it has the lowest version).", selected.Count (), string.Join ("', '", deviceClasses), string.Join ("', '", selected.Select ((v) => v.Name).ToArray ()), selected_data.Name);
|
||||
} else {
|
||||
selected_data = selected.First ();
|
||||
}
|
||||
DeviceName = selected_data.Name;
|
||||
device_name = selected_data.Name;
|
||||
|
||||
if (mode == "watchos")
|
||||
CompanionDeviceName = devs.FindCompanionDevice (MainLog, selected_data).Name;
|
||||
companion_device_name = devs.FindCompanionDevice (main_log, selected_data).Name;
|
||||
}
|
||||
|
||||
bool initialized;
|
||||
public void Initialize ()
|
||||
{
|
||||
if (initialized)
|
||||
|
@ -180,11 +208,11 @@ namespace Xharness {
|
|||
|
||||
var csproj = new XmlDocument ();
|
||||
csproj.LoadWithoutNetworkAccess (ProjectFile);
|
||||
AppName = csproj.GetAssemblyName ();
|
||||
appName = csproj.GetAssemblyName ();
|
||||
var info_plist_path = csproj.GetInfoPListInclude ();
|
||||
var info_plist = new XmlDocument ();
|
||||
info_plist.LoadWithoutNetworkAccess (Path.Combine (Path.GetDirectoryName (ProjectFile), info_plist_path.Replace ('\\', '/')));
|
||||
BundleIdentifier = info_plist.GetCFBundleIdentifier ();
|
||||
bundle_identifier = info_plist.GetCFBundleIdentifier ();
|
||||
|
||||
var extensionPointIdentifier = info_plist.GetNSExtensionPointIdentifier ();
|
||||
if (!string.IsNullOrEmpty (extensionPointIdentifier))
|
||||
|
@ -235,7 +263,7 @@ namespace Xharness {
|
|||
throw new Exception (string.Format ("Unknown target: {0}", Harness.Target));
|
||||
}
|
||||
|
||||
appPath = Path.Combine (Path.GetDirectoryName (ProjectFile), csproj.GetOutputPath (platform, Configuration).Replace ('\\', '/'), AppName + (IsExtension ? ".appex" : ".app"));
|
||||
appPath = Path.Combine (Path.GetDirectoryName (ProjectFile), csproj.GetOutputPath (platform, Configuration).Replace ('\\', '/'), appName + (isExtension ? ".appex" : ".app"));
|
||||
if (!Directory.Exists (appPath))
|
||||
throw new Exception (string.Format ("The app directory {0} does not exist. This is probably a bug in the test harness.", appPath));
|
||||
|
||||
|
@ -267,7 +295,7 @@ namespace Xharness {
|
|||
|
||||
args.Add ("--installdev");
|
||||
args.Add (appPath);
|
||||
AddDeviceName (args, CompanionDeviceName ?? DeviceName);
|
||||
AddDeviceName (args, companion_device_name ?? device_name);
|
||||
|
||||
if (mode == "watchos") {
|
||||
args.Add ("--device");
|
||||
|
@ -275,9 +303,9 @@ namespace Xharness {
|
|||
}
|
||||
|
||||
var totalSize = Directory.GetFiles (appPath, "*", SearchOption.AllDirectories).Select ((v) => new FileInfo (v).Length).Sum ();
|
||||
MainLog.WriteLine ($"Installing '{appPath}' to '{CompanionDeviceName ?? DeviceName}'. Size: {totalSize} bytes = {totalSize / 1024.0 / 1024.0:N2} MB");
|
||||
main_log.WriteLine ($"Installing '{appPath}' to '{companion_device_name ?? device_name}'. 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 (Harness.MlaunchPath, args, main_log, TimeSpan.FromHours (1), cancellation_token: cancellation_token);
|
||||
}
|
||||
|
||||
public async Task<ProcessExecutionResult> UninstallAsync ()
|
||||
|
@ -298,10 +326,20 @@ namespace Xharness {
|
|||
args.Add ("-v");
|
||||
|
||||
args.Add ("--uninstalldevbundleid");
|
||||
args.Add (BundleIdentifier);
|
||||
AddDeviceName (args, CompanionDeviceName ?? DeviceName);
|
||||
args.Add (bundle_identifier);
|
||||
AddDeviceName (args, companion_device_name ?? device_name);
|
||||
|
||||
return await ProcessManager.ExecuteCommandAsync (Harness.MlaunchPath, args, MainLog, TimeSpan.FromMinutes (1));
|
||||
return await ProcessManager.ExecuteCommandAsync (Harness.MlaunchPath, args, main_log, TimeSpan.FromMinutes (1));
|
||||
}
|
||||
|
||||
bool ensure_clean_simulator_state = true;
|
||||
public bool EnsureCleanSimulatorState {
|
||||
get {
|
||||
return ensure_clean_simulator_state && string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("SKIP_SIMULATOR_SETUP"));
|
||||
}
|
||||
set {
|
||||
ensure_clean_simulator_state = value;
|
||||
}
|
||||
}
|
||||
|
||||
(string resultLine, bool failed, bool crashed) ParseResult (string test_log_path, bool timed_out, out bool crashed)
|
||||
|
@ -334,7 +372,7 @@ namespace Xharness {
|
|||
|
||||
// at this point, we have the test results, but we want to be able to have attachments in vsts, so if the format is
|
||||
// the right one (NUnitV3) add the nodes. ATM only TouchUnit uses V3.
|
||||
var testRunName = $"{AppName} {Variation}";
|
||||
var testRunName = $"{appName} {Variation}";
|
||||
if (xmlType == XmlResultJargon.NUnitV3) {
|
||||
var logFiles = new List<string> ();
|
||||
// add our logs AND the logs of the previous task, which is the build task
|
||||
|
@ -363,24 +401,24 @@ namespace Xharness {
|
|||
return parseResult;
|
||||
|
||||
} catch (Exception e) {
|
||||
MainLog.WriteLine ("Could not parse xml result file: {0}", e);
|
||||
main_log.WriteLine ("Could not parse xml result file: {0}", e);
|
||||
// print file for better debugging
|
||||
MainLog.WriteLine ("File data is:");
|
||||
MainLog.WriteLine (new string ('#', 10));
|
||||
main_log.WriteLine ("File data is:");
|
||||
main_log.WriteLine (new string ('#', 10));
|
||||
using (var stream = new StreamReader (path)) {
|
||||
string line;
|
||||
while ((line = stream.ReadLine ()) != null) {
|
||||
MainLog.WriteLine (line);
|
||||
main_log.WriteLine (line);
|
||||
}
|
||||
}
|
||||
MainLog.WriteLine (new string ('#', 10));
|
||||
MainLog.WriteLine ("End of xml results.");
|
||||
main_log.WriteLine (new string ('#', 10));
|
||||
main_log.WriteLine ("End of xml results.");
|
||||
if (timed_out) {
|
||||
Harness.LogWrench ($"@MonkeyWrench: AddSummary: <b><i>{mode} timed out</i></b><br/>");
|
||||
return parseResult;
|
||||
} else {
|
||||
Harness.LogWrench ($"@MonkeyWrench: AddSummary: <b><i>{mode} crashed</i></b><br/>");
|
||||
MainLog.WriteLine ("Test run crashed");
|
||||
main_log.WriteLine ("Test run crashed");
|
||||
crashed = true;
|
||||
parseResult.crashed = true;
|
||||
return parseResult;
|
||||
|
@ -418,11 +456,11 @@ namespace Xharness {
|
|||
var tests_run = resultLine.Replace ("Tests run: ", "");
|
||||
if (failed) {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddSummary: <b>{0} failed: {1}</b><br/>", mode, tests_run);
|
||||
MainLog.WriteLine ("Test run failed");
|
||||
main_log.WriteLine ("Test run failed");
|
||||
return false;
|
||||
} else {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddSummary: {0} succeeded: {1}<br/>", mode, tests_run);
|
||||
MainLog.WriteLine ("Test run succeeded");
|
||||
main_log.WriteLine ("Test run succeeded");
|
||||
return true;
|
||||
}
|
||||
} else if (timed_out) {
|
||||
|
@ -430,7 +468,7 @@ namespace Xharness {
|
|||
return false;
|
||||
} else {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} crashed</i></b><br/>", mode);
|
||||
MainLog.WriteLine ("Test run crashed");
|
||||
main_log.WriteLine ("Test run crashed");
|
||||
crashed = true;
|
||||
return false;
|
||||
}
|
||||
|
@ -444,7 +482,7 @@ namespace Xharness {
|
|||
CrashReportSnapshot crash_reports;
|
||||
ILog device_system_log = null;
|
||||
ILog listener_log = null;
|
||||
ILog run_log = MainLog;
|
||||
ILog run_log = main_log;
|
||||
|
||||
Initialize ();
|
||||
|
||||
|
@ -453,9 +491,9 @@ namespace Xharness {
|
|||
|
||||
crash_reports = new CrashReportSnapshot () {
|
||||
Device = !isSimulator,
|
||||
DeviceName = DeviceName,
|
||||
DeviceName = device_name,
|
||||
Harness = Harness,
|
||||
Log = MainLog,
|
||||
Log = main_log,
|
||||
Logs = Logs,
|
||||
LogDirectory = LogDirectory,
|
||||
};
|
||||
|
@ -503,8 +541,8 @@ namespace Xharness {
|
|||
ips.Append (ipAddresses [i].ToString ());
|
||||
}
|
||||
|
||||
args.Add ($"-argument=-app-arg:-hostname:{ips}");
|
||||
args.Add ($"-setenv=NUNIT_HOSTNAME={ips}");
|
||||
args.Add ($"-argument=-app-arg:-hostname:{ips.ToString ()}");
|
||||
args.Add ($"-setenv=NUNIT_HOSTNAME={ips.ToString ()}");
|
||||
}
|
||||
|
||||
listener_log = Logs.Create ($"test-{mode}-{Harness.Timestamp}.log", LogType.TestLog.ToString (), timestamp: !useXmlOutput);
|
||||
|
@ -518,7 +556,7 @@ namespace Xharness {
|
|||
|
||||
|
||||
listener.TestLog = listener_log;
|
||||
listener.Log = MainLog;
|
||||
listener.Log = main_log;
|
||||
listener.AutoExit = true;
|
||||
listener.Address = System.Net.IPAddress.Any;
|
||||
listener.XmlOutput = useXmlOutput;
|
||||
|
@ -533,17 +571,17 @@ namespace Xharness {
|
|||
var timed_out = false;
|
||||
|
||||
listener.ConnectedTask
|
||||
.TimeoutAfter (Harness.LaunchTimeout)
|
||||
.TimeoutAfter (TimeSpan.FromMinutes (Harness.LaunchTimeout))
|
||||
.ContinueWith ((v) => {
|
||||
if (v.IsFaulted) {
|
||||
MainLog.WriteLine ("Test launch failed: {0}", v.Exception);
|
||||
main_log.WriteLine ("Test launch failed: {0}", v.Exception);
|
||||
} else if (v.IsCanceled) {
|
||||
MainLog.WriteLine ("Test launch was cancelled.");
|
||||
main_log.WriteLine ("Test launch was cancelled.");
|
||||
} else if (v.Result) {
|
||||
MainLog.WriteLine ("Test run started");
|
||||
main_log.WriteLine ("Test run started");
|
||||
} else {
|
||||
cancellation_source.Cancel ();
|
||||
MainLog.WriteLine ("Test launch timed out after {0} minute(s).", Harness.LaunchTimeout);
|
||||
main_log.WriteLine ("Test launch timed out after {0} minute(s).", Harness.LaunchTimeout);
|
||||
timed_out = true;
|
||||
}
|
||||
}).DoNotAwait ();
|
||||
|
@ -554,7 +592,7 @@ namespace Xharness {
|
|||
bool? success = null;
|
||||
bool launch_failure = false;
|
||||
|
||||
if (IsExtension) {
|
||||
if (isExtension) {
|
||||
switch (extension) {
|
||||
case Extension.TodayExtension:
|
||||
args.Add (isSimulator ? "--launchsimbundleid" : "--launchdevbundleid");
|
||||
|
@ -592,9 +630,9 @@ namespace Xharness {
|
|||
}
|
||||
|
||||
var systemLogs = new List<CaptureLog> ();
|
||||
foreach (var sim in Simulators) {
|
||||
foreach (var sim in simulators) {
|
||||
// Upload the system log
|
||||
MainLog.WriteLine ("System log for the '{1}' simulator is: {0}", sim.SystemLog, sim.Name);
|
||||
main_log.WriteLine ("System log for the '{1}' simulator is: {0}", sim.SystemLog, sim.Name);
|
||||
bool isCompanion = sim != simulator;
|
||||
|
||||
var log = new CaptureLog (Logs, Path.Combine (LogDirectory, sim.Name + ".log"), sim.SystemLog, entire_file: Harness.Action != HarnessAction.Jenkins)
|
||||
|
@ -607,29 +645,29 @@ namespace Xharness {
|
|||
Harness.LogWrench ("@MonkeyWrench: AddFile: {0}", log.Path);
|
||||
}
|
||||
|
||||
MainLog.WriteLine ("*** Executing {0}/{1} in the simulator ***", AppName, mode);
|
||||
main_log.WriteLine ("*** Executing {0}/{1} in the simulator ***", appName, mode);
|
||||
|
||||
if (EnsureCleanSimulatorState) {
|
||||
foreach (var sim in Simulators)
|
||||
await sim.PrepareSimulatorAsync (MainLog, BundleIdentifier);
|
||||
foreach (var sim in simulators)
|
||||
await sim.PrepareSimulatorAsync (main_log, bundle_identifier);
|
||||
}
|
||||
|
||||
args.Add ($"--device=:v2:udid={simulator.UDID}");
|
||||
|
||||
await crash_reports.StartCaptureAsync ();
|
||||
|
||||
MainLog.WriteLine ("Starting test run");
|
||||
main_log.WriteLine ("Starting test run");
|
||||
|
||||
var result = await ProcessManager.ExecuteCommandAsync (Harness.MlaunchPath, args, run_log, timeout, cancellation_token: cancellation_source.Token);
|
||||
if (result.TimedOut) {
|
||||
timed_out = true;
|
||||
success = false;
|
||||
MainLog.WriteLine ("Test run timed out after {0} minute(s).", timeout);
|
||||
main_log.WriteLine ("Test run timed out after {0} minute(s).", timeout);
|
||||
} else if (result.Succeeded) {
|
||||
MainLog.WriteLine ("Test run completed");
|
||||
main_log.WriteLine ("Test run completed");
|
||||
success = true;
|
||||
} else {
|
||||
MainLog.WriteLine ("Test run failed");
|
||||
main_log.WriteLine ("Test run failed");
|
||||
success = false;
|
||||
}
|
||||
|
||||
|
@ -642,11 +680,11 @@ namespace Xharness {
|
|||
if (line.StartsWith ("Application launched. PID = ", StringComparison.Ordinal)) {
|
||||
var pidstr = line.Substring ("Application launched. PID = ".Length);
|
||||
if (!int.TryParse (pidstr, out pid))
|
||||
MainLog.WriteLine ("Could not parse pid: {0}", pidstr);
|
||||
main_log.WriteLine ("Could not parse pid: {0}", pidstr);
|
||||
} else if (line.Contains ("Xamarin.Hosting: Launched ") && line.Contains (" with pid ")) {
|
||||
var pidstr = line.Substring (line.LastIndexOf (' '));
|
||||
if (!int.TryParse (pidstr, out pid))
|
||||
MainLog.WriteLine ("Could not parse pid: {0}", pidstr);
|
||||
main_log.WriteLine ("Could not parse pid: {0}", pidstr);
|
||||
} else if (line.Contains ("error MT1008")) {
|
||||
launch_failure = true;
|
||||
}
|
||||
|
@ -655,24 +693,24 @@ namespace Xharness {
|
|||
if (pid > 0) {
|
||||
var launchTimedout = cancellation_source.IsCancellationRequested;
|
||||
var timeoutType = launchTimedout ? "Launch" : "Completion";
|
||||
var timeoutValue = launchTimedout ? Harness.LaunchTimeout.TotalSeconds : timeout.TotalSeconds;
|
||||
MainLog.WriteLine ($"{timeoutType} timed out after {timeoutValue} seconds");
|
||||
await ProcessManager.KillTreeAsync (pid, MainLog, true);
|
||||
var timeoutValue = launchTimedout ? Harness.LaunchTimeout : timeout.TotalSeconds;
|
||||
main_log.WriteLine ($"{timeoutType} timed out after {timeoutValue} seconds");
|
||||
await ProcessManager.KillTreeAsync (pid, main_log, true);
|
||||
} else {
|
||||
MainLog.WriteLine ("Could not find pid in mtouch output.");
|
||||
main_log.WriteLine ("Could not find pid in mtouch output.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// cleanup after us
|
||||
if (EnsureCleanSimulatorState)
|
||||
await SimDevice.KillEverythingAsync (MainLog);
|
||||
await SimDevice.KillEverythingAsync (main_log);
|
||||
|
||||
foreach (var log in systemLogs)
|
||||
log.StopCapture ();
|
||||
|
||||
} else {
|
||||
MainLog.WriteLine ("*** Executing {0}/{1} on device '{2}' ***", AppName, mode, DeviceName);
|
||||
main_log.WriteLine ("*** Executing {0}/{1} on device '{2}' ***", appName, mode, device_name);
|
||||
|
||||
if (mode == "watchos") {
|
||||
args.Add ("--attach-native-debugger"); // this prevents the watch from backgrounding the app.
|
||||
|
@ -682,18 +720,18 @@ namespace Xharness {
|
|||
|
||||
AddDeviceName (args);
|
||||
|
||||
device_system_log = Logs.Create ($"device-{DeviceName}-{Harness.Timestamp}.log", "Device log");
|
||||
device_system_log = Logs.Create ($"device-{device_name}-{Harness.Timestamp}.log", "Device log");
|
||||
var logdev = new DeviceLogCapturer () {
|
||||
Harness = Harness,
|
||||
Log = device_system_log,
|
||||
DeviceName = DeviceName,
|
||||
DeviceName = device_name,
|
||||
};
|
||||
logdev.StartCapture ();
|
||||
|
||||
try {
|
||||
await crash_reports.StartCaptureAsync ();
|
||||
|
||||
MainLog.WriteLine ("Starting test run");
|
||||
main_log.WriteLine ("Starting test run");
|
||||
|
||||
bool waitedForExit = true;
|
||||
// We need to check for MT1111 (which means that mlaunch won't wait for the app to exit).
|
||||
|
@ -703,13 +741,13 @@ namespace Xharness {
|
|||
if (line?.Contains ("error MT1007") == true)
|
||||
launch_failure = true;
|
||||
});
|
||||
var runLog = Log.CreateAggregatedLog (callbackLog, MainLog);
|
||||
var runLog = Log.CreateAggregatedLog (callbackLog, main_log);
|
||||
var timeoutWatch = Stopwatch.StartNew ();
|
||||
var result = await ProcessManager.ExecuteCommandAsync (Harness.MlaunchPath, args, runLog, timeout, cancellation_token: cancellation_source.Token);
|
||||
|
||||
if (!waitedForExit && !result.TimedOut) {
|
||||
// mlaunch couldn't wait for exit for some reason. Let's assume the app exits when the test listener completes.
|
||||
MainLog.WriteLine ("Waiting for listener to complete, since mlaunch won't tell.");
|
||||
main_log.WriteLine ("Waiting for listener to complete, since mlaunch won't tell.");
|
||||
if (!await listener.CompletionTask.TimeoutAfter (timeout - timeoutWatch.Elapsed)) {
|
||||
result.TimedOut = true;
|
||||
}
|
||||
|
@ -718,12 +756,12 @@ namespace Xharness {
|
|||
if (result.TimedOut) {
|
||||
timed_out = true;
|
||||
success = false;
|
||||
MainLog.WriteLine ("Test run timed out after {0} minute(s).", timeout.TotalMinutes);
|
||||
main_log.WriteLine ("Test run timed out after {0} minute(s).", timeout.TotalMinutes);
|
||||
} else if (result.Succeeded) {
|
||||
MainLog.WriteLine ("Test run completed");
|
||||
main_log.WriteLine ("Test run completed");
|
||||
success = true;
|
||||
} else {
|
||||
MainLog.WriteLine ("Test run failed");
|
||||
main_log.WriteLine ("Test run failed");
|
||||
success = false;
|
||||
}
|
||||
} finally {
|
||||
|
@ -733,7 +771,7 @@ namespace Xharness {
|
|||
|
||||
// Upload the system log
|
||||
if (File.Exists (device_system_log.FullPath)) {
|
||||
MainLog.WriteLine ("A capture of the device log is: {0}", device_system_log.FullPath);
|
||||
main_log.WriteLine ("A capture of the device log is: {0}", device_system_log.FullPath);
|
||||
Harness.LogWrench ("@MonkeyWrench: AddFile: {0}", device_system_log.FullPath);
|
||||
}
|
||||
}
|
||||
|
@ -748,15 +786,15 @@ namespace Xharness {
|
|||
success = TestsSucceeded (listener_log.FullPath, timed_out, out crashed);
|
||||
} else if (timed_out) {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} never launched</i></b><br/>", mode);
|
||||
MainLog.WriteLine ("Test run never launched");
|
||||
main_log.WriteLine ("Test run never launched");
|
||||
success = false;
|
||||
} else if (launch_failure) {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} failed to launch</i></b><br/>", mode);
|
||||
MainLog.WriteLine ("Test run failed to launch");
|
||||
main_log.WriteLine ("Test run failed to launch");
|
||||
success = false;
|
||||
} else {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} crashed at startup (no log)</i></b><br/>", mode);
|
||||
MainLog.WriteLine ("Test run crashed before it started (no log file produced)");
|
||||
main_log.WriteLine ("Test run crashed before it started (no log file produced)");
|
||||
crashed = true;
|
||||
success = false;
|
||||
}
|
||||
|
@ -784,7 +822,7 @@ namespace Xharness {
|
|||
try {
|
||||
if (pid == 0) {
|
||||
// Find the pid
|
||||
using (var log_reader = MainLog.GetReader ()) {
|
||||
using (var log_reader = main_log.GetReader ()) {
|
||||
string line;
|
||||
while ((line = log_reader.ReadLine ()) != null) {
|
||||
const string str = "was launched with pid '";
|
||||
|
@ -816,7 +854,7 @@ namespace Xharness {
|
|||
if (crash_reason != null) {
|
||||
// if in CI, do write an xml error that will be picked as a failure by VSTS
|
||||
if (Harness.InCI)
|
||||
XmlResultParser.GenerateFailure (Logs, "crash", AppName, Variation, "AppCrash", $"App crashed {crash_reason}.", crash_reports.Log.FullPath, Harness.XmlJargon);
|
||||
XmlResultParser.GenerateFailure (Logs, "crash", appName, Variation, "AppCrash", $"App crashed {crash_reason}.", crash_reports.Log.FullPath, Harness.XmlJargon);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -830,18 +868,18 @@ namespace Xharness {
|
|||
FailureMessage = $"Killed by the OS ({crash_reason})";
|
||||
}
|
||||
if (Harness.InCI)
|
||||
XmlResultParser.GenerateFailure (Logs, "crash", AppName, Variation, "AppCrash", $"App crashed: {FailureMessage}", crash_reports.Log.FullPath, Harness.XmlJargon);
|
||||
XmlResultParser.GenerateFailure (Logs, "crash", appName, Variation, "AppCrash", $"App crashed: {FailureMessage}", crash_reports.Log.FullPath, Harness.XmlJargon);
|
||||
} else if (launch_failure) {
|
||||
// same as with a crash
|
||||
FailureMessage = $"Launch failure";
|
||||
if (Harness.InCI)
|
||||
XmlResultParser.GenerateFailure (Logs, "launch", AppName, Variation, $"AppLaunch on {DeviceName}", $"{FailureMessage} on {DeviceName}", MainLog.FullPath, XmlResultJargon.NUnitV3);
|
||||
XmlResultParser.GenerateFailure (Logs, "launch", appName, Variation, $"AppLaunch on {device_name}", $"{FailureMessage} on {device_name}", main_log.FullPath, XmlResultJargon.NUnitV3);
|
||||
} else if (!isSimulator && crashed && string.IsNullOrEmpty (crash_reason) && Harness.InCI) {
|
||||
// this happens more that what we would like on devices, the main reason most of the time is that we have had netwoking problems and the
|
||||
// tcp connection could not be stablished. We are going to report it as an error since we have not parsed the logs, evne when the app might have
|
||||
// not crashed. We need to check the main_log to see if we do have an tcp issue or not
|
||||
var isTcp = false;
|
||||
using (var reader = new StreamReader (MainLog.FullPath)) {
|
||||
using (var reader = new StreamReader (main_log.FullPath)) {
|
||||
string line;
|
||||
while ((line = reader.ReadLine ()) != null) {
|
||||
if (line.Contains ("Couldn't establish a TCP connection with any of the hostnames")) {
|
||||
|
@ -851,9 +889,9 @@ namespace Xharness {
|
|||
}
|
||||
}
|
||||
if (isTcp)
|
||||
XmlResultParser.GenerateFailure (Logs, "tcp-connection", AppName, Variation, $"TcpConnection on {DeviceName}", $"Device {DeviceName} could not reach the host over tcp.", MainLog.FullPath, Harness.XmlJargon);
|
||||
XmlResultParser.GenerateFailure (Logs, "tcp-connection", appName, Variation, $"TcpConnection on {device_name}", $"Device {device_name} could not reach the host over tcp.", main_log.FullPath, Harness.XmlJargon);
|
||||
} else if (timed_out && Harness.InCI) {
|
||||
XmlResultParser.GenerateFailure (Logs, "timeout", AppName, Variation, "AppTimeout", $"Test run timed out after {timeout.TotalMinutes} minute(s).", MainLog.FullPath, Harness.XmlJargon);
|
||||
XmlResultParser.GenerateFailure (Logs, "timeout", appName, Variation, "AppTimeout", $"Test run timed out after {timeout.TotalMinutes} minute(s).", main_log.FullPath, Harness.XmlJargon);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -862,7 +900,7 @@ namespace Xharness {
|
|||
|
||||
public void AddDeviceName (IList<string> args)
|
||||
{
|
||||
AddDeviceName (args, DeviceName);
|
||||
AddDeviceName (args, device_name);
|
||||
}
|
||||
|
||||
public static void AddDeviceName (IList<string> args, string device_name)
|
||||
|
@ -873,4 +911,107 @@ namespace Xharness {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Monitor the output from 'mlaunch --installdev' and cancel the installation if there's no output for 1 minute.
|
||||
class AppInstallMonitorLog : Log {
|
||||
public override string FullPath => copy_to.FullPath;
|
||||
|
||||
ILog copy_to;
|
||||
CancellationTokenSource cancellation_source;
|
||||
|
||||
public bool CopyingApp;
|
||||
public bool CopyingWatchApp;
|
||||
public TimeSpan AppCopyDuration;
|
||||
public TimeSpan WatchAppCopyDuration;
|
||||
public Stopwatch AppCopyStart = new Stopwatch ();
|
||||
public Stopwatch WatchAppCopyStart = new Stopwatch ();
|
||||
public int AppPercentComplete;
|
||||
public int WatchAppPercentComplete;
|
||||
public long AppBytes;
|
||||
public long WatchAppBytes;
|
||||
public long AppTotalBytes;
|
||||
public long WatchAppTotalBytes;
|
||||
|
||||
public CancellationToken CancellationToken {
|
||||
get {
|
||||
return cancellation_source.Token;
|
||||
}
|
||||
}
|
||||
|
||||
public AppInstallMonitorLog (ILog copy_to)
|
||||
: base (copy_to.Logs, $"Watch transfer log for {copy_to.Description}")
|
||||
{
|
||||
this.copy_to = copy_to;
|
||||
cancellation_source = new CancellationTokenSource ();
|
||||
cancellation_source.Token.Register (() => {
|
||||
copy_to.WriteLine ("App installation cancelled: it timed out after no output for 1 minute.");
|
||||
});
|
||||
}
|
||||
|
||||
public override Encoding Encoding => copy_to.Encoding;
|
||||
public override void Flush ()
|
||||
{
|
||||
copy_to.Flush ();
|
||||
}
|
||||
|
||||
public override StreamReader GetReader ()
|
||||
{
|
||||
return copy_to.GetReader ();
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
base.Dispose (disposing);
|
||||
copy_to.Dispose ();
|
||||
cancellation_source.Dispose ();
|
||||
}
|
||||
|
||||
void ResetTimer ()
|
||||
{
|
||||
cancellation_source.CancelAfter (TimeSpan.FromMinutes (1));
|
||||
}
|
||||
|
||||
public override void WriteLine (string value)
|
||||
{
|
||||
var v = value.Trim ();
|
||||
if (v.StartsWith ("Installing application bundle", StringComparison.Ordinal)) {
|
||||
if (!CopyingApp) {
|
||||
CopyingApp = true;
|
||||
AppCopyStart.Start ();
|
||||
} else if (!CopyingWatchApp) {
|
||||
CopyingApp = false;
|
||||
CopyingWatchApp = true;
|
||||
AppCopyStart.Stop ();
|
||||
WatchAppCopyStart.Start ();
|
||||
}
|
||||
} else if (v.StartsWith ("PercentComplete: ", StringComparison.Ordinal) && int.TryParse (v.Substring ("PercentComplete: ".Length).Trim (), out var percent)) {
|
||||
if (CopyingApp)
|
||||
AppPercentComplete = percent;
|
||||
else if (CopyingWatchApp)
|
||||
WatchAppPercentComplete = percent;
|
||||
} else if (v.StartsWith ("NumBytes: ", StringComparison.Ordinal) && int.TryParse (v.Substring ("NumBytes: ".Length).Trim (), out var num_bytes)) {
|
||||
if (CopyingApp) {
|
||||
AppBytes = num_bytes;
|
||||
AppCopyDuration = AppCopyStart.Elapsed;
|
||||
} else if (CopyingWatchApp) {
|
||||
WatchAppBytes = num_bytes;
|
||||
WatchAppCopyDuration = WatchAppCopyStart.Elapsed;
|
||||
}
|
||||
} else if (v.StartsWith ("TotalBytes: ", StringComparison.Ordinal) && int.TryParse (v.Substring ("TotalBytes: ".Length).Trim (), out var total_bytes)) {
|
||||
if (CopyingApp)
|
||||
AppTotalBytes = total_bytes;
|
||||
else if (CopyingWatchApp)
|
||||
WatchAppTotalBytes = total_bytes;
|
||||
}
|
||||
|
||||
ResetTimer ();
|
||||
|
||||
copy_to.WriteLine (value);
|
||||
}
|
||||
|
||||
public override void Write (byte [] buffer, int offset, int count)
|
||||
{
|
||||
copy_to.Write (buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using BCLTestImporter;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.BCLTestImporter {
|
||||
// Class that is use as the connection between xharness and the BCLImporter
|
||||
|
@ -17,7 +16,7 @@ namespace Xharness.BCLTestImporter {
|
|||
public BCLTestImportTargetFactory (Harness harness)
|
||||
{
|
||||
Harness = harness;
|
||||
var outputDir = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "bcl-test"));
|
||||
var outputDir = Path.GetFullPath (Path.Combine (Harness.RootDirectory, "bcl-test"));
|
||||
var projectTemplatePath = outputDir;
|
||||
var registerTypesTemplatePath = Path.Combine (outputDir, "RegisterType.cs.in");
|
||||
var plistTemplatePath = outputDir;
|
||||
|
@ -26,7 +25,7 @@ namespace Xharness.BCLTestImporter {
|
|||
iOSMonoSDKPath = Harness.MONO_IOS_SDK_DESTDIR,
|
||||
MacMonoSDKPath = Harness.MONO_MAC_SDK_DESTDIR,
|
||||
Override = true,
|
||||
GuidGenerator = Helpers.GenerateStableGuid,
|
||||
GuidGenerator = Harness.NewStableGuid,
|
||||
GroupTests = Harness.InCI || Harness.UseGroupedApps,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
|||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using Xharness;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace BCLTestImporter {
|
||||
/// <summary>
|
||||
|
@ -141,7 +140,7 @@ namespace BCLTestImporter {
|
|||
new BclTestProjectInfo { Name = "mscorlib Part 3", assemblies = new [] { "monotouch_corlib_xunit-test.part3.dll" }, Group = "mscorlib Part 3" },
|
||||
new BclTestProjectInfo { Name = "SystemCoreXunit Part 1", assemblies = new [] { "monotouch_System.Core_xunit-test.part1.dll" }, Group = "SystemCoreXunit Part 1" },
|
||||
new BclTestProjectInfo { Name = "SystemCoreXunit Part 2", assemblies = new [] { "monotouch_System.Core_xunit-test.part2.dll" }, Group = "SystemCoreXunit Part 2" },
|
||||
new BclTestProjectInfo { Name = "SystemXunit", assemblies = new [] { "monotouch_System_xunit-test.dll" }, ExtraArgs = $"--xml={Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "bcl-test", "SystemXunitLinker.xml")} --optimize=-custom-attributes-removal", Group = "SystemXunit" }, // special case due to the need of the extra args
|
||||
new BclTestProjectInfo { Name = "SystemXunit", assemblies = new [] { "monotouch_System_xunit-test.dll" }, ExtraArgs = $"--xml={Path.Combine (Harness.RootDirectory, "bcl-test", "SystemXunitLinker.xml")} --optimize=-custom-attributes-removal", Group = "SystemXunit" }, // special case due to the need of the extra args
|
||||
};
|
||||
|
||||
static readonly List <string> CommonIgnoredAssemblies = new List <string> {
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Xharness.Collections {
|
||||
// This is a collection whose enumerator will wait enumerating until
|
||||
// the collection has been marked as completed (but the enumerator can still
|
||||
// be created; this allows the creation of linq queries whose execution is
|
||||
// delayed until later).
|
||||
internal class BlockingEnumerableCollection<T> : IEnumerable<T> where T : class {
|
||||
List<T> list = new List<T> ();
|
||||
TaskCompletionSource<bool> completed = new TaskCompletionSource<bool> ();
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
WaitForCompletion ();
|
||||
return list.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add (T device)
|
||||
{
|
||||
if (completed.Task.IsCompleted)
|
||||
Console.WriteLine ("Adding to completed collection!");
|
||||
list.Add (device);
|
||||
}
|
||||
|
||||
public void SetCompleted ()
|
||||
{
|
||||
completed.TrySetResult (true);
|
||||
}
|
||||
|
||||
void WaitForCompletion ()
|
||||
{
|
||||
completed.Task.Wait ();
|
||||
}
|
||||
|
||||
public void Reset ()
|
||||
{
|
||||
completed = new TaskCompletionSource<bool> ();
|
||||
list.Clear ();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator ()
|
||||
{
|
||||
return new Enumerator (this);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return GetEnumerator ();
|
||||
}
|
||||
|
||||
class Enumerator : IEnumerator<T> {
|
||||
BlockingEnumerableCollection<T> collection;
|
||||
IEnumerator<T> enumerator;
|
||||
|
||||
public Enumerator (BlockingEnumerableCollection<T> collection)
|
||||
{
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public T Current {
|
||||
get {
|
||||
return enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current {
|
||||
get {
|
||||
return enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
enumerator.Dispose ();
|
||||
}
|
||||
|
||||
public bool MoveNext ()
|
||||
{
|
||||
collection.WaitForCompletion ();
|
||||
if (enumerator == null)
|
||||
enumerator = collection.list.GetEnumerator ();
|
||||
return enumerator.MoveNext ();
|
||||
}
|
||||
|
||||
public void Reset ()
|
||||
{
|
||||
enumerator.Reset ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Xharness.Collections {
|
||||
public interface IAsyncEnumerable {
|
||||
Task ReadyTask { get; }
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Xharness;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Collections{
|
||||
public interface ILoadAsync {
|
||||
Task LoadAsync (ILog log, bool include_locked, bool force);
|
||||
IHarness Harness { get; set; }
|
||||
}
|
||||
}
|
|
@ -63,7 +63,7 @@ namespace Xharness
|
|||
var result = await Harness.ProcessManager.ExecuteCommandAsync (Harness.MlaunchPath, sb, Log, TimeSpan.FromMinutes (1));
|
||||
if (result.Succeeded) {
|
||||
Log.WriteLine ("Downloaded crash report {0} to {1}", file, crash_report_target.Path);
|
||||
crash_report_target = await SymbolicateCrashReportAsync (crash_report_target);
|
||||
crash_report_target = await Harness.SymbolicateCrashReportAsync (Logs, Log, crash_report_target);
|
||||
downloaded_crash_reports.Add (crash_report_target);
|
||||
} else {
|
||||
Log.WriteLine ("Could not download crash report {0}", file);
|
||||
|
@ -86,29 +86,5 @@ namespace Xharness
|
|||
}
|
||||
} while (!crash_report_search_done);
|
||||
}
|
||||
|
||||
async Task<ILogFile> SymbolicateCrashReportAsync (ILogFile report)
|
||||
{
|
||||
var symbolicatecrash = Path.Combine (Harness.XcodeRoot, "Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash");
|
||||
if (!File.Exists (symbolicatecrash))
|
||||
symbolicatecrash = Path.Combine (Harness.XcodeRoot, "Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash");
|
||||
|
||||
if (!File.Exists (symbolicatecrash)) {
|
||||
Log.WriteLine ("Can't symbolicate {0} because the symbolicatecrash script {1} does not exist", report.Path, symbolicatecrash);
|
||||
return report;
|
||||
}
|
||||
|
||||
var name = Path.GetFileName (report.Path);
|
||||
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 (Harness.XcodeRoot, "Contents", "Developer") } };
|
||||
var rv = await Harness.ProcessManager.ExecuteCommandAsync (symbolicatecrash, new [] { report.Path }, symbolicated, TimeSpan.FromMinutes (1), environment);
|
||||
if (rv.Succeeded) {;
|
||||
Log.WriteLine ("Symbolicated {0} successfully.", report.Path);
|
||||
return symbolicated;
|
||||
} else {
|
||||
Log.WriteLine ("Failed to symbolicate {0}.", report.Path);
|
||||
return report;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace Xharness.Execution {
|
|||
Task<ProcessExecutionResult> ExecuteCommandAsync (string filename, IList<string> 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> 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, 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, TextWriter StdoutStream, TextWriter StderrStream, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null);
|
||||
Task<bool> WaitForExitAsync (Process process, TimeSpan? timeout = null);
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Xharness.Execution {
|
||||
// mlaunch is really important and has a lot of arguments that are known but
|
||||
// used to be passed as strings. This class allows to add arguments without
|
||||
// knowing the exact string and will also validate that an argument that
|
||||
// needs a value does contain the value
|
||||
public enum MlaunchArgumentType {
|
||||
SdkRoot,
|
||||
ListDev,
|
||||
ListSim,
|
||||
OutputFormat,
|
||||
ListExtraData,
|
||||
}
|
||||
|
||||
struct MlaunchArgument {
|
||||
public MlaunchArgumentType Type { get; set; }
|
||||
public string Value { get; set; }
|
||||
|
||||
public MlaunchArgument (MlaunchArgumentType type, string value)
|
||||
{
|
||||
Type = type;
|
||||
Value = value;
|
||||
if (!IsValid (out var reason))
|
||||
throw new ArgumentException (reason);
|
||||
}
|
||||
|
||||
public MlaunchArgument (MlaunchArgumentType type)
|
||||
{
|
||||
Type = type;
|
||||
Value = null;
|
||||
if (!IsValid (out var reason))
|
||||
throw new ArgumentException (reason);
|
||||
}
|
||||
|
||||
bool IsValid (out string reason)
|
||||
{
|
||||
reason = "";
|
||||
switch (Type) {
|
||||
case MlaunchArgumentType.SdkRoot:
|
||||
case MlaunchArgumentType.ListDev:
|
||||
case MlaunchArgumentType.ListSim:
|
||||
case MlaunchArgumentType.OutputFormat:
|
||||
if (Value == null) {
|
||||
reason = $"Argument type {Type} requires a value.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case MlaunchArgumentType.ListExtraData:
|
||||
if (Value != null) {
|
||||
reason = $"Argument type {Type} does not take a value.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// return the string needed to be used in the cmd
|
||||
public string AsCommandLineArgument () => Type switch
|
||||
{
|
||||
MlaunchArgumentType.SdkRoot => $"--sdkroot={Value}",
|
||||
MlaunchArgumentType.ListDev => $"--listdev={Value}",
|
||||
MlaunchArgumentType.ListSim => $"--listsim={Value}",
|
||||
MlaunchArgumentType.OutputFormat => $"--output-format={Value}",
|
||||
MlaunchArgumentType.ListExtraData => "--list-extra-data",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
public class MlaunchArguments {
|
||||
readonly List<MlaunchArgument> arguments = new List<MlaunchArgument> ();
|
||||
|
||||
public MlaunchArguments (params MlaunchArgumentType [] args)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
Add (arg);
|
||||
}
|
||||
|
||||
public MlaunchArguments (params (MlaunchArgumentType type, string value) [] args)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
Add (arg);
|
||||
}
|
||||
|
||||
public void Add (MlaunchArgumentType type) => arguments.Add (new MlaunchArgument (type));
|
||||
public void Add ((MlaunchArgumentType type, string value) arg) => arguments.Add (new MlaunchArgument (arg.type, arg.value));
|
||||
public void Add (params MlaunchArgumentType [] types) => Array.ForEach (types, t => Add (t));
|
||||
public void Add (params (MlaunchArgumentType type, string value) [] arguments) => Array.ForEach (arguments, arg => Add (arg));
|
||||
public string AsCommandLine () => string.Join (" ", arguments.Select (a => a.AsCommandLineArgument ()));
|
||||
public IEnumerable<(MlaunchArgumentType type, string value)> GetArguments ()
|
||||
{
|
||||
foreach (var arg in arguments)
|
||||
yield return (type: arg.Type, value: arg.Value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -58,12 +58,6 @@ namespace Xharness.Execution {
|
|||
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 ();
|
||||
return RunAsync (process, log, timeout, environment_variables, cancellation_token, diagnostics);
|
||||
}
|
||||
|
||||
public 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)
|
||||
{
|
||||
if (stdoutLog is TextWriter StdoutStream && stderrLog is TextWriter StderrStream) {
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Xharness.Hardware {
|
||||
public class Device : IHardwareDevice {
|
||||
public string DeviceIdentifier { get; set; }
|
||||
public string DeviceClass { get; set; }
|
||||
public string CompanionIdentifier { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string BuildVersion { get; set; }
|
||||
public string ProductVersion { get; set; }
|
||||
public string ProductType { get; set; }
|
||||
public string InterfaceType { get; set; }
|
||||
public bool? IsUsableForDebugging { get; set; }
|
||||
public bool IsLocked { get; set; }
|
||||
|
||||
public string UDID { get { return DeviceIdentifier; } set { DeviceIdentifier = value; } }
|
||||
|
||||
public string OSVersion => ProductVersion;
|
||||
|
||||
// Add a speed property that can be used to sort a list of devices according to speed.
|
||||
public int DebugSpeed => InterfaceType?.ToLowerInvariant () switch
|
||||
{
|
||||
"usb" => 0, // fastest
|
||||
null => 1, // mlaunch doesn't know - not sure when this can happen, but wifi is quite slow, so maybe this faster
|
||||
"wifi" => 2, // wifi is quite slow
|
||||
_ => 3, // Anything else is probably slower than wifi (e.g. watch).
|
||||
};
|
||||
|
||||
public DevicePlatform DevicePlatform => DeviceClass switch
|
||||
{
|
||||
_ when DeviceClass == "iPhone" || DeviceClass == "iPod" || DeviceClass == "iPad" => DevicePlatform.iOS,
|
||||
_ when DeviceClass == "AppleTV" => DevicePlatform.tvOS,
|
||||
_ when DeviceClass == "Watch" => DevicePlatform.watchOS,
|
||||
_ => DevicePlatform.Unknown,
|
||||
};
|
||||
|
||||
public bool Supports64Bit => Architecture == Architecture.ARM64;
|
||||
|
||||
public bool Supports32Bit => DevicePlatform switch
|
||||
{
|
||||
DevicePlatform.iOS => Version.Parse (ProductVersion).Major < 11,
|
||||
DevicePlatform.tvOS => false,
|
||||
DevicePlatform.watchOS => true,
|
||||
_ => throw new NotImplementedException ()
|
||||
};
|
||||
|
||||
public bool IsSupported (iOSTestProject project)
|
||||
{
|
||||
if (project.MonoNativeInfo == null)
|
||||
return true;
|
||||
var min_version = MonoNativeHelper.GetMinimumOSVersion (DevicePlatform, project.MonoNativeInfo.Flavor);
|
||||
return Version.Parse (ProductVersion) >= Version.Parse (min_version);
|
||||
}
|
||||
|
||||
public Architecture Architecture {
|
||||
get {
|
||||
var model = ProductType;
|
||||
|
||||
// https://www.theiphonewiki.com/wiki/Models
|
||||
if (model.StartsWith ("iPhone", StringComparison.Ordinal)) {
|
||||
var identifier = model.Substring ("iPhone".Length);
|
||||
var values = identifier.Split (',');
|
||||
|
||||
switch (values [0]) {
|
||||
case "1": // iPhone (1) and iPhone 3G (2)
|
||||
return Architecture.ARMv6;
|
||||
case "2": // iPhone 3GS (1)
|
||||
case "3": // iPhone 4 (1-3)
|
||||
case "4": // iPhone 4S (1)
|
||||
return Architecture.ARMv7;
|
||||
case "5": // iPhone 5 (1-2) and iPhone 5c (3-4)
|
||||
return Architecture.ARMv7s;
|
||||
case "6": // iPhone 5s (1-2)
|
||||
case "7": // iPhone 6+ (1) and iPhone 6 (2)
|
||||
case "8": // iPhone 6s (1), iPhone 6s+ (2), iPhoneSE (4)
|
||||
case "9": // iPhone 7 (1,3) and iPhone 7+ (2,4)
|
||||
default:
|
||||
return Architecture.ARM64;
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.theiphonewiki.com/wiki/List_of_iPads
|
||||
if (model.StartsWith ("iPad", StringComparison.Ordinal)) {
|
||||
var identifier = model.Substring ("iPad".Length);
|
||||
var values = identifier.Split (',');
|
||||
|
||||
switch (values [0]) {
|
||||
case "1": // iPad (1)
|
||||
case "2": // iPad 2 (1-4) and iPad Mini (5-7)
|
||||
case "3": // iPad 3 (1-3) and iPad 4 (4-6)
|
||||
return Architecture.ARMv7;
|
||||
case "4": // iPad Air (1-3), iPad Mini 2 (4-6) and iPad Mini 3 (7-9)
|
||||
case "5": // iPad Air 2 (3-4)
|
||||
case "6": // iPad Pro 9.7-inch (3-4), iPad Pro 12.9-inch (7-8)
|
||||
default:
|
||||
return Architecture.ARM64;
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.theiphonewiki.com/wiki/List_of_iPod_touches
|
||||
if (model.StartsWith ("iPod", StringComparison.Ordinal)) {
|
||||
var identifier = model.Substring ("iPod".Length);
|
||||
var values = identifier.Split (',');
|
||||
|
||||
switch (values [0]) {
|
||||
case "1": // iPod touch (1)
|
||||
case "2": // iPod touch 2G (1)
|
||||
return Architecture.ARMv6;
|
||||
case "3": // iPod touch 3G (1)
|
||||
case "4": // iPod touch 4G (1)
|
||||
case "5": // iPod touch 5G (1)
|
||||
return Architecture.ARMv7;
|
||||
case "7": // iPod touch 6G (1)
|
||||
default:
|
||||
return Architecture.ARM64;
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.theiphonewiki.com/wiki/List_of_Apple_Watches
|
||||
if (model.StartsWith ("Watch", StringComparison.Ordinal)) {
|
||||
var identifier = model.Substring ("Watch".Length);
|
||||
var values = identifier.Split (',');
|
||||
switch (values [0]) {
|
||||
case "1": // Apple Watch (1st gen)
|
||||
case "2": // Apple Watch Series 1 and Series 2
|
||||
case "3": // Apple Watch Series 3
|
||||
return Architecture.ARMv7k;
|
||||
|
||||
case "4": // Apple Watch Series 4
|
||||
default:
|
||||
return Architecture.ARM64_32;
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.theiphonewiki.com/wiki/List_of_Apple_TVs
|
||||
if (model.StartsWith ("AppleTV", StringComparison.Ordinal))
|
||||
return Architecture.ARM64;
|
||||
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Xharness.Collections;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Hardware {
|
||||
public class Devices : IDeviceLoader {
|
||||
public IHarness Harness { get; set; }
|
||||
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
|
||||
|
||||
bool loaded;
|
||||
|
||||
BlockingEnumerableCollection<IHardwareDevice> connected_devices = new BlockingEnumerableCollection<IHardwareDevice> ();
|
||||
|
||||
public IEnumerable<IHardwareDevice> ConnectedDevices => connected_devices;
|
||||
public IEnumerable<IHardwareDevice> Connected64BitIOS => connected_devices.Where (x => x.DevicePlatform == DevicePlatform.iOS && x.Supports64Bit);
|
||||
public IEnumerable<IHardwareDevice> Connected32BitIOS => connected_devices.Where (x => x.DevicePlatform == DevicePlatform.iOS && x.Supports32Bit);
|
||||
public IEnumerable<IHardwareDevice> ConnectedTV => connected_devices.Where (x => x.DevicePlatform == DevicePlatform.tvOS);
|
||||
public IEnumerable<IHardwareDevice> ConnectedWatch => connected_devices.Where (x => x.DevicePlatform == DevicePlatform.watchOS && x.Architecture == Architecture.ARMv7k);
|
||||
public IEnumerable<IHardwareDevice> ConnectedWatch32_64 {
|
||||
get {
|
||||
return connected_devices.Where ((x) => {
|
||||
return x.DevicePlatform == DevicePlatform.watchOS && x.Architecture == Architecture.ARM64_32;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Task ILoadAsync.LoadAsync (ILog log, bool include_locked, bool force)
|
||||
{
|
||||
return LoadAsync (log, extra_data: false, removed_locked: !include_locked, force: force);
|
||||
}
|
||||
|
||||
public async Task LoadAsync (ILog log, bool extra_data = false, bool removed_locked = false, bool force = false)
|
||||
{
|
||||
if (loaded) {
|
||||
if (!force)
|
||||
return;
|
||||
connected_devices.Reset ();
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
|
||||
await Task.Run (async () => {
|
||||
var tmpfile = Path.GetTempFileName ();
|
||||
try {
|
||||
using (var process = new Process ()) {
|
||||
process.StartInfo.FileName = Harness.MlaunchPath;
|
||||
var arguments = new MlaunchArguments (
|
||||
(MlaunchArgumentType.SdkRoot, Harness.XcodeRoot),
|
||||
(MlaunchArgumentType.ListDev, tmpfile),
|
||||
(MlaunchArgumentType.OutputFormat, "xml")
|
||||
);
|
||||
if (extra_data)
|
||||
arguments.Add (MlaunchArgumentType.ListExtraData);
|
||||
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)
|
||||
throw new Exception ("Failed to list devices.");
|
||||
log.WriteLine ("Result:");
|
||||
log.WriteLine (File.ReadAllText (tmpfile));
|
||||
log.Flush ();
|
||||
|
||||
var doc = new XmlDocument ();
|
||||
doc.LoadWithoutNetworkAccess (tmpfile);
|
||||
|
||||
foreach (XmlNode dev in doc.SelectNodes ("/MTouch/Device")) {
|
||||
var usable = dev.SelectSingleNode ("IsUsableForDebugging")?.InnerText;
|
||||
Device d = new Device {
|
||||
DeviceIdentifier = dev.SelectSingleNode ("DeviceIdentifier")?.InnerText,
|
||||
DeviceClass = dev.SelectSingleNode ("DeviceClass")?.InnerText,
|
||||
CompanionIdentifier = dev.SelectSingleNode ("CompanionIdentifier")?.InnerText,
|
||||
Name = dev.SelectSingleNode ("Name")?.InnerText,
|
||||
BuildVersion = dev.SelectSingleNode ("BuildVersion")?.InnerText,
|
||||
ProductVersion = dev.SelectSingleNode ("ProductVersion")?.InnerText,
|
||||
ProductType = dev.SelectSingleNode ("ProductType")?.InnerText,
|
||||
InterfaceType = dev.SelectSingleNode ("InterfaceType")?.InnerText,
|
||||
IsUsableForDebugging = usable == null ? (bool?)null : ((bool?)(usable == "True")),
|
||||
};
|
||||
bool.TryParse (dev.SelectSingleNode ("IsLocked")?.InnerText, out var locked);
|
||||
d.IsLocked = locked;
|
||||
if (removed_locked && d.IsLocked) {
|
||||
log.WriteLine ($"Skipping device {d.Name} ({d.DeviceIdentifier}) because it's locked.");
|
||||
continue;
|
||||
}
|
||||
if (d.IsUsableForDebugging.HasValue && !d.IsUsableForDebugging.Value) {
|
||||
log.WriteLine ($"Skipping device {d.Name} ({d.DeviceIdentifier}) because it's not usable for debugging.");
|
||||
continue;
|
||||
}
|
||||
connected_devices.Add (d);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
connected_devices.SetCompleted ();
|
||||
File.Delete (tmpfile);
|
||||
log.Flush ();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public IHardwareDevice FindCompanionDevice (ILog log, IHardwareDevice device)
|
||||
{
|
||||
var companion = ConnectedDevices.Where ((v) => v.DeviceIdentifier == device.CompanionIdentifier);
|
||||
if (companion.Count () == 0)
|
||||
throw new Exception ($"Could not find the companion device for '{device.Name}'");
|
||||
|
||||
if (companion.Count () > 1)
|
||||
log.WriteLine ("Found {0} companion devices for {1}?!?", companion.Count (), device.Name);
|
||||
|
||||
return companion.First ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
namespace Xharness.Hardware {
|
||||
|
||||
public enum Architecture {
|
||||
ARMv6,
|
||||
ARMv7,
|
||||
ARMv7k,
|
||||
ARMv7s,
|
||||
ARM64,
|
||||
ARM64_32,
|
||||
i386,
|
||||
x86_64,
|
||||
}
|
||||
|
||||
public enum DevicePlatform {
|
||||
Unknown,
|
||||
iOS,
|
||||
tvOS,
|
||||
watchOS,
|
||||
macOS,
|
||||
}
|
||||
|
||||
public interface IDevice {
|
||||
string Name { get; set; }
|
||||
string UDID { get; set; }
|
||||
string OSVersion { get; }
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Xharness.Collections;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Hardware {
|
||||
public interface IHardwareDevice : IDevice {
|
||||
string DeviceIdentifier { get; set; }
|
||||
string DeviceClass { get; set; }
|
||||
string CompanionIdentifier { get; set; }
|
||||
string BuildVersion { get; set; }
|
||||
string ProductVersion { get; set; }
|
||||
string ProductType { get; set; }
|
||||
string InterfaceType { get; set; }
|
||||
bool? IsUsableForDebugging { get; set; }
|
||||
bool IsLocked { get; set; }
|
||||
int DebugSpeed { get; }
|
||||
DevicePlatform DevicePlatform { get; }
|
||||
bool Supports64Bit { get; }
|
||||
bool Supports32Bit { get; }
|
||||
Architecture Architecture { get; }
|
||||
bool IsSupported (iOSTestProject project); // TODO: Move out of this class, since we are looking at a specific case for xamarin-macions
|
||||
}
|
||||
|
||||
public interface IDeviceLoader : ILoadAsync {
|
||||
IProcessManager ProcessManager { get; set; }
|
||||
IEnumerable<IHardwareDevice> ConnectedDevices { get; }
|
||||
IEnumerable<IHardwareDevice> Connected64BitIOS { get; }
|
||||
IEnumerable<IHardwareDevice> Connected32BitIOS { get; }
|
||||
IEnumerable<IHardwareDevice> ConnectedTV { get; }
|
||||
IEnumerable<IHardwareDevice> ConnectedWatch { get; }
|
||||
IEnumerable<IHardwareDevice> ConnectedWatch32_64 { get; }
|
||||
IHardwareDevice FindCompanionDevice (ILog log, IHardwareDevice device);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xharness.Collections;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Hardware {
|
||||
public class SimRuntime {
|
||||
public string Name;
|
||||
public string Identifier;
|
||||
public long Version;
|
||||
}
|
||||
|
||||
public class SimDeviceType {
|
||||
public string Name;
|
||||
public string Identifier;
|
||||
public string ProductFamilyId;
|
||||
public long MinRuntimeVersion;
|
||||
public long MaxRuntimeVersion;
|
||||
public bool Supports64Bits;
|
||||
}
|
||||
|
||||
public class SimDevicePair {
|
||||
public string UDID;
|
||||
public string Companion;
|
||||
public string Gizmo;
|
||||
}
|
||||
|
||||
public class SimDeviceSpecification {
|
||||
public SimDevice Main;
|
||||
public SimDevice Companion; // the phone for watch devices
|
||||
}
|
||||
|
||||
public interface ISimulatorDevice : IDevice {
|
||||
IProcessManager ProcessManager { get; set; }
|
||||
ITCCDatabase TCCDatabase { get; set; }
|
||||
string SimRuntime { get; set; }
|
||||
string SimDeviceType { get; set; }
|
||||
string DataPath { get; set; }
|
||||
string LogPath { get; set; }
|
||||
string SystemLog { get; }
|
||||
bool IsWatchSimulator { get; }
|
||||
Task EraseAsync (ILog log);
|
||||
Task ShutdownAsync (ILog log);
|
||||
Task PrepareSimulatorAsync (ILog log, params string [] bundle_identifiers);
|
||||
}
|
||||
|
||||
public interface ISimulatorsLoader : ILoadAsync {
|
||||
IProcessManager ProcessManager { get; set; }
|
||||
IEnumerable<SimRuntime> SupportedRuntimes { get; }
|
||||
IEnumerable<SimDeviceType> SupportedDeviceTypes { get; }
|
||||
IEnumerable<SimDevice> AvailableDevices { get; }
|
||||
IEnumerable<SimDevicePair> AvailableDevicePairs { get; }
|
||||
Task<ISimulatorDevice []> FindAsync (AppRunnerTarget target, ILog log, bool create_if_needed = true, bool min_version = false);
|
||||
ISimulatorDevice FindCompanionDevice (ILog log, ISimulatorDevice device);
|
||||
IEnumerable<ISimulatorDevice> SelectDevices (AppRunnerTarget target, ILog log, bool min_version);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Xharness;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Hardware {
|
||||
|
||||
public class SimDevice : ISimulatorDevice {
|
||||
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
|
||||
public ITCCDatabase TCCDatabase { get; set; } = new TCCDatabase ();
|
||||
|
||||
|
||||
public string UDID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string SimRuntime { get; set; }
|
||||
public string SimDeviceType { get; set; }
|
||||
public string DataPath { get; set; }
|
||||
public string LogPath { get; set; }
|
||||
public string SystemLog => Path.Combine (LogPath, "system.log");
|
||||
|
||||
public IHarness Harness;
|
||||
|
||||
public bool IsWatchSimulator => SimRuntime.StartsWith ("com.apple.CoreSimulator.SimRuntime.watchOS", StringComparison.Ordinal);
|
||||
|
||||
public string OSVersion {
|
||||
get {
|
||||
var v = SimRuntime.Substring ("com.apple.CoreSimulator.SimRuntime.".Length);
|
||||
var dash = v.IndexOf ('-');
|
||||
return v.Substring (0, dash) + " " + v.Substring (dash + 1).Replace ('-', '.');
|
||||
}
|
||||
}
|
||||
|
||||
public async Task EraseAsync (ILog log)
|
||||
{
|
||||
// here we don't care if execution fails.
|
||||
// erase the simulator (make sure the device isn't running first)
|
||||
await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1));
|
||||
await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "erase", UDID }, log, TimeSpan.FromMinutes (1));
|
||||
|
||||
// boot & shutdown to make sure it actually works
|
||||
await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "boot", UDID }, log, TimeSpan.FromMinutes (1));
|
||||
await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1));
|
||||
}
|
||||
|
||||
public async Task ShutdownAsync (ILog log)
|
||||
{
|
||||
await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "shutdown", UDID }, log, TimeSpan.FromMinutes (1));
|
||||
}
|
||||
|
||||
public static async Task KillEverythingAsync (ILog log, IProcessManager processManager = null)
|
||||
{
|
||||
if (processManager == null)
|
||||
processManager = new ProcessManager ();
|
||||
await processManager.ExecuteCommandAsync ("launchctl", new [] { "remove", "com.apple.CoreSimulator.CoreSimulatorService" }, log, TimeSpan.FromSeconds (10));
|
||||
|
||||
var to_kill = new string [] { "iPhone Simulator", "iOS Simulator", "Simulator", "Simulator (Watch)", "com.apple.CoreSimulator.CoreSimulatorService", "ibtoold" };
|
||||
|
||||
var args = new List<string> ();
|
||||
args.Add ("-9");
|
||||
args.AddRange (to_kill);
|
||||
await processManager.ExecuteCommandAsync ("killall", args, log, TimeSpan.FromSeconds (10));
|
||||
|
||||
foreach (var dir in new string [] {
|
||||
Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), "Library", "Saved Application State", "com.apple.watchsimulator.savedState"),
|
||||
Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), "Library", "Saved Application State", "com.apple.iphonesimulator.savedState"),
|
||||
}) {
|
||||
try {
|
||||
if (Directory.Exists (dir))
|
||||
Directory.Delete (dir, true);
|
||||
} catch (Exception e) {
|
||||
log.WriteLine ("Could not delete the directory '{0}': {1}", dir, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task OpenSimulator (ILog log)
|
||||
{
|
||||
string simulator_app;
|
||||
|
||||
if (IsWatchSimulator && Harness.XcodeVersion.Major < 9) {
|
||||
simulator_app = Path.Combine (Harness.XcodeRoot, "Contents", "Developer", "Applications", "Simulator (Watch).app");
|
||||
} else {
|
||||
simulator_app = Path.Combine (Harness.XcodeRoot, "Contents", "Developer", "Applications", "Simulator.app");
|
||||
if (!Directory.Exists (simulator_app))
|
||||
simulator_app = Path.Combine (Harness.XcodeRoot, "Contents", "Developer", "Applications", "iOS Simulator.app");
|
||||
}
|
||||
|
||||
await ProcessManager.ExecuteCommandAsync ("open", new [] { "-a", simulator_app, "--args", "-CurrentDeviceUDID", UDID }, log, TimeSpan.FromSeconds (15));
|
||||
}
|
||||
|
||||
public async Task PrepareSimulatorAsync (ILog log, params string [] bundle_identifiers)
|
||||
{
|
||||
// Kill all existing processes
|
||||
await KillEverythingAsync (log);
|
||||
|
||||
// We shutdown and erase all simulators.
|
||||
await EraseAsync (log);
|
||||
|
||||
// Edit the permissions to prevent dialog boxes in the test app
|
||||
var TCC_db = Path.Combine (DataPath, "data", "Library", "TCC", "TCC.db");
|
||||
if (!File.Exists (TCC_db)) {
|
||||
log.WriteLine ("Opening simulator to create TCC.db");
|
||||
await OpenSimulator (log);
|
||||
|
||||
var tcc_creation_timeout = 60;
|
||||
var watch = new Stopwatch ();
|
||||
watch.Start ();
|
||||
while (!File.Exists (TCC_db) && watch.Elapsed.TotalSeconds < tcc_creation_timeout) {
|
||||
log.WriteLine ("Waiting for simulator to create TCC.db... {0}", (int)(tcc_creation_timeout - watch.Elapsed.TotalSeconds));
|
||||
await Task.Delay (TimeSpan.FromSeconds (0.250));
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists (TCC_db)) {
|
||||
await TCCDatabase.AgreeToPromptsAsync (SimRuntime, TCC_db, log, bundle_identifiers);
|
||||
} else {
|
||||
log.WriteLine ("No TCC.db found for the simulator {0} (SimRuntime={1} and SimDeviceType={1})", UDID, SimRuntime, SimDeviceType);
|
||||
}
|
||||
|
||||
// Make sure we're in a clean state
|
||||
await KillEverythingAsync (log);
|
||||
|
||||
// Make 100% sure we're shutdown
|
||||
await ShutdownAsync (log);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,416 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Xamarin;
|
||||
using Xharness.Collections;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Hardware {
|
||||
public class Simulators : ISimulatorsLoader {
|
||||
public IHarness Harness { get; set; }
|
||||
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
|
||||
|
||||
bool loaded;
|
||||
readonly SemaphoreSlim semaphore = new SemaphoreSlim (1);
|
||||
|
||||
BlockingEnumerableCollection<SimRuntime> supported_runtimes = new BlockingEnumerableCollection<SimRuntime> ();
|
||||
BlockingEnumerableCollection<SimDeviceType> supported_device_types = new BlockingEnumerableCollection<SimDeviceType> ();
|
||||
BlockingEnumerableCollection<SimDevice> available_devices = new BlockingEnumerableCollection<SimDevice> ();
|
||||
BlockingEnumerableCollection<SimDevicePair> available_device_pairs = new BlockingEnumerableCollection<SimDevicePair> ();
|
||||
|
||||
public IEnumerable<SimRuntime> SupportedRuntimes => supported_runtimes;
|
||||
public IEnumerable<SimDeviceType> SupportedDeviceTypes => supported_device_types;
|
||||
public IEnumerable<SimDevice> AvailableDevices => available_devices;
|
||||
public IEnumerable<SimDevicePair> AvailableDevicePairs => available_device_pairs;
|
||||
|
||||
public async Task LoadAsync (ILog log, bool include_locked = false, bool force = false)
|
||||
{
|
||||
await semaphore.WaitAsync ();
|
||||
if (loaded) {
|
||||
if (!force) {
|
||||
semaphore.Release ();
|
||||
return;
|
||||
}
|
||||
supported_runtimes.Reset ();
|
||||
supported_device_types.Reset ();
|
||||
available_devices.Reset ();
|
||||
available_device_pairs.Reset ();
|
||||
}
|
||||
loaded = true;
|
||||
|
||||
await Task.Run (async () => {
|
||||
var tmpfile = Path.GetTempFileName ();
|
||||
try {
|
||||
using (var process = new Process ()) {
|
||||
process.StartInfo.FileName = Harness.MlaunchPath;
|
||||
var arguments = new MlaunchArguments (
|
||||
(MlaunchArgumentType.SdkRoot, Harness.XcodeRoot),
|
||||
(MlaunchArgumentType.ListSim, tmpfile)
|
||||
);
|
||||
process.StartInfo.Arguments = arguments.AsCommandLine ();
|
||||
log.WriteLine ("Launching {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||
var rv = await ProcessManager.RunAsync (process, log, timeout: TimeSpan.FromSeconds (30));
|
||||
if (!rv.Succeeded)
|
||||
throw new Exception ("Failed to list simulators.");
|
||||
log.WriteLine ("Result:");
|
||||
log.WriteLine (File.ReadAllText (tmpfile));
|
||||
var simulator_data = new XmlDocument ();
|
||||
simulator_data.LoadWithoutNetworkAccess (tmpfile);
|
||||
foreach (XmlNode sim in simulator_data.SelectNodes ("/MTouch/Simulator/SupportedRuntimes/SimRuntime")) {
|
||||
supported_runtimes.Add (new SimRuntime () {
|
||||
Name = sim.SelectSingleNode ("Name").InnerText,
|
||||
Identifier = sim.SelectSingleNode ("Identifier").InnerText,
|
||||
Version = long.Parse (sim.SelectSingleNode ("Version").InnerText),
|
||||
});
|
||||
}
|
||||
|
||||
foreach (XmlNode sim in simulator_data.SelectNodes ("/MTouch/Simulator/SupportedDeviceTypes/SimDeviceType")) {
|
||||
supported_device_types.Add (new SimDeviceType () {
|
||||
Name = sim.SelectSingleNode ("Name").InnerText,
|
||||
Identifier = sim.SelectSingleNode ("Identifier").InnerText,
|
||||
ProductFamilyId = sim.SelectSingleNode ("ProductFamilyId").InnerText,
|
||||
MinRuntimeVersion = long.Parse (sim.SelectSingleNode ("MinRuntimeVersion").InnerText),
|
||||
MaxRuntimeVersion = long.Parse (sim.SelectSingleNode ("MaxRuntimeVersion").InnerText),
|
||||
Supports64Bits = bool.Parse (sim.SelectSingleNode ("Supports64Bits").InnerText),
|
||||
});
|
||||
}
|
||||
|
||||
foreach (XmlNode sim in simulator_data.SelectNodes ("/MTouch/Simulator/AvailableDevices/SimDevice")) {
|
||||
available_devices.Add (new SimDevice () {
|
||||
Harness = Harness,
|
||||
Name = sim.Attributes ["Name"].Value,
|
||||
UDID = sim.Attributes ["UDID"].Value,
|
||||
SimRuntime = sim.SelectSingleNode ("SimRuntime").InnerText,
|
||||
SimDeviceType = sim.SelectSingleNode ("SimDeviceType").InnerText,
|
||||
DataPath = sim.SelectSingleNode ("DataPath").InnerText,
|
||||
LogPath = sim.SelectSingleNode ("LogPath").InnerText,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var sim_device_pairs = simulator_data.
|
||||
SelectNodes ("/MTouch/Simulator/AvailableDevicePairs/SimDevicePair").
|
||||
Cast<XmlNode> ().
|
||||
// There can be duplicates, so remove those.
|
||||
Distinct (new SimulatorXmlNodeComparer ());
|
||||
foreach (XmlNode sim in sim_device_pairs) {
|
||||
available_device_pairs.Add (new SimDevicePair () {
|
||||
UDID = sim.Attributes ["UDID"].Value,
|
||||
Companion = sim.SelectSingleNode ("Companion").InnerText,
|
||||
Gizmo = sim.SelectSingleNode ("Gizmo").InnerText,
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
supported_runtimes.SetCompleted ();
|
||||
supported_device_types.SetCompleted ();
|
||||
available_devices.SetCompleted ();
|
||||
available_device_pairs.SetCompleted ();
|
||||
File.Delete (tmpfile);
|
||||
semaphore.Release ();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
string CreateName (string devicetype, string runtime)
|
||||
{
|
||||
var runtime_name = supported_runtimes?.Where ((v) => v.Identifier == runtime).FirstOrDefault ()?.Name ?? Path.GetExtension (runtime).Substring (1);
|
||||
var device_name = supported_device_types?.Where ((v) => v.Identifier == devicetype).FirstOrDefault ()?.Name ?? Path.GetExtension (devicetype).Substring (1);
|
||||
return $"{device_name} ({runtime_name}) - created by xharness";
|
||||
}
|
||||
|
||||
// Will return all devices that match the runtime + devicetype (even if a new device was created, any other devices will also be returned)
|
||||
async Task<IEnumerable<ISimulatorDevice>> FindOrCreateDevicesAsync (ILog log, string runtime, string devicetype, bool force = false)
|
||||
{
|
||||
if (runtime == null || devicetype == null)
|
||||
return null;
|
||||
|
||||
IEnumerable<ISimulatorDevice> devices = null;
|
||||
|
||||
if (!force) {
|
||||
devices = AvailableDevices.Where ((SimDevice v) => v.SimRuntime == runtime && v.SimDeviceType == devicetype);
|
||||
if (devices.Any ())
|
||||
return devices;
|
||||
}
|
||||
|
||||
var rv = await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "create", CreateName (devicetype, runtime), devicetype, runtime }, log, TimeSpan.FromMinutes (1));
|
||||
if (!rv.Succeeded) {
|
||||
log.WriteLine ($"Could not create device for runtime={runtime} and device type={devicetype}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
await LoadAsync (log, force: true);
|
||||
|
||||
devices = AvailableDevices.Where ((ISimulatorDevice v) => v.SimRuntime == runtime && v.SimDeviceType == devicetype);
|
||||
if (!devices.Any ()) {
|
||||
log.WriteLine ($"No devices loaded after creating it? runtime={runtime} device type={devicetype}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
async Task<bool> CreateDevicePair (ILog log, ISimulatorDevice device, ISimulatorDevice companion_device, string runtime, string devicetype, bool create_device)
|
||||
{
|
||||
if (create_device) {
|
||||
// watch device is already paired to some other phone. Create a new watch device
|
||||
var matchingDevices = await FindOrCreateDevicesAsync (log, runtime, devicetype, force: true);
|
||||
var unPairedDevices = matchingDevices.Where ((v) => !AvailableDevicePairs.Any ((SimDevicePair p) => { return p.Gizmo == v.UDID; }));
|
||||
if (device != null) {
|
||||
// If we're creating a new watch device, assume that the one we were given is not usable.
|
||||
unPairedDevices = unPairedDevices.Where ((v) => v.UDID != device.UDID);
|
||||
}
|
||||
if (unPairedDevices?.Any () != true)
|
||||
return false;
|
||||
device = unPairedDevices.First ();
|
||||
}
|
||||
log.WriteLine ($"Creating device pair for '{device.Name}' and '{companion_device.Name}'");
|
||||
var capturedLog = new StringBuilder ();
|
||||
var pairLog = new CallbackLog ((string value) => {
|
||||
log.WriteImpl (value);
|
||||
capturedLog.Append (value);
|
||||
});
|
||||
var rv = await Harness.ExecuteXcodeCommandAsync ("simctl", new [] { "pair", device.UDID, companion_device.UDID }, pairLog, TimeSpan.FromMinutes (1));
|
||||
if (!rv.Succeeded) {
|
||||
if (!create_device) {
|
||||
var try_creating_device = false;
|
||||
var captured_log = capturedLog.ToString ();
|
||||
try_creating_device |= captured_log.Contains ("At least one of the requested devices is already paired with the maximum number of supported devices and cannot accept another pairing.");
|
||||
try_creating_device |= captured_log.Contains ("The selected devices are already paired with each other.");
|
||||
if (try_creating_device) {
|
||||
log.WriteLine ($"Could not create device pair for '{device.Name}' ({device.UDID}) and '{companion_device.Name}' ({companion_device.UDID}), but will create a new watch device and try again.");
|
||||
return await CreateDevicePair (log, device, companion_device, runtime, devicetype, true);
|
||||
}
|
||||
}
|
||||
|
||||
log.WriteLine ($"Could not create device pair for '{device.Name}' ({device.UDID}) and '{companion_device.Name}' ({companion_device.UDID})");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async Task<SimDevicePair> FindOrCreateDevicePairAsync (ILog log, IEnumerable<ISimulatorDevice> devices, IEnumerable<ISimulatorDevice> companion_devices)
|
||||
{
|
||||
// Check if we already have a device pair with the specified devices
|
||||
var pairs = AvailableDevicePairs.Where ((SimDevicePair pair) => {
|
||||
if (!devices.Any ((v) => v.UDID == pair.Gizmo))
|
||||
return false;
|
||||
if (!companion_devices.Any ((v) => v.UDID == pair.Companion))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!pairs.Any ()) {
|
||||
// No device pair. Create one.
|
||||
// First check if the watch is already paired
|
||||
var unPairedDevices = devices.Where ((v) => !AvailableDevicePairs.Any ((SimDevicePair p) => { return p.Gizmo == v.UDID; }));
|
||||
var unpairedDevice = unPairedDevices.FirstOrDefault ();
|
||||
var companion_device = companion_devices.First ();
|
||||
var device = devices.First ();
|
||||
if (!await CreateDevicePair (log, unpairedDevice, companion_device, device.SimRuntime, device.SimDeviceType, unpairedDevice == null))
|
||||
return null;
|
||||
|
||||
await LoadAsync (log, force: true);
|
||||
|
||||
pairs = AvailableDevicePairs.Where ((SimDevicePair pair) => {
|
||||
if (!devices.Any ((v) => v.UDID == pair.Gizmo))
|
||||
return false;
|
||||
if (!companion_devices.Any ((v) => v.UDID == pair.Companion))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return pairs.FirstOrDefault ();
|
||||
}
|
||||
|
||||
public async Task<ISimulatorDevice []> FindAsync (AppRunnerTarget target, ILog log, bool create_if_needed = true, bool min_version = false)
|
||||
{
|
||||
ISimulatorDevice [] simulators = null;
|
||||
|
||||
string simulator_devicetype;
|
||||
string simulator_runtime;
|
||||
string companion_devicetype = null;
|
||||
string companion_runtime = null;
|
||||
|
||||
switch (target) {
|
||||
case AppRunnerTarget.Simulator_iOS32:
|
||||
simulator_devicetype = "com.apple.CoreSimulator.SimDeviceType.iPhone-5";
|
||||
simulator_runtime = "com.apple.CoreSimulator.SimRuntime.iOS-" + (min_version ? SdkVersions.MiniOSSimulator : "10-3").Replace ('.', '-');
|
||||
break;
|
||||
case AppRunnerTarget.Simulator_iOS64:
|
||||
simulator_devicetype = "com.apple.CoreSimulator.SimDeviceType." + (min_version ? "iPhone-6" : "iPhone-X");
|
||||
simulator_runtime = "com.apple.CoreSimulator.SimRuntime.iOS-" + (min_version ? SdkVersions.MiniOSSimulator : SdkVersions.MaxiOSSimulator).Replace ('.', '-');
|
||||
break;
|
||||
case AppRunnerTarget.Simulator_iOS:
|
||||
simulator_devicetype = "com.apple.CoreSimulator.SimDeviceType.iPhone-5";
|
||||
simulator_runtime = "com.apple.CoreSimulator.SimRuntime.iOS-" + (min_version ? SdkVersions.MiniOSSimulator : SdkVersions.MaxiOSSimulator).Replace ('.', '-');
|
||||
break;
|
||||
case AppRunnerTarget.Simulator_tvOS:
|
||||
simulator_devicetype = "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p";
|
||||
simulator_runtime = "com.apple.CoreSimulator.SimRuntime.tvOS-" + (min_version ? SdkVersions.MinTVOSSimulator : SdkVersions.MaxTVOSSimulator).Replace ('.', '-');
|
||||
break;
|
||||
case AppRunnerTarget.Simulator_watchOS:
|
||||
simulator_devicetype = "com.apple.CoreSimulator.SimDeviceType." + (min_version ? "Apple-Watch-38mm" : "Apple-Watch-Series-3-38mm");
|
||||
simulator_runtime = "com.apple.CoreSimulator.SimRuntime.watchOS-" + (min_version ? SdkVersions.MinWatchOSSimulator : SdkVersions.MaxWatchOSSimulator).Replace ('.', '-');
|
||||
companion_devicetype = "com.apple.CoreSimulator.SimDeviceType." + (min_version ? "iPhone-6" : "iPhone-X");
|
||||
companion_runtime = "com.apple.CoreSimulator.SimRuntime.iOS-" + (min_version ? SdkVersions.MinWatchOSCompanionSimulator : SdkVersions.MaxWatchOSCompanionSimulator).Replace ('.', '-');
|
||||
break;
|
||||
default:
|
||||
throw new Exception (string.Format ("Unknown simulator target: {0}", target));
|
||||
}
|
||||
|
||||
var devices = await FindOrCreateDevicesAsync (log, simulator_runtime, simulator_devicetype);
|
||||
var companion_devices = await FindOrCreateDevicesAsync (log, companion_runtime, companion_devicetype);
|
||||
|
||||
if (devices?.Any () != true) {
|
||||
log.WriteLine ($"Could not find or create devices runtime={simulator_runtime} and device type={simulator_devicetype}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (companion_runtime == null) {
|
||||
simulators = new ISimulatorDevice [] { devices.First () };
|
||||
} else {
|
||||
if (companion_devices?.Any () != true) {
|
||||
log.WriteLine ($"Could not find or create companion devices runtime={companion_runtime} and device type={companion_devicetype}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var pair = await FindOrCreateDevicePairAsync (log, devices, companion_devices);
|
||||
if (pair == null) {
|
||||
log.WriteLine ($"Could not find or create device pair runtime={companion_runtime} and device type={companion_devicetype}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
simulators = new ISimulatorDevice [] {
|
||||
devices.First ((v) => v.UDID == pair.Gizmo),
|
||||
companion_devices.First ((v) => v.UDID == pair.Companion),
|
||||
};
|
||||
}
|
||||
|
||||
if (simulators == null) {
|
||||
log.WriteLine ($"Could not find simulator for runtime={simulator_runtime} and device type={simulator_devicetype}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
log.WriteLine ("Found simulator: {0} {1}", simulators [0].Name, simulators [0].UDID);
|
||||
if (simulators.Length > 1)
|
||||
log.WriteLine ("Found companion simulator: {0} {1}", simulators [1].Name, simulators [1].UDID);
|
||||
|
||||
return simulators;
|
||||
}
|
||||
|
||||
public ISimulatorDevice FindCompanionDevice (ILog log, ISimulatorDevice device)
|
||||
{
|
||||
var pair = available_device_pairs.Where ((v) => v.Gizmo == device.UDID).Single ();
|
||||
return available_devices.Single ((v) => v.UDID == pair.Companion);
|
||||
}
|
||||
|
||||
public IEnumerable<ISimulatorDevice> SelectDevices (AppRunnerTarget target, ILog log, bool min_version)
|
||||
{
|
||||
return new SimulatorEnumerable {
|
||||
Simulators = this,
|
||||
Target = target,
|
||||
MinVersion = min_version,
|
||||
Log = log,
|
||||
};
|
||||
}
|
||||
|
||||
class SimulatorXmlNodeComparer : IEqualityComparer<XmlNode> {
|
||||
public bool Equals (XmlNode a, XmlNode b)
|
||||
{
|
||||
return a ["Gizmo"].InnerText == b ["Gizmo"].InnerText && a ["Companion"].InnerText == b ["Companion"].InnerText;
|
||||
}
|
||||
|
||||
public int GetHashCode (XmlNode node)
|
||||
{
|
||||
return node ["Gizmo"].InnerText.GetHashCode () ^ node ["Companion"].InnerText.GetHashCode ();
|
||||
}
|
||||
}
|
||||
|
||||
class SimulatorEnumerable : IEnumerable<ISimulatorDevice>, IAsyncEnumerable {
|
||||
public Simulators Simulators;
|
||||
public AppRunnerTarget Target;
|
||||
public bool MinVersion;
|
||||
public ILog Log;
|
||||
object lock_obj = new object ();
|
||||
Task<ISimulatorDevice []> findTask;
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return $"Simulators for {Target} (MinVersion: {MinVersion})";
|
||||
}
|
||||
|
||||
public IEnumerator<ISimulatorDevice> GetEnumerator ()
|
||||
{
|
||||
return new Enumerator () {
|
||||
Enumerable = this,
|
||||
};
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return GetEnumerator ();
|
||||
}
|
||||
|
||||
Task<ISimulatorDevice []> Find ()
|
||||
{
|
||||
lock (lock_obj) {
|
||||
if (findTask == null)
|
||||
findTask = Simulators.FindAsync (Target, Log, min_version: MinVersion);
|
||||
return findTask;
|
||||
}
|
||||
}
|
||||
|
||||
public Task ReadyTask {
|
||||
get { return Find (); }
|
||||
}
|
||||
|
||||
class Enumerator : IEnumerator<ISimulatorDevice> {
|
||||
internal SimulatorEnumerable Enumerable;
|
||||
ISimulatorDevice [] devices;
|
||||
bool moved;
|
||||
|
||||
public ISimulatorDevice Current {
|
||||
get {
|
||||
return devices [0];
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current {
|
||||
get {
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext ()
|
||||
{
|
||||
if (moved)
|
||||
return false;
|
||||
if (devices == null)
|
||||
devices = Enumerable.Find ()?.Result?.ToArray (); // Create a copy of the list of devices, so we can have enumerator-specific current index.
|
||||
moved = true;
|
||||
return devices?.Length > 0;
|
||||
}
|
||||
|
||||
public void Reset ()
|
||||
{
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Hardware {
|
||||
|
||||
public interface ITCCDatabase {
|
||||
IProcessManager ProcessManager { get; set; }
|
||||
Task AgreeToPromptsAsync (string simRuntime, string dataPath, ILog log, params string [] bundle_identifiers);
|
||||
int GetTCCFormat (string simRuntime);
|
||||
}
|
||||
|
||||
public class TCCDatabase : ITCCDatabase {
|
||||
static readonly string iOSSimRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.iOS-";
|
||||
static readonly string tvOSSimRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.tvOS-";
|
||||
static readonly string watchOSRuntimePrefix = "com.apple.CoreSimulator.SimRuntime.watchOS-";
|
||||
|
||||
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
|
||||
|
||||
public int GetTCCFormat (string simRuntime) {
|
||||
|
||||
// v1: < iOS 9
|
||||
// v2: >= iOS 9 && < iOS 12
|
||||
// v3: >= iOS 12
|
||||
if (simRuntime.StartsWith (iOSSimRuntimePrefix, StringComparison.Ordinal)) {
|
||||
var v = Version.Parse (simRuntime.Substring (iOSSimRuntimePrefix.Length).Replace ('-', '.'));
|
||||
if (v.Major >= 12) {
|
||||
return 3;
|
||||
} else if (v.Major >= 9) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else if (simRuntime.StartsWith (tvOSSimRuntimePrefix, StringComparison.Ordinal)) {
|
||||
var v = Version.Parse (simRuntime.Substring (tvOSSimRuntimePrefix.Length).Replace ('-', '.'));
|
||||
if (v.Major >= 12) {
|
||||
return 3;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else if (simRuntime.StartsWith (watchOSRuntimePrefix, StringComparison.Ordinal)) {
|
||||
var v = Version.Parse (simRuntime.Substring (watchOSRuntimePrefix.Length).Replace ('-', '.'));
|
||||
if (v.Major >= 5) {
|
||||
return 3;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AgreeToPromptsAsync (string simRuntime, string TCCDb, ILog log, params string [] bundle_identifiers)
|
||||
{
|
||||
if (bundle_identifiers == null || bundle_identifiers.Length == 0) {
|
||||
log.WriteLine ("No bundle identifiers given when requested permission editing.");
|
||||
return;
|
||||
}
|
||||
|
||||
var sim_services = new string [] {
|
||||
"kTCCServiceAddressBook",
|
||||
"kTCCServiceCalendar",
|
||||
"kTCCServicePhotos",
|
||||
"kTCCServiceMediaLibrary",
|
||||
"kTCCServiceMicrophone",
|
||||
"kTCCServiceUbiquity",
|
||||
"kTCCServiceWillow"
|
||||
};
|
||||
|
||||
var failure = false;
|
||||
var tcc_edit_timeout = 30;
|
||||
var watch = new Stopwatch ();
|
||||
watch.Start ();
|
||||
|
||||
do {
|
||||
if (failure) {
|
||||
log.WriteLine ("Failed to edit TCC.db, trying again in 1 second... ", (int)(tcc_edit_timeout - watch.Elapsed.TotalSeconds));
|
||||
await Task.Delay (TimeSpan.FromSeconds (1));
|
||||
}
|
||||
failure = false;
|
||||
foreach (var bundle_identifier in bundle_identifiers) {
|
||||
var args = new List<string> ();
|
||||
var sql = new System.Text.StringBuilder ();
|
||||
args.Add (TCCDb);
|
||||
foreach (var service in sim_services) {
|
||||
switch (GetTCCFormat (simRuntime)) {
|
||||
case 1:
|
||||
// CREATE TABLE access (service TEXT NOT NULL, client TEXT NOT NULL, client_type INTEGER NOT NULL, allowed INTEGER NOT NULL, prompt_count INTEGER NOT NULL, csreq BLOB, CONSTRAINT key PRIMARY KEY (service, client, client_type));
|
||||
sql.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL);", service, bundle_identifier);
|
||||
sql.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL);", service, bundle_identifier + ".watchkitapp");
|
||||
break;
|
||||
case 2:
|
||||
// CREATE TABLE access (service TEXT NOT NULL, client TEXT NOT NULL, client_type INTEGER NOT NULL, allowed INTEGER NOT NULL, prompt_count INTEGER NOT NULL, csreq BLOB, policy_id INTEGER, PRIMARY KEY (service, client, client_type), FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE ON UPDATE CASCADE);
|
||||
sql.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL);", service, bundle_identifier);
|
||||
sql.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL);", service, bundle_identifier + ".watchkitapp");
|
||||
break;
|
||||
case 3: // Xcode 10+
|
||||
// CREATE TABLE access ( service TEXT NOT NULL, client TEXT NOT NULL, client_type INTEGER NOT NULL, allowed INTEGER NOT NULL, prompt_count INTEGER NOT NULL, csreq BLOB, policy_id INTEGER, indirect_object_identifier_type INTEGER, indirect_object_identifier TEXT, indirect_object_code_identity BLOB, flags INTEGER, last_modified INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER)), PRIMARY KEY (service, client, client_type, indirect_object_identifier), FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE ON UPDATE CASCADE)
|
||||
sql.AppendFormat ("INSERT OR REPLACE INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL,NULL,'UNUSED',NULL,NULL,{2});", service, bundle_identifier, DateTimeOffset.Now.ToUnixTimeSeconds ());
|
||||
sql.AppendFormat ("INSERT OR REPLACE INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL,NULL,'UNUSED',NULL,NULL,{2});", service, bundle_identifier + ".watchkitapp", DateTimeOffset.Now.ToUnixTimeSeconds ());
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
args.Add (sql.ToString ());
|
||||
var rv = await ProcessManager.ExecuteCommandAsync ("sqlite3", args, log, TimeSpan.FromSeconds (5));
|
||||
if (!rv.Succeeded) {
|
||||
failure = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (failure && watch.Elapsed.TotalSeconds <= tcc_edit_timeout);
|
||||
|
||||
if (failure) {
|
||||
log.WriteLine ("Failed to edit TCC.db, the test run might hang due to permission request dialogs");
|
||||
} else {
|
||||
log.WriteLine ("Successfully edited TCC.db");
|
||||
}
|
||||
|
||||
log.WriteLine ("Current TCC database contents:");
|
||||
await ProcessManager.ExecuteCommandAsync ("sqlite3", new [] { TCCDb, ".dump" }, log, TimeSpan.FromSeconds (5));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
@ -24,14 +25,7 @@ namespace Xharness
|
|||
Jenkins,
|
||||
}
|
||||
|
||||
public interface IHarness {
|
||||
string MlaunchPath { get; }
|
||||
string XcodeRoot { get; }
|
||||
Version XcodeVersion { get; }
|
||||
Task<ProcessExecutionResult> ExecuteXcodeCommandAsync (string executable, IList<string> args, ILog log, TimeSpan timeout);
|
||||
}
|
||||
|
||||
public class Harness : IHarness
|
||||
public class Harness
|
||||
{
|
||||
public HarnessAction Action { get; set; }
|
||||
public int Verbosity { get; set; }
|
||||
|
@ -42,7 +36,7 @@ namespace Xharness
|
|||
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
|
||||
|
||||
public string XIBuildPath {
|
||||
get { return Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "tools", "xibuild", "xibuild")); }
|
||||
get { return Path.GetFullPath (Path.Combine (RootDirectory, "..", "tools", "xibuild", "xibuild")); }
|
||||
}
|
||||
|
||||
public static string Timestamp {
|
||||
|
@ -51,6 +45,33 @@ namespace Xharness
|
|||
}
|
||||
}
|
||||
|
||||
// This is the maccore/tests directory.
|
||||
static string root_directory;
|
||||
public static string RootDirectory {
|
||||
get {
|
||||
if (root_directory == null) {
|
||||
var testAssemblyDirectory = Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly ().Location);
|
||||
var dir = testAssemblyDirectory;
|
||||
var path = Path.Combine (testAssemblyDirectory, ".git");
|
||||
while (!Directory.Exists (path) && path.Length > 3) {
|
||||
dir = Path.GetDirectoryName (dir);
|
||||
path = Path.Combine (dir, ".git");
|
||||
}
|
||||
if (!Directory.Exists (path))
|
||||
throw new Exception ("Could not find the xamarin-macios repo.");
|
||||
path = Path.Combine (Path.GetDirectoryName (path), "tests");
|
||||
if (!Directory.Exists (path))
|
||||
throw new Exception ("Could not find the tests directory.");
|
||||
root_directory = path;
|
||||
}
|
||||
return root_directory;
|
||||
}
|
||||
set {
|
||||
root_directory = value;
|
||||
if (root_directory != null)
|
||||
root_directory = Path.GetFullPath (root_directory).TrimEnd ('/');
|
||||
}
|
||||
}
|
||||
|
||||
public List<iOSTestProject> IOSTestProjects { get; set; } = new List<iOSTestProject> ();
|
||||
public List<MacTestProject> MacTestProjects { get; set; } = new List<MacTestProject> ();
|
||||
|
@ -85,7 +106,7 @@ namespace Xharness
|
|||
public string LogFile { get; set; }
|
||||
public string LogDirectory { get; set; } = Environment.CurrentDirectory;
|
||||
public double Timeout { get; set; } = 15; // in minutes
|
||||
public TimeSpan LaunchTimeout { get; set; } // in minutes
|
||||
public double LaunchTimeout { get; set; } // in minutes
|
||||
public bool DryRun { get; set; } // Most things don't support this. If you need it somewhere, implement it!
|
||||
public string JenkinsConfiguration { get; set; }
|
||||
public Dictionary<string, string> EnvironmentVariables { get; set; } = new Dictionary<string, string> ();
|
||||
|
@ -98,7 +119,7 @@ namespace Xharness
|
|||
|
||||
public Harness ()
|
||||
{
|
||||
LaunchTimeout = TimeSpan.FromMinutes(InCI ? 3 : 120);
|
||||
LaunchTimeout = InCI ? 3 : 120;
|
||||
}
|
||||
|
||||
public bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device)
|
||||
|
@ -165,6 +186,59 @@ namespace Xharness
|
|||
}
|
||||
}
|
||||
|
||||
object mlaunch_lock = new object ();
|
||||
string DownloadMlaunch ()
|
||||
{
|
||||
// NOTE: the filename part in the url must be unique so that the caching logic works properly.
|
||||
var mlaunch_url = "https://dl.xamarin.com/ios/mlaunch-acdb43d346c431b2c40663c938c919dcb0e91bd7.zip";
|
||||
var extraction_dir = Path.Combine (Path.GetTempPath (), Path.GetFileNameWithoutExtension (mlaunch_url));
|
||||
var mlaunch_path = Path.Combine (extraction_dir, "bin", "mlaunch");
|
||||
|
||||
lock (mlaunch_lock) {
|
||||
if (File.Exists (mlaunch_path))
|
||||
return mlaunch_path;
|
||||
|
||||
try {
|
||||
var local_zip = extraction_dir + ".zip";
|
||||
Log ("Downloading mlaunch to: {0}", local_zip);
|
||||
var wc = new System.Net.WebClient ();
|
||||
wc.DownloadFile (mlaunch_url, local_zip);
|
||||
Log ("Downloaded mlaunch.");
|
||||
|
||||
var tmp_extraction_dir = extraction_dir + ".tmp";
|
||||
if (Directory.Exists (tmp_extraction_dir))
|
||||
Directory.Delete (tmp_extraction_dir, true);
|
||||
if (Directory.Exists (extraction_dir))
|
||||
Directory.Delete (extraction_dir, true);
|
||||
|
||||
Log ("Extracting mlaunch...");
|
||||
using (var p = new Process ()) {
|
||||
p.StartInfo.FileName = "unzip";
|
||||
p.StartInfo.Arguments = StringUtils.FormatArguments ("-d", tmp_extraction_dir, local_zip);
|
||||
Log ("{0} {1}", p.StartInfo.FileName, p.StartInfo.Arguments);
|
||||
p.Start ();
|
||||
p.WaitForExit ();
|
||||
if (p.ExitCode != 0) {
|
||||
Log ("Could not unzip mlaunch, exit code: {0}", p.ExitCode);
|
||||
return mlaunch_path;
|
||||
}
|
||||
}
|
||||
Directory.Move (tmp_extraction_dir, extraction_dir);
|
||||
|
||||
Log ("Final mlaunch path: {0}", mlaunch_path);
|
||||
} catch (Exception e) {
|
||||
Log ("Could not download mlaunch: {0}", e);
|
||||
}
|
||||
return mlaunch_path;
|
||||
}
|
||||
}
|
||||
|
||||
public string MtouchPath {
|
||||
get {
|
||||
return Path.Combine (IOS_DESTDIR, "Library", "Frameworks", "Xamarin.iOS.framework", "Versions", "Current", "bin", "mtouch");
|
||||
}
|
||||
}
|
||||
|
||||
public string MlaunchPath {
|
||||
get {
|
||||
return Path.Combine (IOS_DESTDIR, "Library", "Frameworks", "Xamarin.iOS.framework", "Versions", "Current", "bin", "mlaunch");
|
||||
|
@ -174,7 +248,7 @@ namespace Xharness
|
|||
void LoadConfig ()
|
||||
{
|
||||
ParseConfigFiles ();
|
||||
var src_root = Path.GetDirectoryName ( DirectoryUtilities.RepositoryRootDirectory);
|
||||
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"]);
|
||||
|
@ -200,13 +274,13 @@ namespace Xharness
|
|||
new { Directory = "linker/mac/dont link", ProjectFile = "dont link-mac", Name = "dont link", Flavors = MacFlavors.Modern | MacFlavors.Full | MacFlavors.System },
|
||||
};
|
||||
foreach (var p in test_suites) {
|
||||
MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p.Directory, p.ProjectFile + ".csproj"))) {
|
||||
MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (RootDirectory, p.Directory, p.ProjectFile + ".csproj"))) {
|
||||
Name = p.Name,
|
||||
TargetFrameworkFlavors = p.Flavors,
|
||||
});
|
||||
}
|
||||
|
||||
MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "introspection", "Mac", "introspection-mac.csproj")), targetFrameworkFlavor: MacFlavors.Modern) { Name = "introspection" });
|
||||
MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "introspection", "Mac", "introspection-mac.csproj")), targetFrameworkFlavor: MacFlavors.Modern) { Name = "introspection" });
|
||||
|
||||
var hard_coded_test_suites = new [] {
|
||||
new { Directory = "mmptest", ProjectFile = "mmptest", Name = "mmptest", IsNUnit = true, Configurations = (string[]) null, Platform = "x86", Flavors = MacFlavors.Console, },
|
||||
|
@ -216,11 +290,10 @@ namespace Xharness
|
|||
new { Directory = "linker/mac/link sdk", ProjectFile = "link sdk-mac", Name = "link sdk", IsNUnit = false, Configurations = new string [] { "Debug", "Release" }, Platform = "x86", Flavors = MacFlavors.Modern, },
|
||||
};
|
||||
foreach (var p in hard_coded_test_suites) {
|
||||
string projectPath = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p.Directory, p.ProjectFile + ".csproj"));
|
||||
MacTestProjects.Add (new MacTestProject (projectPath, targetFrameworkFlavor: p.Flavors) {
|
||||
MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (RootDirectory, p.Directory, p.ProjectFile + ".csproj")), targetFrameworkFlavor: p.Flavors) {
|
||||
Name = p.Name,
|
||||
IsNUnitProject = p.IsNUnit,
|
||||
SolutionPath = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "tests-mac.sln")),
|
||||
SolutionPath = Path.GetFullPath (Path.Combine (RootDirectory, "tests-mac.sln")),
|
||||
Configurations = p.Configurations,
|
||||
Platform = p.Platform,
|
||||
});
|
||||
|
@ -319,18 +392,18 @@ namespace Xharness
|
|||
var fsharp_library_projects = new string [] { "fsharplibrary" };
|
||||
|
||||
foreach (var p in test_suites)
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".csproj"))) { Name = p });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, p + "/" + p + ".csproj"))) { Name = p });
|
||||
foreach (var p in fsharp_test_suites)
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".fsproj"))) { Name = p });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, p + "/" + p + ".fsproj"))) { Name = p });
|
||||
foreach (var p in library_projects)
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".csproj")), false) { Name = p });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, p + "/" + p + ".csproj")), false) { Name = p });
|
||||
foreach (var p in fsharp_library_projects)
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".fsproj")), false) { Name = p });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, p + "/" + p + ".fsproj")), false) { Name = p });
|
||||
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "introspection", "iOS", "introspection-ios.csproj"))) { Name = "introspection" });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "linker", "ios", "dont link", "dont link.csproj"))) { Configurations = new string [] { "Debug", "Release" } });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "linker", "ios", "link all", "link all.csproj"))) { Configurations = new string [] { "Debug", "Release" } });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "linker", "ios", "link sdk", "link sdk.csproj"))) { Configurations = new string [] { "Debug", "Release" } });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "introspection", "iOS", "introspection-ios.csproj"))) { Name = "introspection" });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "linker", "ios", "dont link", "dont link.csproj"))) { Configurations = new string [] { "Debug", "Release" } });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "linker", "ios", "link all", "link all.csproj"))) { Configurations = new string [] { "Debug", "Release" } });
|
||||
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "linker", "ios", "link sdk", "link sdk.csproj"))) { Configurations = new string [] { "Debug", "Release" } });
|
||||
|
||||
foreach (var flavor in new MonoNativeFlavor[] { MonoNativeFlavor.Compat, MonoNativeFlavor.Unified }) {
|
||||
var monoNativeInfo = new MonoNativeInfo (this, flavor);
|
||||
|
@ -347,19 +420,19 @@ namespace Xharness
|
|||
var monoImportTestFactory = new BCLTestImportTargetFactory (this);
|
||||
IOSTestProjects.AddRange (monoImportTestFactory.GetiOSBclTargets ());
|
||||
|
||||
WatchOSContainerTemplate = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "templates/WatchContainer"));
|
||||
WatchOSAppTemplate = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "templates/WatchApp"));
|
||||
WatchOSExtensionTemplate = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "templates/WatchExtension"));
|
||||
WatchOSContainerTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "templates/WatchContainer"));
|
||||
WatchOSAppTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "templates/WatchApp"));
|
||||
WatchOSExtensionTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "templates/WatchExtension"));
|
||||
|
||||
TodayContainerTemplate = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "templates", "TodayContainer"));
|
||||
TodayExtensionTemplate = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "templates", "TodayExtension"));
|
||||
BCLTodayExtensionTemplate = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "bcl-test", "templates", "today"));
|
||||
TodayContainerTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "templates", "TodayContainer"));
|
||||
TodayExtensionTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "templates", "TodayExtension"));
|
||||
BCLTodayExtensionTemplate = Path.GetFullPath (Path.Combine (RootDirectory, "bcl-test", "templates", "today"));
|
||||
}
|
||||
|
||||
Dictionary<string, string> make_config = new Dictionary<string, string> ();
|
||||
IEnumerable<string> FindConfigFiles (string name)
|
||||
{
|
||||
var dir = DirectoryUtilities.RepositoryRootDirectory;
|
||||
var dir = Path.GetFullPath (RootDirectory);
|
||||
while (dir != "/") {
|
||||
var file = Path.Combine (dir, name);
|
||||
if (File.Exists (file))
|
||||
|
@ -396,7 +469,7 @@ namespace Xharness
|
|||
}
|
||||
}
|
||||
|
||||
int Configure ()
|
||||
public int Configure ()
|
||||
{
|
||||
return Mac ? AutoConfigureMac (true) : ConfigureIOS ();
|
||||
}
|
||||
|
@ -474,7 +547,7 @@ namespace Xharness
|
|||
return rv;
|
||||
}
|
||||
|
||||
int Install ()
|
||||
public int Install ()
|
||||
{
|
||||
if (HarnessLog == null)
|
||||
HarnessLog = new ConsoleLog ();
|
||||
|
@ -494,7 +567,7 @@ namespace Xharness
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Uninstall ()
|
||||
public int Uninstall ()
|
||||
{
|
||||
if (HarnessLog == null)
|
||||
HarnessLog = new ConsoleLog ();
|
||||
|
@ -513,7 +586,7 @@ namespace Xharness
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Run ()
|
||||
public int Run ()
|
||||
{
|
||||
if (HarnessLog == null)
|
||||
HarnessLog = new ConsoleLog ();
|
||||
|
@ -531,20 +604,6 @@ namespace Xharness
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Jenkins ()
|
||||
{
|
||||
if (AutoConf) {
|
||||
AutoConfigureIOS ();
|
||||
AutoConfigureMac (false);
|
||||
}
|
||||
|
||||
var jenkins = new Jenkins.Jenkins ()
|
||||
{
|
||||
Harness = this,
|
||||
};
|
||||
return jenkins.Run ();
|
||||
}
|
||||
|
||||
public void Log (int min_level, string message)
|
||||
{
|
||||
if (Verbosity < min_level)
|
||||
|
@ -621,6 +680,20 @@ namespace Xharness
|
|||
}
|
||||
}
|
||||
|
||||
public int Jenkins ()
|
||||
{
|
||||
if (AutoConf) {
|
||||
AutoConfigureIOS ();
|
||||
AutoConfigureMac (false);
|
||||
}
|
||||
|
||||
var jenkins = new Jenkins.Jenkins ()
|
||||
{
|
||||
Harness = this,
|
||||
};
|
||||
return jenkins.Run ();
|
||||
}
|
||||
|
||||
public void Save (XmlDocument doc, string path)
|
||||
{
|
||||
if (!File.Exists (path)) {
|
||||
|
@ -661,6 +734,42 @@ namespace Xharness
|
|||
}
|
||||
}
|
||||
|
||||
public void Save (string doc, string path)
|
||||
{
|
||||
if (!File.Exists (path)) {
|
||||
File.WriteAllText (path, doc);
|
||||
Log (1, "Created {0}", path);
|
||||
} else {
|
||||
var existing = File.ReadAllText (path);
|
||||
if (existing == doc) {
|
||||
Log (1, "Not saved {0}, no change", path);
|
||||
} else {
|
||||
File.WriteAllText (path, doc);
|
||||
Log (1, "Updated {0}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We want guids that nobody else has, but we also want to generate the same guid
|
||||
// on subsequent invocations (so that csprojs don't change unnecessarily, which is
|
||||
// annoying when XS reloads the projects, and also causes unnecessary rebuilds).
|
||||
// Nothing really breaks when the sequence isn't identical from run to run, so
|
||||
// this is just a best minimal effort.
|
||||
static Random guid_generator = new Random (unchecked ((int) 0xdeadf00d));
|
||||
public Guid NewStableGuid (string seed = null)
|
||||
{
|
||||
var bytes = new byte [16];
|
||||
if (seed == null) {
|
||||
guid_generator.NextBytes (bytes);
|
||||
} else {
|
||||
using (var provider = MD5.Create ()) {
|
||||
var inputBytes = Encoding.UTF8.GetBytes (seed);
|
||||
bytes = provider.ComputeHash (inputBytes);
|
||||
}
|
||||
}
|
||||
return new Guid (bytes);
|
||||
}
|
||||
|
||||
bool? disable_watchos_on_wrench;
|
||||
public bool DisableWatchOSOnWrench {
|
||||
get {
|
||||
|
@ -675,6 +784,35 @@ namespace Xharness
|
|||
return ProcessManager.ExecuteCommandAsync (Path.Combine (XcodeRoot, "Contents", "Developer", "usr", "bin", executable), args, log, timeout: timeout);
|
||||
}
|
||||
|
||||
public async Task ShowSimulatorList (Log log)
|
||||
{
|
||||
await ExecuteXcodeCommandAsync ("simctl", new [] { "list" }, log, TimeSpan.FromSeconds (10));
|
||||
}
|
||||
|
||||
public async Task<ILogFile> SymbolicateCrashReportAsync (ILogs logs, ILog log, ILogFile report)
|
||||
{
|
||||
var symbolicatecrash = Path.Combine (XcodeRoot, "Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash");
|
||||
if (!File.Exists (symbolicatecrash))
|
||||
symbolicatecrash = Path.Combine (XcodeRoot, "Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash");
|
||||
|
||||
if (!File.Exists (symbolicatecrash)) {
|
||||
log.WriteLine ("Can't symbolicate {0} because the symbolicatecrash script {1} does not exist", report.Path, symbolicatecrash);
|
||||
return report;
|
||||
}
|
||||
|
||||
var name = Path.GetFileName (report.Path);
|
||||
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 rv = await ProcessManager.ExecuteCommandAsync (symbolicatecrash, new [] { report.Path }, symbolicated, TimeSpan.FromMinutes (1), environment);
|
||||
if (rv.Succeeded) {;
|
||||
log.WriteLine ("Symbolicated {0} successfully.", report.Path);
|
||||
return symbolicated;
|
||||
} else {
|
||||
log.WriteLine ("Failed to symbolicate {0}.", report.Path);
|
||||
return report;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<HashSet<string>> CreateCrashReportsSnapshotAsync (ILog log, bool simulatorOrDesktop, string device)
|
||||
{
|
||||
var rv = new HashSet<string> ();
|
||||
|
|
|
@ -9,8 +9,6 @@ using System.Text;
|
|||
using Xharness.Logging;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Jenkins.TestTasks;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Collections;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Jenkins
|
||||
|
@ -73,8 +71,8 @@ namespace Xharness.Jenkins
|
|||
}
|
||||
}
|
||||
|
||||
public ISimulatorsLoader Simulators = new Simulators ();
|
||||
public IDeviceLoader Devices = new Devices ();
|
||||
public Simulators Simulators = new Simulators ();
|
||||
public Devices Devices = new Devices ();
|
||||
|
||||
List<TestTask> Tasks = new List<TestTask> ();
|
||||
Dictionary<string, MakeTask> DependencyTasks = new Dictionary<string, MakeTask> ();
|
||||
|
@ -83,7 +81,7 @@ namespace Xharness.Jenkins
|
|||
internal static Resource NugetResource = new Resource ("Nuget", 1); // nuget is not parallel-safe :(
|
||||
|
||||
static Dictionary<string, Resource> device_resources = new Dictionary<string, Resource> ();
|
||||
internal static Resources GetDeviceResources (IEnumerable<IHardwareDevice> devices)
|
||||
internal static Resources GetDeviceResources (IEnumerable<Device> devices)
|
||||
{
|
||||
List<Resource> resources = new List<Resource> ();
|
||||
lock (device_resources) {
|
||||
|
@ -647,7 +645,7 @@ namespace Xharness.Jenkins
|
|||
rv.AddRange (projectTasks);
|
||||
}
|
||||
|
||||
return Task.FromResult<IEnumerable<TestTask>> (CreateTestVariations (rv, (buildTask, test, candidates) => new RunDeviceTask (buildTask, candidates?.Cast<IHardwareDevice> () ?? test.Candidates)));
|
||||
return Task.FromResult<IEnumerable<TestTask>> (CreateTestVariations (rv, (buildTask, test, candidates) => new RunDeviceTask (buildTask, candidates?.Cast<Device> () ?? test.Candidates)));
|
||||
}
|
||||
|
||||
static string AddSuffixToPath (string path, string suffix)
|
||||
|
@ -922,17 +920,17 @@ namespace Xharness.Jenkins
|
|||
var buildiOSMSBuild_net461 = new MSBuildTask ()
|
||||
{
|
||||
Jenkins = this,
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "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,
|
||||
SpecifyConfiguration = true,
|
||||
ProjectConfiguration = "Debug-net461",
|
||||
Platform = TestPlatform.iOS,
|
||||
SolutionPath = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "msbuild", "Xamarin.MacDev.Tasks.sln")),
|
||||
SolutionPath = Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "msbuild", "Xamarin.MacDev.Tasks.sln")),
|
||||
SupportsParallelExecution = false,
|
||||
};
|
||||
var nunitExecutioniOSMSBuild_net461 = new NUnitExecuteTask (buildiOSMSBuild_net461)
|
||||
{
|
||||
TestLibrary = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "bin", "Debug-net461", "net461", "Xamarin.iOS.Tasks.Tests.dll"),
|
||||
TestLibrary = Path.Combine (Harness.RootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "bin", "Debug-net461", "net461", "Xamarin.iOS.Tasks.Tests.dll"),
|
||||
TestProject = buildiOSMSBuild_net461.TestProject,
|
||||
ProjectConfiguration = "Debug-net461",
|
||||
Platform = TestPlatform.iOS,
|
||||
|
@ -946,16 +944,16 @@ namespace Xharness.Jenkins
|
|||
|
||||
var buildiOSMSBuild_netstandard2 = new MSBuildTask () {
|
||||
Jenkins = this,
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "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,
|
||||
SpecifyConfiguration = true,
|
||||
ProjectConfiguration = "Debug-netstandard2.0",
|
||||
Platform = TestPlatform.iOS,
|
||||
SolutionPath = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "msbuild", "Xamarin.MacDev.Tasks.sln")),
|
||||
SolutionPath = Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "msbuild", "Xamarin.MacDev.Tasks.sln")),
|
||||
SupportsParallelExecution = false,
|
||||
};
|
||||
var nunitExecutioniOSMSBuild_netstandard2 = new NUnitExecuteTask (buildiOSMSBuild_netstandard2) {
|
||||
TestLibrary = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "bin", "Debug-netstandard2.0", "net461", "Xamarin.iOS.Tasks.Tests.dll"),
|
||||
TestLibrary = Path.Combine (Harness.RootDirectory, "..", "msbuild", "tests", "Xamarin.iOS.Tasks.Tests", "bin", "Debug-netstandard2.0", "net461", "Xamarin.iOS.Tasks.Tests.dll"),
|
||||
TestProject = buildiOSMSBuild_netstandard2.TestProject,
|
||||
ProjectConfiguration = "Debug-netstandard2.0",
|
||||
Platform = TestPlatform.iOS,
|
||||
|
@ -970,15 +968,15 @@ namespace Xharness.Jenkins
|
|||
var buildInstallSources = new MSBuildTask ()
|
||||
{
|
||||
Jenkins = this,
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "InstallSourcesTests.csproj"))),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "InstallSourcesTests.csproj"))),
|
||||
SpecifyPlatform = false,
|
||||
SpecifyConfiguration = false,
|
||||
Platform = TestPlatform.iOS,
|
||||
};
|
||||
buildInstallSources.SolutionPath = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "tools", "install-source", "install-source.sln")); // this is required for nuget restore to be executed
|
||||
buildInstallSources.SolutionPath = Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "tools", "install-source", "install-source.sln")); // this is required for nuget restore to be executed
|
||||
var nunitExecutionInstallSource = new NUnitExecuteTask (buildInstallSources)
|
||||
{
|
||||
TestLibrary = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "bin", "Release", "InstallSourcesTests.dll"),
|
||||
TestLibrary = Path.Combine (Harness.RootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "bin", "Release", "InstallSourcesTests.dll"),
|
||||
TestProject = buildInstallSources.TestProject,
|
||||
Platform = TestPlatform.iOS,
|
||||
TestName = "Install Sources tests",
|
||||
|
@ -1063,17 +1061,17 @@ namespace Xharness.Jenkins
|
|||
var buildMTouch = new MakeTask ()
|
||||
{
|
||||
Jenkins = this,
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mtouch", "mtouch.sln"))),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "mtouch", "mtouch.sln"))),
|
||||
SpecifyPlatform = false,
|
||||
SpecifyConfiguration = false,
|
||||
Platform = TestPlatform.iOS,
|
||||
Target = "dependencies",
|
||||
WorkingDirectory = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mtouch")),
|
||||
WorkingDirectory = Path.GetFullPath (Path.Combine (Harness.RootDirectory, "mtouch")),
|
||||
};
|
||||
var nunitExecutionMTouch = new NUnitExecuteTask (buildMTouch)
|
||||
{
|
||||
TestLibrary = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mtouch", "bin", "Debug", "mtouch.dll"),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mtouch", "mtouch.csproj"))),
|
||||
TestLibrary = Path.Combine (Harness.RootDirectory, "mtouch", "bin", "Debug", "mtouch.dll"),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "mtouch", "mtouch.csproj"))),
|
||||
Platform = TestPlatform.iOS,
|
||||
TestName = "MTouch tests",
|
||||
Timeout = TimeSpan.FromMinutes (180),
|
||||
|
@ -1084,16 +1082,16 @@ namespace Xharness.Jenkins
|
|||
|
||||
var buildGenerator = new MakeTask {
|
||||
Jenkins = this,
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "src", "generator.sln"))),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "src", "generator.sln"))),
|
||||
SpecifyPlatform = false,
|
||||
SpecifyConfiguration = false,
|
||||
Platform = TestPlatform.iOS,
|
||||
Target = "build-unit-tests",
|
||||
WorkingDirectory = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "generator")),
|
||||
WorkingDirectory = Path.GetFullPath (Path.Combine (Harness.RootDirectory, "generator")),
|
||||
};
|
||||
var runGenerator = new NUnitExecuteTask (buildGenerator) {
|
||||
TestLibrary = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "generator", "bin", "Debug", "generator-tests.dll"),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "generator", "generator-tests.csproj"))),
|
||||
TestLibrary = Path.Combine (Harness.RootDirectory, "generator", "bin", "Debug", "generator-tests.dll"),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "generator", "generator-tests.csproj"))),
|
||||
Platform = TestPlatform.iOS,
|
||||
TestName = "Generator tests",
|
||||
Timeout = TimeSpan.FromMinutes (10),
|
||||
|
@ -1107,7 +1105,7 @@ namespace Xharness.Jenkins
|
|||
Platform = TestPlatform.Mac,
|
||||
TestName = "MMP Regression Tests",
|
||||
Target = "all", // -j" + Environment.ProcessorCount,
|
||||
WorkingDirectory = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mmptest", "regression"),
|
||||
WorkingDirectory = Path.Combine (Harness.RootDirectory, "mmptest", "regression"),
|
||||
Ignored = !IncludeMmpTest || !IncludeMac,
|
||||
Timeout = TimeSpan.FromMinutes (30),
|
||||
SupportsParallelExecution = false, // Already doing parallel execution by running "make -jX"
|
||||
|
@ -1126,7 +1124,7 @@ namespace Xharness.Jenkins
|
|||
Platform = TestPlatform.Mac,
|
||||
TestName = "Mac Binding Projects",
|
||||
Target = "all",
|
||||
WorkingDirectory = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mac-binding-project"),
|
||||
WorkingDirectory = Path.Combine (Harness.RootDirectory, "mac-binding-project"),
|
||||
Ignored = !IncludeMacBindingProject || !IncludeMac,
|
||||
Timeout = TimeSpan.FromMinutes (15),
|
||||
};
|
||||
|
@ -1137,7 +1135,7 @@ namespace Xharness.Jenkins
|
|||
Platform = TestPlatform.All,
|
||||
TestName = "Xtro",
|
||||
Target = "wrench",
|
||||
WorkingDirectory = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "xtro-sharpie"),
|
||||
WorkingDirectory = Path.Combine (Harness.RootDirectory, "xtro-sharpie"),
|
||||
Ignored = !IncludeXtro,
|
||||
Timeout = TimeSpan.FromMinutes (15),
|
||||
};
|
||||
|
@ -1155,7 +1153,7 @@ namespace Xharness.Jenkins
|
|||
Platform = TestPlatform.All,
|
||||
TestName = "Cecil",
|
||||
Target = "build",
|
||||
WorkingDirectory = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "cecil-tests"),
|
||||
WorkingDirectory = Path.Combine (Harness.RootDirectory, "cecil-tests"),
|
||||
Ignored = !IncludeCecil,
|
||||
Timeout = TimeSpan.FromMinutes (5),
|
||||
};
|
||||
|
@ -1175,7 +1173,7 @@ namespace Xharness.Jenkins
|
|||
Platform = TestPlatform.All,
|
||||
TestName = "Documentation",
|
||||
Target = "wrench-docs",
|
||||
WorkingDirectory = DirectoryUtilities.RepositoryRootDirectory,
|
||||
WorkingDirectory = Harness.RootDirectory,
|
||||
Ignored = !IncludeDocs,
|
||||
Timeout = TimeSpan.FromMinutes (45),
|
||||
};
|
||||
|
@ -1183,14 +1181,14 @@ namespace Xharness.Jenkins
|
|||
|
||||
var buildSampleTests = new MSBuildTask {
|
||||
Jenkins = this,
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "sampletester", "sampletester.sln"))),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "sampletester", "sampletester.sln"))),
|
||||
SpecifyPlatform = false,
|
||||
Platform = TestPlatform.All,
|
||||
ProjectConfiguration = "Debug",
|
||||
};
|
||||
var runSampleTests = new NUnitExecuteTask (buildSampleTests) {
|
||||
TestLibrary = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "sampletester", "bin", "Debug", "sampletester.dll"),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "sampletester", "sampletester.csproj"))),
|
||||
TestLibrary = Path.Combine (Harness.RootDirectory, "sampletester", "bin", "Debug", "sampletester.dll"),
|
||||
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "sampletester", "sampletester.csproj"))),
|
||||
Platform = TestPlatform.All,
|
||||
TestName = "Sample tests",
|
||||
Timeout = TimeSpan.FromDays (1), // These can take quite a while to execute.
|
||||
|
@ -1280,7 +1278,7 @@ namespace Xharness.Jenkins
|
|||
|
||||
void BuildTestLibraries ()
|
||||
{
|
||||
Harness.ProcessManager.ExecuteCommandAsync ("make", new [] { "all", $"-j{Environment.ProcessorCount}", "-C", Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "test-libraries") }, MainLog, TimeSpan.FromMinutes (10)).Wait ();
|
||||
Harness.ProcessManager.ExecuteCommandAsync ("make", new [] { "all", $"-j{Environment.ProcessorCount}", "-C", Path.Combine (Harness.RootDirectory, "test-libraries") }, MainLog, TimeSpan.FromMinutes (10)).Wait ();
|
||||
}
|
||||
|
||||
Task RunTestServer ()
|
||||
|
@ -1554,7 +1552,7 @@ namespace Xharness.Jenkins
|
|||
server.Stop ();
|
||||
break;
|
||||
case "/favicon.ico":
|
||||
serveFile = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "xharness", "favicon.ico");
|
||||
serveFile = Path.Combine (Harness.RootDirectory, "xharness", "favicon.ico");
|
||||
goto default;
|
||||
case "/index.html":
|
||||
var redirect_to = request.Url.AbsoluteUri.Replace ("/index.html", "/" + Path.GetFileName (LogDirectory) + "/index.html");
|
||||
|
@ -1717,7 +1715,7 @@ namespace Xharness.Jenkins
|
|||
foreach (var file in new string [] { "xharness.js", "xharness.css" }) {
|
||||
File.Copy (Path.Combine (dependentFileLocation, file), Path.Combine (LogDirectory, file), true);
|
||||
}
|
||||
File.Copy (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "xharness", "favicon.ico"), Path.Combine (LogDirectory, "favicon.ico"), true);
|
||||
File.Copy (Path.Combine (Harness.RootDirectory, "xharness", "favicon.ico"), Path.Combine (LogDirectory, "favicon.ico"), true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.MainLog.WriteLine ("Failed to write log: {0}", e);
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xharness.Hardware;
|
||||
|
||||
namespace Xharness.Jenkins.TestTasks
|
||||
{
|
||||
|
|
|
@ -76,15 +76,15 @@ namespace Xharness.Jenkins.TestTasks
|
|||
}
|
||||
|
||||
if (is_packageref) {
|
||||
TestExecutable = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "tools", $"nunit3-console-{nunit_version}");
|
||||
TestExecutable = Path.Combine (Harness.RootDirectory, "..", "tools", $"nunit3-console-{nunit_version}");
|
||||
if (!File.Exists (TestExecutable))
|
||||
throw new FileNotFoundException ($"The helper script to execute the unit tests does not exist: {TestExecutable}");
|
||||
WorkingDirectory = Path.GetDirectoryName (TestProject.Path);
|
||||
} else if (nunit_version [0] == '2') {
|
||||
TestExecutable = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "packages", "NUnit.Runners." + nunit_version, "tools", "nunit-console.exe");
|
||||
TestExecutable = Path.Combine (Harness.RootDirectory, "..", "packages", "NUnit.Runners." + nunit_version, "tools", "nunit-console.exe");
|
||||
WorkingDirectory = Path.Combine (Path.GetDirectoryName (TestExecutable), "lib");
|
||||
} else {
|
||||
TestExecutable = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "packages", "NUnit.ConsoleRunner." + nunit_version, "tools", "nunit3-console.exe");
|
||||
TestExecutable = Path.Combine (Harness.RootDirectory, "..", "packages", "NUnit.ConsoleRunner." + nunit_version, "tools", "nunit3-console.exe");
|
||||
WorkingDirectory = Path.GetDirectoryName (TestLibrary);
|
||||
}
|
||||
TestExecutable = Path.GetFullPath (TestExecutable);
|
||||
|
@ -162,7 +162,7 @@ namespace Xharness.Jenkins.TestTasks
|
|||
if (ProduceHtmlReport) {
|
||||
try {
|
||||
var output = Logs.Create ($"Log-{Timestamp}.html", "HTML log");
|
||||
using (var srt = new StringReader (File.ReadAllText (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "HtmlTransform.xslt")))) {
|
||||
using (var srt = new StringReader (File.ReadAllText (Path.Combine (Harness.RootDirectory, "HtmlTransform.xslt")))) {
|
||||
using (var sri = File.OpenRead (xmlLog)) {
|
||||
using (var xrt = XmlReader.Create (srt)) {
|
||||
using (var xri = XmlReader.Create (sri)) {
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xharness.Hardware;
|
||||
|
||||
namespace Xharness.Jenkins.TestTasks
|
||||
{
|
||||
class RunDeviceTask : RunXITask<IHardwareDevice>
|
||||
class RunDeviceTask : RunXITask<Device>
|
||||
{
|
||||
AppInstallMonitorLog install_log;
|
||||
public override string ProgressMessage {
|
||||
|
@ -33,7 +32,7 @@ namespace Xharness.Jenkins.TestTasks
|
|||
}
|
||||
}
|
||||
|
||||
public RunDeviceTask (MSBuildTask build_task, IEnumerable<IHardwareDevice> candidates)
|
||||
public RunDeviceTask (MSBuildTask build_task, IEnumerable<Device> candidates)
|
||||
: base (build_task, candidates.OrderBy ((v) => v.DebugSpeed))
|
||||
{
|
||||
switch (build_task.Platform) {
|
||||
|
|
|
@ -3,28 +3,26 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xharness.Collections;
|
||||
using Xharness.Hardware;
|
||||
|
||||
namespace Xharness.Jenkins.TestTasks
|
||||
{
|
||||
class RunSimulatorTask : RunXITask<ISimulatorDevice>
|
||||
class RunSimulatorTask : RunXITask<SimDevice>
|
||||
{
|
||||
public IAcquiredResource AcquiredResource;
|
||||
|
||||
public ISimulatorDevice [] Simulators {
|
||||
public SimDevice[] Simulators {
|
||||
get {
|
||||
if (Device == null) {
|
||||
return new ISimulatorDevice [] { };
|
||||
return new SimDevice [] { };
|
||||
} else if (CompanionDevice == null) {
|
||||
return new ISimulatorDevice [] { Device };
|
||||
return new SimDevice [] { Device };
|
||||
} else {
|
||||
return new ISimulatorDevice [] { Device, CompanionDevice };
|
||||
return new SimDevice [] { Device, CompanionDevice };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RunSimulatorTask (MSBuildTask build_task, IEnumerable<ISimulatorDevice> candidates = null)
|
||||
public RunSimulatorTask (MSBuildTask build_task, IEnumerable<SimDevice> candidates = null)
|
||||
: base (build_task, candidates)
|
||||
{
|
||||
var project = Path.GetFileNameWithoutExtension (ProjectFile);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xharness.Collections;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Jenkins.TestTasks
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using Xharness.Targets;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness
|
||||
{
|
||||
|
@ -59,7 +58,7 @@ namespace Xharness
|
|||
|
||||
public static void CreateMacMakefile (Harness harness, IEnumerable<MacTarget> targets)
|
||||
{
|
||||
var makefile = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "Makefile-mac.inc");
|
||||
var makefile = Path.Combine (Harness.RootDirectory, "Makefile-mac.inc");
|
||||
using (var writer = new StreamWriter (makefile, false, new UTF8Encoding (false))) {
|
||||
writer.WriteLine (".stamp-configure-projects-mac: Makefile xharness/xharness.exe");
|
||||
writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug $(XIBUILD_EXE_PATH) -t -- $(CURDIR)/xharness/xharness.exe $(XHARNESS_VERBOSITY) --configure --autoconf --rootdir $(CURDIR)");
|
||||
|
@ -214,7 +213,7 @@ namespace Xharness
|
|||
public static void CreateMakefile (Harness harness, IEnumerable<UnifiedTarget> unified_targets, IEnumerable<TVOSTarget> tvos_targets, IEnumerable<WatchOSTarget> watchos_targets, IEnumerable<TodayExtensionTarget> today_targets)
|
||||
{
|
||||
var executeSim32 = !harness.InCI; // Waiting for iOS 10.3 simulator to be installed on wrench
|
||||
var makefile = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "Makefile.inc");
|
||||
var makefile = Path.Combine (Harness.RootDirectory, "Makefile.inc");
|
||||
using (var writer = new StreamWriter (makefile, false, new UTF8Encoding (false))) {
|
||||
writer.WriteLine (".stamp-configure-projects: Makefile xharness/xharness.exe");
|
||||
writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug $(XIBUILD_EXE_PATH) -t -- $(CURDIR)/xharness/xharness.exe $(XHARNESS_VERBOSITY) --configure --autoconf --rootdir $(CURDIR)");
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
using Xamarin;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness
|
||||
|
@ -157,9 +154,9 @@ namespace Xharness
|
|||
|
||||
public string FlavorSuffix => Flavor == MonoNativeFlavor.Compat ? "-compat" : "-unified";
|
||||
public string ProjectName => "mono-native" + FlavorSuffix;
|
||||
public string ProjectPath => Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mono-native", TemplateName + FlavorSuffix + ".csproj");
|
||||
public string ProjectPath => Path.Combine (Harness.RootDirectory, "mono-native", TemplateName + FlavorSuffix + ".csproj");
|
||||
string TemplateName => "mono-native" + TemplateSuffix;
|
||||
public string TemplatePath => Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "mono-native", TemplateName + ".csproj.template");
|
||||
public string TemplatePath => Path.Combine (Harness.RootDirectory, "mono-native", TemplateName + ".csproj.template");
|
||||
protected virtual string TemplateSuffix => string.Empty;
|
||||
|
||||
public void Convert ()
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Xharness {
|
|||
{ "mac", "Configure for Xamarin.Mac instead of iOS.", (v) => harness.Mac = true },
|
||||
{ "configure", "Creates project files and makefiles.", (v) => harness.Action = HarnessAction.Configure },
|
||||
{ "autoconf", "Automatically decide what to configure.", (v) => harness.AutoConf = true },
|
||||
{ "rootdir=", "The root directory for the tests.", (v) => DirectoryUtilities.RepositoryRootDirectory = v },
|
||||
{ "rootdir=", "The root directory for the tests.", (v) => Harness.RootDirectory = v },
|
||||
{ "project=", "Add a project file to process. This can be specified multiple times.", (v) => harness.IOSTestProjects.Add (new iOSTestProject (v)) },
|
||||
{ "watchos-container-template=", "The directory to use as a template for a watchos container app.", (v) => harness.WatchOSContainerTemplate = v },
|
||||
{ "watchos-app-template=", "The directory to use as a template for a watchos app.", (v) => harness.WatchOSAppTemplate = v },
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -57,8 +57,8 @@ namespace Xharness
|
|||
{
|
||||
var folders = new StringBuilder ();
|
||||
|
||||
var srcDirectory = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "src");
|
||||
var sln_path = exeTarget == null ? Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "tests-" + infix + ".sln") : Path.Combine (Path.GetDirectoryName (exeTarget.ProjectPath), Path.GetFileNameWithoutExtension (exeTarget.ProjectPath) + ".sln");
|
||||
var srcDirectory = Path.Combine (Harness.RootDirectory, "..", "src");
|
||||
var sln_path = exeTarget == null ? Path.Combine (Harness.RootDirectory, "tests-" + infix + ".sln") : Path.Combine (Path.GetDirectoryName (exeTarget.ProjectPath), Path.GetFileNameWithoutExtension (exeTarget.ProjectPath) + ".sln");
|
||||
|
||||
using (var writer = new StringWriter ()) {
|
||||
writer.WriteLine ();
|
||||
|
|
|
@ -182,7 +182,7 @@ namespace Xharness.Targets
|
|||
{
|
||||
base.PostProcessExecutableProject ();
|
||||
|
||||
ProjectGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
|
||||
ProjectGuid = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
|
||||
inputProject.SetProjectGuid (ProjectGuid);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Xamarin;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Targets
|
||||
|
@ -113,7 +111,7 @@ namespace Xharness.Targets
|
|||
MonoNativeHelper.RemoveSymlinkMode (inputProject);
|
||||
}
|
||||
|
||||
var srcDirectory = Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "src");
|
||||
var srcDirectory = Path.Combine (Harness.RootDirectory, "..", "src");
|
||||
|
||||
string project_guid;
|
||||
var mt_nunitlite_project_path = Path.GetFullPath (Path.Combine (srcDirectory, "MonoTouch.NUnitLite.tvos.csproj"));
|
||||
|
|
|
@ -2,8 +2,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Xamarin;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Utilities;
|
||||
|
||||
namespace Xharness.Targets
|
||||
|
@ -63,7 +61,7 @@ namespace Xharness.Targets
|
|||
csproj.SetProjectReferenceInclude ("TodayExtension.csproj", TodayExtensionProjectPath.Replace ('/', '\\'));
|
||||
csproj.FixCompileInclude ("Main.cs", Path.Combine (Harness.TodayContainerTemplate, "Main.cs").Replace ('/', '\\'));
|
||||
csproj.FixInfoPListInclude (suffix, IsGeneratedBclTest ? GeneratedPath : null);
|
||||
TodayContainerGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
|
||||
TodayContainerGuid = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
|
||||
ProjectGuid = TodayContainerGuid;
|
||||
csproj.SetProjectGuid (TodayContainerGuid);
|
||||
if (MonoNativeInfo != null) {
|
||||
|
|
|
@ -3,9 +3,6 @@ using System.IO;
|
|||
using System.Xml;
|
||||
using Xharness.Utilities;
|
||||
|
||||
using Xamarin;
|
||||
using Xharness.Hardware;
|
||||
|
||||
namespace Xharness.Targets
|
||||
{
|
||||
public class UnifiedTarget : iOSTarget
|
||||
|
|
|
@ -4,9 +4,6 @@ using System.IO;
|
|||
using System.Xml;
|
||||
using Xharness.Utilities;
|
||||
|
||||
using Xamarin;
|
||||
using Xharness.Hardware;
|
||||
|
||||
namespace Xharness.Targets
|
||||
{
|
||||
public class WatchOSTarget : iOSTarget
|
||||
|
@ -39,7 +36,7 @@ namespace Xharness.Targets
|
|||
csproj.FindAndReplace ("%WATCHEXTENSION_CSPROJ%", Path.GetFileName (WatchOSExtensionProjectPath));
|
||||
csproj.SetProjectReferenceValue (Path.GetFileName (WatchOSExtensionProjectPath), "Project", WatchOSExtensionGuid);
|
||||
csproj.SetProjectReferenceValue (Path.GetFileName (WatchOSExtensionProjectPath), "Name", Path.GetFileNameWithoutExtension (WatchOSExtensionProjectPath));
|
||||
WatchOSAppGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
|
||||
WatchOSAppGuid = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
|
||||
csproj.SetProjectGuid (WatchOSAppGuid);
|
||||
csproj.FixInfoPListInclude (suffix);
|
||||
if (MonoNativeInfo != null) {
|
||||
|
@ -67,7 +64,7 @@ namespace Xharness.Targets
|
|||
csproj.FindAndReplace ("%CONTAINER_PATH%", Path.GetFullPath (Harness.WatchOSContainerTemplate).Replace ('/', '\\') + "\\");
|
||||
csproj.FindAndReplace ("%WATCHAPP_CSPROJ%", Path.GetFileName (WatchOSAppProjectPath));
|
||||
csproj.SetProjectReferenceValue (Path.GetFileName (WatchOSAppProjectPath), "Name", Path.GetFileNameWithoutExtension (WatchOSAppProjectPath));
|
||||
WatchOSGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
|
||||
WatchOSGuid = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
|
||||
csproj.SetProjectGuid (WatchOSGuid);
|
||||
csproj.FixInfoPListInclude (Suffix);
|
||||
if (MonoNativeInfo != null) {
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace Xharness
|
|||
|
||||
internal async Task CreateCopyAsync (TestTask test = null)
|
||||
{
|
||||
var directory = DirectoryUtilities.CreateTemporaryDirectory (test?.TestName ?? System.IO.Path.GetFileNameWithoutExtension (Path));
|
||||
var directory = TempDirectory.CreateTemporaryDirectory (test?.TestName ?? System.IO.Path.GetFileNameWithoutExtension (Path));
|
||||
Directory.CreateDirectory (directory);
|
||||
var original_path = Path;
|
||||
Path = System.IO.Path.Combine (directory, System.IO.Path.GetFileName (Path));
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Xharness.Utilities {
|
||||
// A class that creates temporary directories next to the test assembly, and cleans the output on startup
|
||||
// Advantages:
|
||||
// * The temporary directories are automatically cleaned on Wrench (unlike /tmp, which isn't)
|
||||
// * The temporary directories stay after a test is run (until a new test run is started),
|
||||
// which makes it easier to re-run (copy-paste) commands that failed.
|
||||
public static class DirectoryUtilities {
|
||||
static string root;
|
||||
static int lastNumber;
|
||||
|
||||
static DirectoryUtilities ()
|
||||
{
|
||||
root = Path.Combine (Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly ().Location), "tmp-test-dir");
|
||||
if (Directory.Exists (root))
|
||||
Directory.Delete (root, true);
|
||||
Directory.CreateDirectory (root);
|
||||
}
|
||||
|
||||
[DllImport ("libc", SetLastError = true)]
|
||||
static extern int mkdir (string path, ushort mode);
|
||||
|
||||
public static string CreateTemporaryDirectory (string name = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty (name)) {
|
||||
var calling_method = new System.Diagnostics.StackFrame (1).GetMethod ();
|
||||
if (calling_method != null) {
|
||||
name = calling_method.DeclaringType.FullName + "." + calling_method.Name;
|
||||
} else {
|
||||
name = "unknown-test";
|
||||
}
|
||||
}
|
||||
|
||||
var rv = Path.Combine (root, name);
|
||||
for (int i = lastNumber; i < 10000 + lastNumber; i++) {
|
||||
// There's no way to know if Directory.CreateDirectory
|
||||
// created the directory or not (which would happen if the directory
|
||||
// already existed). Checking if the directory exists before
|
||||
// creating it would result in a race condition if multiple
|
||||
// threads create temporary directories at the same time.
|
||||
if (mkdir (rv, Convert.ToUInt16 ("777", 8)) == 0) {
|
||||
lastNumber = i;
|
||||
return rv;
|
||||
}
|
||||
rv = Path.Combine (root, name + i);
|
||||
}
|
||||
|
||||
throw new Exception ("Could not create temporary directory");
|
||||
}
|
||||
|
||||
static string gitRoot;
|
||||
public static string RepositoryRootDirectory {
|
||||
get {
|
||||
if (gitRoot == null)
|
||||
gitRoot = FindRootDirectory ();
|
||||
|
||||
return gitRoot;
|
||||
}
|
||||
|
||||
set {
|
||||
gitRoot = value;
|
||||
if (gitRoot != null)
|
||||
gitRoot = Path.GetFullPath (gitRoot).TrimEnd ('/');
|
||||
}
|
||||
}
|
||||
|
||||
static string FindRootDirectory ()
|
||||
{
|
||||
// Keep going up and look for .git
|
||||
var testAssemblyDirectory = Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly ().Location);
|
||||
var dir = testAssemblyDirectory;
|
||||
var path = Path.Combine (testAssemblyDirectory, ".git");
|
||||
while (!Directory.Exists (path) && path.Length > 3) {
|
||||
dir = Path.GetDirectoryName (dir);
|
||||
path = Path.Combine (dir, ".git");
|
||||
}
|
||||
|
||||
if (!Directory.Exists (path))
|
||||
throw new Exception ("Could not find the xamarin-macios repo.");
|
||||
|
||||
path = Path.Combine (Path.GetDirectoryName (path), "tests");
|
||||
|
||||
if (!Directory.Exists (path))
|
||||
throw new Exception ("Could not find the tests directory.");
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Xharness.Utilities {
|
||||
|
||||
static class Helpers {
|
||||
|
||||
// We want guids that nobody else has, but we also want to generate the same guid
|
||||
// on subsequent invocations (so that csprojs don't change unnecessarily, which is
|
||||
// annoying when XS reloads the projects, and also causes unnecessary rebuilds).
|
||||
// Nothing really breaks when the sequence isn't identical from run to run, so
|
||||
// this is just a best minimal effort.
|
||||
static Random guid_generator = new Random (unchecked ((int) 0xdeadf00d));
|
||||
public static Guid GenerateStableGuid (string seed = null)
|
||||
{
|
||||
var bytes = new byte [16];
|
||||
if (seed == null) {
|
||||
guid_generator.NextBytes (bytes);
|
||||
} else {
|
||||
using (var provider = MD5.Create ()) {
|
||||
var inputBytes = Encoding.UTF8.GetBytes (seed);
|
||||
bytes = provider.ComputeHash (inputBytes);
|
||||
}
|
||||
}
|
||||
return new Guid (bytes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using Xharness.Execution;
|
||||
|
||||
namespace Xharness.Tests.Execution.Tests {
|
||||
|
||||
[TestFixture]
|
||||
public class MlaunchArgumentsTest {
|
||||
|
||||
class CommandLineDataTestSource {
|
||||
public static IEnumerable CommandLineArgs {
|
||||
get {
|
||||
string listDevFile = "/my/listdev.txt";
|
||||
string listSimFile = "/my/listsim.txt";
|
||||
string xmlOutputType = "xml";
|
||||
yield return new TestCaseData (new [] { (MlaunchArgumentType.ListDev, listDevFile) }).Returns ($"--listdev={listDevFile}");
|
||||
yield return new TestCaseData (new [] { (MlaunchArgumentType.ListSim, listSimFile) }).Returns ($"--listsim={listSimFile}");
|
||||
yield return new TestCaseData (new [] { (MlaunchArgumentType.OutputFormat, xmlOutputType) }).Returns ($"--output-format={xmlOutputType}");
|
||||
yield return new TestCaseData (new [] { (MlaunchArgumentType.ListExtraData, (string) null) }).Returns ("--list-extra-data");
|
||||
yield return new TestCaseData (new [] { (MlaunchArgumentType.ListDev, listDevFile), (MlaunchArgumentType.ListSim, listSimFile) }).Returns ($"--listdev={listDevFile} --listsim={listSimFile}");
|
||||
yield return new TestCaseData (new [] { (MlaunchArgumentType.ListDev, listDevFile), (MlaunchArgumentType.ListExtraData, (string)null) }).Returns ($"--listdev={listDevFile} --list-extra-data");
|
||||
yield return new TestCaseData (new [] { (MlaunchArgumentType.ListDev, listDevFile), (MlaunchArgumentType.OutputFormat, xmlOutputType), (MlaunchArgumentType.ListExtraData, (string)null) }).Returns ($"--listdev={listDevFile} --output-format={xmlOutputType} --list-extra-data");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase (MlaunchArgumentType.ListDev)]
|
||||
[TestCase (MlaunchArgumentType.ListSim)]
|
||||
[TestCase (MlaunchArgumentType.OutputFormat)]
|
||||
[TestCase (MlaunchArgumentType.SdkRoot)]
|
||||
public void MissingValueThrowsTest (MlaunchArgumentType arg)
|
||||
{
|
||||
Assert.Throws<ArgumentException> (() => {
|
||||
_ = new MlaunchArguments (arg);
|
||||
});
|
||||
}
|
||||
|
||||
public void ExtraArgumentThrows (MlaunchArgumentType arg)
|
||||
{
|
||||
Assert.Throws<ArgumentException> (() => {
|
||||
_ = new MlaunchArguments ((arg, "value"));
|
||||
});
|
||||
}
|
||||
|
||||
[TestCaseSource (typeof (CommandLineDataTestSource), "CommandLineArgs")]
|
||||
public string AsCommandLineTest((MlaunchArgumentType type, string value) [] args)
|
||||
{
|
||||
var mlaunchArgs = new MlaunchArguments (args);
|
||||
return mlaunchArgs.AsCommandLine ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Xharness.Hardware;
|
||||
|
||||
namespace Xharness.Tests.Hardware.Tests {
|
||||
[TestFixture]
|
||||
public class DeviceTest {
|
||||
|
||||
class DevicesDataTestSource {
|
||||
public static IEnumerable DebugSpeedDevices {
|
||||
get {
|
||||
var data = new [] {
|
||||
(interfaceType: "usb", result: 0),
|
||||
(interfaceType: "USB", result: 0),
|
||||
(interfaceType: "wifi", result: 2),
|
||||
(interfaceType: "WIFI", result: 2),
|
||||
(interfaceType: (string) null, result: 1),
|
||||
(interfaceType: "HOLA", result: 3),
|
||||
};
|
||||
foreach (var (interfaceType, result) in data) {
|
||||
yield return new TestCaseData (new Device { InterfaceType = interfaceType }).Returns (result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable DevicePlatformDevices {
|
||||
get {
|
||||
var data = new [] {
|
||||
(deviceClass: "iPhone", result: DevicePlatform.iOS),
|
||||
(deviceClass: "iPod", result: DevicePlatform.iOS),
|
||||
(deviceClass: "iPad", result: DevicePlatform.iOS),
|
||||
(deviceClass: "AppleTV", result: DevicePlatform.tvOS),
|
||||
(deviceClass: "Watch", result: DevicePlatform.watchOS),
|
||||
(deviceClass: "Glasses??", result: DevicePlatform.Unknown),
|
||||
};
|
||||
foreach (var (deviceClass, result) in data) {
|
||||
yield return new TestCaseData (new Device { DeviceClass = deviceClass }).Returns (result);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable Supports64bDevices {
|
||||
get {
|
||||
var data = new Dictionary<string, (string version, bool result) []> () {
|
||||
["iPhone"] = new [] {
|
||||
(version: "1,1", result: false),
|
||||
(version: "1,2", result: false),
|
||||
(version: "2,1", result: false),
|
||||
(version: "3,1", result: false),
|
||||
(version: "3,2", result: false),
|
||||
(version: "3,3", result: false),
|
||||
(version: "4,1", result: false),
|
||||
(version: "5,1", result: false),
|
||||
(version: "5,2", result: false),
|
||||
(version: "5,3", result: false),
|
||||
(version: "6,1", result: true),
|
||||
(version: "6,2", result: true),
|
||||
(version: "7,1", result: true),
|
||||
(version: "7,2", result: true),
|
||||
(version: "8,4", result: true),
|
||||
(version: "9,1", result: true),
|
||||
(version: "9,2", result: true),
|
||||
(version: "10,1", result: true),
|
||||
(version: "11,1", result: true),
|
||||
(version: "12,1", result: true),
|
||||
},
|
||||
["iPad"] = new [] {
|
||||
(version: "1,1", result: false),
|
||||
(version: "1,2", result: false),
|
||||
(version: "2,1", result: false),
|
||||
(version: "3,1", result: false),
|
||||
(version: "3,2", result: false),
|
||||
(version: "3,3", result: false),
|
||||
(version: "4,1", result: true),
|
||||
(version: "4,2", result: true),
|
||||
(version: "5,1", result: true),
|
||||
(version: "6,1", result: true),
|
||||
(version: "6,3", result: true),
|
||||
(version: "7,1", result: true),
|
||||
},
|
||||
["iPod"] = new [] {
|
||||
(version: "1,1", result: false),
|
||||
(version: "1,2", result: false),
|
||||
(version: "2,1", result: false),
|
||||
(version: "3,3", result: false),
|
||||
(version: "4,1", result: false),
|
||||
(version: "5,1", result: false),
|
||||
(version: "5,2", result: false),
|
||||
(version: "7,1", result: true),
|
||||
(version: "7,2", result: true),
|
||||
},
|
||||
["AppleTV"] = new [] {
|
||||
(version: "1,1", result: true),
|
||||
(version: "2,1", result: true),
|
||||
(version: "3,1", result: true),
|
||||
},
|
||||
["Watch"] = new [] {
|
||||
(version: "1,1", result: false),
|
||||
(version: "1,2", result: false),
|
||||
(version: "2,1", result: false),
|
||||
(version: "3,1", result: false),
|
||||
(version: "3,2", result: false),
|
||||
(version: "3,3", result: false),
|
||||
(version: "4,1", result: false),
|
||||
(version: "4,2", result: false),
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
foreach (var product in data.Keys) {
|
||||
foreach (var (version, result) in data[product])
|
||||
yield return new TestCaseData (new Device { ProductType = $"{product}{version}" }).Returns (result).SetDescription ($"{product} {version}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable Supports32bDevices {
|
||||
get {
|
||||
var iOSCommon = new [] {
|
||||
(version: new Version (1,1), result: true),
|
||||
(version: new Version (2,1), result: true),
|
||||
(version: new Version (3,1), result: true),
|
||||
(version: new Version (4,1), result: true),
|
||||
(version: new Version (5,1), result: true),
|
||||
(version: new Version (6,1), result: true),
|
||||
(version: new Version (7,1), result: true),
|
||||
(version: new Version (8,1), result: true),
|
||||
(version: new Version (11,1), result: false),
|
||||
(version: new Version (11,2), result: false),
|
||||
(version: new Version (12,1), result: false),
|
||||
};
|
||||
var data = new Dictionary<string, (Version version, bool result) []> {
|
||||
["iPhone"] = iOSCommon,
|
||||
["iPad"] = iOSCommon,
|
||||
["iPod"] = iOSCommon,
|
||||
["AppleTV"] = new [] {
|
||||
(version: new Version (1,1), result: false),
|
||||
(version: new Version (2,1), result: false),
|
||||
(version: new Version (3,1), result: false),
|
||||
(version: new Version (4,1), result: false),
|
||||
},
|
||||
["Watch"] = new [] {
|
||||
(version: new Version (1,1), result: true),
|
||||
(version: new Version (2,1), result: true),
|
||||
(version: new Version (3,1), result: true),
|
||||
(version: new Version (4,1), result: true),
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var deviceClass in data.Keys) {
|
||||
foreach (var (version, result) in data [deviceClass]) {
|
||||
yield return new TestCaseData (new Device { DeviceClass = deviceClass, ProductVersion = version.ToString () }).Returns (result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource (typeof (DevicesDataTestSource), "DebugSpeedDevices")]
|
||||
public int DebugSpeedTest (Device device) => device.DebugSpeed;
|
||||
|
||||
[TestCaseSource (typeof (DevicesDataTestSource), "DevicePlatformDevices")]
|
||||
public DevicePlatform DevicePlatformTest (Device device) => device.DevicePlatform;
|
||||
|
||||
[TestCaseSource (typeof (DevicesDataTestSource), "Supports64bDevices")]
|
||||
public bool Supports64bTest (Device device) => device.Supports64Bit;
|
||||
|
||||
[TestCaseSource (typeof (DevicesDataTestSource), "Supports32bDevices")]
|
||||
public bool Supports32BTest (Device device) => device.Supports32Bit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Tests.Hardware.Tests {
|
||||
|
||||
[TestFixture]
|
||||
public class DevicesTest {
|
||||
|
||||
Devices devices;
|
||||
string mlaunchPath;
|
||||
string sdkPath;
|
||||
Mock<IHarness> harness;
|
||||
Mock<IProcessManager> processManager;
|
||||
Mock<ILog> executionLog;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp ()
|
||||
{
|
||||
harness = new Mock<IHarness> ();
|
||||
processManager = new Mock<IProcessManager> ();
|
||||
devices = new Devices {
|
||||
Harness = harness.Object,
|
||||
ProcessManager = processManager.Object,
|
||||
};
|
||||
executionLog = new Mock<ILog> ();
|
||||
mlaunchPath = "/usr/bin/mlaunch"; // any will be ok, is mocked
|
||||
sdkPath = "/Applications/Xcode.app";
|
||||
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown ()
|
||||
{
|
||||
harness = null;
|
||||
processManager = null;
|
||||
executionLog = null;
|
||||
devices = null;
|
||||
}
|
||||
|
||||
[TestCase (false)] // no timeout
|
||||
[TestCase (true)] // timeoout
|
||||
public void LoadAsyncProcessErrorTest (bool timeout)
|
||||
{
|
||||
string processPath = null;
|
||||
MlaunchArguments passedArguments = null;
|
||||
// set the expectations of the mocks to get an error when
|
||||
// executing the process
|
||||
harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath);
|
||||
harness.Setup (h => h.XcodeRoot).Returns (sdkPath);
|
||||
// moq It.Is is not working as nicelly as we would like it, we capture data and use asserts
|
||||
processManager.Setup (p => p.RunAsync (It.IsAny<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) => {
|
||||
// we are going set the used args to validate them later, will always return an error from this method
|
||||
processPath = p.StartInfo.FileName;
|
||||
passedArguments = args;
|
||||
if (!timeout)
|
||||
return Task.FromResult (new ProcessExecutionResult { ExitCode = 1, TimedOut = false });
|
||||
else
|
||||
return Task.FromResult (new ProcessExecutionResult { ExitCode = 0, TimedOut = true });
|
||||
});
|
||||
Assert.ThrowsAsync<Exception> (async () => {
|
||||
await devices.LoadAsync (executionLog.Object);
|
||||
});
|
||||
|
||||
// validate the execution of mlaunch
|
||||
Assert.AreEqual (mlaunchPath, processPath, "process path");
|
||||
Assert.AreEqual (1, passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.SdkRoot).Count (), "sdk arg missing");
|
||||
var sdkArg = passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.SdkRoot).First ();
|
||||
Assert.AreEqual (sdkArg.value, sdkPath, "sdk path");
|
||||
Assert.AreEqual (1, passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.ListDev).Count (), "sdk path missing.");
|
||||
var listDevArg = passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.ListDev).First ();
|
||||
Assert.IsNotNull (listDevArg.value, "litdev file");
|
||||
Assert.AreEqual (1, passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.OutputFormat).Count (), "output format missing.");
|
||||
var outputFormat = passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.OutputFormat).First ();
|
||||
Assert.AreEqual (outputFormat.value, "xml"); // format
|
||||
}
|
||||
|
||||
[TestCase (true)]
|
||||
[TestCase (false)]
|
||||
public async Task LoadAsyncProcessSuccess (bool extraData)
|
||||
{
|
||||
string processPath = null;
|
||||
MlaunchArguments passedArguments = null;
|
||||
// set the expectations of the mocks to get an error when
|
||||
// executing the process
|
||||
harness.Setup (h => h.MlaunchPath).Returns (mlaunchPath);
|
||||
harness.Setup (h => h.XcodeRoot).Returns (sdkPath);
|
||||
// moq It.Is is not working as nicelly as we would like it, we capture data and use asserts
|
||||
processManager.Setup (p => p.RunAsync (It.IsAny<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) => {
|
||||
processPath = p.StartInfo.FileName;
|
||||
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 (type, value) = args.GetArguments ().Where (a => a.type == MlaunchArgumentType.ListDev).First ();
|
||||
var tempPath = value;
|
||||
var name = GetType ().Assembly.GetManifestResourceNames ().Where (a => a.EndsWith ("devices.xml", StringComparison.Ordinal)).FirstOrDefault ();
|
||||
using (var outputStream = new StreamWriter (tempPath))
|
||||
using (var sampleStream = new StreamReader (GetType ().Assembly.GetManifestResourceStream (name))) {
|
||||
string line;
|
||||
while ((line = sampleStream.ReadLine ()) != null)
|
||||
outputStream.WriteLine (line);
|
||||
}
|
||||
return Task.FromResult (new ProcessExecutionResult { ExitCode = 0, TimedOut = false });
|
||||
});
|
||||
await devices.LoadAsync (executionLog.Object, extraData);
|
||||
// assert the devices that are expected from the sample xml
|
||||
// validate the execution of mlaunch
|
||||
Assert.AreEqual (mlaunchPath, processPath, "process path");
|
||||
Assert.AreEqual (1, passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.SdkRoot).Count (), "sdk arg missing");
|
||||
var sdkArg = passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.SdkRoot).First ();
|
||||
Assert.AreEqual (sdkArg.value, sdkPath, "sdk path");
|
||||
Assert.AreEqual (1, passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.ListDev).Count (), "sdk path missing.");
|
||||
var listDevArg = passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.ListDev).First ();
|
||||
Assert.IsNotNull (listDevArg.value, "litdev file");
|
||||
Assert.AreEqual (1, passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.OutputFormat).Count (), "output format missing.");
|
||||
var outputFormat = passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.OutputFormat).First ();
|
||||
Assert.AreEqual (outputFormat.value, "xml"); // format
|
||||
if (extraData) {
|
||||
var extraDataArg = passedArguments.GetArguments ().Where (a => a.type == MlaunchArgumentType.ListExtraData).First ();
|
||||
Assert.IsNull (extraDataArg.value, "extra data takes no values");
|
||||
}
|
||||
Assert.AreEqual (2, devices.Connected64BitIOS.Count ());
|
||||
Assert.AreEqual (1, devices.Connected32BitIOS.Count());
|
||||
Assert.AreEqual (0, devices.ConnectedTV.Count ());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Xharness.Hardware;
|
||||
using Xharness.Execution;
|
||||
using Xharness.Logging;
|
||||
|
||||
namespace Xharness.Tests.Hardware.Tests {
|
||||
|
||||
[TestFixture]
|
||||
public class TCCDatabaseTests {
|
||||
|
||||
Mock<IProcessManager> processManager;
|
||||
TCCDatabase database;
|
||||
Mock<ILog> executionLog;
|
||||
string simRuntime;
|
||||
string dataPath;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp ()
|
||||
{
|
||||
processManager = new Mock<IProcessManager> ();
|
||||
database = new TCCDatabase {
|
||||
ProcessManager = processManager.Object,
|
||||
};
|
||||
executionLog = new Mock<ILog> ();
|
||||
simRuntime = "com.apple.CoreSimulator.SimRuntime.iOS-12-1";
|
||||
dataPath = "/path/to/my/data";
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown ()
|
||||
{
|
||||
processManager = null;
|
||||
database = null;
|
||||
}
|
||||
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.iOS-12-1", 3)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.iOS-10-1", 2)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.iOS-9-1", 2)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.iOS-7-1", 1)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.tvOS-12-3", 3)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.tvOS-8-1", 2)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.watchOS-5-1", 3)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.watchOS-4-1", 2)]
|
||||
public void GetTCCFormatTest (string runtime, int expected)
|
||||
{
|
||||
Assert.AreEqual (expected, database.GetTCCFormat (runtime));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetTCCFormatUnknownTest ()
|
||||
{
|
||||
Assert.Throws<NotImplementedException> (() => database.GetTCCFormat ("unknown-sim-runtime"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AgreeToPromptsAsyncNoIdentifiers ()
|
||||
{
|
||||
// we should write in the log that we did not managed to agree to it
|
||||
executionLog.Setup (l => l.WriteLine (It.IsAny<string> ()));
|
||||
await database.AgreeToPromptsAsync (simRuntime, dataPath, executionLog.Object);
|
||||
executionLog.Verify (l => l.WriteLine ("No bundle identifiers given when requested permission editing."));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AgreeToPropmtsAsyncTimeoutsTest ()
|
||||
{
|
||||
string processName = null;
|
||||
// set the process manager to always return a failure so that we do eventually get a timeout
|
||||
processManager.Setup (p => p.ExecuteCommandAsync (It.IsAny<string> (), It.IsAny<List<string>> (), It.IsAny<ILog> (), It.IsAny<TimeSpan> (), null, null))
|
||||
.Returns<string, IList<string>, ILog, TimeSpan, Dictionary<string,string>, CancellationToken?> ((p, a, l, t, e, c) => {
|
||||
processName = p;
|
||||
return Task.FromResult (new ProcessExecutionResult { ExitCode = 1, TimedOut = true });
|
||||
});
|
||||
// try to accept and fail because we always timeout
|
||||
await database.AgreeToPromptsAsync (simRuntime, dataPath, executionLog.Object, "my-bundle-id", "your-bundle-id");
|
||||
|
||||
// verify that we did write in the logs and that we did call sqlite3
|
||||
Assert.AreEqual ("sqlite3", processName, "sqlite3 process");
|
||||
executionLog.Verify (l => l.WriteLine ("Failed to edit TCC.db, the test run might hang due to permission request dialogs"), Times.AtLeastOnce);
|
||||
}
|
||||
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.iOS-12-1", 3)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.iOS-10-1", 2)]
|
||||
[TestCase ("com.apple.CoreSimulator.SimRuntime.iOS-7-1", 1)]
|
||||
public async Task AgreeToPropmtsAsyncSuccessTest (string runtime, int dbVersion)
|
||||
{
|
||||
string bundleIdentifier = "my-bundle-identifier";
|
||||
var services = new string [] {
|
||||
"kTCCServiceAddressBook",
|
||||
"kTCCServiceCalendar",
|
||||
"kTCCServicePhotos",
|
||||
"kTCCServiceMediaLibrary",
|
||||
"kTCCServiceMicrophone",
|
||||
"kTCCServiceUbiquity",
|
||||
"kTCCServiceWillow"
|
||||
};
|
||||
var expectedArgs = new StringBuilder ();
|
||||
// assert the sql used depending on the version
|
||||
switch (dbVersion) {
|
||||
case 1:
|
||||
foreach (var s in services) {
|
||||
expectedArgs.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL);", s, bundleIdentifier);
|
||||
expectedArgs.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL);", s, bundleIdentifier + ".watchkitapp");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
foreach (var s in services) {
|
||||
expectedArgs.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL);", s, bundleIdentifier);
|
||||
expectedArgs.AppendFormat ("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL);", s, bundleIdentifier + ".watchkitapp");
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
foreach (var s in services) {
|
||||
expectedArgs.AppendFormat ("INSERT OR REPLACE INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL,NULL,'UNUSED',NULL,NULL,{2});", s, bundleIdentifier, DateTimeOffset.Now.ToUnixTimeSeconds ());
|
||||
expectedArgs.AppendFormat ("INSERT OR REPLACE INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL,NULL,'UNUSED',NULL,NULL,{2});", s, bundleIdentifier + ".watchkitapp", DateTimeOffset.Now.ToUnixTimeSeconds ());
|
||||
}
|
||||
break;
|
||||
}
|
||||
string processName = null;
|
||||
IList<string> args = new List<string> ();
|
||||
processManager.Setup (p => p.ExecuteCommandAsync (It.IsAny<string> (), It.IsAny<List<string>> (), It.IsAny<ILog> (), It.IsAny<TimeSpan> (), null, null))
|
||||
.Returns<string, IList<string>, ILog, TimeSpan, Dictionary<string, string>, CancellationToken?> ((p, a, l, t, e, c) => {
|
||||
processName = p;
|
||||
args = a;
|
||||
return Task.FromResult (new ProcessExecutionResult { ExitCode = 0, TimedOut = false });
|
||||
});
|
||||
|
||||
await database.AgreeToPromptsAsync (runtime, dataPath, executionLog.Object, bundleIdentifier);
|
||||
|
||||
Assert.AreEqual ("sqlite3", processName, "sqlite3 process");
|
||||
// assert that the sql is present
|
||||
Assert.That (args, Has.Member (dataPath));
|
||||
Assert.That (args, Has.Member (expectedArgs.ToString ()), "insert sql");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -47,9 +47,7 @@ namespace Xharness.Tests.Logging.Tests {
|
|||
public void ConstructorNullILogsTest ()
|
||||
{
|
||||
Assert.DoesNotThrow (() => {
|
||||
#pragma warning disable CS0642 // Possible mistaken empty statement
|
||||
using (var log = new LogFile (null, description, path)) ;
|
||||
#pragma warning restore CS0642 // Possible mistaken empty statement
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -63,9 +61,7 @@ namespace Xharness.Tests.Logging.Tests {
|
|||
public void ConstructorNullDescriptionTest ()
|
||||
{
|
||||
Assert.DoesNotThrow (() => {
|
||||
#pragma warning disable CS0642 // Possible mistaken empty statement
|
||||
using (var log = new LogFile (logs.Object, null, path)) ;
|
||||
#pragma warning restore CS0642 // Possible mistaken empty statement
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MTouch Version="0" Revision="0">
|
||||
<SdkRoot>/Applications/Xcode113.app/Contents/Developer</SdkRoot>
|
||||
<Device>
|
||||
<ActivationState>Activated</ActivationState>
|
||||
<AmountDataAvailable>5650776064</AmountDataAvailable>
|
||||
<BatteryCurrentCapacity>100</BatteryCurrentCapacity>
|
||||
<BluetoothAddress>b0:19:c6:94:f2:26</BluetoothAddress>
|
||||
<BuildVersion>17D50</BuildVersion>
|
||||
<ChipID>32789</ChipID>
|
||||
<CPUArchitecture>arm64</CPUArchitecture>
|
||||
<DeveloperStatus>Development</DeveloperStatus>
|
||||
<DeviceClass>iPhone</DeviceClass>
|
||||
<DeviceColor>1</DeviceColor>
|
||||
<DeviceEnclosureColor>1</DeviceEnclosureColor>
|
||||
<DeviceIdentifier>5696DC36EE3249859D465DA37E6EA912</DeviceIdentifier>
|
||||
<DevToolsAvailable>Standard</DevToolsAvailable>
|
||||
<EnableWifiDebugging />
|
||||
<HardwareModel>D211AP</HardwareModel>
|
||||
<InterfaceType>Usb</InterfaceType>
|
||||
<InternationalMobileEquipmentIdentity>359401080217877</InternationalMobileEquipmentIdentity>
|
||||
<IsPaired>True</IsPaired>
|
||||
<IsUsableForDebugging>True</IsUsableForDebugging>
|
||||
<IsValid>True</IsValid>
|
||||
<ModelNumber>MQ8L2</ModelNumber>
|
||||
<Name>iPhone</Name>
|
||||
<PasswordProtected>True</PasswordProtected>
|
||||
<ProductionSOC>1</ProductionSOC>
|
||||
<ProductType>iPhone10,5</ProductType>
|
||||
<ProductVersion>13.3.1</ProductVersion>
|
||||
<SerialNumber>C39V7FLJJCM2</SerialNumber>
|
||||
<TotalDataCapacity>58561933312</TotalDataCapacity>
|
||||
<UDID>D9DCBED1EC414ECE9A2353364C2AC454</UDID>
|
||||
<UniqueChipID>1434502442682426</UniqueChipID>
|
||||
<WatchCompanionCapability>True</WatchCompanionCapability>
|
||||
<WiFiAddress>b0:19:c6:94:f2:25</WiFiAddress>
|
||||
</Device>
|
||||
<Device>
|
||||
<ActivationState />
|
||||
<AmountDataAvailable />
|
||||
<BatteryCurrentCapacity />
|
||||
<BluetoothAddress />
|
||||
<BuildVersion />
|
||||
<ChipID />
|
||||
<CPUArchitecture />
|
||||
<DeveloperStatus />
|
||||
<DeviceClass>iPhone</DeviceClass>
|
||||
<DeviceColor />
|
||||
<DeviceEnclosureColor />
|
||||
<DeviceIdentifier>E383EA784E604083B5B602853A364759</DeviceIdentifier>
|
||||
<DevToolsAvailable />
|
||||
<EnableWifiDebugging />
|
||||
<HardwareModel />
|
||||
<InterfaceType>Usb</InterfaceType>
|
||||
<InternationalMobileEquipmentIdentity />
|
||||
<IsPaired>False</IsPaired>
|
||||
<IsUsableForDebugging />
|
||||
<IsValid>True</IsValid>
|
||||
<ModelNumber />
|
||||
<Name>iPhone</Name>
|
||||
<PasswordProtected />
|
||||
<ProductionSOC />
|
||||
<ProductType />
|
||||
<ProductVersion />
|
||||
<SerialNumber />
|
||||
<TotalDataCapacity />
|
||||
<UDID>6D6C141F40CC4A4DB7967FCCE974ECE3</UDID>
|
||||
<UniqueChipID />
|
||||
<WatchCompanionCapability />
|
||||
<WiFiAddress />
|
||||
</Device>
|
||||
<Device>
|
||||
<ActivationState />
|
||||
<AmountDataAvailable />
|
||||
<BatteryCurrentCapacity />
|
||||
<BluetoothAddress />
|
||||
<BuildVersion />
|
||||
<ChipID />
|
||||
<CPUArchitecture />
|
||||
<DeveloperStatus />
|
||||
<DeviceClass>iPhone</DeviceClass>
|
||||
<DeviceColor />
|
||||
<DeviceEnclosureColor />
|
||||
<DeviceIdentifier>D384F1159D5748C2A590420D64FA8CBE</DeviceIdentifier>
|
||||
<DevToolsAvailable />
|
||||
<EnableWifiDebugging />
|
||||
<HardwareModel />
|
||||
<InterfaceType>Usb</InterfaceType>
|
||||
<InternationalMobileEquipmentIdentity />
|
||||
<IsPaired>False</IsPaired>
|
||||
<IsUsableForDebugging />
|
||||
<IsValid>True</IsValid>
|
||||
<ModelNumber />
|
||||
<Name>XQAiPhone5Sa</Name>
|
||||
<PasswordProtected />
|
||||
<ProductionSOC />
|
||||
<ProductType />
|
||||
<ProductVersion />
|
||||
<SerialNumber />
|
||||
<TotalDataCapacity />
|
||||
<UDID>245481CA878E4AC0825DFBFDBCFD16BB</UDID>
|
||||
<UniqueChipID />
|
||||
<WatchCompanionCapability />
|
||||
<WiFiAddress />
|
||||
</Device>
|
||||
<Device>
|
||||
<ActivationState />
|
||||
<AmountDataAvailable />
|
||||
<BatteryCurrentCapacity />
|
||||
<BluetoothAddress />
|
||||
<BuildVersion />
|
||||
<ChipID />
|
||||
<CPUArchitecture />
|
||||
<DeveloperStatus />
|
||||
<DeviceClass>iPod</DeviceClass>
|
||||
<DeviceColor />
|
||||
<DeviceEnclosureColor />
|
||||
<DeviceIdentifier>5D61F84BC2804AA698C2DFC1B7FDD200</DeviceIdentifier>
|
||||
<DevToolsAvailable />
|
||||
<EnableWifiDebugging />
|
||||
<HardwareModel />
|
||||
<InterfaceType>Usb</InterfaceType>
|
||||
<InternationalMobileEquipmentIdentity />
|
||||
<IsPaired>False</IsPaired>
|
||||
<IsUsableForDebugging />
|
||||
<IsValid>True</IsValid>
|
||||
<ModelNumber />
|
||||
<Name>XQAiPodTouch5f</Name>
|
||||
<PasswordProtected />
|
||||
<ProductionSOC />
|
||||
<ProductType />
|
||||
<ProductVersion />
|
||||
<SerialNumber />
|
||||
<TotalDataCapacity />
|
||||
<UDID>1CBD36A8F42441A78D57443EFE0BD666</UDID>
|
||||
<UniqueChipID />
|
||||
<WatchCompanionCapability />
|
||||
<WiFiAddress />
|
||||
</Device>
|
||||
<Device>
|
||||
<ActivationState>Activated</ActivationState>
|
||||
<AmountDataAvailable>43999293440</AmountDataAvailable>
|
||||
<BatteryCurrentCapacity>100</BatteryCurrentCapacity>
|
||||
<BluetoothAddress>88:64:40:5c:ee:c5</BluetoothAddress>
|
||||
<BuildVersion>17A577</BuildVersion>
|
||||
<ChipID>32816</ChipID>
|
||||
<CPUArchitecture>arm64e</CPUArchitecture>
|
||||
<DeveloperStatus>Development</DeveloperStatus>
|
||||
<DeviceClass>iPhone</DeviceClass>
|
||||
<DeviceColor>1</DeviceColor>
|
||||
<DeviceEnclosureColor>1</DeviceEnclosureColor>
|
||||
<DeviceIdentifier>8A450AA31EA94191AD6B02455F377CC1</DeviceIdentifier>
|
||||
<DevToolsAvailable>Standard</DevToolsAvailable>
|
||||
<EnableWifiDebugging>False</EnableWifiDebugging>
|
||||
<HardwareModel>N104AP</HardwareModel>
|
||||
<InterfaceType>Usb</InterfaceType>
|
||||
<InternationalMobileEquipmentIdentity>353981100627011</InternationalMobileEquipmentIdentity>
|
||||
<IsPaired>True</IsPaired>
|
||||
<IsUsableForDebugging>True</IsUsableForDebugging>
|
||||
<IsValid>True</IsValid>
|
||||
<ModelNumber>MWL72</ModelNumber>
|
||||
<Name>Manuel’s iPhone</Name>
|
||||
<PasswordProtected>True</PasswordProtected>
|
||||
<ProductionSOC>1</ProductionSOC>
|
||||
<ProductType>iPhone12,1</ProductType>
|
||||
<ProductVersion>13.0</ProductVersion>
|
||||
<SerialNumber>DNPZ893NN72J</SerialNumber>
|
||||
<TotalDataCapacity>54814302208</TotalDataCapacity>
|
||||
<UDID>58F21118E4D34FD69EAB7860BB9B38A0</UDID>
|
||||
<UniqueChipID>2852055891869742</UniqueChipID>
|
||||
<WatchCompanionCapability>True</WatchCompanionCapability>
|
||||
<WiFiAddress>88:64:40:67:a1:06</WiFiAddress>
|
||||
</Device>
|
||||
<Device>
|
||||
<ActivationState />
|
||||
<AmountDataAvailable />
|
||||
<BatteryCurrentCapacity />
|
||||
<BluetoothAddress />
|
||||
<BuildVersion />
|
||||
<ChipID />
|
||||
<CPUArchitecture />
|
||||
<DeveloperStatus />
|
||||
<DeviceClass>Watch</DeviceClass>
|
||||
<DeviceColor />
|
||||
<DeviceEnclosureColor />
|
||||
<DeviceIdentifier>9608C09A197C4A6EB41B454D91976654</DeviceIdentifier>
|
||||
<DevToolsAvailable />
|
||||
<EnableWifiDebugging />
|
||||
<HardwareModel />
|
||||
<InterfaceType>3</InterfaceType>
|
||||
<InternationalMobileEquipmentIdentity />
|
||||
<IsPaired>False</IsPaired>
|
||||
<IsUsableForDebugging />
|
||||
<IsValid>True</IsValid>
|
||||
<ModelNumber />
|
||||
<Name>Manuel’s Apple Watch</Name>
|
||||
<PasswordProtected />
|
||||
<ProductionSOC />
|
||||
<ProductType />
|
||||
<ProductVersion />
|
||||
<SerialNumber />
|
||||
<TotalDataCapacity />
|
||||
<UDID>BC87FE47DA2A421CA791AD667E7E57E8</UDID>
|
||||
<UniqueChipID />
|
||||
<WatchCompanionCapability />
|
||||
<WiFiAddress />
|
||||
<CompanionIdentifier>bd3fd054136767445ff47819f65b74867a48e591</CompanionIdentifier>
|
||||
</Device>
|
||||
<Device>
|
||||
<ActivationState>Activated</ActivationState>
|
||||
<AmountDataAvailable>22636388352</AmountDataAvailable>
|
||||
<BatteryCurrentCapacity>90</BatteryCurrentCapacity>
|
||||
<BluetoothAddress>a4:d1:d2:74:24:89</BluetoothAddress>
|
||||
<BuildVersion>13G36</BuildVersion>
|
||||
<ChipID>35136</ChipID>
|
||||
<CPUArchitecture>armv7f</CPUArchitecture>
|
||||
<DeveloperStatus />
|
||||
<DeviceClass>iPad</DeviceClass>
|
||||
<DeviceColor>white</DeviceColor>
|
||||
<DeviceEnclosureColor>unknown</DeviceEnclosureColor>
|
||||
<DeviceIdentifier>E854B2C3E7C8451BAF8053EC4DAAEE49</DeviceIdentifier>
|
||||
<DevToolsAvailable>Standard</DevToolsAvailable>
|
||||
<EnableWifiDebugging />
|
||||
<HardwareModel>K93AP</HardwareModel>
|
||||
<InterfaceType>Usb</InterfaceType>
|
||||
<InternationalMobileEquipmentIdentity />
|
||||
<IsPaired>True</IsPaired>
|
||||
<IsUsableForDebugging>True</IsUsableForDebugging>
|
||||
<IsValid>True</IsValid>
|
||||
<ModelNumber>MC980</ModelNumber>
|
||||
<Name>Manuel de la Pena Saenz’s iPad</Name>
|
||||
<PasswordProtected>False</PasswordProtected>
|
||||
<ProductionSOC>1</ProductionSOC>
|
||||
<ProductType>iPad2,1</ProductType>
|
||||
<ProductVersion>9.3.5</ProductVersion>
|
||||
<SerialNumber>DN6FV2LSDKPJ</SerialNumber>
|
||||
<TotalDataCapacity>29631791104</TotalDataCapacity>
|
||||
<UDID>51F3354D448D4814825D07DC5658C19B</UDID>
|
||||
<UniqueChipID>4130031754541</UniqueChipID>
|
||||
<WatchCompanionCapability>False</WatchCompanionCapability>
|
||||
<WiFiAddress>a4:d1:d2:74:24:88</WiFiAddress>
|
||||
</Device>
|
||||
</MTouch>
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\..\..\packages\NUnit.3.12.0\build\NUnit.props')" />
|
||||
<PropertyGroup>
|
||||
|
@ -18,14 +18,12 @@
|
|||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
|
@ -65,10 +63,6 @@
|
|||
<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="Hardware\Tests\DeviceTest.cs" />
|
||||
<Compile Include="Hardware\Tests\DevicesTest.cs" />
|
||||
<Compile Include="Hardware\Tests\TCCDatabaseTests.cs" />
|
||||
<Compile Include="Utilities\Tests\StringUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -79,7 +73,6 @@
|
|||
<EmbeddedResource Include="Samples\NUnitV3Sample.xml" />
|
||||
<EmbeddedResource Include="Samples\TouchUnitSample.xml" />
|
||||
<EmbeddedResource Include="Samples\xUnitSample.xml" />
|
||||
<EmbeddedResource Include="Samples\devices.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../DummyTestProcess/DummyTestProcess.csproj">
|
||||
|
@ -90,10 +83,6 @@
|
|||
<Name>xharness</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Hardware\" />
|
||||
<Folder Include="Hardware\Tests\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
|
@ -101,4 +90,4 @@
|
|||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\NUnit.3.12.0\build\NUnit.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
@ -21,7 +21,6 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
|
@ -30,7 +29,6 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
<Externalconsole>true</Externalconsole>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(RunConfiguration)' == 'Default' ">
|
||||
<StartAction>Project</StartAction>
|
||||
|
@ -72,7 +70,6 @@
|
|||
<PackageReference Include="Mono.Options" Version="5.3.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AppInstallMonitorLog.cs" />
|
||||
<Compile Include="AppRunner.cs" />
|
||||
<Compile Include="BCLTestImporter\BCLTestAssemblyDefinition.cs" />
|
||||
<Compile Include="BCLTestImporter\BCLTestImportTargetFactory.cs" />
|
||||
|
@ -82,22 +79,10 @@
|
|||
<Compile Include="BCLTestImporter\Platform.cs" />
|
||||
<Compile Include="BCLTestImporter\RegisterTypeGenerator.cs" />
|
||||
<Compile Include="CrashReportSnapshot.cs" />
|
||||
<Compile Include="Collections\BlockingEnumerableCollection.cs" />
|
||||
<Compile Include="Collections\ILoadAsync.cs" />
|
||||
<Compile Include="Collections\IAsyncEnumerable.cs" />
|
||||
<Compile Include="DeviceLogCapturer.cs" />
|
||||
<Compile Include="Execution\MlaunchArguments.cs" />
|
||||
<Compile Include="Execution\IProcessManager.cs" />
|
||||
<Compile Include="Execution\ProcessManager.cs" />
|
||||
<Compile Include="GitHub.cs" />
|
||||
<Compile Include="Hardware\Simulators.cs" />
|
||||
<Compile Include="Hardware\SimDevice.cs" />
|
||||
<Compile Include="Hardware\IDevice.cs" />
|
||||
<Compile Include="Hardware\Device.cs" />
|
||||
<Compile Include="Hardware\Devices.cs" />
|
||||
<Compile Include="Hardware\IHardwareDevice.cs" />
|
||||
<Compile Include="Hardware\ISimulatorDevice.cs" />
|
||||
<Compile Include="Hardware\TCCDatabase.cs" />
|
||||
<Compile Include="Harness.cs" />
|
||||
<Compile Include="Jenkins\Jenkins.cs" />
|
||||
<Compile Include="Jenkins\Resource.cs" />
|
||||
|
@ -147,11 +132,10 @@
|
|||
<Compile Include="TestPlatform.cs" />
|
||||
<Compile Include="TestProject.cs" />
|
||||
<Compile Include="Utilities\Extensions.cs" />
|
||||
<Compile Include="Utilities\Helpers.cs" />
|
||||
<Compile Include="Utilities\PlistExtensions.cs" />
|
||||
<Compile Include="Utilities\ProjectFileExtensions.cs" />
|
||||
<Compile Include="Utilities\StringUtils.cs" />
|
||||
<Compile Include="Utilities\DirectoryUtilities.cs" />
|
||||
<Compile Include="Utilities\TempDirectory.cs" />
|
||||
<Compile Include="XmlResultParser.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -168,4 +152,4 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
</Project>
|
Загрузка…
Ссылка в новой задаче