Fail ios workflow when simctl does not work (#15628) * fail ios workflow when simctl does not work * missed rename commit * address comments
diff --git a/packages/flutter_tools/lib/src/ios/ios_workflow.dart b/packages/flutter_tools/lib/src/ios/ios_workflow.dart index 55b5ed3..d561ff0 100644 --- a/packages/flutter_tools/lib/src/ios/ios_workflow.dart +++ b/packages/flutter_tools/lib/src/ios/ios_workflow.dart
@@ -23,7 +23,7 @@ // We need xcode (+simctl) to list simulator devices, and libimobiledevice to list real devices. @override - bool get canListDevices => xcode.isInstalledAndMeetsVersionCheck; + bool get canListDevices => xcode.isInstalledAndMeetsVersionCheck && xcode.isSimctlInstalled; // We need xcode to launch simulator devices, and ideviceinstaller and ios-deploy // for real devices. @@ -87,6 +87,13 @@ 'Xcode end user license agreement not signed; open Xcode or run the command \'sudo xcodebuild -license\'.' )); } + if (!xcode.isSimctlInstalled) { + xcodeStatus = ValidationType.partial; + messages.add(new ValidationMessage.error( + 'Xcode requires additional components to be installed in order to run.\n' + 'Launch Xcode and install additional required components when prompted.' + )); + } if ((await macDevMode).contains('disabled')) { xcodeStatus = ValidationType.partial; messages.add(new ValidationMessage.error(
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 29bf8c8..aff5667 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -149,6 +149,23 @@ return _eulaSigned; } + bool _isSimctlInstalled; + + /// Verifies that simctl is installed by trying to run it. + bool get isSimctlInstalled { + if (_isSimctlInstalled == null) { + try { + // This command will error if additional components need to be installed in + // xcode 9.2 and above. + final ProcessResult result = processManager.runSync(<String>['/usr/bin/xcrun', 'simctl', 'list']); + _isSimctlInstalled = result.stderr == null; + } on ProcessException { + _isSimctlInstalled = false; + } + } + return _isSimctlInstalled; + } + bool get isVersionSatisfactory { if (!xcodeProjectInterpreter.isInstalled) return false;
diff --git a/packages/flutter_tools/test/ios/ios_workflow_test.dart b/packages/flutter_tools/test/ios/ios_workflow_test.dart index 401947a..29c1ad6 100644 --- a/packages/flutter_tools/test/ios/ios_workflow_test.dart +++ b/packages/flutter_tools/test/ios/ios_workflow_test.dart
@@ -83,6 +83,7 @@ .thenReturn('Xcode 7.0.1\nBuild version 7C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(false); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -98,6 +99,7 @@ .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(false); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -113,6 +115,7 @@ .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(macDevMode: 'Developer mode is currently disabled.'); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -128,6 +131,7 @@ .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasPythonSixModule: false); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -143,6 +147,7 @@ .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasHomebrew: false); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -158,6 +163,7 @@ .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -173,6 +179,7 @@ .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -187,6 +194,7 @@ when(xcode.versionText) .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasIosDeploy: false); final ValidationResult result = await workflow.validate(); @@ -203,6 +211,7 @@ .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(iosDeployVersionText: '1.8.0'); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -220,6 +229,7 @@ when(xcode.eulaSigned).thenReturn(true); when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenReturn(false); when(cocoaPods.hasCocoaPods).thenReturn(false); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -238,6 +248,7 @@ when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenReturn(false); when(cocoaPods.hasCocoaPods).thenReturn(true); when(cocoaPods.cocoaPodsVersionText).thenReturn('0.39.0'); + when(xcode.isSimctlInstalled).thenReturn(true); final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); final ValidationResult result = await workflow.validate(); expect(result.type, ValidationType.partial); @@ -256,6 +267,7 @@ when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenReturn(false); when(cocoaPods.hasCocoaPods).thenReturn(true); when(cocoaPods.isCocoaPodsInitialized).thenReturn(false); + when(xcode.isSimctlInstalled).thenReturn(true); final ValidationResult result = await new IOSWorkflowTestTarget().validate(); expect(result.type, ValidationType.partial); @@ -267,12 +279,30 @@ ProcessManager: () => processManager, }); + testUsingContext('Emits partial status when simctl is not installed', () async { + when(xcode.isInstalled).thenReturn(true); + when(xcode.versionText) + .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); + when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); + when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(false); + final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(); + final ValidationResult result = await workflow.validate(); + expect(result.type, ValidationType.partial); + }, overrides: <Type, Generator>{ + IMobileDevice: () => iMobileDevice, + Xcode: () => xcode, + CocoaPods: () => cocoaPods, + }); + + testUsingContext('Succeeds when all checks pass', () async { when(xcode.isInstalled).thenReturn(true); when(xcode.versionText) .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.eulaSigned).thenReturn(true); + when(xcode.isSimctlInstalled).thenReturn(true); ensureDirectoryExists(fs.path.join(homeDirPath, '.cocoapods', 'repos', 'master', 'README.md'));