xamarin-macios/tests/xharness/Jenkins/TestVariationsFactory.cs

277 строки
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.DotNet.XHarness.Common.Execution;
using Microsoft.DotNet.XHarness.iOS.Shared;
using Microsoft.DotNet.XHarness.iOS.Shared.Hardware;
using Microsoft.DotNet.XHarness.iOS.Shared.Utilities;
using Xharness.Jenkins.TestTasks;
namespace Xharness.Jenkins {
interface ITestVariationsFactory {
IEnumerable<T> CreateTestVariations<T> (IEnumerable<T> tests, Func<MSBuildTask, T, IEnumerable<IDevice>, T> creator) where T : RunTestTask;
}
class TestVariationsFactory : ITestVariationsFactory {
readonly Jenkins jenkins;
readonly IProcessManager processManager;
public TestVariationsFactory (Jenkins jenkins, IProcessManager processManager)
{
this.jenkins = jenkins ?? throw new ArgumentNullException (nameof (jenkins));
this.processManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
}
IEnumerable<TestData> GetTestData (RunTestTask test)
{
// This function returns additional test configurations (in addition to the default one) for the specific test
// 32-bit interpreter doesn't work yet: https://github.com/mono/mono/issues/9871
var supports_interpreter = test.Platform != TestPlatform.iOS_Unified32;
var supports_dynamic_registrar_on_device = test.Platform == TestPlatform.iOS_Unified64 || test.Platform == TestPlatform.tvOS;
var ignore = test.TestProject.Ignore;
var mac_supports_arm64 = Harness.CanRunArm64;
var arm64_runtime_identifier = string.Empty;
if (test.Platform == TestPlatform.Mac) {
arm64_runtime_identifier = "osx-arm64";
} else if (test.Platform == TestPlatform.MacCatalyst) {
arm64_runtime_identifier = "maccatalyst-arm64";
}
switch (test.ProjectPlatform) {
case "iPhone":
// arm64_32 is only supported for Release builds for now.
// arm32 bits too big for debug builds - https://github.com/xamarin/maccore/issues/2080
var supports_debug = test.Platform != TestPlatform.watchOS_64_32 && !(test.TestName == "dont link" && test.Platform == TestPlatform.iOS_Unified32);
/* we don't add --assembly-build-target=@all=staticobject because that's the default in all our test projects */
if (supports_debug && !test.TestProject.IsDotNetProject) {
yield return new TestData { Variation = "AssemblyBuildTarget: dylib (debug)", MTouchExtraArgs = $"--assembly-build-target=@all=dynamiclibrary {test.TestProject.MTouchExtraArgs}", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Dynamic, Ignored = ignore };
yield return new TestData { Variation = "AssemblyBuildTarget: SDK framework (debug)", MTouchExtraArgs = $"--assembly-build-target=@sdk=framework=Xamarin.Sdk --assembly-build-target=@all=staticobject {test.TestProject.MTouchExtraArgs}", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, Ignored = ignore };
yield return new TestData { Variation = "AssemblyBuildTarget: dylib (debug, profiling)", MTouchExtraArgs = $"--assembly-build-target=@all=dynamiclibrary {test.TestProject.MTouchExtraArgs}", Debug = true, Profiling = true, MonoNativeLinkMode = MonoNativeLinkMode.Dynamic, Ignored = ignore };
yield return new TestData { Variation = "AssemblyBuildTarget: SDK framework (debug, profiling)", MTouchExtraArgs = $"--assembly-build-target=@sdk=framework=Xamarin.Sdk --assembly-build-target=@all=staticobject {test.TestProject.MTouchExtraArgs}", Debug = true, Profiling = true, MonoNativeLinkMode = MonoNativeLinkMode.Static, Ignored = ignore };
}
if (test.ProjectConfiguration.Contains ("Debug"))
yield return new TestData { Variation = "Release", MTouchExtraArgs = test.TestProject.MTouchExtraArgs, Debug = false, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static };
if (test.Platform == TestPlatform.iOS_Unified32 && !test.TestProject.IsDotNetProject)
yield return new TestData { Variation = "Release: UseThumb", MTouchExtraArgs = test.TestProject.MTouchExtraArgs, Debug = false, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, UseThumb = true };
// Disable this by default for tvOS/Release because the app ends up being too big (https://github.com/xamarin/maccore/issues/2282)
var sdk_release_skip = test.Platform == TestPlatform.tvOS && test.TestName == "dont link";
sdk_release_skip = sdk_release_skip || test.TestProject.IsDotNetProject;
if (!sdk_release_skip)
yield return new TestData { Variation = "AssemblyBuildTarget: SDK framework (release)", MTouchExtraArgs = $"--assembly-build-target=@sdk=framework=Xamarin.Sdk --assembly-build-target=@all=staticobject {test.TestProject.MTouchExtraArgs}", Debug = false, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, };
switch (test.TestName) {
case "monotouch-test":
if (test.TestProject.IsDotNetProject)
ignore = true;
if (supports_dynamic_registrar_on_device)
yield return new TestData { Variation = "Debug (dynamic registrar)", MTouchExtraArgs = "--registrar:dynamic", Debug = true, Profiling = false, Ignored = ignore };
yield return new TestData { Variation = "Release (all optimizations)", MTouchExtraArgs = "--registrar:static --optimize:all", Debug = false, Profiling = false, Defines = "OPTIMIZEALL", Ignored = ignore };
if (supports_debug) {
yield return new TestData { Variation = "Debug (all optimizations)", MTouchExtraArgs = "--registrar:static --optimize:all", Debug = true, Profiling = false, Defines = "OPTIMIZEALL", Ignored = ignore };
yield return new TestData { Variation = "Debug: SGenConc", MTouchExtraArgs = "", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, EnableSGenConc = true, Ignored = ignore };
}
if (supports_interpreter) {
if (supports_debug) {
yield return new TestData { Variation = "Debug (interpreter)", MTouchExtraArgs = "--interpreter", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME", Ignored = ignore };
yield return new TestData { Variation = "Debug (interpreter -mscorlib)", MTouchExtraArgs = "--interpreter=-mscorlib", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME", Ignored = ignore };
}
yield return new TestData { Variation = "Release (interpreter -mscorlib)", MTouchExtraArgs = "--interpreter=-mscorlib", Debug = false, Profiling = false, Undefines = "FULL_AOT_RUNTIME", Ignored = ignore };
}
if (test.TestProject.IsDotNetProject)
yield return new TestData { Variation = "Release (LLVM)", Debug = false, UseLlvm = true, Ignored = ignore };
break;
case string name when name.StartsWith ("mscorlib", StringComparison.Ordinal):
if (supports_debug)
yield return new TestData { Variation = "Debug: SGenConc", MTouchExtraArgs = "", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, EnableSGenConc = true};
if (supports_interpreter) {
if (supports_debug) {
yield return new TestData { Variation = "Debug (interpreter)", MTouchExtraArgs = "--interpreter", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME", KnownFailure = new KnownIssue ("#1683", issueLink: "https://github.com/xamarin/maccore/issues/1683") };
yield return new TestData { Variation = "Debug (interpreter -mscorlib)", MTouchExtraArgs = "--interpreter=-mscorlib", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME", KnownFailure = new KnownIssue ("#1682", issueLink: "https://github.com/xamarin/maccore/issues/1682") };
}
yield return new TestData { Variation = "Release (interpreter -mscorlib)", MTouchExtraArgs = "--interpreter=-mscorlib", Debug = false, Profiling = false, Undefines = "FULL_AOT_RUNTIME", KnownFailure = new KnownIssue ("#1682", issueLink: "https://github.com/xamarin/maccore/issues/1682") };
}
break;
}
break;
case "iPhoneSimulator":
if (test.Platform == TestPlatform.iOS_Unified32)
ignore = true;
switch (test.TestName) {
case "monotouch-test":
// The default is to run monotouch-test with the dynamic registrar (in the simulator), so that's already covered
yield return new TestData { Variation = "Debug (LinkSdk)", Debug = true, Profiling = false, LinkMode = test.TestProject.IsDotNetProject ? "SdkOnly" : "LinkSdk", Ignored = ignore };
yield return new TestData { Variation = "Debug (static registrar)", MTouchExtraArgs = "--registrar:static", Debug = true, Profiling = false, Undefines = "DYNAMIC_REGISTRAR", Ignored = ignore };
yield return new TestData { Variation = "Release (all optimizations)", MTouchExtraArgs = "--registrar:static --optimize:all", Debug = false, Profiling = false, LinkMode = "Full", Defines = "OPTIMIZEALL", Undefines = "DYNAMIC_REGISTRAR", Ignored = ignore };
yield return new TestData { Variation = "Debug (all optimizations)", MTouchExtraArgs = "--registrar:static --optimize:all,-remove-uithread-checks", Debug = true, Profiling = false, LinkMode = "Full", Defines = "OPTIMIZEALL", Undefines = "DYNAMIC_REGISTRAR", Ignored = ignore ?? !jenkins.IncludeAll };
break;
case "introspection":
foreach (var target in test.Platform.GetAppRunnerTargets ())
yield return new TestData {
Variation = $"Debug ({test.Platform.GetSimulatorMinVersion ()})",
Debug = true,
Candidates = jenkins.Simulators.SelectDevices (target.GetTargetOs (true), jenkins.SimulatorLoadLog, true),
Ignored = ignore ?? !jenkins.IncludeOldSimulatorTests,
};
break;
}
break;
case "AnyCPU":
case "x86":
switch (test.TestName) {
case "monotouch-test":
if (test.TestProject.IsDotNetProject) {
yield return new TestData { Variation = "Debug (ARM64)", Debug = true, Profiling = false, Ignored = !jenkins.IncludeMac || !mac_supports_arm64, RuntimeIdentifier = arm64_runtime_identifier, };
if (test.Platform != TestPlatform.MacCatalyst) {
yield return new TestData { Variation = "Debug (static registrar)", MonoBundlingExtraArgs = "--registrar:static", Debug = true, Undefines = "DYNAMIC_REGISTRAR", Ignored = !jenkins.IncludeMac, };
yield return new TestData { Variation = "Debug (static registrar, ARM64)", MonoBundlingExtraArgs = "--registrar:static", Debug = true, Undefines = "DYNAMIC_REGISTRAR", Profiling = false, Ignored = !jenkins.IncludeMac || !mac_supports_arm64, RuntimeIdentifier = arm64_runtime_identifier, };
}
if (test.Platform == TestPlatform.MacCatalyst)
yield return new TestData { Variation = "Release (ARM64, LLVM)", Debug = false, UseLlvm = true, Ignored = !jenkins.IncludeMacCatalyst || !mac_supports_arm64, RuntimeIdentifier = arm64_runtime_identifier };
}
break;
case "xammac tests":
switch (test.ProjectConfiguration) {
case "Release":
yield return new TestData { Variation = "Release (all optimizations)", MonoBundlingExtraArgs = "--registrar:static --optimize:all", Debug = false, LinkMode = "Full", Defines = "OPTIMIZEALL", Undefines = "DYNAMIC_REGISTRAR" };
yield return new TestData { Variation = "Release (ARM64)", XamMacArch = "ARM64", Debug = false, Ignored = !mac_supports_arm64 || !jenkins.IncludeMac };
break;
case "Debug":
yield return new TestData { Variation = "Debug (all optimizations)", MonoBundlingExtraArgs = "--registrar:static --optimize:all,-remove-uithread-checks", Debug = true, LinkMode = "Full", Defines = "OPTIMIZEALL", Undefines = "DYNAMIC_REGISTRAR", Ignored = !(jenkins.IncludeAll && jenkins.IncludeMac) };
yield return new TestData { Variation = "Debug (ARM64)", XamMacArch = "ARM64", Debug = true, Ignored = !mac_supports_arm64 || !jenkins.IncludeMac };
break;
}
break;
}
break;
default:
throw new NotImplementedException (test.ProjectPlatform);
}
}
public IEnumerable<T> CreateTestVariations<T> (IEnumerable<T> tests, Func<MSBuildTask, T, IEnumerable<IDevice>, T> creator) where T : RunTestTask
{
foreach (var task in tests) {
if (string.IsNullOrEmpty (task.Variation))
task.Variation = task.ProjectConfiguration.Contains ("Debug") ? "Debug" : "Release";
if (task.TestProject.IsDotNetProject)
task.Variation += " [dotnet]";
}
var rv = new List<T> (tests);
foreach (var task in tests.ToArray ()) {
foreach (var test_data in GetTestData (task)) {
var variation = test_data.Variation;
var mtouch_extra_args = test_data.MTouchExtraArgs;
var bundling_extra_args = test_data.MonoBundlingExtraArgs;
var configuration = test_data.Debug ? task.ProjectConfiguration : task.ProjectConfiguration.Replace ("Debug", "Release");
var debug = test_data.Debug;
var profiling = test_data.Profiling;
var link_mode = test_data.LinkMode;
var defines = test_data.Defines;
var undefines = test_data.Undefines;
var ignored = test_data.Ignored;
var known_failure = test_data.KnownFailure;
var candidates = test_data.Candidates;
var use_mono_runtime = test_data.UseMonoRuntime;
var xammac_arch = test_data.XamMacArch;
var runtime_identifer = test_data.RuntimeIdentifier;
var use_llvm = test_data.UseLlvm;
if (task.TestProject.IsDotNetProject)
variation += " [dotnet]";
if (known_failure is not null)
ignored = true;
var clone = task.TestProject.Clone ();
var clone_task = Task.Run (async () => {
await task.BuildTask.InitialTask; // this is the project cloning above
await clone.CreateCopyAsync (jenkins.MainLog, processManager, task, HarnessConfiguration.RootDirectory);
var isMac = task.Platform.IsMac ();
var canSymlink = task.Platform.CanSymlink();
if (!string.IsNullOrEmpty (mtouch_extra_args))
clone.Xml.AddExtraMtouchArgs (mtouch_extra_args, task.ProjectPlatform, configuration);
if (!string.IsNullOrEmpty (bundling_extra_args))
clone.Xml.AddMonoBundlingExtraArgs (bundling_extra_args, task.ProjectPlatform, configuration);
if (!string.IsNullOrEmpty (link_mode))
clone.Xml.SetNode (isMac ? "LinkMode" : "MtouchLink", link_mode, task.ProjectPlatform, configuration);
if (!string.IsNullOrEmpty (defines)) {
clone.Xml.AddAdditionalDefines (defines, task.ProjectPlatform, configuration);
if (clone.ProjectReferences != null) {
foreach (var pr in clone.ProjectReferences) {
pr.Xml.AddAdditionalDefines (defines, task.ProjectPlatform, configuration);
pr.Xml.Save (pr.Path);
}
}
}
if (!string.IsNullOrEmpty (undefines)) {
clone.Xml.RemoveDefines (undefines, task.ProjectPlatform, configuration);
if (clone.ProjectReferences != null) {
foreach (var pr in clone.ProjectReferences) {
pr.Xml.RemoveDefines (undefines, task.ProjectPlatform, configuration);
pr.Xml.Save (pr.Path);
}
}
}
clone.Xml.SetNode (isMac ? "Profiling" : "MTouchProfiling", profiling ? "True" : "False", task.ProjectPlatform, configuration);
if (test_data.MonoNativeLinkMode != MonoNativeLinkMode.None) {
var mono_native_link = test_data.MonoNativeLinkMode;
if (!canSymlink && mono_native_link == MonoNativeLinkMode.Symlink)
mono_native_link = MonoNativeLinkMode.Static;
MonoNativeHelper.AddProjectDefines (clone.Xml, mono_native_link);
}
if (test_data.EnableSGenConc)
clone.Xml.SetTopLevelPropertyGroupValue ("EnableSGenConc", "true");
if (test_data.UseThumb) // no need to check the platform, already done at the data iterator
clone.Xml.SetNode ("MtouchUseThumb", "true", task.ProjectPlatform, configuration);
if (use_llvm)
clone.Xml.SetTopLevelPropertyGroupValue ("MtouchUseLlvm", "true");
if (!debug && !isMac)
clone.Xml.SetMtouchUseLlvm (true, task.ProjectPlatform, configuration);
if (use_mono_runtime.HasValue)
clone.Xml.SetTopLevelPropertyGroupValue ("UseMonoRuntime", use_mono_runtime.Value ? "true" : "false");
if (!string.IsNullOrEmpty (xammac_arch))
clone.Xml.SetNode ("XamMacArch", xammac_arch, task.ProjectPlatform, configuration);
if (!string.IsNullOrEmpty (runtime_identifer))
clone.Xml.SetTopLevelPropertyGroupValue ("RuntimeIdentifier", runtime_identifer);
clone.Xml.Save (clone.Path);
});
ignored |= clone.IsDotNetProject && !jenkins.IncludeDotNet;
var build = new MSBuildTask (jenkins: jenkins, testProject: clone, processManager: processManager);
build.ProjectConfiguration = configuration;
build.ProjectPlatform = task.ProjectPlatform;
build.Platform = task.Platform;
build.InitialTask = clone_task;
build.TestName = clone.Name;
T newVariation = creator (build, task, candidates);
newVariation.Variation = variation;
newVariation.Ignored = ignored ?? task.Ignored;
newVariation.BuildOnly = task.BuildOnly;
newVariation.TimeoutMultiplier = task.TimeoutMultiplier;
newVariation.KnownFailure = known_failure;
rv.Add (newVariation);
}
}
return rv;
}
}
}