diff --git a/mk/xamarin.mk b/mk/xamarin.mk index 537af408111..1dc19353839 100644 --- a/mk/xamarin.mk +++ b/mk/xamarin.mk @@ -1,5 +1,5 @@ # Available versions can be seen here: # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/Microsoft.Tools.Mlaunch/versions -MLAUNCH_NUGET_VERSION=1.1.113 +MLAUNCH_NUGET_VERSION=1.1.115 # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/AppleDocReader/versions ADR_NUGET_VERSION=1.0.0 diff --git a/tests/common/DotNet.cs b/tests/common/DotNet.cs index 1f7a5c73e86..5ee58a7720b 100644 --- a/tests/common/DotNet.cs +++ b/tests/common/DotNet.cs @@ -222,6 +222,7 @@ public static ExecutionResult Execute (string verb, string project, Dictionary (); args.Add (verb); args.Add (project); @@ -288,11 +289,15 @@ public static ExecutionResult Execute (string verb, string project, Dictionary", " true\n "); + File.WriteAllText (proj, csproj); + + // Replace generated tests with a single passing test + var testFile = Path.Combine (outputDir, "Test1.cs"); + File.WriteAllText (testFile, $@"namespace {template}; + +[TestClass] +public sealed class Test1 {{ + [TestMethod] + public void TestMethod1 () + {{ + }} +}} +"); + + // Boot a simulator so that ComputeRunArguments can find a device + var deviceUdid = GetDeviceUdid (platform); + BootSimulator (deviceUdid); + + // Run 'dotnet test' directly using Execution.RunAsync. + // dotnet test's MTP flow doesn't forward /p: properties to its internal + // ComputeRunArguments MSBuild API call, so properties must be in the csproj. + var env = new Dictionary (); + env ["MSBuildSDKsPath"] = null; + env ["MSBUILD_EXE_PATH"] = null; + var binlog = Path.Combine (outputDir, "log-test.binlog"); + var testArgs = new List { "test", proj, $"/bl:{binlog}" }; + var testResult = Execution.RunAsync (DotNet.Executable, testArgs, env, Console.Out, workingDirectory: outputDir, timeout: TimeSpan.FromMinutes (10)).Result; + Assert.That (testResult.ExitCode, Is.EqualTo (0), $"'dotnet test' failed with exit code {testResult.ExitCode}.\nBinlog: {binlog}\nOutput:\n{testResult.Output.MergedOutput}"); + } + + static string GetDeviceUdid (ApplePlatform platform) + { + // Use xcrun simctl directly to find available simulator devices. + var rv = Execution.RunAsync ("xcrun", new List { "simctl", "list", "devices", "available", "--json" }, timeout: TimeSpan.FromMinutes (1)).Result; + Assert.That (rv.ExitCode, Is.EqualTo (0), $"Failed to list simulators. Output:\n{rv.Output.MergedOutput}"); + + var runtimePrefix = platform switch { + ApplePlatform.iOS => "com.apple.CoreSimulator.SimRuntime.iOS-", + ApplePlatform.TVOS => "com.apple.CoreSimulator.SimRuntime.tvOS-", + _ => throw new ArgumentException ($"Unsupported platform: {platform}"), + }; + + var doc = JsonDocument.Parse (rv.Output.MergedOutput); + var devicesObj = doc.RootElement.GetProperty ("devices"); + var allDevices = new List<(string Udid, string Runtime)> (); + foreach (var runtimeProp in devicesObj.EnumerateObject ()) { + if (!runtimeProp.Name.StartsWith (runtimePrefix, StringComparison.Ordinal)) + continue; + foreach (var device in runtimeProp.Value.EnumerateArray ()) { + var udid = device.GetProperty ("udid").GetString ()!; + allDevices.Add ((udid, runtimeProp.Name)); + } + } + + Assert.That (allDevices, Is.Not.Empty, $"No {platform} simulators found. Output:\n{rv.Output.MergedOutput}"); + // Pick the last runtime (highest version) and first device + return allDevices.OrderByDescending (d => d.Runtime).First ().Udid; + } + + static void BootSimulator (string udid) + { + var rv = Execution.RunAsync ("xcrun", new List { "simctl", "boot", udid }, timeout: TimeSpan.FromMinutes (1)).Result; + // Exit code 149 means "already booted", which is fine + if (rv.ExitCode != 0 && rv.ExitCode != 149) + Assert.Fail ($"Failed to boot simulator {udid}. Exit code: {rv.ExitCode}\nOutput:\n{rv.Output.MergedOutput}"); + } + } +}