From 9ac3360f11a5ed09179b01b24ca2d2f64b8f647d Mon Sep 17 00:00:00 2001 From: Premek Vysoky Date: Thu, 13 Aug 2020 14:26:05 +0200 Subject: [PATCH 1/3] [xharness] Do not mark DeviceLoaders as loaded when loading fails --- .../Hardware/DevicesTest.cs | 49 +++++++++++++++++-- .../Hardware/SimulatorsTest.cs | 37 ++++++++++++-- .../Hardware/HardwareDeviceLoader.cs | 4 +- .../Hardware/SimulatorLoader.cs | 3 +- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/DevicesTest.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/DevicesTest.cs index 160b5c99438e..59fb022b1993 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/DevicesTest.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/DevicesTest.cs @@ -113,10 +113,53 @@ public async Task LoadAsyncProcessSuccess (bool extraData) Assert.AreEqual (0, devices.ConnectedTV.Count ()); } - private void AssertArgumentValue (MlaunchArgument arg, string expected, string message = null) + [Test] + public async Task FindAndCacheDevicesWithFailingMlaunchTest () { - var value = arg.AsCommandLineArgument ().Split (new char [] { '=' }, 2).LastOrDefault (); - Assert.AreEqual (expected, value, message); + string processPath = null; + MlaunchArguments passedArguments = null; + + // Moq.SetupSequence doesn't allow custom callbacks so we need to count ourselves + var calls = 0; + + // moq It.Is is not working as nicelly as we would like it, we capture data and use asserts + processManager.Setup (p => p.RunAsync (It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny (), It.IsAny> (), It.IsAny (), It.IsAny ())) + .Returns, CancellationToken?, bool?> ((p, args, log, t, env, token, d) => { + calls++; + + if (calls == 1) { + // Mlaunch can sometimes time out and we are testing that a subsequent Load will trigger it again + return Task.FromResult (new ProcessExecutionResult { ExitCode = 137, TimedOut = true }); + } + + processPath = p.StartInfo.FileName; + passedArguments = args; + + // we get the temp file that was passed as the args, and write our sample xml, which will be parsed to get the devices :) + var tempPath = args.Where (a => a is ListDevicesArgument).First ().AsCommandLineArgument (); + tempPath = tempPath.Substring (tempPath.IndexOf ('=') + 1).Replace ("\"", string.Empty); + + var name = GetType ().Assembly.GetManifestResourceNames ().Where (a => a.EndsWith ("devices.xml", StringComparison.Ordinal)).FirstOrDefault (); + using (var outputStream = new StreamWriter (tempPath)) + using (var sampleStream = new StreamReader (GetType ().Assembly.GetManifestResourceStream (name))) { + string line; + while ((line = sampleStream.ReadLine ()) != null) + outputStream.WriteLine (line); + } + return Task.FromResult (new ProcessExecutionResult { ExitCode = 0, TimedOut = false }); + }); + + Assert.ThrowsAsync (async () => await devices.LoadDevices (executionLog.Object)); + + Assert.IsEmpty (devices.ConnectedDevices); + Assert.AreEqual (1, calls); + await devices.LoadDevices (executionLog.Object); + Assert.AreEqual (2, calls); + Assert.IsNotEmpty (devices.ConnectedDevices); + await devices.LoadDevices (executionLog.Object); + Assert.AreEqual (2, calls); + await devices.LoadDevices (executionLog.Object); + Assert.AreEqual (2, calls); } } } diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/SimulatorsTest.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/SimulatorsTest.cs index ca763bd44758..8bee89e42d73 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/SimulatorsTest.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Hardware/SimulatorsTest.cs @@ -149,10 +149,41 @@ public async Task FindAsyncDoNotCreateTest (TestTarget target, int expected) Assert.AreEqual (expected, sims.Count (), $"{target} simulators count"); } - private void AssertArgumentValue (MlaunchArgument arg, string expected, string message = null) + [Test] + public async Task FindAndCacheSimulatorsWithFailingMlaunchTest () { - var value = arg.AsCommandLineArgument ().Split (new char [] { '=' }, 2).LastOrDefault (); - Assert.AreEqual (expected, value, message); + // Moq.SetupSequence doesn't allow custom callbacks so we need to count ourselves + var calls = 0; + + processManager + .Setup (p => p.RunAsync (It.IsAny(), It.Is (args => args.Any (a => a is ListSimulatorsArgument)), It.IsAny (), It.IsAny (), It.IsAny> (), It.IsAny (), It.IsAny ())) + .Returns, CancellationToken?, bool?> ((process, args, log, t, env, token, diagnostics) => { + calls++; + + if (calls == 1) { + // Mlaunch can sometimes time out and we are testing that a subsequent Load will trigger it again + return Task.FromResult (new ProcessExecutionResult { ExitCode = 137, TimedOut = true }); + } + + // We get the temp file that was passed as the args, and write our sample xml, which will be parsed to get the devices + var tempPath = args.Where (a => a is ListSimulatorsArgument).First ().AsCommandLineArgument (); + tempPath = tempPath.Substring (tempPath.IndexOf ('=') + 1).Replace ("\"", string.Empty); + + CopySampleData (tempPath); + return Task.FromResult (new ProcessExecutionResult { ExitCode = 0, TimedOut = false }); + }); + + Assert.ThrowsAsync (async () => await simulators.LoadDevices (executionLog.Object)); + + Assert.IsEmpty (simulators.AvailableDevices); + Assert.AreEqual (1, calls); + await simulators.LoadDevices (executionLog.Object); + Assert.AreEqual (2, calls); + Assert.IsNotEmpty (simulators.AvailableDevices); + await simulators.LoadDevices (executionLog.Object); + Assert.AreEqual (2, calls); + await simulators.LoadDevices (executionLog.Object); + Assert.AreEqual (2, calls); } } } diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs index 3899c82fd0df..7e752256e282 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs @@ -52,8 +52,6 @@ public async Task LoadDevices (ILog log, bool includeLocked = false, bool forceR connectedDevices.Reset (); } - loaded = true; - var tmpfile = Path.GetTempFileName (); try { using (var process = new Process ()) { @@ -92,6 +90,8 @@ public async Task LoadDevices (ILog log, bool includeLocked = false, bool forceR } connectedDevices.Add (d); } + + loaded = true; } } finally { connectedDevices.SetCompleted (); diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/SimulatorLoader.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/SimulatorLoader.cs index b65659cbbd4e..6b86af262d55 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/SimulatorLoader.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/SimulatorLoader.cs @@ -49,7 +49,6 @@ public async Task LoadDevices (ILog log, bool includeLocked = false, bool forceR available_devices.Reset (); available_device_pairs.Reset (); } - loaded = true; await Task.Run (async () => { var tmpfile = Path.GetTempFileName (); @@ -115,6 +114,8 @@ await Task.Run (async () => { }); } } + + loaded = true; } finally { supported_runtimes.SetCompleted (); supported_device_types.SetCompleted (); From 065be7fa8b9e5b157720145a885b9cd390a54f0f Mon Sep 17 00:00:00 2001 From: Premek Vysoky Date: Fri, 14 Aug 2020 16:36:42 +0200 Subject: [PATCH 2/3] Add semaphore to HW device loader too --- .../Hardware/HardwareDeviceLoader.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs index 7e752256e282..15a3b7d9d3c2 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs @@ -27,6 +27,7 @@ public interface IHardwareDeviceLoader : IDeviceLoader { } public class HardwareDeviceLoader : IHardwareDeviceLoader { + readonly SemaphoreSlim semaphore = new SemaphoreSlim (1); readonly IProcessManager processManager; bool loaded; @@ -46,9 +47,13 @@ public HardwareDeviceLoader (IProcessManager processManager) public async Task LoadDevices (ILog log, bool includeLocked = false, bool forceRefresh = false, bool listExtraData = false) { + await semaphore.WaitAsync (); + if (loaded) { - if (!forceRefresh) + if (!forceRefresh) { + semaphore.Release (); return; + } connectedDevices.Reset (); } @@ -97,6 +102,7 @@ public async Task LoadDevices (ILog log, bool includeLocked = false, bool forceR connectedDevices.SetCompleted (); File.Delete (tmpfile); log.Flush (); + semaphore.Release (); } } From 6ed17cd1e0d9a202d07ea853ab459fd6a067fcc5 Mon Sep 17 00:00:00 2001 From: Premek Vysoky Date: Fri, 14 Aug 2020 18:01:24 +0200 Subject: [PATCH 3/3] Fix compile issue --- .../Hardware/HardwareDeviceLoader.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs index 15a3b7d9d3c2..ba9b3feca58b 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Hardware/HardwareDeviceLoader.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Xml; using Microsoft.DotNet.XHarness.iOS.Shared.Collections;