flutter/packages/flutter_tools/test/ios/devices_test.dart
Chris Bracken eba6ceb85d Use idevice_id, ideviceinfo for iOS device listing (#11883)
This patch migrates iOS device listing from using Xcode instruments to
using the libimobiledevice tools idevice_id and ideviceinfo.

ideviceinfo was previously incompatible with iOS 11 physical devices;
this has now been fixed.

In 37bb5f1300e67fe590c44bb9ecda653b2967e347 flutter_tools migrated from
libimobiledevice-based device listing on iOS to using Xcode instruments
to work around the lack of support for iOS 11. Using instruments entails
several downsides, including a significantly higher performance hit, and
leaking hung DTServiceHub processes in certain cases when a simulator is
running, necessitating workarounds in which we watched for, and cleaned
up leaked DTServiceHub processes. This patch returns reverts the move to
instruments now that it's no longer necessary.
2017-09-01 10:10:49 -07:00

109 lines
4.8 KiB
Dart

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:file/file.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/ios/mac.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'package:test/test.dart';
import '../src/context.dart';
class MockIMobileDevice extends Mock implements IMobileDevice {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockXcode extends Mock implements Xcode {}
class MockFile extends Mock implements File {}
class MockProcess extends Mock implements Process {}
void main() {
final FakePlatform osx = new FakePlatform.fromPlatform(const LocalPlatform());
osx.operatingSystem = 'macos';
group('getAttachedDevices', () {
MockIMobileDevice mockIMobileDevice;
setUp(() {
mockIMobileDevice = new MockIMobileDevice();
});
testUsingContext('return no devices if Xcode is not installed', () async {
when(mockIMobileDevice.isInstalled).thenReturn(false);
expect(await IOSDevice.getAttachedDevices(), isEmpty);
}, overrides: <Type, Generator>{
IMobileDevice: () => mockIMobileDevice,
});
testUsingContext('returns no devices if none are attached', () async {
when(iMobileDevice.isInstalled).thenReturn(true);
when(iMobileDevice.getAvailableDeviceIDs()).thenReturn(new Future<String>.value(''));
final List<IOSDevice> devices = await IOSDevice.getAttachedDevices();
expect(devices, isEmpty);
}, overrides: <Type, Generator>{
IMobileDevice: () => mockIMobileDevice,
});
testUsingContext('returns attached devices', () async {
when(iMobileDevice.isInstalled).thenReturn(true);
when(iMobileDevice.getAvailableDeviceIDs()).thenReturn(new Future<String>.value('''
98206e7a4afd4aedaff06e687594e089dede3c44
f577a7903cc54959be2e34bc4f7f80b7009efcf4
'''));
when(iMobileDevice.getInfoForDevice('98206e7a4afd4aedaff06e687594e089dede3c44', 'DeviceName')).thenReturn('La tele me regarde');
when(iMobileDevice.getInfoForDevice('98206e7a4afd4aedaff06e687594e089dede3c44', 'ProductVersion')).thenReturn('10.3.2');
when(iMobileDevice.getInfoForDevice('f577a7903cc54959be2e34bc4f7f80b7009efcf4', 'DeviceName')).thenReturn('Puits sans fond');
when(iMobileDevice.getInfoForDevice('f577a7903cc54959be2e34bc4f7f80b7009efcf4', 'ProductVersion')).thenReturn('11.0');
final List<IOSDevice> devices = await IOSDevice.getAttachedDevices();
expect(devices, hasLength(2));
expect(devices[0].id, '98206e7a4afd4aedaff06e687594e089dede3c44');
expect(devices[0].name, 'La tele me regarde');
expect(devices[1].id, 'f577a7903cc54959be2e34bc4f7f80b7009efcf4');
expect(devices[1].name, 'Puits sans fond');
}, overrides: <Type, Generator>{
IMobileDevice: () => mockIMobileDevice,
});
});
group('logging', () {
MockIMobileDevice mockIMobileDevice;
setUp(() {
mockIMobileDevice = new MockIMobileDevice();
});
testUsingContext('suppresses blacklisted lines from output', () async {
when(mockIMobileDevice.startLogger()).thenAnswer((_) {
final Process mockProcess = new MockProcess();
when(mockProcess.stdout).thenReturn(new Stream<List<int>>.fromIterable(<List<int>>['''
Runner(libsystem_asl.dylib)[297] <Notice>: A is for ari
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt MobileGestaltSupport.m:153: pid 123 (Runner) does not have sandbox access for frZQaeyWLUvLjeuEK43hmg and IS NOT appropriately entitled
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt MobileGestalt.c:550: no access to InverseDeviceID (see <rdar://problem/11744455>)
Runner(libsystem_asl.dylib)[297] <Notice>: I is for ichigo
'''.codeUnits]));
when(mockProcess.stderr).thenReturn(const Stream<List<int>>.empty());
// Delay return of exitCode until after stdout stream data, since it terminates the logger.
when(mockProcess.exitCode).thenReturn(new Future<int>.delayed(Duration.ZERO, () => 0));
return new Future<Process>.value(mockProcess);
});
final IOSDevice device = new IOSDevice('123456');
final DeviceLogReader logReader = device.getLogReader(
app: new BuildableIOSApp(projectBundleId: 'bundleId'),
);
final List<String> lines = await logReader.logLines.toList();
expect(lines, <String>['A is for ari', 'I is for ichigo']);
}, overrides: <Type, Generator>{
IMobileDevice: () => mockIMobileDevice,
});
});
}