[Harness] Move utilities out of Harness.cs (#8125)

Co-authored-by: Premek Vysoky <prvysoky@microsoft.com>
This commit is contained in:
Přemek Vysoký 2020-03-17 19:42:21 +01:00 коммит произвёл GitHub
Родитель 13a56ffb95
Коммит 5f2905c5a4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 318 добавлений и 425 удалений

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

@ -0,0 +1,111 @@
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;
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);
}
}
}

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

@ -14,10 +14,9 @@ using Xharness.Jenkins.TestTasks;
using Xharness.Listeners;
using Xharness.Logging;
using Xharness.Utilities;
using System.Net;
namespace Xharness
{
namespace Xharness {
public enum RunMode {
Sim32,
Sim64,
@ -136,9 +135,6 @@ namespace Xharness
AppInformation Initialize ()
{
if (AppInformation != null)
return AppInformation;
var csproj = new XmlDocument ();
csproj.LoadWithoutNetworkAccess (projectFilePath);
string appName = csproj.GetAssemblyName ();
@ -238,8 +234,6 @@ namespace Xharness
public async Task<ProcessExecutionResult> InstallAsync (CancellationToken cancellation_token)
{
var appInfo = Initialize ();
if (isSimulator) {
// We reset the simulator when running, so a separate install step does not make much sense.
throw new InvalidOperationException ("Installing to a simulator is not supported.");
@ -256,7 +250,7 @@ namespace Xharness
args.Add ("-v");
args.Add ("--installdev");
args.Add (appInfo.AppPath);
args.Add (AppInformation.AppPath);
AddDeviceName (args, companionDeviceName ?? deviceName);
if (mode == RunMode.WatchOS) {
@ -264,16 +258,14 @@ namespace Xharness
args.Add ("ios,watchos");
}
var totalSize = Directory.GetFiles (appInfo.AppPath, "*", SearchOption.AllDirectories).Select ((v) => new FileInfo (v).Length).Sum ();
MainLog.WriteLine ($"Installing '{appInfo.AppPath}' to '{companionDeviceName ?? deviceName}'. Size: {totalSize} bytes = {totalSize / 1024.0 / 1024.0:N2} MB");
var totalSize = Directory.GetFiles (AppInformation.AppPath, "*", SearchOption.AllDirectories).Select ((v) => new FileInfo (v).Length).Sum ();
MainLog.WriteLine ($"Installing '{AppInformation.AppPath}' to '{companionDeviceName ?? deviceName}'. Size: {totalSize} bytes = {totalSize / 1024.0 / 1024.0:N2} MB");
return await processManager.ExecuteCommandAsync (harness.MlaunchPath, args, MainLog, TimeSpan.FromHours (1), cancellation_token: cancellation_token);
}
public async Task<ProcessExecutionResult> UninstallAsync ()
{
var appInfo = Initialize ();
if (isSimulator)
throw new InvalidOperationException ("Uninstalling from a simulator is not supported.");
@ -288,7 +280,7 @@ namespace Xharness
args.Add ("-v");
args.Add ("--uninstalldevbundleid");
args.Add (appInfo.BundleIdentifier);
args.Add (AppInformation.BundleIdentifier);
AddDeviceName (args, companionDeviceName ?? deviceName);
return await processManager.ExecuteCommandAsync (harness.MlaunchPath, args, MainLog, TimeSpan.FromMinutes (1));
@ -366,10 +358,10 @@ namespace Xharness
MainLog.WriteLine (new string ('#', 10));
MainLog.WriteLine ("End of xml results.");
if (timed_out) {
harness.LogWrench ($"@MonkeyWrench: AddSummary: <b><i>{mode} timed out</i></b><br/>");
WrenchLog.WriteLine ($"AddSummary: <b><i>{mode} timed out</i></b><br/>");
return parseResult;
} else {
harness.LogWrench ($"@MonkeyWrench: AddSummary: <b><i>{mode} crashed</i></b><br/>");
WrenchLog.WriteLine ($"AddSummary: <b><i>{mode} crashed</i></b><br/>");
MainLog.WriteLine ("Test run crashed");
crashed = true;
parseResult.crashed = true;
@ -407,19 +399,19 @@ namespace Xharness
if (resultLine != null) {
var tests_run = resultLine.Replace ("Tests run: ", "");
if (failed) {
harness.LogWrench ("@MonkeyWrench: AddSummary: <b>{0} failed: {1}</b><br/>", mode, tests_run);
WrenchLog.WriteLine ("AddSummary: <b>{0} failed: {1}</b><br/>", mode, tests_run);
MainLog.WriteLine ("Test run failed");
return false;
} else {
harness.LogWrench ("@MonkeyWrench: AddSummary: {0} succeeded: {1}<br/>", mode, tests_run);
WrenchLog.WriteLine ("AddSummary: {0} succeeded: {1}<br/>", mode, tests_run);
MainLog.WriteLine ("Test run succeeded");
return true;
}
} else if (timed_out) {
harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} timed out</i></b><br/>", mode);
WrenchLog.WriteLine ("AddSummary: <b><i>{0} timed out</i></b><br/>", mode);
return false;
} else {
harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} crashed</i></b><br/>", mode);
WrenchLog.WriteLine ("AddSummary: <b><i>{0} crashed</i></b><br/>", mode);
MainLog.WriteLine ("Test run crashed");
crashed = true;
return false;
@ -436,19 +428,10 @@ namespace Xharness
ILog listener_log = null;
ILog run_log = MainLog;
var appInfo = Initialize ();
if (!isSimulator)
FindDevice ();
crash_reports = new CrashReportSnapshot () {
Device = !isSimulator,
DeviceName = deviceName,
Harness = harness,
Log = MainLog,
Logs = Logs,
LogDirectory = logDirectory,
};
crash_reports = new CrashReportSnapshot (harness, MainLog, Logs, isDevice: !isSimulator, deviceName);
var args = new List<string> ();
if (!string.IsNullOrEmpty (harness.XcodeRoot)) {
@ -539,12 +522,12 @@ namespace Xharness
bool launch_failure = false;
if (IsExtension) {
switch (appInfo.Extension) {
switch (AppInformation.Extension) {
case Extension.TodayExtension:
args.Add (isSimulator ? "--launchsimbundleid" : "--launchdevbundleid");
args.Add ("todayviewforextensions:" + appInfo.BundleIdentifier);
args.Add ("todayviewforextensions:" + AppInformation.BundleIdentifier);
args.Add ("--observe-extension");
args.Add (appInfo.LaunchAppPath);
args.Add (AppInformation.LaunchAppPath);
break;
case Extension.WatchKit2:
default:
@ -552,7 +535,7 @@ namespace Xharness
}
} else {
args.Add (isSimulator ? "--launchsim" : "--launchdev");
args.Add (appInfo.LaunchAppPath);
args.Add (AppInformation.LaunchAppPath);
}
if (!isSimulator)
args.Add ("--disable-memory-limits");
@ -588,14 +571,14 @@ namespace Xharness
log.StartCapture ();
Logs.Add (log);
systemLogs.Add (log);
harness.LogWrench ("@MonkeyWrench: AddFile: {0}", log.Path);
WrenchLog.WriteLine ("AddFile: {0}", log.Path);
}
MainLog.WriteLine ("*** Executing {0}/{1} in the simulator ***", appInfo.AppName, mode);
MainLog.WriteLine ("*** Executing {0}/{1} in the simulator ***", AppInformation.AppName, mode);
if (EnsureCleanSimulatorState) {
foreach (var sim in simulators)
await sim.PrepareSimulatorAsync (MainLog, appInfo.BundleIdentifier);
await sim.PrepareSimulatorAsync (MainLog, AppInformation.BundleIdentifier);
}
args.Add ($"--device=:v2:udid={simulator.UDID}");
@ -656,7 +639,7 @@ namespace Xharness
log.StopCapture ();
} else {
MainLog.WriteLine ("*** Executing {0}/{1} on device '{2}' ***", appInfo.AppName, mode, deviceName);
MainLog.WriteLine ("*** Executing {0}/{1} on device '{2}' ***", AppInformation.AppName, mode, deviceName);
if (mode == RunMode.WatchOS) {
args.Add ("--attach-native-debugger"); // this prevents the watch from backgrounding the app.
@ -718,7 +701,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);
harness.LogWrench ("@MonkeyWrench: AddFile: {0}", device_system_log.FullPath);
WrenchLog.WriteLine ("AddFile: {0}", device_system_log.FullPath);
}
}
@ -728,18 +711,18 @@ namespace Xharness
// check the final status
var crashed = false;
if (File.Exists (listener_log.FullPath)) {
harness.LogWrench ("@MonkeyWrench: AddFile: {0}", listener_log.FullPath);
success = TestsSucceeded (AppInformation, listener_log.FullPath, timed_out, out crashed);
WrenchLog.WriteLine ("AddFile: {0}", listener_log.FullPath);
success = TestsSucceeded (this.AppInformation, listener_log.FullPath, timed_out, out crashed);
} else if (timed_out) {
harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} never launched</i></b><br/>", mode);
WrenchLog.WriteLine ("AddSummary: <b><i>{0} never launched</i></b><br/>", mode);
MainLog.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);
WrenchLog.WriteLine ("AddSummary: <b><i>{0} failed to launch</i></b><br/>", mode);
MainLog.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);
WrenchLog.WriteLine ("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)");
crashed = true;
success = false;
@ -802,9 +785,9 @@ namespace Xharness
if (harness.InCI) {
XmlResultParser.GenerateFailure (Logs,
"crash",
appInfo.AppName,
AppInformation.AppName,
variation,
$"App Crash {appInfo.AppName} {variation}",
$"App Crash {AppInformation.AppName} {variation}",
$"App crashed {crash_reason}.",
crash_reports.Log.FullPath,
harness.XmlJargon);
@ -826,9 +809,9 @@ namespace Xharness
XmlResultParser.GenerateFailure (
Logs,
"crash",
appInfo.AppName,
AppInformation.AppName,
variation,
$"App Crash {appInfo.AppName} {variation}",
$"App Crash {AppInformation.AppName} {variation}",
$"App crashed: {FailureMessage}",
crash_reports.Log.FullPath,
harness.XmlJargon);
@ -840,9 +823,9 @@ namespace Xharness
XmlResultParser.GenerateFailure (
Logs,
"launch",
appInfo.AppName,
AppInformation.AppName,
variation,
$"App Launch {appInfo.AppName} {variation} on {deviceName}",
$"App Launch {AppInformation.AppName} {variation} on {deviceName}",
$"{FailureMessage} on {deviceName}",
MainLog.FullPath,
XmlResultJargon.NUnitV3);
@ -865,7 +848,7 @@ namespace Xharness
if (isTcp) {
XmlResultParser.GenerateFailure (Logs,
"tcp-connection",
appInfo.AppName,
AppInformation.AppName,
variation,
$"TcpConnection on {deviceName}",
$"Device {deviceName} could not reach the host over tcp.",
@ -875,10 +858,10 @@ namespace Xharness
} else if (timed_out && harness.InCI) {
XmlResultParser.GenerateFailure (Logs,
"timeout",
appInfo.AppName,
AppInformation.AppName,
variation,
$"App Timeout {appInfo.AppName} {variation} on bot {deviceName}",
$"{appInfo.AppName} {variation} Test run timed out after {timeout.TotalMinutes} minute(s) on bot {deviceName}.",
$"App Timeout {AppInformation.AppName} {variation} on bot {deviceName}",
$"{AppInformation.AppName} {variation} Test run timed out after {timeout.TotalMinutes} minute(s) on bot {deviceName}.",
MainLog.FullPath,
harness.XmlJargon);
}
@ -900,107 +883,4 @@ 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);
}
}
}

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

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Collections.Generic;
using Xharness.Utilities;
namespace Xharness.BCLTestImporter {
// Class that is use as the connection between xharness and the BCLImporter
@ -20,7 +21,7 @@ namespace Xharness.BCLTestImporter {
projectGenerator = new BCLTestProjectGenerator (outputDir, Harness.MONO_PATH) {
iOSMonoSDKPath = Harness.MONO_IOS_SDK_DESTDIR,
MacMonoSDKPath = Harness.MONO_MAC_SDK_DESTDIR,
GuidGenerator = Harness.NewStableGuid,
GuidGenerator = Helpers.GenerateStableGuid,
GroupTests = Harness.InCI || Harness.UseGroupedApps,
};
}

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

@ -10,19 +10,27 @@ namespace Xharness
{
public class CrashReportSnapshot
{
public IHarness Harness { get; set; }
public ILog Log { get; set; }
public ILogs Logs { get; set; }
public string LogDirectory { get; set; }
public bool Device { get; set; }
public string DeviceName { get; set; }
readonly IHarness harness;
readonly bool isDevice;
readonly string deviceName;
public ILog Log { get; }
public ILogs Logs { get; }
public HashSet<string> InitialSet { get; private set; }
public IEnumerable<string> Reports { get; private set; }
public CrashReportSnapshot (IHarness harness, ILog log, ILogs logs, bool isDevice, string deviceName)
{
this.harness = harness ?? throw new ArgumentNullException (nameof (harness));
this.Log = log ?? throw new ArgumentNullException (nameof (log));
this.Logs = logs ?? throw new ArgumentNullException (nameof (logs));
this.isDevice = isDevice;
this.deviceName = deviceName;
}
public async Task StartCaptureAsync ()
{
InitialSet = await Harness.CreateCrashReportsSnapshotAsync (Log, !Device, DeviceName);
InitialSet = await CreateCrashReportsSnapshotAsync ();
}
public async Task EndCaptureAsync (TimeSpan timeout)
@ -33,13 +41,12 @@ namespace Xharness
var watch = new Stopwatch ();
watch.Start ();
do {
var end_crashes = await Harness.CreateCrashReportsSnapshotAsync (Log, !Device, DeviceName);
var end_crashes = await CreateCrashReportsSnapshotAsync ();
end_crashes.ExceptWith (InitialSet);
Reports = end_crashes;
if (end_crashes.Count > 0) {
Log.WriteLine ("Found {0} new crash report(s)", end_crashes.Count);
List<ILogFile> crash_reports;
if (!Device) {
if (!isDevice) {
crash_reports = new List<ILogFile> (end_crashes.Count);
foreach (var path in end_crashes) {
Logs.AddFile (path, $"Crash report: {Path.GetFileName (path)}");
@ -55,15 +62,15 @@ namespace Xharness
sb.Add ($"--download-crash-report={file}");
sb.Add ($"--download-crash-report-to={crash_report_target.Path}");
sb.Add ("--sdkroot");
sb.Add (Harness.XcodeRoot);
if (!string.IsNullOrEmpty (DeviceName)) {
sb.Add (harness.XcodeRoot);
if (!string.IsNullOrEmpty (deviceName)) {
sb.Add ("--devname");
sb.Add (DeviceName);
sb.Add (deviceName);
}
var result = await Harness.ProcessManager.ExecuteCommandAsync (Harness.MlaunchPath, sb, Log, TimeSpan.FromMinutes (1));
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 Harness.SymbolicateCrashReportAsync (Logs, Log, crash_report_target);
crash_report_target = await SymbolicateCrashReportAsync (crash_report_target);
downloaded_crash_reports.Add (crash_report_target);
} else {
Log.WriteLine ("Could not download crash report {0}", file);
@ -72,7 +79,7 @@ namespace Xharness
crash_reports = downloaded_crash_reports;
}
foreach (var cp in crash_reports) {
Harness.LogWrench ("@MonkeyWrench: AddFile: {0}", cp.Path);
WrenchLog.WriteLine ("AddFile: {0}", cp.Path);
Log.WriteLine (" {0}", cp.Path);
}
crash_report_search_done = true;
@ -86,5 +93,59 @@ 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;
}
}
async Task<HashSet<string>> CreateCrashReportsSnapshotAsync ()
{
var rv = new HashSet<string> ();
if (!isDevice) {
var dir = Path.Combine (Environment.GetEnvironmentVariable ("HOME"), "Library", "Logs", "DiagnosticReports");
if (Directory.Exists (dir))
rv.UnionWith (Directory.EnumerateFiles (dir));
} else {
var tmp = Path.GetTempFileName ();
try {
var sb = new List<string> ();
sb.Add ($"--list-crash-reports={tmp}");
sb.Add ("--sdkroot");
sb.Add (harness.XcodeRoot);
if (!string.IsNullOrEmpty (deviceName)) {
sb.Add ("--devname");
sb.Add (deviceName);
}
var result = await harness.ProcessManager.ExecuteCommandAsync (harness.MlaunchPath, sb, Log, TimeSpan.FromMinutes (1));
if (result.Succeeded)
rv.UnionWith (File.ReadAllLines (tmp));
} finally {
File.Delete (tmp);
}
}
return rv;
}
}
}

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

@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Xharness.BCLTestImporter;
@ -29,7 +26,7 @@ namespace Xharness
public class HarnessConfiguration {
public bool AutoConf { get; set; }
public string Configuration { get; set; } = "Debug";
public string BuildConfiguration { get; set; } = "Debug";
public bool DryRun { get; set; }
public Dictionary<string, string> EnvironmentVariables { get; set; } = new Dictionary<string, string> ();
public bool? IncludeSystemPermissionTests { get; set; }
@ -42,7 +39,6 @@ namespace Xharness
public string PeriodicCommand { get; set; }
public string PeriodicCommandArguments { get; set; }
public TimeSpan PeriodicCommandInterval { get; set; }
public string RootDirectory { get; set; }
public string SdkRoot { get; set; }
public AppRunnerTarget Target { get; set; }
public double TimeoutInMinutes { get; set; } = 15;
@ -55,8 +51,6 @@ namespace Xharness
public interface IHarness {
HarnessAction Action { get; }
string BCLTodayExtensionTemplate { get; }
string Configuration { get; }
bool DisableWatchOSOnWrench { get; }
string DOTNET { get; }
bool DryRun { get; }
@ -71,7 +65,6 @@ namespace Xharness
bool? IncludeSystemPermissionTests { get; set; }
string IOS_DESTDIR { get; }
List<iOSTestProject> IOSTestProjects { get; }
bool IsBetaXcode { get; }
string JENKINS_RESULTS_DIRECTORY { get; }
string JenkinsConfiguration { get; }
HashSet<string> Labels { get; }
@ -88,12 +81,9 @@ namespace Xharness
string PeriodicCommandArguments { get; }
TimeSpan PeriodicCommandInterval { get; }
IProcessManager ProcessManager { get; }
string SdkRoot { get; }
AppRunnerTarget Target { get; }
double Timeout { get; }
string TodayContainerTemplate { get; }
string TodayExtensionTemplate { get; }
string TVOS_MONO_PATH { get; }
bool UseGroupedApps { get; }
int Verbosity { get; }
string WatchOSAppTemplate { get; }
@ -103,28 +93,19 @@ namespace Xharness
Version XcodeVersion { get; }
string XIBuildPath { get; }
XmlResultJargon XmlJargon { get; }
int Configure ();
Task<HashSet<string>> CreateCrashReportsSnapshotAsync (ILog log, bool simulatorOrDesktop, string device);
int Execute ();
Task<ProcessExecutionResult> ExecuteXcodeCommandAsync (string executable, IList<string> args, ILog log, TimeSpan timeout);
bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device);
int Install ();
int Jenkins ();
void Log (int min_level, string message);
void Log (int min_level, string message, params object [] args);
void Log (string message);
void Log (string message, params object [] args);
void LogWrench (string message);
void LogWrench (string message, params object [] args);
Guid NewStableGuid (string seed = null);
int Run ();
void Save (StringWriter doc, string path);
Task<ILogFile> SymbolicateCrashReportAsync (ILogs logs, ILog log, ILogFile report);
int Uninstall ();
}
public class Harness : IHarness {
readonly AppRunnerTarget target;
readonly string buildConfiguration = "Debug";
string sdkRoot;
public HarnessAction Action { get; }
public int Verbosity { get; }
public ILog HarnessLog { get; set; }
@ -132,15 +113,9 @@ namespace Xharness
public XmlResultJargon XmlJargon { get; }
public IProcessManager ProcessManager { get; }
public string XIBuildPath {
get { return Path.GetFullPath (Path.Combine (RootDirectory, "..", "tools", "xibuild", "xibuild")); }
}
public string XIBuildPath => Path.GetFullPath (Path.Combine (RootDirectory, "..", "tools", "xibuild", "xibuild"));
public static string Timestamp {
get {
return $"{DateTime.Now:yyyyMMdd_HHmmss}";
}
}
public static string Timestamp => $"{DateTime.Now:yyyyMMdd_HHmmss}";
// This is the maccore/tests directory.
static string root_directory;
@ -199,19 +174,16 @@ namespace Xharness
public string DOTNET { get; private set; }
// Run
public AppRunnerTarget Target { get; }
public string SdkRoot { get; private set; }
public string Configuration { get; }
public string LogDirectory { get; }
public string LogDirectory { get; } = Environment.CurrentDirectory;
public double Timeout { get; } = 15; // in minutes
public double LaunchTimeout { get; } // in minutes
public bool DryRun { get; } // Most things don't support this. If you need it somewhere, implement it!
public string JenkinsConfiguration { get; }
public Dictionary<string, string> EnvironmentVariables { get; }
public Dictionary<string, string> EnvironmentVariables { get; } = new Dictionary<string, string> ();
public string MarkdownSummaryPath { get; }
public string PeriodicCommand { get; }
public string PeriodicCommandArguments { get; }
public TimeSpan PeriodicCommandInterval { get; }
public TimeSpan PeriodicCommandInterval { get;}
// whether tests that require access to system resources (system contacts, photo library, etc) should be executed or not
public bool? IncludeSystemPermissionTests { get; set; }
@ -224,7 +196,7 @@ namespace Xharness
throw new ArgumentNullException (nameof (configuration));
autoConf = configuration.AutoConf;
Configuration = configuration.Configuration ?? throw new ArgumentNullException (nameof (configuration));
buildConfiguration = configuration.BuildConfiguration ?? throw new ArgumentNullException (nameof (configuration));
DryRun = configuration.DryRun;
IncludeSystemPermissionTests = configuration.IncludeSystemPermissionTests;
IOSTestProjects = configuration.IOSTestProjects;
@ -235,9 +207,8 @@ namespace Xharness
PeriodicCommand = configuration.PeriodicCommand;
PeriodicCommandArguments = configuration.PeriodicCommandArguments;
PeriodicCommandInterval = configuration.PeriodicCommandInterval;
RootDirectory = configuration.RootDirectory;
SdkRoot = configuration.SdkRoot;
Target = configuration.Target;
sdkRoot = configuration.SdkRoot;
target = configuration.Target;
Timeout = configuration.TimeoutInMinutes;
useSystemXamarinIOSMac = configuration.UseSystemXamarinIOSMac;
Verbosity = configuration.Verbosity;
@ -280,13 +251,6 @@ namespace Xharness
}
}
public bool IsBetaXcode {
get {
// There's no string.Contains (string, StringComparison) overload, so use IndexOf instead.
return XcodeRoot.IndexOf ("beta", StringComparison.OrdinalIgnoreCase) >= 0;
}
}
static string FindXcode (string path)
{
var p = path;
@ -302,7 +266,7 @@ namespace Xharness
public string XcodeRoot {
get {
return FindXcode (SdkRoot);
return FindXcode (sdkRoot);
}
}
@ -318,59 +282,6 @@ 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");
@ -390,8 +301,8 @@ namespace Xharness
INCLUDE_MAC = make_config.ContainsKey ("INCLUDE_MAC") && !string.IsNullOrEmpty (make_config ["INCLUDE_MAC"]);
MAC_DESTDIR = make_config ["MAC_DESTDIR"];
IOS_DESTDIR = make_config ["IOS_DESTDIR"];
if (string.IsNullOrEmpty (SdkRoot))
SdkRoot = make_config ["XCODE_DEVELOPER_ROOT"];
if (string.IsNullOrEmpty (sdkRoot))
sdkRoot = make_config ["XCODE_DEVELOPER_ROOT"];
MONO_IOS_SDK_DESTDIR = make_config ["MONO_IOS_SDK_DESTDIR"];
MONO_MAC_SDK_DESTDIR = make_config ["MONO_MAC_SDK_DESTDIR"];
ENABLE_XAMARIN = make_config.ContainsKey ("ENABLE_XAMARIN") && !string.IsNullOrEmpty (make_config ["ENABLE_XAMARIN"]);
@ -602,7 +513,7 @@ namespace Xharness
}
}
public int Configure ()
int Configure ()
{
return mac ? AutoConfigureMac (true) : ConfigureIOS ();
}
@ -680,7 +591,7 @@ namespace Xharness
return rv;
}
public int Install ()
int Install ()
{
if (HarnessLog == null)
HarnessLog = new ConsoleLog ();
@ -690,11 +601,11 @@ namespace Xharness
new SimulatorsLoaderFactory (this, ProcessManager),
new SimpleListenerFactory (),
new DeviceLoaderFactory (this, ProcessManager),
Target,
target,
this,
HarnessLog,
project.Path,
Configuration);
buildConfiguration);
using (var install_log = new AppInstallMonitorLog (runner.MainLog)) {
var rv = runner.InstallAsync (install_log.CancellationToken).Result;
@ -705,7 +616,7 @@ namespace Xharness
return 0;
}
public int Uninstall ()
int Uninstall ()
{
if (HarnessLog == null)
HarnessLog = new ConsoleLog ();
@ -715,11 +626,11 @@ namespace Xharness
new SimulatorsLoaderFactory (this, ProcessManager),
new SimpleListenerFactory (),
new DeviceLoaderFactory (this, ProcessManager),
Target,
target,
this,
HarnessLog,
project.Path,
Configuration);
buildConfiguration);
var rv = runner.UninstallAsync ().Result;
if (!rv.Succeeded)
@ -728,7 +639,7 @@ namespace Xharness
return 0;
}
public int Run ()
int Run ()
{
if (HarnessLog == null)
HarnessLog = new ConsoleLog ();
@ -738,11 +649,11 @@ namespace Xharness
new SimulatorsLoaderFactory (this, ProcessManager),
new SimpleListenerFactory (),
new DeviceLoaderFactory (this, ProcessManager),
Target,
target,
this,
HarnessLog,
project.Path,
Configuration);
buildConfiguration);
var rv = runner.RunAsync ().Result;
if (rv != 0)
@ -751,7 +662,7 @@ namespace Xharness
return 0;
}
public void Log (int min_level, string message)
void Log (int min_level, string message)
{
if (Verbosity < min_level)
return;
@ -777,23 +688,6 @@ namespace Xharness
Log (0, message, args);
}
public void LogWrench (string message, params object [] args)
{
// Disable this for now, since we're not uploading directly to wrench anymore, but instead using the Html Report.
//if (!InWrench)
// return;
//Console.WriteLine (message, args);
}
public void LogWrench (string message)
{
if (!InCI)
return;
Console.WriteLine (message);
}
public bool InCI {
get {
// We use the 'BUILD_REVISION' variable to detect whether we're running CI or not.
@ -827,7 +721,7 @@ namespace Xharness
}
}
public int Jenkins ()
int Jenkins ()
{
if (autoConf) {
AutoConfigureIOS ();
@ -878,42 +772,6 @@ 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 {
@ -927,65 +785,5 @@ 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> ();
if (simulatorOrDesktop) {
var dir = Path.Combine (Environment.GetEnvironmentVariable ("HOME"), "Library", "Logs", "DiagnosticReports");
if (Directory.Exists (dir))
rv.UnionWith (Directory.EnumerateFiles (dir));
} else {
var tmp = Path.GetTempFileName ();
try {
var sb = new List<string> ();
sb.Add ($"--list-crash-reports={tmp}");
sb.Add ("--sdkroot");
sb.Add (XcodeRoot);
if (!string.IsNullOrEmpty (device)) {
sb.Add ("--devname");
sb.Add (device);
}
var result = await ProcessManager.ExecuteCommandAsync (MlaunchPath, sb, log, TimeSpan.FromMinutes (1));
if (result.Succeeded)
rv.UnionWith (File.ReadAllLines (tmp));
} finally {
File.Delete (tmp);
}
}
return rv;
}
}
}

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

