Check if simctl is installed before trying to list devices or runtimes (#163895)
After https://github.com/flutter/flutter/pull/163785 there was still an unexpected `xcrun simctl` output on a machine with Xcode only half installed https://github.com/flutter/flutter/issues/161655. Check `simctl` is installed before trying to list booted simulator devices or runtimes. Should address https://github.com/flutter/flutter/issues/161655. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
d0e8fa157a
commit
898ab2479e
@ -66,7 +66,7 @@ class IOSSimulatorUtils {
|
|||||||
final Xcode _xcode;
|
final Xcode _xcode;
|
||||||
|
|
||||||
Future<List<IOSSimulator>> getAttachedDevices() async {
|
Future<List<IOSSimulator>> getAttachedDevices() async {
|
||||||
if (!_xcode.isInstalledAndMeetsVersionCheck) {
|
if (!_xcode.isInstalledAndMeetsVersionCheck || !_xcode.isSimctlInstalled) {
|
||||||
return <IOSSimulator>[];
|
return <IOSSimulator>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ class IOSSimulatorUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<IOSSimulatorRuntime>> getAvailableIOSRuntimes() async {
|
Future<List<IOSSimulatorRuntime>> getAvailableIOSRuntimes() async {
|
||||||
if (!_xcode.isInstalledAndMeetsVersionCheck) {
|
if (!_xcode.isInstalledAndMeetsVersionCheck || !_xcode.isSimctlInstalled) {
|
||||||
return <IOSSimulatorRuntime>[];
|
return <IOSSimulatorRuntime>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,7 +894,10 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''',
|
|||||||
|
|
||||||
late FakeProcessManager fakeProcessManager;
|
late FakeProcessManager fakeProcessManager;
|
||||||
Xcode xcode;
|
Xcode xcode;
|
||||||
|
Xcode xcodeBadSimctl;
|
||||||
late SimControl simControl;
|
late SimControl simControl;
|
||||||
|
late IOSSimulatorUtils simulatorUtils;
|
||||||
|
late IOSSimulatorUtils simulatorUtilsBadSimctl;
|
||||||
late BufferLogger logger;
|
late BufferLogger logger;
|
||||||
const String deviceId = 'smart-phone';
|
const String deviceId = 'smart-phone';
|
||||||
const String appId = 'flutterApp';
|
const String appId = 'flutterApp';
|
||||||
@ -902,8 +905,32 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''',
|
|||||||
setUp(() {
|
setUp(() {
|
||||||
fakeProcessManager = FakeProcessManager.empty();
|
fakeProcessManager = FakeProcessManager.empty();
|
||||||
xcode = Xcode.test(processManager: FakeProcessManager.any());
|
xcode = Xcode.test(processManager: FakeProcessManager.any());
|
||||||
|
|
||||||
|
final FakeProcessManager fakeProcessManagerBadSimctl = FakeProcessManager.list(<FakeCommand>[
|
||||||
|
const FakeCommand(command: <String>['which', 'sysctl']),
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>['sysctl', 'hw.optional.arm64'],
|
||||||
|
stdout: 'hw.optional.arm64: 0',
|
||||||
|
),
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted'],
|
||||||
|
stderr: 'failed to run',
|
||||||
|
exitCode: 1,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
xcodeBadSimctl = Xcode.test(processManager: fakeProcessManagerBadSimctl);
|
||||||
logger = BufferLogger.test();
|
logger = BufferLogger.test();
|
||||||
simControl = SimControl(logger: logger, processManager: fakeProcessManager, xcode: xcode);
|
simControl = SimControl(logger: logger, processManager: fakeProcessManager, xcode: xcode);
|
||||||
|
simulatorUtils = IOSSimulatorUtils(
|
||||||
|
logger: logger,
|
||||||
|
processManager: fakeProcessManager,
|
||||||
|
xcode: xcode,
|
||||||
|
);
|
||||||
|
simulatorUtilsBadSimctl = IOSSimulatorUtils(
|
||||||
|
logger: logger,
|
||||||
|
processManager: fakeProcessManager,
|
||||||
|
xcode: xcodeBadSimctl,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('getConnectedDevices succeeds', () async {
|
testWithoutContext('getConnectedDevices succeeds', () async {
|
||||||
@ -933,6 +960,33 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''',
|
|||||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('IOSSimulatorUtils.getAttachedDevices succeeds', () async {
|
||||||
|
fakeProcessManager.addCommand(
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted', 'iOS', '--json'],
|
||||||
|
stdout: validSimControlOutput,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<IOSSimulator> devices = await simulatorUtils.getAttachedDevices();
|
||||||
|
|
||||||
|
final IOSSimulator phone1 = devices[0];
|
||||||
|
expect(phone1.category, Category.mobile);
|
||||||
|
expect(phone1.name, 'iPhone 11');
|
||||||
|
expect(phone1.simulatorCategory, 'com.apple.CoreSimulator.SimRuntime.iOS-14-0');
|
||||||
|
|
||||||
|
final IOSSimulator phone2 = devices[1];
|
||||||
|
expect(phone2.category, Category.mobile);
|
||||||
|
expect(phone2.name, 'Phone w Watch');
|
||||||
|
expect(phone2.simulatorCategory, 'com.apple.CoreSimulator.SimRuntime.iOS-16-0');
|
||||||
|
|
||||||
|
final IOSSimulator phone3 = devices[2];
|
||||||
|
expect(phone3.category, Category.mobile);
|
||||||
|
expect(phone3.name, 'iPhone 13');
|
||||||
|
expect(phone3.simulatorCategory, 'com.apple.CoreSimulator.SimRuntime.iOS-16-0');
|
||||||
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
});
|
||||||
|
|
||||||
testWithoutContext('getConnectedDevices handles bad simctl output', () async {
|
testWithoutContext('getConnectedDevices handles bad simctl output', () async {
|
||||||
fakeProcessManager.addCommand(
|
fakeProcessManager.addCommand(
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
@ -947,6 +1001,16 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''',
|
|||||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext(
|
||||||
|
'IOSSimulatorUtils.getAttachedDevices handles simctl not properly installed',
|
||||||
|
() async {
|
||||||
|
final List<IOSSimulator> devices = await simulatorUtilsBadSimctl.getAttachedDevices();
|
||||||
|
|
||||||
|
expect(devices, isEmpty);
|
||||||
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
testWithoutContext('sdkMajorVersion defaults to 11 when sdkNameAndVersion is junk', () async {
|
testWithoutContext('sdkMajorVersion defaults to 11 when sdkNameAndVersion is junk', () async {
|
||||||
final IOSSimulator iosSimulatorA = IOSSimulator(
|
final IOSSimulator iosSimulatorA = IOSSimulator(
|
||||||
'x',
|
'x',
|
||||||
@ -1186,6 +1250,17 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''',
|
|||||||
expect(logger.errorText, contains('simctl returned non-JSON response:'));
|
expect(logger.errorText, contains('simctl returned non-JSON response:'));
|
||||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext(
|
||||||
|
'IOSSimulatorUtils.getAvailableIOSRuntimes handles simctl not properly installed',
|
||||||
|
() async {
|
||||||
|
final List<IOSSimulatorRuntime> runtimes =
|
||||||
|
await simulatorUtilsBadSimctl.getAvailableIOSRuntimes();
|
||||||
|
|
||||||
|
expect(runtimes, isEmpty);
|
||||||
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
group('startApp', () {
|
group('startApp', () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user