protected async Task <ExitCode> OrchestrateOperation( TestTargetOs target, string?deviceName, bool includeWirelessDevices, bool resetSimulator, bool enableLldb, GetAppBundleInfoFunc getAppBundle, ExecuteMacCatalystAppFunc executeMacCatalystApp, ExecuteAppFunc executeApp, CancellationToken cancellationToken) { try { return(await OrchestrateOperationInternal( target, deviceName, includeWirelessDevices, resetSimulator, enableLldb, getAppBundle, executeMacCatalystApp, executeApp, cancellationToken)); } catch (OperationCanceledException e) { _logger.LogDebug(e.ToString()); return(ExitCode.APP_LAUNCH_TIMEOUT); } }
private async Task <ExitCode> OrchestrateOperationInternal( TestTargetOs target, string?deviceName, bool includeWirelessDevices, bool resetSimulator, bool enableLldb, GetAppBundleInfoFunc getAppBundle, ExecuteMacCatalystAppFunc executeMacCatalystApp, ExecuteAppFunc executeApp, CancellationToken cancellationToken) { _lldbFileCreated = false; var isLldbEnabled = IsLldbEnabled(); if (isLldbEnabled && !enableLldb) { // the file is present, but the user did not set it, warn him about it _logger.LogWarning("Lldb will be used since '~/.mtouch-launch-with-lldb' was found in the system but it was not created by xharness."); } else if (enableLldb) { if (!File.Exists(s_mlaunchLldbConfigFile)) { // create empty file File.WriteAllText(s_mlaunchLldbConfigFile, string.Empty); _lldbFileCreated = true; } } if (includeWirelessDevices && target.Platform.IsSimulator()) { _logger.LogWarning("Including wireless devices while targeting a simulator has no effect"); } if (resetSimulator && !target.Platform.IsSimulator()) { _logger.LogWarning("Targeting device but requesting simulator reset has no effect"); resetSimulator = false; } ExitCode exitCode; IDevice device; IDevice? companionDevice; AppBundleInformation appBundleInfo; if (target.Platform == TestTarget.MacCatalyst) { try { appBundleInfo = await getAppBundle(target, null !, cancellationToken); } catch (Exception e) { cancellationToken.ThrowIfCancellationRequested(); _logger.LogError(e.Message); return(ExitCode.PACKAGE_NOT_FOUND); } try { return(await executeMacCatalystApp(appBundleInfo)); } catch (Exception e) { var message = new StringBuilder().AppendLine("Application run failed:"); exitCode = ExitCode.APP_LAUNCH_FAILURE; if (_errorKnowledgeBase.IsKnownTestIssue(_mainLog, out var failure)) { message.Append(failure.HumanMessage); if (failure.IssueLink != null) { message.AppendLine($" Find more information at {failure.IssueLink}"); } if (failure.SuggestedExitCode.HasValue) { exitCode = (ExitCode)failure.SuggestedExitCode.Value; } } else { message.AppendLine(e.ToString()); } _logger.LogError(message.ToString()); return(exitCode); } } try { _logger.LogInformation($"Looking for available {target.AsString()} {(target.Platform.IsSimulator() ? "simulators" : "devices")}.."); var finderLogName = $"list-{target.AsString()}-{_helpers.Timestamp}.log"; using var finderLog = _logs.Create(finderLogName, "DeviceList", true); _mainLog.WriteLine( $"Looking for available {target.AsString()} {(target.Platform.IsSimulator() ? "simulators" : "devices")}. " + $"Storing logs into {finderLogName}"); (device, companionDevice) = await _deviceFinder.FindDevice(target, deviceName, finderLog, includeWirelessDevices, cancellationToken); _logger.LogInformation($"Found {(target.Platform.IsSimulator() ? "simulator" : "physical")} device '{device.Name}'"); if (companionDevice != null) { _logger.LogInformation($"Found companion {(target.Platform.IsSimulator() ? "simulator" : "physical")} device '{companionDevice.Name}'"); } } catch (NoDeviceFoundException e) { _logger.LogError(e.Message); return(ExitCode.DEVICE_NOT_FOUND); } cancellationToken.ThrowIfCancellationRequested(); try { appBundleInfo = await getAppBundle(target, device, cancellationToken); } catch (Exception e) { cancellationToken.ThrowIfCancellationRequested(); _logger.LogError(e.Message); return(ExitCode.PACKAGE_NOT_FOUND); } cancellationToken.ThrowIfCancellationRequested(); if (target.Platform.IsSimulator() && resetSimulator) { try { var simulator = (ISimulatorDevice)device; var bundleIds = appBundleInfo.BundleIdentifier == string.Empty ? Array.Empty <string>() : new[] { appBundleInfo.BundleIdentifier }; _logger.LogInformation($"Reseting simulator '{device.Name}'"); await simulator.PrepareSimulator(_mainLog, bundleIds); if (companionDevice != null) { _logger.LogInformation($"Reseting companion simulator '{companionDevice.Name}'"); var companionSimulator = (ISimulatorDevice)companionDevice; await companionSimulator.PrepareSimulator(_mainLog, bundleIds); } _logger.LogInformation("Simulator reset finished"); } catch (Exception e) { _logger.LogError($"Failed to reset simulator: " + Environment.NewLine + e); return(ExitCode.SIMULATOR_FAILURE); } } cancellationToken.ThrowIfCancellationRequested(); // Note down the actual test target // For simulators (e.g. "iOS 13.4"), we strip the iOS part and keep the version only, for devices there's no OS _diagnosticsData.TargetOS = target.Platform.IsSimulator() ? device.OSVersion.Split(' ', 2).Last() : device.OSVersion; _diagnosticsData.Device = device.Name ?? device.UDID; // Uninstall the app first to get a clean state if (!resetSimulator) { await UninstallApp(target.Platform, appBundleInfo.BundleIdentifier, device, isPreparation : true, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); } exitCode = await InstallApp(appBundleInfo, device, target, cancellationToken); if (exitCode != ExitCode.SUCCESS) { _logger.LogInformation($"Cleaning up the failed installation from '{device.Name}'"); var uninstallResult = await UninstallApp(target.Platform, appBundleInfo.BundleIdentifier, device, isPreparation : false, new CancellationToken()); if (uninstallResult == ExitCode.SIMULATOR_FAILURE) { // Sometimes the simulator gets in a bad shape and we won't be able to install the app, we can tell here return(ExitCode.SIMULATOR_FAILURE); } return(exitCode); } try { exitCode = await executeApp(appBundleInfo, device, companionDevice); } catch (Exception e) { exitCode = ExitCode.GENERAL_FAILURE; var message = new StringBuilder().AppendLine("Application run failed:"); if (_errorKnowledgeBase.IsKnownTestIssue(_mainLog, out var failure)) { message.Append(failure.HumanMessage); if (failure.IssueLink != null) { message.AppendLine($" Find more information at {failure.IssueLink}"); } if (failure.SuggestedExitCode.HasValue) { exitCode = (ExitCode)failure.SuggestedExitCode.Value; } } else { message.AppendLine(e.ToString()); } _logger.LogError(message.ToString()); } finally { if (target.Platform.IsSimulator() && resetSimulator) { await CleanUpSimulators(device, companionDevice); } else if (device != null) // Do not uninstall if device was cleaned up { var uninstallResult = await UninstallApp(target.Platform, appBundleInfo.BundleIdentifier, device, false, new CancellationToken()); // We are able to detect a case when simulator is in a bad shape // If it also failed the test/run, we should present that as the failure if (uninstallResult == ExitCode.SIMULATOR_FAILURE && exitCode != ExitCode.SUCCESS && exitCode != ExitCode.TESTS_FAILED) { exitCode = ExitCode.SIMULATOR_FAILURE; } } } return(exitCode); }