@ -881,12 +881,14 @@ namespace Xharness.Jenkins
// old simulator tests is also a bit special:
// - enabled by default if using a beta Xcode, otherwise disabled by default
changed = SetEnabled (labels, "old-simulator", ref IncludeOldSimulatorTests);
if (!changed && Harness.IsBetaXcode) {
if (!changed && IsBetaXcode) {
IncludeOldSimulatorTests = true;
MainLog.WriteLine ("Enabled 'old-simulator' tests because we're using a beta Xcode.");
}
}
bool IsBetaXcode => Harness.XcodeRoot.IndexOf ("beta", StringComparison.OrdinalIgnoreCase) >= 0;
// Returns true if the value was changed.
bool SetEnabled (HashSet<string> labels, string testname, ref bool value)
{

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

@ -91,7 +91,7 @@ namespace Xharness.Jenkins.TestTasks
if (!Harness.DryRun) {
ExecutionResult = TestExecutingResult.Running;
var snapshot = new CrashReportSnapshot () { Device = false, Harness = Harness, Log = log, Logs = Logs, LogDirectory = LogDirectory };
var snapshot = new CrashReportSnapshot (Harness, log, Logs, isDevice: false, deviceName: null);
await snapshot.StartCaptureAsync ();
ProcessExecutionResult result = null;

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

@ -29,7 +29,7 @@ namespace Xharness.Jenkins.TestTasks
if (!Harness.DryRun) {
ExecutionResult = TestExecutingResult.Running;
var snapshot = new CrashReportSnapshot () { Device = false, Harness = Harness, Log = log, Logs = Logs, LogDirectory = LogDirectory };
var snapshot = new CrashReportSnapshot (Harness, log, Logs, isDevice: false, deviceName: null);
await snapshot.StartCaptureAsync ();
try {

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

@ -0,0 +1,18 @@
namespace Xharness.Logging {
public static class WrenchLog {
public static void WriteLine (string message, params object [] args)
{
WriteLine (string.Format (message, args));
}
public static void WriteLine (string message)
{
// Disable this for now, since we're not uploading directly to wrench anymore, but instead using the Html Report.
//if (!InWrench)
// return;
//Console.WriteLine ("@MonkeyWrench: " + message, args);
}
}
}

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

@ -21,7 +21,7 @@ namespace Xharness {
{ "mac", "Configure for Xamarin.Mac instead of iOS.", (v) => configuration.Mac = true },
{ "configure", "Creates project files and makefiles.", (v) => action = HarnessAction.Configure },
{ "autoconf", "Automatically decide what to configure.", (v) => configuration.AutoConf = true },
{ "rootdir=", "The root directory for the tests.", (v) => configuration.RootDirectory = 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) => configuration.IOSTestProjects.Add (new iOSTestProject (v)) },
{ "watchos-container-template=", "The directory to use as a template for a watchos container app.", (v) => configuration.WatchOSContainerTemplate = v },
{ "watchos-app-template=", "The directory to use as a template for a watchos app.", (v) => configuration.WatchOSAppTemplate = v },
@ -47,7 +47,7 @@ namespace Xharness {
{ "sdkroot=", "Where Xcode is", (v) => configuration.SdkRoot = v },
{ "sdkroot94=", "Where Xcode 9.4 is", (v) => Console.WriteLine ("--sdkroot94 is deprecated"), true },
{ "target=", "Where to run the project ([ios|watchos|tvos]-[device|simulator|simulator-32|simulator-64]).", (v) => configuration.Target = v.ParseAsAppRunnerTarget () },
{ "configuration=", "Which configuration to run (defaults to Debug).", (v) => configuration.Configuration = v },
{ "configuration=", "Which configuration to run (defaults to Debug).", (v) => configuration.BuildConfiguration = v },
{ "logdirectory=", "Where to store logs.", (v) => configuration.LogDirectory = v },
{ "logfile=", "Where to store the log.", (v) => Console.WriteLine("The logfile option is deprecated. Please use logdirectory."), true },
{ "timeout=", $"Timeout for a test run (in minutes). Default is {configuration.TimeoutInMinutes} minutes.", (v) => configuration.TimeoutInMinutes = double.Parse (v) },

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

@ -182,7 +182,7 @@ namespace Xharness.Targets
{
base.PostProcessExecutableProject ();
ProjectGuid = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
ProjectGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
inputProject.SetProjectGuid (ProjectGuid);
}
}

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

@ -63,7 +63,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 = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
TodayContainerGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
ProjectGuid = TodayContainerGuid;
csproj.SetProjectGuid (TodayContainerGuid);
if (MonoNativeInfo != null) {

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

@ -38,7 +38,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 = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
WatchOSAppGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
csproj.SetProjectGuid (WatchOSAppGuid);
csproj.FixInfoPListInclude (suffix);
if (MonoNativeInfo != null) {
@ -66,7 +66,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 = "{" + Harness.NewStableGuid ().ToString ().ToUpper () + "}";
WatchOSGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}";
csproj.SetProjectGuid (WatchOSGuid);
csproj.FixInfoPListInclude (Suffix);
if (MonoNativeInfo != null) {

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

@ -0,0 +1,29 @@
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);
}
}
}

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

@ -73,6 +73,7 @@
<PackageReference Include="Mono.Options" Version="5.3.0.1" />
</ItemGroup>
<ItemGroup>
<Compile Include="AppInstallMonitorLog.cs" />
<Compile Include="AppRunner.cs" />
<Compile Include="AppRunnerTarget.cs" />
<Compile Include="BCLTestImporter\BCLTestAssemblyDefinition.cs" />
@ -133,6 +134,7 @@
<Compile Include="Logging\Log.cs" />
<Compile Include="Logging\LogFile.cs" />
<Compile Include="Logging\Logs.cs" />
<Compile Include="Logging\WrenchLog.cs" />
<Compile Include="MakefileGenerator.cs" />
<Compile Include="MonoNativeInfo.cs" />
<Compile Include="NoDeviceFoundException.cs" />
@ -150,6 +152,7 @@
<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" />
@ -179,17 +182,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="BCLTestImporter\Templates\" />
<Folder Include="BCLTestImporter\Templates\Managed\" />
<Folder Include="BCLTestImporter\Templates\Managed\Resources\" />
<Folder Include="BCLTestImporter\Templates\Managed\Resources\src\" />
<Folder Include="BCLTestImporter\Templates\Managed\Resources\src\common\TestRunner\" />
<Folder Include="BCLTestImporter\Templates\Managed\Resources\src\common\TestRunner\Core\" />
<Folder Include="BCLTestImporter\Templates\Managed\Resources\src\common\TestRunner\NUnit\" />
<Folder Include="BCLTestImporter\Templates\Managed\Resources\src\common\TestRunner\xUnit\" />
<Folder Include="BCLTestImporter\Xamarin\" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<EmbeddedResource Include="BCLTestImporter\Templates\Managed\Resources\Managed.iOS.csproj.in" />
<EmbeddedResource Include="BCLTestImporter\Templates\Managed\Resources\Managed.macOS.csproj.in" />