xamarin-macios/tests/xharness/Harness.cs

710 строки
25 KiB
C#
Исходник Обычный вид История

using System;
2016-05-26 16:06:52 +03:00
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
2016-05-26 16:06:52 +03:00
using System.Text;
using System.Threading.Tasks;
2016-05-26 16:06:52 +03:00
using System.Xml;
using Xharness.BCLTestImporter;
using Xharness.Logging;
using Xharness.Execution;
[Harness] Split out Targets, Utils and remove external links (#8061) * [Harness] Refactor process management to be testable. Move all the extension methods to a class. After this refactor, we will be able to DI the manager in the other classes and assert that the processes are called with the correct parameters without the need of launching them. Also added tests for the manager. We create a dummy console app that will be executed by the tests. The console app has a number of parameters that will be used to ensure that the new process behaves as we want: - Use the passed exit code. - Create child proecesses if needed. - Sleep to force a timeout. - Writer messages to stdout and stderr. Our tests call the dummy app and ensures that the results match the behaviour expected by the dummy app. * Apply suggestions from code review Co-Authored-By: Přemek Vysoký <premek.vysoky@microsoft.com> * Move out utils into a separate namespace * Move Cache to the test project * Fix namespaces after merge * Remove unneeded code * Move Target files * Sort csproj * Refactor Targets * Rename Cache to TempDirectory * Fix using * Move ProjectFileExtensions * Remove dead code * Move Extensions * Add empty StringUtilsTests * Add StringUtils tests * Revert refactorings * Update tests/xharness/Utilities/StringUtils.cs Co-Authored-By: Rolf Bjarne Kvinge <rolf@xamarin.com> * Update tests/xharness/Utilities/StringUtils.cs Co-Authored-By: Rolf Bjarne Kvinge <rolf@xamarin.com> * Add better formatarguments test * Update tests/xharness/Utilities/StringUtils.cs Co-Authored-By: Rolf Bjarne Kvinge <rolf@xamarin.com> Co-authored-by: Manuel de la Pena <mandel@microsoft.com> Co-authored-by: Premek Vysoky <prvysoky@microsoft.com> Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
2020-03-10 15:12:33 +03:00
using Xharness.Targets;
using Xharness.Utilities;
2016-05-26 16:06:52 +03:00
namespace Xharness
2016-05-26 16:06:52 +03:00
{
public enum HarnessAction
{
None,
Configure,
Run,
Install,
Uninstall,
Jenkins,
2016-05-26 16:06:52 +03:00
}
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
2016-05-26 16:06:52 +03:00
{
public HarnessAction Action { get; set; }
public int Verbosity { get; set; }
public ILog HarnessLog { get; set; }
public bool UseSystem { get; set; } // if the system XI/XM should be used, or the locally build XI/XM.
public HashSet<string> Labels { get; } = new HashSet<string> ();
public XmlResultJargon XmlJargon { get; set; } = XmlResultJargon.NUnitV3;
public IProcessManager ProcessManager { get; set; } = new ProcessManager ();
2016-05-26 16:06:52 +03:00
public string XIBuildPath {
get { return Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "..", "tools", "xibuild", "xibuild")); }
}
public static string Timestamp {
get {
return $"{DateTime.Now:yyyyMMdd_HHmmss}";
}
}
2016-05-26 16:06:52 +03:00
public List<iOSTestProject> IOSTestProjects { get; set; } = new List<iOSTestProject> ();
public List<MacTestProject> MacTestProjects { get; set; } = new List<MacTestProject> ();
2017-02-01 19:05:08 +03:00
2016-05-26 16:06:52 +03:00
// Configure
public bool AutoConf { get; set; }
public bool Mac { get; set; }
2016-05-26 16:06:52 +03:00
public string WatchOSContainerTemplate { get; set; }
public string WatchOSAppTemplate { get; set; }
public string WatchOSExtensionTemplate { get; set; }
public string TodayContainerTemplate { get; set; }
public string TodayExtensionTemplate { get; set; }
public string BCLTodayExtensionTemplate { get; set; }
2016-05-26 16:06:52 +03:00
public string MONO_PATH { get; set; } // Use same name as in Makefiles, so that a grep finds it.
public string TVOS_MONO_PATH { get; set; } // Use same name as in Makefiles, so that a grep finds it.
public bool INCLUDE_IOS { get; set; }
public bool INCLUDE_TVOS { get; set; }
2016-05-26 16:06:52 +03:00
public bool INCLUDE_WATCH { get; set; }
public bool INCLUDE_MAC { get; set; }
public string JENKINS_RESULTS_DIRECTORY { get; set; } // Use same name as in Makefiles, so that a grep finds it.
public string MAC_DESTDIR { get; set; }
public string IOS_DESTDIR { get; set; }
public string MONO_IOS_SDK_DESTDIR { get; set; }
public string MONO_MAC_SDK_DESTDIR { get; set; }
public bool IncludeMac32 { get; set; }
public bool ENABLE_XAMARIN { get; set; }
2016-05-26 16:06:52 +03:00
// Run
public AppRunnerTarget Target { get; set; }
public string SdkRoot { get; set; }
2016-05-26 16:06:52 +03:00
public string Configuration { get; set; } = "Debug";
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 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> ();
public string MarkdownSummaryPath { get; set; }
public string PeriodicCommand { get; set; }
public string PeriodicCommandArguments { get; set; }
public TimeSpan PeriodicCommandInterval { get; set; }
// whether tests that require access to system resources (system contacts, photo library, etc) should be executed or not
public bool? IncludeSystemPermissionTests { get; set; }
2016-05-26 16:06:52 +03:00
public Harness ()
{
LaunchTimeout = TimeSpan.FromMinutes(InCI ? 3 : 120);
2016-05-26 16:06:52 +03:00
}
public bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device)
{
// If we've been told something in particular, that takes precedence.
if (IncludeSystemPermissionTests.HasValue)
return IncludeSystemPermissionTests.Value;
// If we haven't been told, try to be smart.
switch (platform) {
case TestPlatform.iOS:
case TestPlatform.Mac:
case TestPlatform.Mac_Full:
case TestPlatform.Mac_Modern:
case TestPlatform.Mac_System:
// On macOS we can't edit the TCC database easily
// (it requires adding the mac has to be using MDM: https://carlashley.com/2018/09/28/tcc-round-up/)
// So by default ignore any tests that would pop up permission dialogs in CI.
return !InCI;
default:
// On device we have the same issue as on the mac: we can't edit the TCC database.
if (device)
return !InCI;
// But in the simulator we can just write to the simulator's TCC database (and we do)
return true;
}
}
2016-05-26 16:06:52 +03:00
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;
do {
if (p == "/") {
throw new Exception (string.Format ("Could not find Xcode.app in {0}", path));
} else if (File.Exists (Path.Combine (p, "Contents", "MacOS", "Xcode"))) {
return p;
}
p = Path.GetDirectoryName (p);
} while (true);
}
2016-05-26 16:06:52 +03:00
public string XcodeRoot {
get {
return FindXcode (SdkRoot);
}
}
Version xcode_version;
public Version XcodeVersion {
get {
if (xcode_version == null) {
var doc = new XmlDocument ();
doc.Load (Path.Combine (XcodeRoot, "Contents", "version.plist"));
xcode_version = Version.Parse (doc.SelectSingleNode ("//key[text() = 'CFBundleShortVersionString']/following-sibling::string").InnerText);
}
return xcode_version;
}
}
2016-05-26 16:06:52 +03:00
public string MlaunchPath {
get {
return Path.Combine (IOS_DESTDIR, "Library", "Frameworks", "Xamarin.iOS.framework", "Versions", "Current", "bin", "mlaunch");
2016-05-26 16:06:52 +03:00
}
}
void LoadConfig ()
{
ParseConfigFiles ();
var src_root = Path.GetDirectoryName ( DirectoryUtilities.RepositoryRootDirectory);
MONO_PATH = Path.GetFullPath (Path.Combine (src_root, "external", "mono"));
TVOS_MONO_PATH = MONO_PATH;
INCLUDE_IOS = make_config.ContainsKey ("INCLUDE_IOS") && !string.IsNullOrEmpty (make_config ["INCLUDE_IOS"]);
INCLUDE_TVOS = make_config.ContainsKey ("INCLUDE_TVOS") && !string.IsNullOrEmpty (make_config ["INCLUDE_TVOS"]);
JENKINS_RESULTS_DIRECTORY = make_config ["JENKINS_RESULTS_DIRECTORY"];
INCLUDE_WATCH = make_config.ContainsKey ("INCLUDE_WATCH") && !string.IsNullOrEmpty (make_config ["INCLUDE_WATCH"]);
INCLUDE_MAC = make_config.ContainsKey ("INCLUDE_MAC") && !string.IsNullOrEmpty (make_config ["INCLUDE_MAC"]);
MAC_DESTDIR = make_config ["MAC_DESTDIR"];
IOS_DESTDIR = make_config ["IOS_DESTDIR"];
if (string.IsNullOrEmpty (SdkRoot))
SdkRoot = make_config ["XCODE_DEVELOPER_ROOT"];
MONO_IOS_SDK_DESTDIR = make_config ["MONO_IOS_SDK_DESTDIR"];
MONO_MAC_SDK_DESTDIR = make_config ["MONO_MAC_SDK_DESTDIR"];
ENABLE_XAMARIN = make_config.ContainsKey ("ENABLE_XAMARIN") && !string.IsNullOrEmpty (make_config ["ENABLE_XAMARIN"]);
}
2016-05-26 16:06:52 +03:00
int AutoConfigureMac (bool generate_projects)
2016-05-26 16:06:52 +03:00
{
int rv = 0;
var test_suites = new [] {
new { Directory = "apitest", ProjectFile = "apitest", Name = "apitest", Flavors = MacFlavors.Full | MacFlavors.Modern },
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"))) {
Name = p.Name,
TargetFrameworkFlavors = p.Flavors,
});
}
2017-02-01 19:05:08 +03:00
MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "introspection", "Mac", "introspection-mac.csproj")), targetFrameworkFlavor: MacFlavors.Modern) { Name = "introspection" });
2017-02-01 19:05:08 +03:00
var hard_coded_test_suites = new [] {
new { Directory = "mmptest", ProjectFile = "mmptest", Name = "mmptest", IsNUnit = true, Configurations = (string[]) null, Platform = "x86", Flavors = MacFlavors.Console, },
new { Directory = "msbuild-mac", ProjectFile = "msbuild-mac", Name = "MSBuild tests", IsNUnit = true, Configurations = (string[]) null, Platform = "x86", Flavors = MacFlavors.Console, },
new { Directory = "xammac_tests", ProjectFile = "xammac_tests", Name = "xammac tests", IsNUnit = false, Configurations = new string [] { "Debug", "Release" }, Platform = "AnyCPU", Flavors = MacFlavors.Modern, },
new { Directory = "linker/mac/link all", ProjectFile = "link all-mac", Name = "link all", IsNUnit = false, Configurations = new string [] { "Debug", "Release" }, Platform = "x86", Flavors = MacFlavors.Modern, },
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) {
Name = p.Name,
IsNUnitProject = p.IsNUnit,
SolutionPath = Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, "tests-mac.sln")),
Configurations = p.Configurations,
Platform = p.Platform,
});
}
2017-02-01 19:05:08 +03:00
foreach (var flavor in new MonoNativeFlavor [] { MonoNativeFlavor.Compat, MonoNativeFlavor.Unified }) {
var monoNativeInfo = new MacMonoNativeInfo (this, flavor);
var macTestProject = new MacTestProject (monoNativeInfo.ProjectPath, targetFrameworkFlavor: MacFlavors.Modern | MacFlavors.Full) {
MonoNativeInfo = monoNativeInfo,
Name = monoNativeInfo.ProjectName,
Platform = "AnyCPU",
};
MacTestProjects.Add (macTestProject);
}
var monoImportTestFactory = new BCLTestImportTargetFactory (this);
MacTestProjects.AddRange (monoImportTestFactory.GetMacBclTargets ());
// Generate test projects from templates (bcl/mono-native templates)
if (generate_projects) {
foreach (var mtp in MacTestProjects.Where (x => x.MonoNativeInfo != null).Select (x => x.MonoNativeInfo))
mtp.Convert ();
}
// All test projects should be either Modern projects or NUnit/console executables at this point.
// If we need to generate Full/System variations, we do that here.
var unified_targets = new List<MacTarget> ();
Action<MacTarget, string, bool, bool> configureTarget = (MacTarget target, string file, bool isNUnitProject, bool skip_generation) => {
target.TemplateProjectPath = file;
target.Harness = this;
target.IsNUnitProject = isNUnitProject;
if (!generate_projects || skip_generation)
target.ShouldSkipProjectGeneration = true;
target.Execute ();
};
foreach (var proj in MacTestProjects) {
var target = new MacTarget (MacFlavors.Modern);
target.MonoNativeInfo = proj.MonoNativeInfo;
configureTarget (target, proj.Path, proj.IsNUnitProject, true);
unified_targets.Add (target);
}
foreach (var proj in MacTestProjects.Where ((v) => v.GenerateVariations).ToArray ()) {
var file = proj.Path;
if (!File.Exists (file)) {
Console.WriteLine ($"Can't find the project file {file}.");
rv = 1;
continue;
}
// Generate variations if requested
if (proj.GenerateFull) {
var target = new MacTarget (MacFlavors.Full);
target.MonoNativeInfo = proj.MonoNativeInfo;
configureTarget (target, file, proj.IsNUnitProject, false);
unified_targets.Add (target);
var cloned_project = (MacTestProject) proj.Clone ();
cloned_project.TargetFrameworkFlavors = MacFlavors.Full;
cloned_project.Path = target.ProjectPath;
MacTestProjects.Add (cloned_project);
}
if (proj.GenerateSystem) {
var target = new MacTarget (MacFlavors.System);
target.MonoNativeInfo = proj.MonoNativeInfo;
configureTarget (target, file, proj.IsNUnitProject, false);
unified_targets.Add (target);
var cloned_project = (MacTestProject) proj.Clone ();
cloned_project.TargetFrameworkFlavors = MacFlavors.System;
cloned_project.Path = target.ProjectPath;
MacTestProjects.Add (cloned_project);
}
// We're done generating now
// Re-use the existing TestProject instance instead of creating a new one.
proj.TargetFrameworkFlavors = MacFlavors.Modern; // the default/template flavor is 'Modern'
}
if (generate_projects)
MakefileGenerator.CreateMacMakefile (this, unified_targets);
return rv;
2016-05-26 16:06:52 +03:00
}
void AutoConfigureIOS ()
2016-05-26 16:06:52 +03:00
{
var test_suites = new string [] { "monotouch-test", "framework-test", "interdependent-binding-projects" };
2017-01-26 15:38:39 +03:00
var library_projects = new string [] { "BundledResources", "EmbeddedResources", "bindings-test", "bindings-test2", "bindings-framework-test" };
2016-05-26 16:06:52 +03:00
var fsharp_test_suites = new string [] { "fsharp" };
var fsharp_library_projects = new string [] { "fsharplibrary" };
2016-05-26 16:06:52 +03:00
foreach (var p in test_suites)
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".csproj"))) { Name = p });
2016-05-26 16:06:52 +03:00
foreach (var p in fsharp_test_suites)
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".fsproj"))) { Name = p });
2016-05-26 16:06:52 +03:00
foreach (var p in library_projects)
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".csproj")), false) { Name = p });
2016-05-26 16:06:52 +03:00
foreach (var p in fsharp_library_projects)
IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (DirectoryUtilities.RepositoryRootDirectory, p + "/" + p + ".fsproj")), false) { Name = p });
2017-02-01 19:05:08 +03:00
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" } });
foreach (var flavor in new MonoNativeFlavor[] { MonoNativeFlavor.Compat, MonoNativeFlavor.Unified }) {
var monoNativeInfo = new MonoNativeInfo (this, flavor);
var iosTestProject = new iOSTestProject (monoNativeInfo.ProjectPath) {
MonoNativeInfo = monoNativeInfo,
Name = monoNativeInfo.ProjectName,
SkipwatchOSARM64_32Variation = monoNativeInfo.ProjectName.Contains ("compat"),
};
IOSTestProjects.Add (iosTestProject);
}
// add all the tests that are using the precompiled mono assemblies
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"));
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"));
2016-05-26 16:06:52 +03:00
}
Dictionary<string, string> make_config = new Dictionary<string, string> ();
IEnumerable<string> FindConfigFiles (string name)
2016-05-26 16:06:52 +03:00
{
var dir = DirectoryUtilities.RepositoryRootDirectory;
2016-05-26 16:06:52 +03:00
while (dir != "/") {
var file = Path.Combine (dir, name);
if (File.Exists (file))
yield return file;
dir = Path.GetDirectoryName (dir);
}
}
void ParseConfigFiles ()
2016-05-26 16:06:52 +03:00
{
ParseConfigFiles (FindConfigFiles (UseSystem ? "test-system.config" : "test.config"));
2016-05-26 16:06:52 +03:00
ParseConfigFiles (FindConfigFiles ("Make.config.local"));
ParseConfigFiles (FindConfigFiles ("Make.config"));
}
void ParseConfigFiles (IEnumerable<string> files)
2016-05-26 16:06:52 +03:00
{
foreach (var file in files)
ParseConfigFile (file);
}
void ParseConfigFile (string file)
2016-05-26 16:06:52 +03:00
{
if (string.IsNullOrEmpty (file))
return;
foreach (var line in File.ReadAllLines (file)) {
var eq = line.IndexOf ('=');
if (eq == -1)
continue;
var key = line.Substring (0, eq);
if (!make_config.ContainsKey (key))
make_config [key] = line.Substring (eq + 1);
}
}
int Configure ()
2016-05-26 16:06:52 +03:00
{
return Mac ? AutoConfigureMac (true) : ConfigureIOS ();
2016-05-26 16:06:52 +03:00
}
int ConfigureIOS ()
2016-05-26 16:06:52 +03:00
{
var rv = 0;
2016-05-26 16:06:52 +03:00
var unified_targets = new List<UnifiedTarget> ();
var tvos_targets = new List<TVOSTarget> ();
var watchos_targets = new List<WatchOSTarget> ();
var today_targets = new List<TodayExtensionTarget> ();
2016-05-26 16:06:52 +03:00
if (AutoConf)
AutoConfigureIOS ();
2016-05-26 16:06:52 +03:00
foreach (var monoNativeInfo in IOSTestProjects.Where (x => x.MonoNativeInfo != null).Select (x => x.MonoNativeInfo))
monoNativeInfo.Convert ();
2016-05-26 16:06:52 +03:00
foreach (var proj in IOSTestProjects) {
var file = proj.Path;
if (proj.MonoNativeInfo != null)
file = proj.MonoNativeInfo.TemplatePath;
if (!File.Exists (file)) {
Console.WriteLine ($"Can't find the project file {file}.");
rv = 1;
continue;
}
2016-05-26 16:06:52 +03:00
if (!proj.SkipwatchOSVariation) {
var watchos = new WatchOSTarget () {
TemplateProjectPath = file,
Harness = this,
TestProject = proj,
};
watchos.Execute ();
watchos_targets.Add (watchos);
}
if (!proj.SkiptvOSVariation) {
var tvos = new TVOSTarget () {
TemplateProjectPath = file,
Harness = this,
TestProject = proj,
};
tvos.Execute ();
tvos_targets.Add (tvos);
}
if (!proj.SkipiOSVariation) {
var unified = new UnifiedTarget () {
TemplateProjectPath = file,
Harness = this,
TestProject = proj,
};
unified.Execute ();
unified_targets.Add (unified);
var today = new TodayExtensionTarget {
TemplateProjectPath = file,
Harness = this,
TestProject = proj,
};
today.Execute ();
today_targets.Add (today);
}
2016-05-26 16:06:52 +03:00
}
SolutionGenerator.CreateSolution (this, watchos_targets, "watchos");
SolutionGenerator.CreateSolution (this, tvos_targets, "tvos");
SolutionGenerator.CreateSolution (this, today_targets, "today");
MakefileGenerator.CreateMakefile (this, unified_targets, tvos_targets, watchos_targets, today_targets);
return rv;
2016-05-26 16:06:52 +03:00
}
int Install ()
2016-05-26 16:06:52 +03:00
{
if (HarnessLog == null)
HarnessLog = new ConsoleLog ();
foreach (var project in IOSTestProjects) {
2016-05-26 16:06:52 +03:00
var runner = new AppRunner () {
Harness = this,
ProjectFile = project.Path,
MainLog = HarnessLog,
2016-05-26 16:06:52 +03:00
};
using (var install_log = new AppInstallMonitorLog (runner.MainLog)) {
var rv = runner.InstallAsync (install_log.CancellationToken).Result;
if (!rv.Succeeded)
return rv.ExitCode;
}
2016-05-26 16:06:52 +03:00
}
return 0;
}
int Uninstall ()
{
if (HarnessLog == null)
HarnessLog = new ConsoleLog ();
foreach (var project in IOSTestProjects) {
var runner = new AppRunner ()
{
Harness = this,
ProjectFile = project.Path,
MainLog = HarnessLog,
};
var rv = runner.UninstallAsync ().Result;
if (!rv.Succeeded)
return rv.ExitCode;
}
return 0;
}
int Run ()
2016-05-26 16:06:52 +03:00
{
if (HarnessLog == null)
HarnessLog = new ConsoleLog ();
foreach (var project in IOSTestProjects) {
2016-05-26 16:06:52 +03:00
var runner = new AppRunner () {
Harness = this,
ProjectFile = project.Path,
MainLog = HarnessLog,
2016-05-26 16:06:52 +03:00
};
var rv = runner.RunAsync ().Result;
2016-05-26 16:06:52 +03:00
if (rv != 0)
return rv;
}
return 0;
}
int Jenkins ()
{
if (AutoConf) {
AutoConfigureIOS ();
AutoConfigureMac (false);
}
var jenkins = new Jenkins.Jenkins ()
{
Harness = this,
};
return jenkins.Run ();
}
2016-05-26 16:06:52 +03:00
public void Log (int min_level, string message)
{
if (Verbosity < min_level)
return;
Console.WriteLine (message);
HarnessLog?.WriteLine (message);
2016-05-26 16:06:52 +03:00
}
public void Log (int min_level, string message, params object[] args)
{
if (Verbosity < min_level)
return;
Console.WriteLine (message, args);
HarnessLog?.WriteLine (message, args);
2016-05-26 16:06:52 +03:00
}
public void Log (string message)
{
Log (0, message);
}
public void Log (string message, params object[] args)
{
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;
2016-05-26 16:06:52 +03:00
//Console.WriteLine (message, args);
2016-05-26 16:06:52 +03:00
}
public void LogWrench (string message)
{
if (!InCI)
2016-05-26 16:06:52 +03:00
return;
Console.WriteLine (message);
}
public bool InCI {
get {
// We use the 'BUILD_REVISION' variable to detect whether we're running CI or not.
return !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("BUILD_REVISION"));
}
}
public bool UseGroupedApps {
get {
var groupApps = Environment.GetEnvironmentVariable ("BCL_GROUPED_APPS");
return string.IsNullOrEmpty (groupApps) || groupApps == "grouped";
}
}
2016-05-26 16:06:52 +03:00
public int Execute ()
{
LoadConfig ();
2016-05-26 16:06:52 +03:00
switch (Action) {
case HarnessAction.Configure:
return Configure ();
case HarnessAction.Run:
return Run ();
case HarnessAction.Install:
return Install ();
case HarnessAction.Uninstall:
return Uninstall ();
case HarnessAction.Jenkins:
return Jenkins ();
2016-05-26 16:06:52 +03:00
default:
throw new NotImplementedException (Action.ToString ());
}
}
public void Save (XmlDocument doc, string path)
{
if (!File.Exists (path)) {
doc.Save (path);
Log (1, "Created {0}", path);
} else {
var tmpPath = path + ".tmp";
doc.Save (tmpPath);
var existing = File.ReadAllText (path);
var updated = File.ReadAllText (tmpPath);
if (existing == updated) {
File.Delete (tmpPath);
Log (1, "Not saved {0}, no change", path);
} else {
File.Delete (path);
File.Move (tmpPath, path);
Log (1, "Updated {0}", path);
}
}
}
public void Save (StringWriter doc, string path)
{
if (!File.Exists (path)) {
File.WriteAllText (path, doc.ToString ());
Log (1, "Created {0}", path);
} else {
var existing = File.ReadAllText (path);
var updated = doc.ToString ();
if (existing == updated) {
Log (1, "Not saved {0}, no change", path);
} else {
File.WriteAllText (path, updated);
Log (1, "Updated {0}", path);
}
}
}
bool? disable_watchos_on_wrench;
public bool DisableWatchOSOnWrench {
get {
if (!disable_watchos_on_wrench.HasValue)
disable_watchos_on_wrench = !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("DISABLE_WATCH_ON_WRENCH"));
return disable_watchos_on_wrench.Value;
}
}
public Task<ProcessExecutionResult> ExecuteXcodeCommandAsync (string executable, IList<string> args, ILog log, TimeSpan timeout)
{
return ProcessManager.ExecuteCommandAsync (Path.Combine (XcodeRoot, "Contents", "Developer", "usr", "bin", executable), args, log, timeout: timeout);
}
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 {
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
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;
}
2016-05-26 16:06:52 +03:00
}
}