Unverified Commit 21858253 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Catch FormatException caused by bad simctl output (#37958)

parent 78cca625
......@@ -46,11 +46,12 @@ class IOSSimulatorUtils {
/// Returns [IOSSimulatorUtils] active in the current app context (i.e. zone).
static IOSSimulatorUtils get instance => context.get<IOSSimulatorUtils>();
List<IOSSimulator> getAttachedDevices() {
Future<List<IOSSimulator>> getAttachedDevices() async {
if (!xcode.isInstalledAndMeetsVersionCheck)
return <IOSSimulator>[];
return SimControl.instance.getConnectedDevices().map<IOSSimulator>((SimDevice device) {
final List<SimDevice> connected = await SimControl.instance.getConnectedDevices();
return connected.map<IOSSimulator>((SimDevice device) {
return IOSSimulator(device.udid, name: device.name, simulatorCategory: device.category);
}).toList();
}
......@@ -63,7 +64,7 @@ class SimControl {
/// Runs `simctl list --json` and returns the JSON of the corresponding
/// [section].
Map<String, dynamic> _list(SimControlListSection section) {
Future<Map<String, dynamic>> _list(SimControlListSection section) async {
// Sample output from `simctl list --json`:
//
// {
......@@ -83,20 +84,27 @@ class SimControl {
final List<String> command = <String>[_xcrunPath, 'simctl', 'list', '--json', section.name];
printTrace(command.join(' '));
final ProcessResult results = processManager.runSync(command);
final ProcessResult results = await processManager.run(command);
if (results.exitCode != 0) {
printError('Error executing simctl: ${results.exitCode}\n${results.stderr}');
return <String, Map<String, dynamic>>{};
}
return json.decode(results.stdout)[section.name];
try {
return json.decode(results.stdout)[section.name];
} on FormatException {
// We failed to parse the simctl output, or it returned junk.
// One known message is "Install Started" isn't valid JSON but is
// returned sometimes.
printError('simctl returned non-JSON response: ${results.stdout}');
return <String, dynamic>{};
}
}
/// Returns a list of all available devices, both potential and connected.
List<SimDevice> getDevices() {
Future<List<SimDevice>> getDevices() async {
final List<SimDevice> devices = <SimDevice>[];
final Map<String, dynamic> devicesSection = _list(SimControlListSection.devices);
final Map<String, dynamic> devicesSection = await _list(SimControlListSection.devices);
for (String deviceCategory in devicesSection.keys) {
final List<dynamic> devicesData = devicesSection[deviceCategory];
......@@ -109,8 +117,9 @@ class SimControl {
}
/// Returns all the connected simulator devices.
List<SimDevice> getConnectedDevices() {
return getDevices().where((SimDevice device) => device.isBooted).toList();
Future<List<SimDevice>> getConnectedDevices() async {
final List<SimDevice> simDevices = await getDevices();
return simDevices.where((SimDevice device) => device.isBooted).toList();
}
Future<bool> isInstalled(String deviceId, String appId) {
......
......@@ -390,14 +390,15 @@ void main() {
setUp(() {
mockProcessManager = MockProcessManager();
when(mockProcessManager.runSync(any))
.thenReturn(ProcessResult(mockPid, 0, validSimControlOutput, ''));
when(mockProcessManager.run(any)).thenAnswer((Invocation _) async {
return ProcessResult(mockPid, 0, validSimControlOutput, '');
});
simControl = SimControl();
});
testUsingContext('getDevices succeeds', () {
final List<SimDevice> devices = simControl.getDevices();
testUsingContext('getDevices succeeds', () async {
final List<SimDevice> devices = await simControl.getDevices();
final SimDevice watch = devices[0];
expect(watch.category, 'watchOS 4.3');
......@@ -426,6 +427,17 @@ void main() {
ProcessManager: () => mockProcessManager,
SimControl: () => simControl,
});
testUsingContext('getDevices handles bad simctl output', () async {
when(mockProcessManager.run(any))
.thenAnswer((Invocation _) async => ProcessResult(mockPid, 0, 'Install Started', ''));
final List<SimDevice> devices = await simControl.getDevices();
expect(devices, isEmpty);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
SimControl: () => simControl,
});
});
group('startApp', () {
......
......@@ -77,7 +77,7 @@ void testUsingContext(
HttpClient: () => MockHttpClient(),
IOSSimulatorUtils: () {
final MockIOSSimulatorUtils mock = MockIOSSimulatorUtils();
when(mock.getAttachedDevices()).thenReturn(<IOSSimulator>[]);
when(mock.getAttachedDevices()).thenAnswer((Invocation _) async => <IOSSimulator>[]);
return mock;
},
OutputPreferences: () => OutputPreferences(showColor: false),
......@@ -227,7 +227,7 @@ class FakeDoctor extends Doctor {
class MockSimControl extends Mock implements SimControl {
MockSimControl() {
when(getConnectedDevices()).thenReturn(<SimDevice>[]);
when(getConnectedDevices()).thenAnswer((Invocation _) async => <SimDevice>[]);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment