diff --git a/Directory.Packages.props b/Directory.Packages.props index 95201b853..c07629eab 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,7 +13,7 @@ - + diff --git a/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTester.cs b/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTester.cs index bbe640e9f..1218b5643 100644 --- a/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTester.cs +++ b/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTester.cs @@ -204,6 +204,7 @@ public AppTester( timeout, null, (level, message) => _mainLog.WriteLine(message)); + IResultFileHandler resultFileHandler = new ResultFileHandler(_processManager, _mainLog); deviceListener.ConnectedTask .TimeoutAfter(testLaunchTimeout) @@ -252,10 +253,13 @@ await RunSimulatorTests( mlaunchArguments, crashReporter, testReporter, + resultFileHandler, + deviceListener, (ISimulatorDevice)device, companionDevice as ISimulatorDevice, timeout, - cancellationToken); + cancellationToken, + runMode); } else { @@ -283,15 +287,18 @@ await RunSimulatorTests( appEndTag); await RunDeviceTests( + appInformation, mlaunchArguments, crashReporter, testReporter, + resultFileHandler, deviceListener, device, appOutputLog, timeout, extraEnvVariables, - cancellationToken); + cancellationToken, + runMode); } } @@ -305,10 +312,13 @@ private async Task RunSimulatorTests( MlaunchArguments mlaunchArguments, ICrashSnapshotReporter crashReporter, ITestReporter testReporter, + IResultFileHandler resultFileHandler, + ISimpleListener deviceListener, ISimulatorDevice simulator, ISimulatorDevice? companionSimulator, TimeSpan timeout, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + RunMode runMode) { var result = await RunSimulatorApp( appInformation, @@ -321,18 +331,36 @@ private async Task RunSimulatorTests( cancellationToken); await testReporter.CollectSimulatorResult(result); + + // On iOS 18 and later, transferring results over a TCP tunnel isn’t supported. + // Instead, copy the results file from the device to the host machine. + if (deviceListener.TestLog != null && + !await resultFileHandler.CopyResultsAsync( + runMode, + true, + simulator.OSVersion, + simulator.UDID, + appInformation.BundleIdentifier, + deviceListener.TestLog.FullPath, + cancellationToken)) + { + throw new InvalidOperationException("Failed to copy test results from simulator to host."); + } } private async Task RunDeviceTests( + AppBundleInformation appInformation, MlaunchArguments mlaunchArguments, ICrashSnapshotReporter crashReporter, ITestReporter testReporter, + IResultFileHandler resultFileHandler, ISimpleListener deviceListener, IDevice device, ILog appOutputLog, TimeSpan timeout, IEnumerable<(string, string)> extraEnvVariables, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + RunMode runMode) { var deviceSystemLog = _logs.Create($"device-{device.Name}-{_helpers.Timestamp}.log", LogType.SystemLog.ToString()); deviceSystemLog.Timestamp = false; @@ -391,6 +419,21 @@ private async Task RunDeviceTests( { _mainLog.WriteLine("Device log captured in {0}", deviceSystemLog.FullPath); } + + // On iOS 18 and later, transferring results over a TCP tunnel isn’t supported. + // Instead, copy the results file from the device to the host machine. + if (deviceListener.TestLog != null && + !await resultFileHandler.CopyResultsAsync( + runMode, + false, + device.OSVersion, + device.UDID, + appInformation.BundleIdentifier, + deviceListener.TestLog.FullPath, + cancellationToken)) + { + throw new InvalidOperationException("Failed to copy test results from device to host."); + } } /// diff --git a/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTesterFactory.cs b/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTesterFactory.cs index 46c5c33a0..111b4f846 100644 --- a/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTesterFactory.cs +++ b/src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTesterFactory.cs @@ -14,7 +14,7 @@ namespace Microsoft.DotNet.XHarness.Apple; public interface IAppTesterFactory { - IAppTester Create(CommunicationChannel communicationChannel, bool isSimulator, IFileBackedLog log, ILogs logs, Action? logCallback); + IAppTester Create(CommunicationChannel communicationChannel, bool isSimulator, IFileBackedLog log, ILogs logs, Action? logCallback, Version? osVersion); } public class AppTesterFactory : IAppTesterFactory @@ -50,9 +50,11 @@ public IAppTester Create( bool isSimulator, IFileBackedLog log, ILogs logs, - Action? logCallback) + Action? logCallback, + Version? osVersion) { - var tunnelBore = (communicationChannel == CommunicationChannel.UsbTunnel && !isSimulator) + // On iOS 18 and later, transferring results over a TCP tunnel isn’t supported. + var tunnelBore = (communicationChannel == CommunicationChannel.UsbTunnel && !isSimulator && osVersion !=null && osVersion.Major < 18) ? new TunnelBore(_processManager) : null; diff --git a/src/Microsoft.DotNet.XHarness.Apple/ExitCodeDetector.cs b/src/Microsoft.DotNet.XHarness.Apple/ExitCodeDetector.cs index 0d29deb33..750198dd9 100644 --- a/src/Microsoft.DotNet.XHarness.Apple/ExitCodeDetector.cs +++ b/src/Microsoft.DotNet.XHarness.Apple/ExitCodeDetector.cs @@ -85,7 +85,11 @@ public class iOSExitCodeDetector : ExitCodeDetector, IiOSExitCodeDetector { // Example line coming from the mlaunch log // [07:02:21.6637600] Application 'net.dot.iOS.Simulator.PInvoke.Test' terminated (with exit code '42' and/or crashing signal '). - private Regex DeviceExitCodeRegex { get; } = new Regex(@"terminated \(with exit code '(?-?[0-9]+)' and/or crashing signal", RegexOptions.Compiled); + private Regex[] DeviceExitCodeRegexes { get; } = new Regex[] + { + new Regex(@"terminated \(with exit code '(?-?[0-9]+)' and/or crashing signal", RegexOptions.Compiled), + new Regex(@"Failed to execute 'devicectl':.*returned the exit code (?\d+)\.", RegexOptions.Compiled) + }; protected override Match? IsSignalLine(AppBundleInformation appBundleInfo, string logLine) { @@ -96,7 +100,14 @@ public class iOSExitCodeDetector : ExitCodeDetector, IiOSExitCodeDetector if (logLine.Contains(appBundleInfo.BundleIdentifier)) { - return DeviceExitCodeRegex.Match(logLine); + foreach (var regex in DeviceExitCodeRegexes) + { + var m = regex.Match(logLine); + if (m.Success) + { + return m; + } + } } return null; diff --git a/src/Microsoft.DotNet.XHarness.Apple/Orchestration/RunOrchestrator.cs b/src/Microsoft.DotNet.XHarness.Apple/Orchestration/RunOrchestrator.cs index d27ab8525..79bc8499b 100644 --- a/src/Microsoft.DotNet.XHarness.Apple/Orchestration/RunOrchestrator.cs +++ b/src/Microsoft.DotNet.XHarness.Apple/Orchestration/RunOrchestrator.cs @@ -313,7 +313,9 @@ private ExitCode ParseResult( return ExitCode.TIMED_OUT; } - if (!result.Succeeded) + // On iOS 18 and later, mlaunch returns exit code 1 with the following error message: + // "Failed to execute 'devicectl': returned the exit code ." + if (!result.Succeeded && result.ExitCode != 1) { _logger.LogError($"App run has failed. mlaunch exited with {result.ExitCode}"); return ExitCode.APP_LAUNCH_FAILURE; diff --git a/src/Microsoft.DotNet.XHarness.Apple/Orchestration/TestOrchestrator.cs b/src/Microsoft.DotNet.XHarness.Apple/Orchestration/TestOrchestrator.cs index 2d2530f0f..d2766f2fb 100644 --- a/src/Microsoft.DotNet.XHarness.Apple/Orchestration/TestOrchestrator.cs +++ b/src/Microsoft.DotNet.XHarness.Apple/Orchestration/TestOrchestrator.cs @@ -214,9 +214,10 @@ private async Task ExecuteApp( bool signalAppEnd, CancellationToken cancellationToken) { + bool versionParsed = Version.TryParse(device.OSVersion, out var version); // iOS 14+ devices do not allow local network access and won't work unless the user confirms a dialog on the screen // https://developer.apple.com/forums/thread/663858 - if (Version.TryParse(device.OSVersion, out var version) && version.Major >= 14 && target.Platform.ToRunMode() == RunMode.iOS && communicationChannel == CommunicationChannel.Network) + if (versionParsed && version!.Major >= 14 && target.Platform.ToRunMode() == RunMode.iOS && communicationChannel == CommunicationChannel.Network) { _logger.LogWarning( "Applications need user permission for communication over local network on iOS 14 and newer." + Environment.NewLine + @@ -231,7 +232,7 @@ private async Task ExecuteApp( _logger.LogInformation("Starting test run for " + appBundleInfo.BundleIdentifier + ".."); - var appTester = GetAppTester(communicationChannel, target.Platform.IsSimulator()); + var appTester = GetAppTester(communicationChannel, target.Platform.IsSimulator(), version); (TestExecutingResult testResult, string resultMessage) = await appTester.TestApp( appBundleInfo, @@ -255,7 +256,7 @@ private async Task ExecuteApp( // Copy system and application logs to the main log for better failure investigation. CopyLogsToMainLog(); } - + return exitCode; } @@ -272,7 +273,7 @@ private async Task ExecuteMacCatalystApp( bool signalAppEnd, CancellationToken cancellationToken) { - var appTester = GetAppTester(communicationChannel, TestTarget.MacCatalyst.IsSimulator()); + var appTester = GetAppTester(communicationChannel, TestTarget.MacCatalyst.IsSimulator(), null); (TestExecutingResult testResult, string resultMessage) = await appTester.TestMacCatalystApp( appBundleInfo, @@ -294,12 +295,12 @@ private async Task ExecuteMacCatalystApp( return exitCode; } - private IAppTester GetAppTester(CommunicationChannel communicationChannel, bool isSimulator) + private IAppTester GetAppTester(CommunicationChannel communicationChannel, bool isSimulator, Version? osVersion) { // Only add the extra callback if we do know that the feature was indeed enabled Action? logCallback = IsLldbEnabled() ? (l) => NotifyUserLldbCommand(_logger, l) : null; - return _appTesterFactory.Create(communicationChannel, isSimulator, _mainLog, _logs, logCallback); + return _appTesterFactory.Create(communicationChannel, isSimulator, _mainLog, _logs, logCallback, osVersion); } private ExitCode ParseResult(TestExecutingResult testResult, string resultMessage, bool listenerConnected) @@ -389,7 +390,7 @@ private void CopyLogsToMainLog() { _mainLog.WriteLine($"==================== {log.Description} ===================="); _mainLog.WriteLine($"Log file: {log.FullPath}"); - + try { // Read and append log content to the main log @@ -406,7 +407,7 @@ private void CopyLogsToMainLog() { _mainLog.WriteLine($"Failed to read {log.Description}: {ex.Message}"); } - + _mainLog.WriteLine($"==================== End of {log.Description} ===================="); _mainLog.WriteLine(string.Empty); } diff --git a/src/Microsoft.DotNet.XHarness.TestRunners.Common/iOSApplicationEntryPointBase.cs b/src/Microsoft.DotNet.XHarness.TestRunners.Common/iOSApplicationEntryPointBase.cs index 0c18581d1..55825b75b 100644 --- a/src/Microsoft.DotNet.XHarness.TestRunners.Common/iOSApplicationEntryPointBase.cs +++ b/src/Microsoft.DotNet.XHarness.TestRunners.Common/iOSApplicationEntryPointBase.cs @@ -3,35 +3,58 @@ // See the LICENSE file in the project root for more information. using System; using System.Threading.Tasks; +using System.IO; #nullable enable namespace Microsoft.DotNet.XHarness.TestRunners.Common; public abstract class iOSApplicationEntryPointBase : ApplicationEntryPoint { + /// + /// Logger used for outputting logs. Defaults to Console.Out. + /// + public TextWriter? Logger = Console.Out; + + /// + /// The final path where test results in XML format will be saved. + /// + public string TestsResultsFinalPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "test-results.xml"); + public override async Task RunAsync() { var options = ApplicationOptions.Current; - TcpTextWriter? writer; - try + // On iOS 18 and later, transferring results over a TCP tunnel isn’t supported. + // Instead, copy the results file from the device to the host machine. + if (!OperatingSystem.IsMacCatalyst() && Environment.OSVersion.Version.Major >= 18) { - writer = options.UseTunnel - ? TcpTextWriter.InitializeWithTunnelConnection(options.HostPort) - : TcpTextWriter.InitializeWithDirectConnection(options.HostName, options.HostPort); + using TextWriter? resultsFileMaybe = options.EnableXml ? System.IO.File.CreateText(TestsResultsFinalPath) : null; + await InternalRunAsync(options, Logger, resultsFileMaybe); + Console.WriteLine($"Test results saved to: {TestsResultsFinalPath}"); } - catch (Exception ex) + else { - Console.WriteLine("Failed to initialize TCP writer. Continuing on console." + Environment.NewLine + ex); - writer = null; // null means we will fall back to console output - } + TcpTextWriter? writer; - using (writer) - { - var logger = (writer == null || options.EnableXml) ? new LogWriter(Device) : new LogWriter(Device, writer); - logger.MinimumLogLevel = MinimumLogLevel.Info; + try + { + writer = options.UseTunnel + ? TcpTextWriter.InitializeWithTunnelConnection(options.HostPort) + : TcpTextWriter.InitializeWithDirectConnection(options.HostName, options.HostPort); + } + catch (Exception ex) + { + Console.WriteLine("Failed to initialize TCP writer. Continuing on console." + Environment.NewLine + ex); + writer = null; // null means we will fall back to console output + } + + using (writer) + { + var logger = (writer == null || options.EnableXml) ? new LogWriter(Device) : new LogWriter(Device, writer); + logger.MinimumLogLevel = MinimumLogLevel.Info; - await InternalRunAsync(options, writer, writer); + await InternalRunAsync(options, writer, writer); + } } } } diff --git a/src/Microsoft.DotNet.XHarness.iOS.Shared/IResultFileHandler.cs b/src/Microsoft.DotNet.XHarness.iOS.Shared/IResultFileHandler.cs new file mode 100644 index 000000000..e2d88f140 --- /dev/null +++ b/src/Microsoft.DotNet.XHarness.iOS.Shared/IResultFileHandler.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; + +#nullable enable +namespace Microsoft.DotNet.XHarness.iOS.Shared; + +public interface IResultFileHandler +{ + /// + /// Copy the XML results file from the app container (simulator or device) to the host path. + /// + Task CopyResultsAsync( + RunMode runMode, + bool isSimulator, + string osVersion, + string udid, + string bundleIdentifier, + string hostDestinationPath, + CancellationToken token); +} diff --git a/src/Microsoft.DotNet.XHarness.iOS.Shared/ResultFileHandler.cs b/src/Microsoft.DotNet.XHarness.iOS.Shared/ResultFileHandler.cs new file mode 100644 index 000000000..c4640ee23 --- /dev/null +++ b/src/Microsoft.DotNet.XHarness.iOS.Shared/ResultFileHandler.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.XHarness.Common.Logging; +using Microsoft.DotNet.XHarness.iOS.Shared.Execution; + +#nullable enable +namespace Microsoft.DotNet.XHarness.iOS.Shared; + +public class ResultFileHandler : IResultFileHandler +{ + private IMlaunchProcessManager _processManager; + private IFileBackedLog _mainLog; + + public ResultFileHandler(IMlaunchProcessManager pm, IFileBackedLog fs) + { + _processManager = pm; + _mainLog = fs; + } + + public async Task CopyResultsAsync( + RunMode runMode, + bool isSimulator, + string osVersion, + string udid, + string bundleIdentifier, + string hostDestinationPath, + CancellationToken token) + { + // This file path is set in iOSApplicationEntryPointBase + string sourcePath = runMode == RunMode.iOS + ? "/Documents/test-results.xml" + : "/Library/Caches/Documents/test-results.xml"; + + if (isSimulator) + { + // Version format contains string like "Simulator 18.0". + string [] osVersionParts = osVersion.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (osVersionParts.Length < 2) + { + _mainLog.WriteLine("Simulator OS version is not in the expected format, skipping result copying."); + return false; + } + + if (!Version.TryParse(osVersionParts[1], out Version osVersionParsed)) + { + _mainLog.WriteLine("Simulator OS version is not in the expected format, skipping result copying."); + return false; + } + + if (osVersionParsed.Major >= 18) + { + + string cmd = $"cp \"$(xcrun simctl get_app_container {udid} {bundleIdentifier} data){sourcePath}\" \"{hostDestinationPath}\""; + + await _processManager.ExecuteCommandAsync( + "/bin/bash", + new[] { "-c", cmd }, + _mainLog, + _mainLog, + _mainLog, + TimeSpan.FromMinutes(1), + null, + cancellationToken: token); + + if (!File.Exists(hostDestinationPath)) + { + _mainLog.WriteLine($"Failed to copy results file from simulator. Expected at: {hostDestinationPath}"); + return false; + } + } + + return true; + } + else + { + if (!Version.TryParse(osVersion, out Version osVersionParsed)) + { + _mainLog.WriteLine($"Device OS version is not in the expected format, skipping result copying."); + return false; + } + + if (osVersionParsed.Major >= 18) + { + string cmd = $"xcrun devicectl device copy from --device {udid} --source {sourcePath} --destination {hostDestinationPath} --domain-type appDataContainer --domain-identifier {bundleIdentifier}"; + await _processManager.ExecuteCommandAsync( + "/bin/bash", + new List { "-c", cmd }, + _mainLog, + _mainLog, + _mainLog, + TimeSpan.FromMinutes(1), + null, + cancellationToken: token); + + if (!File.Exists(hostDestinationPath)) + { + _mainLog.WriteLine($"Failed to copy results file from device. Expected at: {hostDestinationPath}"); + return false; + } + } + + return true; + } + } +} diff --git a/tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests.csproj b/tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests.csproj index 01307fd06..ef11c8698 100644 --- a/tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests.csproj +++ b/tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests.csproj @@ -53,7 +53,7 @@ - + diff --git a/tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests/ResultFileHandlerTests.cs b/tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests/ResultFileHandlerTests.cs new file mode 100644 index 000000000..7bd403e35 --- /dev/null +++ b/tests/Microsoft.DotNet.XHarness.iOS.Shared.Tests/ResultFileHandlerTests.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.XHarness.Common.Logging; +using Microsoft.DotNet.XHarness.iOS.Shared.Execution; +using Moq; +using Xunit; + +namespace Microsoft.DotNet.XHarness.iOS.Shared.Tests; + +public class ResultFileHandlerTests : IDisposable +{ + private readonly string _tempFile; + + public ResultFileHandlerTests() + { + _tempFile = Path.GetTempFileName(); + } + + public void Dispose() + { + if (File.Exists(_tempFile)) + { + File.Delete(_tempFile); + } + } + + private static ResultFileHandler CreateHandler( + Mock processManagerMock, + Mock logMock) + { + return new ResultFileHandler(processManagerMock.Object, logMock.Object); + } + + [Fact] + public async Task SimulatorBadOsVersionFormatReturnsFalse() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, true, "Simulator", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.False(result); + log.Verify(l => l.WriteLine("Simulator OS version is not in the expected format, skipping result copying."), Times.Once); + } + + [Fact] + public async Task SimulatorBadOsVersionNumberReturnsFalse() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, true, "Simulator notanumber", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.False(result); + log.Verify(l => l.WriteLine("Simulator OS version is not in the expected format, skipping result copying."), Times.Once); + } + + [Fact] + public async Task SimulatorOsVersionLessThan18ReturnsFalse() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, true, "Simulator 17.4", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.True(result); + } + + [Fact] + public async Task SimulatorOsVersion18FileExistsReturnsTrue() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + File.WriteAllText(_tempFile, "dummy"); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, true, "Simulator 18.0", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.True(result); + } + + [Fact] + public async Task SimulatorOsVersion18FileMissingReturnsFalse() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + if (File.Exists(_tempFile)) + File.Delete(_tempFile); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, true, "Simulator 18.0", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.False(result); + log.Verify(l => l.WriteLine($"Failed to copy results file from simulator. Expected at: {_tempFile}"), Times.Once); + } + + [Fact] + public async Task DeviceBadOsVersionFormatReturnsFalse() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, false, "notanumber", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.False(result); + log.Verify(l => l.WriteLine("Device OS version is not in the expected format, skipping result copying."), Times.Once); + } + + [Fact] + public async Task DeviceOsVersionLessThan18ReturnsTrue() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, false, "17.4", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.True(result); + } + + [Fact] + public async Task DeviceOsVersion18FileExistsReturnsTrue() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + File.WriteAllText(_tempFile, "dummy"); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, false, "18.0", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.True(result); + } + + [Fact] + public async Task DeviceOsVersion18FileMissingReturnsFalse() + { + Mock pm = new Mock(); + Mock log = new Mock(); + ResultFileHandler handler = CreateHandler(pm, log); + + if (File.Exists(_tempFile)) + File.Delete(_tempFile); + + bool result = await handler.CopyResultsAsync( + RunMode.iOS, false, "18.0", "udid", "bundle", _tempFile, CancellationToken.None); + + Assert.False(result); + log.Verify(l => l.WriteLine($"Failed to copy results file from device. Expected at: {_tempFile}"), Times.Once); + } +} diff --git a/tests/integration-tests/Apple/Device.Commands.Tests.proj b/tests/integration-tests/Apple/Device.Commands.Tests.proj index 3a0de57b8..7a79f7188 100644 --- a/tests/integration-tests/Apple/Device.Commands.Tests.proj +++ b/tests/integration-tests/Apple/Device.Commands.Tests.proj @@ -6,8 +6,8 @@ System.Buffers.Tests - $(AssetsBaseUri)/ios/test-app/ios-device/$(TestAppBundleName).app.zip - $(ArtifactsTmpDir)test-app\ios-device + $(AssetsBaseUri)/ios/test-app-new/ios-device/$(TestAppBundleName).app.zip + $(ArtifactsTmpDir)test-app-new\ios-device diff --git a/tests/integration-tests/Apple/Simulator.Commands.Tests.proj b/tests/integration-tests/Apple/Simulator.Commands.Tests.proj index 8fa960587..bca59f7e7 100644 --- a/tests/integration-tests/Apple/Simulator.Commands.Tests.proj +++ b/tests/integration-tests/Apple/Simulator.Commands.Tests.proj @@ -10,8 +10,8 @@ System.Numerics.Vectors.Tests - $(AssetsBaseUri)/ios/test-app/ios-simulator-64/$(TestAppBundleName).app.zip - $(ArtifactsTmpDir)test-app\ios-simulator-64 + $(AssetsBaseUri)/ios/test-app-new/ios-simulator-64/$(TestAppBundleName).app.zip + $(ArtifactsTmpDir)test-app-new\ios-simulator-64 diff --git a/tests/integration-tests/Apple/Simulator.Scouting.Commands.Tests.proj b/tests/integration-tests/Apple/Simulator.Scouting.Commands.Tests.proj index c10cb9f07..eda021197 100644 --- a/tests/integration-tests/Apple/Simulator.Scouting.Commands.Tests.proj +++ b/tests/integration-tests/Apple/Simulator.Scouting.Commands.Tests.proj @@ -6,7 +6,7 @@ - @@ -16,8 +16,8 @@ System.Numerics.Vectors.Tests - $(AssetsBaseUri)/ios/test-app/ios-simulator-64/$(TestAppBundleName).app.zip - $(ArtifactsTmpDir)test-app\ios-simulator-64 + $(AssetsBaseUri)/ios/test-app-new/ios-simulator-64/$(TestAppBundleName).app.zip + $(ArtifactsTmpDir)test-app-new\ios-simulator-64 diff --git a/tests/integration-tests/Apple/TestAppBundle.proj b/tests/integration-tests/Apple/TestAppBundle.proj index 48b3460ec..c28668355 100644 --- a/tests/integration-tests/Apple/TestAppBundle.proj +++ b/tests/integration-tests/Apple/TestAppBundle.proj @@ -13,9 +13,9 @@ - $(AssetsBaseUri)/ios/test-app/$(TestTarget) + $(AssetsBaseUri)/ios/test-app-new/$(TestTarget) $(AppStorageUrl)/$(TestAppBundleName).zip - $(ArtifactsTmpDir)test-app\$(TestTarget) + $(ArtifactsTmpDir)test-app-new\$(TestTarget)