Catch FormatException caused by bad simctl output (#37958)
This commit is contained in:
parent
78cca6250a
commit
2185825338
@ -46,11 +46,12 @@ class IOSSimulatorUtils {
|
|||||||
/// Returns [IOSSimulatorUtils] active in the current app context (i.e. zone).
|
/// Returns [IOSSimulatorUtils] active in the current app context (i.e. zone).
|
||||||
static IOSSimulatorUtils get instance => context.get<IOSSimulatorUtils>();
|
static IOSSimulatorUtils get instance => context.get<IOSSimulatorUtils>();
|
||||||
|
|
||||||
List<IOSSimulator> getAttachedDevices() {
|
Future<List<IOSSimulator>> getAttachedDevices() async {
|
||||||
if (!xcode.isInstalledAndMeetsVersionCheck)
|
if (!xcode.isInstalledAndMeetsVersionCheck)
|
||||||
return <IOSSimulator>[];
|
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);
|
return IOSSimulator(device.udid, name: device.name, simulatorCategory: device.category);
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
@ -63,7 +64,7 @@ class SimControl {
|
|||||||
|
|
||||||
/// Runs `simctl list --json` and returns the JSON of the corresponding
|
/// Runs `simctl list --json` and returns the JSON of the corresponding
|
||||||
/// [section].
|
/// [section].
|
||||||
Map<String, dynamic> _list(SimControlListSection section) {
|
Future<Map<String, dynamic>> _list(SimControlListSection section) async {
|
||||||
// Sample output from `simctl list --json`:
|
// Sample output from `simctl list --json`:
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
@ -83,20 +84,27 @@ class SimControl {
|
|||||||
|
|
||||||
final List<String> command = <String>[_xcrunPath, 'simctl', 'list', '--json', section.name];
|
final List<String> command = <String>[_xcrunPath, 'simctl', 'list', '--json', section.name];
|
||||||
printTrace(command.join(' '));
|
printTrace(command.join(' '));
|
||||||
final ProcessResult results = processManager.runSync(command);
|
final ProcessResult results = await processManager.run(command);
|
||||||
if (results.exitCode != 0) {
|
if (results.exitCode != 0) {
|
||||||
printError('Error executing simctl: ${results.exitCode}\n${results.stderr}');
|
printError('Error executing simctl: ${results.exitCode}\n${results.stderr}');
|
||||||
return <String, Map<String, dynamic>>{};
|
return <String, Map<String, dynamic>>{};
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
return json.decode(results.stdout)[section.name];
|
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.
|
/// 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 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) {
|
for (String deviceCategory in devicesSection.keys) {
|
||||||
final List<dynamic> devicesData = devicesSection[deviceCategory];
|
final List<dynamic> devicesData = devicesSection[deviceCategory];
|
||||||
@ -109,8 +117,9 @@ class SimControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all the connected simulator devices.
|
/// Returns all the connected simulator devices.
|
||||||
List<SimDevice> getConnectedDevices() {
|
Future<List<SimDevice>> getConnectedDevices() async {
|
||||||
return getDevices().where((SimDevice device) => device.isBooted).toList();
|
final List<SimDevice> simDevices = await getDevices();
|
||||||
|
return simDevices.where((SimDevice device) => device.isBooted).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> isInstalled(String deviceId, String appId) {
|
Future<bool> isInstalled(String deviceId, String appId) {
|
||||||
|
@ -390,14 +390,15 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
mockProcessManager = MockProcessManager();
|
mockProcessManager = MockProcessManager();
|
||||||
when(mockProcessManager.runSync(any))
|
when(mockProcessManager.run(any)).thenAnswer((Invocation _) async {
|
||||||
.thenReturn(ProcessResult(mockPid, 0, validSimControlOutput, ''));
|
return ProcessResult(mockPid, 0, validSimControlOutput, '');
|
||||||
|
});
|
||||||
|
|
||||||
simControl = SimControl();
|
simControl = SimControl();
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('getDevices succeeds', () {
|
testUsingContext('getDevices succeeds', () async {
|
||||||
final List<SimDevice> devices = simControl.getDevices();
|
final List<SimDevice> devices = await simControl.getDevices();
|
||||||
|
|
||||||
final SimDevice watch = devices[0];
|
final SimDevice watch = devices[0];
|
||||||
expect(watch.category, 'watchOS 4.3');
|
expect(watch.category, 'watchOS 4.3');
|
||||||
@ -426,6 +427,17 @@ void main() {
|
|||||||
ProcessManager: () => mockProcessManager,
|
ProcessManager: () => mockProcessManager,
|
||||||
SimControl: () => simControl,
|
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', () {
|
group('startApp', () {
|
||||||
|
@ -77,7 +77,7 @@ void testUsingContext(
|
|||||||
HttpClient: () => MockHttpClient(),
|
HttpClient: () => MockHttpClient(),
|
||||||
IOSSimulatorUtils: () {
|
IOSSimulatorUtils: () {
|
||||||
final MockIOSSimulatorUtils mock = MockIOSSimulatorUtils();
|
final MockIOSSimulatorUtils mock = MockIOSSimulatorUtils();
|
||||||
when(mock.getAttachedDevices()).thenReturn(<IOSSimulator>[]);
|
when(mock.getAttachedDevices()).thenAnswer((Invocation _) async => <IOSSimulator>[]);
|
||||||
return mock;
|
return mock;
|
||||||
},
|
},
|
||||||
OutputPreferences: () => OutputPreferences(showColor: false),
|
OutputPreferences: () => OutputPreferences(showColor: false),
|
||||||
@ -227,7 +227,7 @@ class FakeDoctor extends Doctor {
|
|||||||
|
|
||||||
class MockSimControl extends Mock implements SimControl {
|
class MockSimControl extends Mock implements SimControl {
|
||||||
MockSimControl() {
|
MockSimControl() {
|
||||||
when(getConnectedDevices()).thenReturn(<SimDevice>[]);
|
when(getConnectedDevices()).thenAnswer((Invocation _) async => <SimDevice>[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user