diff --git a/dev/devicelab/bin/run.dart b/dev/devicelab/bin/run.dart index c386349556..a776a750e0 100644 --- a/dev/devicelab/bin/run.dart +++ b/dev/devicelab/bin/run.dart @@ -51,9 +51,11 @@ Future main(List rawArgs) async { return null; } + bool silent = args['silent']; + for (String taskName in taskNames) { section('Running task "$taskName"'); - Map result = await runTask(taskName); + Map result = await runTask(taskName, silent: silent); if (!result['success']) exitCode = 1; @@ -98,4 +100,9 @@ final ArgParser _argParser = new ArgParser() ); } }, + ) + ..addFlag( + 'silent', + negatable: true, + defaultsTo: false, ); diff --git a/dev/devicelab/bin/tasks/complex_layout__start_up.dart b/dev/devicelab/bin/tasks/complex_layout__start_up.dart index f2e5f9e4fe..940a10092c 100644 --- a/dev/devicelab/bin/tasks/complex_layout__start_up.dart +++ b/dev/devicelab/bin/tasks/complex_layout__start_up.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createComplexLayoutStartupTest(ios: false)); + await task(createComplexLayoutStartupTest(os: DeviceOperatingSystem.android)); } diff --git a/dev/devicelab/bin/tasks/complex_layout_ios__start_up.dart b/dev/devicelab/bin/tasks/complex_layout_ios__start_up.dart index cac132d815..12d59c25d7 100644 --- a/dev/devicelab/bin/tasks/complex_layout_ios__start_up.dart +++ b/dev/devicelab/bin/tasks/complex_layout_ios__start_up.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createComplexLayoutStartupTest(ios: true)); + await task(createComplexLayoutStartupTest(os: DeviceOperatingSystem.ios)); } diff --git a/dev/devicelab/bin/tasks/complex_layout_scroll_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/complex_layout_scroll_perf__timeline_summary.dart index a9f4d0c308..2a94874cee 100644 --- a/dev/devicelab/bin/tasks/complex_layout_scroll_perf__timeline_summary.dart +++ b/dev/devicelab/bin/tasks/complex_layout_scroll_perf__timeline_summary.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createComplexLayoutScrollPerfTest(ios: false)); + await task(createComplexLayoutScrollPerfTest(os: DeviceOperatingSystem.android)); } diff --git a/dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart index 5cc6fa13ee..d6cda8c97a 100644 --- a/dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart +++ b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createComplexLayoutScrollPerfTest(ios: true)); + await task(createComplexLayoutScrollPerfTest(os: DeviceOperatingSystem.ios)); } diff --git a/dev/devicelab/bin/tasks/flutter_gallery__start_up.dart b/dev/devicelab/bin/tasks/flutter_gallery__start_up.dart index c6024e4028..24a2704cae 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery__start_up.dart +++ b/dev/devicelab/bin/tasks/flutter_gallery__start_up.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createFlutterGalleryStartupTest(ios: false)); + await task(createFlutterGalleryStartupTest(os: DeviceOperatingSystem.android)); } diff --git a/dev/devicelab/bin/tasks/flutter_gallery__transition_perf.dart b/dev/devicelab/bin/tasks/flutter_gallery__transition_perf.dart index d541ff9915..ace44f19c4 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery__transition_perf.dart +++ b/dev/devicelab/bin/tasks/flutter_gallery__transition_perf.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/gallery.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createGalleryTransitionTest(ios: false)); + await task(createGalleryTransitionTest(os: DeviceOperatingSystem.android)); } diff --git a/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up.dart b/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up.dart index 24042a0149..1968f4f734 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up.dart +++ b/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createFlutterGalleryStartupTest(ios: true)); + await task(createFlutterGalleryStartupTest(os: DeviceOperatingSystem.ios)); } diff --git a/dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart b/dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart index 1745cb04b8..996e027cad 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart +++ b/dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart @@ -5,8 +5,9 @@ import 'dart:async'; import 'package:flutter_devicelab/tasks/gallery.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; Future main() async { - await task(createGalleryTransitionTest(ios: true)); + await task(createGalleryTransitionTest(os: DeviceOperatingSystem.ios)); } diff --git a/dev/devicelab/bin/tasks/hot_mode_dev_cycle__benchmark.dart b/dev/devicelab/bin/tasks/hot_mode_dev_cycle__benchmark.dart index 66dd522652..a9d73201be 100644 --- a/dev/devicelab/bin/tasks/hot_mode_dev_cycle__benchmark.dart +++ b/dev/devicelab/bin/tasks/hot_mode_dev_cycle__benchmark.dart @@ -12,7 +12,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; void main() { task(() async { - Adb device = await adb(); + Device device = await devices.workingDevice; await device.unlock(); Directory appDir = dir(path.join(flutterDirectory.path, 'examples/flutter_gallery')); diff --git a/dev/devicelab/lib/framework/adb.dart b/dev/devicelab/lib/framework/adb.dart index ed2c48b82a..6c482c75e2 100644 --- a/dev/devicelab/lib/framework/adb.dart +++ b/dev/devicelab/lib/framework/adb.dart @@ -6,109 +6,135 @@ import 'dart:async'; import 'dart:io'; import 'dart:math' as math; +import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import 'utils.dart'; -typedef Future AdbGetter(); +/// The root of the API for controlling devices. +DeviceDiscovery get devices => new DeviceDiscovery(); -/// Get an instance of [Adb]. -/// -/// See [realAdbGetter] for signature. This can be overwritten for testing. -AdbGetter adb = realAdbGetter; +/// Device operating system the test is configured to test. +enum DeviceOperatingSystem { android, ios } -Adb _currentDevice; +/// Device OS to test on. +DeviceOperatingSystem deviceOperatingSystem = DeviceOperatingSystem.android; -/// Picks a random Android device out of connected devices and sets it as -/// [_currentDevice]. -Future pickNextDevice() async { - List allDevices = - (await Adb.deviceIds).map((String id) => new Adb(deviceId: id)).toList(); - - if (allDevices.length == 0) throw 'No Android devices detected'; - - // TODO(yjbanov): filter out and warn about those with low battery level - _currentDevice = allDevices[new math.Random().nextInt(allDevices.length)]; -} - -Future realAdbGetter() async { - if (_currentDevice == null) await pickNextDevice(); - return _currentDevice; -} - -/// Gets the ID of an unlocked device, unlocking it if necessary. -// TODO(yjbanov): abstract away iOS from Android. -Future getUnlockedDeviceId({ bool ios: false }) async { - if (ios) { - // We currently do not have a way to lock/unlock iOS devices, or even to - // pick one out of many. So we pick the first random iPhone and assume it's - // already unlocked. For now we'll just keep them at minimum screen - // brightness so they don't drain battery too fast. - List iosDeviceIds = - grep('UniqueDeviceID', from: await eval('ideviceinfo', [])) - .map((String line) => line.split(' ').last) - .toList(); - - if (iosDeviceIds.isEmpty) throw 'No connected iOS devices found.'; - - return iosDeviceIds.first; +/// Discovers available devices and chooses one to work with. +abstract class DeviceDiscovery { + factory DeviceDiscovery() { + switch(deviceOperatingSystem) { + case DeviceOperatingSystem.android: + return new AndroidDeviceDiscovery(); + case DeviceOperatingSystem.ios: + return new IosDeviceDiscovery(); + default: + throw new StateError('Unsupported device operating system: {config.deviceOperatingSystem}'); + } } - Adb device = await adb(); - await device.unlock(); - return device.deviceId; + /// Selects a device to work with, load-balancing between devices if more than + /// one are available. + /// + /// Calling this method does not guarantee that the same device will be + /// returned. For such behavior see [workingDevice]. + Future chooseWorkingDevice(); + + /// A device to work with. + /// + /// Returns the same device when called repeatedly (unlike + /// [chooseWorkingDevice]). This is useful when you need to perform multiple + /// perations on one. + Future get workingDevice; + + /// Lists all available devices' IDs. + Future> discoverDevices(); + + /// Checks the health of the available devices. + Future> checkDevices(); + + /// Prepares the system to run tasks. + Future performPreflightTasks(); } -/// Android Debug Bridge (`adb`) client that exposes a subset of functions -/// relevant to on-device testing. -class Adb { - Adb({ this.deviceId }); +/// A proxy for one specific device. +abstract class Device { + /// A unique device identifier. + String get deviceId; - final String deviceId; + /// Whether the device is awake. + Future isAwake(); + /// Whether the device is asleep. + Future isAsleep(); + + /// Wake up the device if it is not awake. + Future wakeUp(); + + /// Send the device to sleep mode. + Future sendToSleep(); + + /// Emulates pressing the power button, toggling the device's on/off state. + Future togglePower(); + + /// Unlocks the device. + /// + /// Assumes the device doesn't have a secure unlock pattern. + Future unlock(); +} + +class AndroidDeviceDiscovery implements DeviceDiscovery { // Parses information about a device. Example: // // 015d172c98400a03 device usb:340787200X product:nakasi model:Nexus_7 device:grouper static final RegExp _kDeviceRegex = new RegExp(r'^(\S+)\s+(\S+)(.*)'); - /// Reports connection health for every device. - static Future> checkDevices() async { - Map results = {}; - for (String deviceId in await deviceIds) { - try { - Adb device = new Adb(deviceId: deviceId); - // Just a smoke test that we can read wakefulness state - // TODO(yjbanov): also check battery level - await device._getWakefulness(); - results['android-device-$deviceId'] = new HealthCheckResult.success(); - } catch (e, s) { - results['android-device-$deviceId'] = new HealthCheckResult.error(e, s); - } + static AndroidDeviceDiscovery _instance; + + factory AndroidDeviceDiscovery() { + return _instance ??= new AndroidDeviceDiscovery._(); + } + + AndroidDeviceDiscovery._(); + + AndroidDevice _workingDevice; + + @override + Future get workingDevice async { + if (_workingDevice == null) { + await chooseWorkingDevice(); } - return results; + + return _workingDevice; } - /// Kills the `adb` server causing it to start a new instance upon next - /// command. - /// - /// Restarting `adb` helps with keeping device connections alive. When `adb` - /// runs non-stop for too long it loses connections to devices. - static Future restart() async { - await exec(adbPath, ['kill-server'], canFail: false); + /// Picks a random Android device out of connected devices and sets it as + /// [workingDevice]. + @override + Future chooseWorkingDevice() async { + List allDevices = (await discoverDevices()) + .map((String id) => new AndroidDevice(deviceId: id)) + .toList(); + + if (allDevices.isEmpty) + throw 'No Android devices detected'; + + // TODO(yjbanov): filter out and warn about those with low battery level + _workingDevice = allDevices[new math.Random().nextInt(allDevices.length)]; } - /// List of device IDs visible to `adb`. - static Future> get deviceIds async { - List output = - (await eval(adbPath, ['devices', '-l'], canFail: false)) - .trim() - .split('\n'); + @override + Future> discoverDevices() async { + List output = (await eval(adbPath, ['devices', '-l'], canFail: false)) + .trim().split('\n'); List results = []; for (String line in output) { // Skip lines like: * daemon started successfully * - if (line.startsWith('* daemon ')) continue; + if (line.startsWith('* daemon ')) + continue; - if (line.startsWith('List of devices')) continue; + if (line.startsWith('List of devices')) + continue; if (_kDeviceRegex.hasMatch(line)) { Match match = _kDeviceRegex.firstMatch(line); @@ -127,28 +153,70 @@ class Adb { return results; } + @override + Future> checkDevices() async { + Map results = {}; + for (String deviceId in await discoverDevices()) { + try { + AndroidDevice device = new AndroidDevice(deviceId: deviceId); + // Just a smoke test that we can read wakefulness state + // TODO(yjbanov): check battery level + await device._getWakefulness(); + results['android-device-$deviceId'] = new HealthCheckResult.success(); + } catch(e, s) { + results['android-device-$deviceId'] = new HealthCheckResult.error(e, s); + } + } + return results; + } + + @override + Future performPreflightTasks() async { + // Kills the `adb` server causing it to start a new instance upon next + // command. + // + // Restarting `adb` helps with keeping device connections alive. When `adb` + // runs non-stop for too long it loses connections to devices. There may be + // a better method, but so far that's the best one I've found. + await exec(adbPath, ['kill-server'], canFail: false); + } +} + +class AndroidDevice implements Device { + AndroidDevice({@required this.deviceId}); + + @override + final String deviceId; + /// Whether the device is awake. + @override Future isAwake() async { return await _getWakefulness() == 'Awake'; } /// Whether the device is asleep. + @override Future isAsleep() async { return await _getWakefulness() == 'Asleep'; } /// Wake up the device if it is not awake using [togglePower]. + @override Future wakeUp() async { - if (!(await isAwake())) await togglePower(); + if (!(await isAwake())) + await togglePower(); } /// Send the device to sleep mode if it is not asleep using [togglePower]. + @override Future sendToSleep() async { - if (!(await isAsleep())) await togglePower(); + if (!(await isAsleep())) + await togglePower(); } /// Sends `KEYCODE_POWER` (26), which causes the device to toggle its mode /// between awake and asleep. + @override Future togglePower() async { await shellExec('input', const ['keyevent', '26']); } @@ -156,6 +224,7 @@ class Adb { /// Unlocks the device by sending `KEYCODE_MENU` (82). /// /// This only works when the device doesn't have a secure unlock pattern. + @override Future unlock() async { await wakeUp(); await shellExec('input', const ['keyevent', '82']); @@ -166,26 +235,117 @@ class Adb { /// See: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/PowerManagerInternal.java Future _getWakefulness() async { String powerInfo = await shellEval('dumpsys', ['power']); - String wakefulness = - grep('mWakefulness=', from: powerInfo).single.split('=')[1].trim(); + String wakefulness = grep('mWakefulness=', from: powerInfo).single.split('=')[1].trim(); return wakefulness; } /// Executes [command] on `adb shell` and returns its exit code. - Future shellExec(String command, List arguments, - { Map env }) async { - await exec(adbPath, ['shell', command]..addAll(arguments), - env: env, canFail: false); + Future shellExec(String command, List arguments, {Map env}) async { + await exec(adbPath, ['shell', command]..addAll(arguments), env: env, canFail: false); } /// Executes [command] on `adb shell` and returns its standard output as a [String]. - Future shellEval(String command, List arguments, - { Map env }) { - return eval(adbPath, ['shell', command]..addAll(arguments), - env: env, canFail: false); + Future shellEval(String command, List arguments, {Map env}) { + return eval(adbPath, ['shell', command]..addAll(arguments), env: env, canFail: false); } } +class IosDeviceDiscovery implements DeviceDiscovery { + + static IosDeviceDiscovery _instance; + + factory IosDeviceDiscovery() { + return _instance ??= new IosDeviceDiscovery._(); + } + + IosDeviceDiscovery._(); + + IosDevice _workingDevice; + + @override + Future get workingDevice async { + if (_workingDevice == null) { + await chooseWorkingDevice(); + } + + return _workingDevice; + } + + /// Picks a random iOS device out of connected devices and sets it as + /// [workingDevice]. + @override + Future chooseWorkingDevice() async { + List allDevices = (await discoverDevices()) + .map((String id) => new IosDevice(deviceId: id)) + .toList(); + + if (allDevices.length == 0) + throw 'No iOS devices detected'; + + // TODO(yjbanov): filter out and warn about those with low battery level + _workingDevice = allDevices[new math.Random().nextInt(allDevices.length)]; + } + + @override + Future> discoverDevices() async { + // TODO: use the -k UniqueDeviceID option, which requires much less parsing. + List iosDeviceIds = grep('UniqueDeviceID', from: await eval('ideviceinfo', [])) + .map((String line) => line.split(' ').last).toList(); + + if (iosDeviceIds.isEmpty) + throw 'No connected iOS devices found.'; + + return iosDeviceIds; + } + + @override + Future> checkDevices() async { + Map results = {}; + for (String deviceId in await discoverDevices()) { + // TODO: do a more meaningful connectivity check than just recording the ID + results['ios-device-$deviceId'] = new HealthCheckResult.success(); + } + return results; + } + + @override + Future performPreflightTasks() async { + // Currently we do not have preflight tasks for iOS. + return null; + } +} + +/// iOS device. +class IosDevice implements Device { + const IosDevice({ @required this.deviceId }); + + @override + final String deviceId; + + // The methods below are stubs for now. They will need to be expanded. + // We currently do not have a way to lock/unlock iOS devices. So we assume the + // devices are already unlocked. For now we'll just keep them at minimum + // screen brightness so they don't drain battery too fast. + + @override + Future isAwake() async => true; + + @override + Future isAsleep() async => false; + + @override + Future wakeUp() async {} + + @override + Future sendToSleep() async {} + + @override + Future togglePower() async {} + + @override + Future unlock() async {} +} + /// Path to the `adb` executable. String get adbPath { String androidHome = Platform.environment['ANDROID_HOME']; diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart index 54fac0d7c9..7eff1c002e 100644 --- a/dev/devicelab/lib/framework/runner.dart +++ b/dev/devicelab/lib/framework/runner.dart @@ -19,7 +19,10 @@ const Duration taskTimeoutWithGracePeriod = const Duration(minutes: 11); /// /// [taskName] is the name of the task. The corresponding task executable is /// expected to be found under `bin/tasks`. -Future> runTask(String taskName) async { +/// +/// Running the task in [silent] mode will suppress standard output from task +/// processes and only print standard errors. +Future> runTask(String taskName, { bool silent: false }) async { String taskExecutable = 'bin/tasks/$taskName.dart'; if (!file(taskExecutable).existsSync()) @@ -42,7 +45,9 @@ Future> runTask(String taskName) async { .transform(new Utf8Decoder()) .transform(new LineSplitter()) .listen((String line) { - stdout.writeln('[$taskName] [STDOUT] $line'); + if (!silent) { + stdout.writeln('[$taskName] [STDOUT] $line'); + } }); StreamSubscription stderrSub = runner.stderr diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart index 5586d22621..6526084afc 100644 --- a/dev/devicelab/lib/framework/utils.dart +++ b/dev/devicelab/lib/framework/utils.dart @@ -242,12 +242,6 @@ String get dartBin => Future dart(List args) => exec(dartBin, args); -Future pub(String command) { - return exec( - path.join(flutterDirectory.path, 'bin', 'cache', 'dart-sdk', 'bin', 'pub'), - [command]); -} - Future inDirectory(dynamic directory, Future action()) async { String previousCwd = cwd; try { diff --git a/dev/devicelab/lib/tasks/analysis.dart b/dev/devicelab/lib/tasks/analysis.dart index 46036d956f..6d4af5e0a8 100644 --- a/dev/devicelab/lib/tasks/analysis.dart +++ b/dev/devicelab/lib/tasks/analysis.dart @@ -105,8 +105,7 @@ class FlutterAnalyzeAppBenchmark extends Benchmark { Future run() async { rm(benchmarkFile); await inDirectory(megaDir, () async { - await flutter('analyze', options: [ - '--watch', + await flutter('watch', options: [ '--benchmark', ]); }); diff --git a/dev/devicelab/lib/tasks/gallery.dart b/dev/devicelab/lib/tasks/gallery.dart index 873ff1a008..88f0279767 100644 --- a/dev/devicelab/lib/tasks/gallery.dart +++ b/dev/devicelab/lib/tasks/gallery.dart @@ -12,23 +12,25 @@ import '../framework/adb.dart'; import '../framework/framework.dart'; import '../framework/utils.dart'; -TaskFunction createGalleryTransitionTest({ @required bool ios: false }) { - return new GalleryTransitionTest(ios: ios); +TaskFunction createGalleryTransitionTest({ @required DeviceOperatingSystem os }) { + return new GalleryTransitionTest(os: os); } class GalleryTransitionTest { - GalleryTransitionTest({ this.ios }); + GalleryTransitionTest({ this.os }) { + deviceOperatingSystem = os; + } - final bool ios; + final DeviceOperatingSystem os; Future call() async { - String deviceId = await getUnlockedDeviceId(ios: ios); + String deviceId = (await devices.workingDevice).deviceId; Directory galleryDirectory = dir('${flutterDirectory.path}/examples/flutter_gallery'); await inDirectory(galleryDirectory, () async { - await pub('get'); + await flutter('packages', options: ['get']); - if (ios) { + if (os == DeviceOperatingSystem.ios) { // This causes an Xcode project to be created. await flutter('build', options: ['ios', '--profile']); } diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 681558430c..ba93bc8283 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -11,26 +11,26 @@ import '../framework/adb.dart'; import '../framework/framework.dart'; import '../framework/utils.dart'; -TaskFunction createComplexLayoutScrollPerfTest({ @required bool ios: false }) { +TaskFunction createComplexLayoutScrollPerfTest({ @required DeviceOperatingSystem os }) { return new PerfTest( '${flutterDirectory.path}/dev/benchmarks/complex_layout', 'test_driver/scroll_perf.dart', 'complex_layout_scroll_perf', - ios: ios + os: os, ); } -TaskFunction createFlutterGalleryStartupTest({ bool ios: false }) { +TaskFunction createFlutterGalleryStartupTest({ @required DeviceOperatingSystem os }) { return new StartupTest( '${flutterDirectory.path}/examples/flutter_gallery', - ios: ios + os: os, ); } -TaskFunction createComplexLayoutStartupTest({ bool ios: false }) { +TaskFunction createComplexLayoutStartupTest({ @required DeviceOperatingSystem os }) { return new StartupTest( '${flutterDirectory.path}/dev/benchmarks/complex_layout', - ios: ios + os: os, ); } @@ -46,17 +46,19 @@ TaskFunction createComplexLayoutBuildTest() { class StartupTest { static const Duration _startupTimeout = const Duration(minutes: 2); - StartupTest(this.testDirectory, { this.ios }); + StartupTest(this.testDirectory, { this.os }) { + deviceOperatingSystem = os; + } final String testDirectory; - final bool ios; + final DeviceOperatingSystem os; Future call() async { return await inDirectory(testDirectory, () async { - String deviceId = await getUnlockedDeviceId(ios: ios); - await pub('get'); + String deviceId = (await devices.workingDevice).deviceId; + await flutter('packages', options: ['get']); - if (ios) { + if (os == DeviceOperatingSystem.ios) { // This causes an Xcode project to be created. await flutter('build', options: ['ios', '--profile']); } @@ -80,19 +82,19 @@ class StartupTest { /// performance. class PerfTest { - PerfTest(this.testDirectory, this.testTarget, this.timelineFileName, { this.ios }); + PerfTest(this.testDirectory, this.testTarget, this.timelineFileName, { this.os }); final String testDirectory; final String testTarget; final String timelineFileName; - final bool ios; + final DeviceOperatingSystem os; Future call() { return inDirectory(testDirectory, () async { - String deviceId = await getUnlockedDeviceId(ios: ios); - await pub('get'); + String deviceId = (await devices.workingDevice).deviceId; + await flutter('packages', options: ['get']); - if (ios) { + if (os == DeviceOperatingSystem.ios) { // This causes an Xcode project to be created. await flutter('build', options: ['ios', '--profile']); } @@ -124,9 +126,9 @@ class BuildTest { Future call() async { return await inDirectory(testDirectory, () async { - Adb device = await adb(); + Device device = await devices.workingDevice; await device.unlock(); - await pub('get'); + await flutter('packages', options: ['get']); Stopwatch watch = new Stopwatch()..start(); await flutter('build', options: [ diff --git a/dev/devicelab/lib/tasks/refresh.dart b/dev/devicelab/lib/tasks/refresh.dart index 5bea990905..ce99ffd2a9 100644 --- a/dev/devicelab/lib/tasks/refresh.dart +++ b/dev/devicelab/lib/tasks/refresh.dart @@ -25,7 +25,7 @@ class EditRefreshTask { final DateTime timestamp; Future call() async { - Adb device = await adb(); + Device device = await devices.workingDevice; await device.unlock(); Benchmark benchmark = new EditRefreshBenchmark(commit, timestamp); section(benchmark.name); @@ -57,7 +57,7 @@ class EditRefreshBenchmark extends Benchmark { @override Future run() async { - Adb device = await adb(); + Device device = await devices.workingDevice; rm(benchmarkFile); int exitCode = await inDirectory(megaDir, () async { return await flutter('run', diff --git a/dev/devicelab/lib/tasks/size_tests.dart b/dev/devicelab/lib/tasks/size_tests.dart index 215162abd9..b1f44f68ee 100644 --- a/dev/devicelab/lib/tasks/size_tests.dart +++ b/dev/devicelab/lib/tasks/size_tests.dart @@ -24,7 +24,7 @@ TaskFunction createBasicMaterialAppSizeTest() { throw 'Failed to create sample Flutter app in ${sampleDir.path}'; await inDirectory(sampleDir, () async { - await pub('get'); + await flutter('packages', options: ['get']); await flutter('build', options: ['clean']); await flutter('build', options: ['apk', '--release']); apkSizeInBytes = await file('${sampleDir.path}/build/app.apk').length(); diff --git a/dev/devicelab/test/adb_test.dart b/dev/devicelab/test/adb_test.dart index 8eb4a2bc48..2a1abf737a 100644 --- a/dev/devicelab/test/adb_test.dart +++ b/dev/devicelab/test/adb_test.dart @@ -10,28 +10,27 @@ import 'package:collection/collection.dart'; import 'package:flutter_devicelab/framework/adb.dart'; void main() { - group('adb', () { - Adb device; + group('device', () { + Device device; setUp(() { - FakeAdb.resetLog(); - adb = null; - device = new FakeAdb(); + FakeDevice.resetLog(); + device = null; + device = new FakeDevice(); }); tearDown(() { - adb = realAdbGetter; }); group('isAwake/isAsleep', () { test('reads Awake', () async { - FakeAdb.pretendAwake(); + FakeDevice.pretendAwake(); expect(await device.isAwake(), isTrue); expect(await device.isAsleep(), isFalse); }); test('reads Asleep', () async { - FakeAdb.pretendAsleep(); + FakeDevice.pretendAsleep(); expect(await device.isAwake(), isFalse); expect(await device.isAsleep(), isTrue); }); @@ -48,7 +47,7 @@ void main() { group('wakeUp', () { test('when awake', () async { - FakeAdb.pretendAwake(); + FakeDevice.pretendAwake(); await device.wakeUp(); expectLog([ cmd(command: 'dumpsys', arguments: ['power']), @@ -56,7 +55,7 @@ void main() { }); test('when asleep', () async { - FakeAdb.pretendAsleep(); + FakeDevice.pretendAsleep(); await device.wakeUp(); expectLog([ cmd(command: 'dumpsys', arguments: ['power']), @@ -67,7 +66,7 @@ void main() { group('sendToSleep', () { test('when asleep', () async { - FakeAdb.pretendAsleep(); + FakeDevice.pretendAsleep(); await device.sendToSleep(); expectLog([ cmd(command: 'dumpsys', arguments: ['power']), @@ -75,7 +74,7 @@ void main() { }); test('when awake', () async { - FakeAdb.pretendAwake(); + FakeDevice.pretendAwake(); await device.sendToSleep(); expectLog([ cmd(command: 'dumpsys', arguments: ['power']), @@ -86,7 +85,7 @@ void main() { group('unlock', () { test('sends unlock event', () async { - FakeAdb.pretendAwake(); + FakeDevice.pretendAwake(); await device.unlock(); expectLog([ cmd(command: 'dumpsys', arguments: ['power']), @@ -98,10 +97,10 @@ void main() { } void expectLog(List log) { - expect(FakeAdb.commandLog, log); + expect(FakeDevice.commandLog, log); } -CommandArgs cmd({ String command, List arguments, Map env }) => new CommandArgs( +CommandArgs cmd({String command, List arguments, Map env}) => new CommandArgs( command: command, arguments: arguments, env: env @@ -110,7 +109,7 @@ CommandArgs cmd({ String command, List arguments, Map en typedef dynamic ExitErrorFactory(); class CommandArgs { - CommandArgs({ this.command, this.arguments, this.env }); + CommandArgs({this.command, this.arguments, this.env}); final String command; final List arguments; @@ -142,8 +141,8 @@ class CommandArgs { : null.hashCode; } -class FakeAdb extends Adb { - FakeAdb({ String deviceId: null }) : super(deviceId: deviceId); +class FakeDevice extends AndroidDevice { + FakeDevice({String deviceId: null}) : super(deviceId: deviceId); static String output = ''; static ExitErrorFactory exitErrorFactory = () => null;