diff --git a/dev/devicelab/analysis_options.yaml b/dev/devicelab/analysis_options.yaml new file mode 100644 index 00000000000..acd91c6c38e --- /dev/null +++ b/dev/devicelab/analysis_options.yaml @@ -0,0 +1,5 @@ +include: ../../analysis_options.yaml + +linter: + rules: + - unawaited_futures diff --git a/dev/devicelab/bin/run.dart b/dev/devicelab/bin/run.dart index 26a9f2651f9..d10c8411425 100644 --- a/dev/devicelab/bin/run.dart +++ b/dev/devicelab/bin/run.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:args/args.dart'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/ab.dart'; import 'package:flutter_devicelab/framework/manifest.dart'; import 'package:flutter_devicelab/framework/runner.dart'; @@ -183,7 +184,7 @@ Future _runABTest() async { abTest.finalize(); final File jsonFile = _uniqueFile(args['ab-result-file'] as String ?? 'ABresults#.json'); - jsonFile.writeAsString(const JsonEncoder.withIndent(' ').convert(abTest.jsonMap)); + unawaited(jsonFile.writeAsString(const JsonEncoder.withIndent(' ').convert(abTest.jsonMap))); if (!silent) { section('Raw results'); diff --git a/dev/devicelab/bin/tasks/build_mode_test.dart b/dev/devicelab/bin/tasks/build_mode_test.dart index 5dd61fe7149..9b7ae9abc11 100644 --- a/dev/devicelab/bin/tasks/build_mode_test.dart +++ b/dev/devicelab/bin/tasks/build_mode_test.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -38,9 +39,9 @@ Future runFlutterAndQuit(List args, Device device) async { stderr.add(line); }, ); - run.exitCode.then((int exitCode) { + unawaited(run.exitCode.then((int exitCode) { runExitCode = exitCode; - }); + })); await Future.any(>[ready.future, run.exitCode]); if (runExitCode != null) { throw 'Failed to run test app; runner unexpected exited, with exit code $runExitCode.'; diff --git a/dev/devicelab/bin/tasks/flutter_attach_test_fuchsia.dart b/dev/devicelab/bin/tasks/flutter_attach_test_fuchsia.dart index d93e93fe762..e9a8145388a 100644 --- a/dev/devicelab/bin/tasks/flutter_attach_test_fuchsia.dart +++ b/dev/devicelab/bin/tasks/flutter_attach_test_fuchsia.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -202,7 +203,7 @@ void main() { section('Hot reload'); runProcess.stdin.write('r'); - runProcess.stdin.flush(); + unawaited(runProcess.stdin.flush()); await eventOrExit(reloadedCompleter.future); section('Waiting for Dart VM'); @@ -212,7 +213,7 @@ void main() { section('Quitting flutter run'); runProcess.stdin.write('q'); - runProcess.stdin.flush(); + unawaited(runProcess.stdin.flush()); final int runExitCode = await runProcess.exitCode; if (runExitCode != 0 || runStderr.isNotEmpty) { diff --git a/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart b/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart index 58a353de10d..a46e5f28d80 100644 --- a/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart +++ b/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart @@ -4,6 +4,7 @@ import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -106,5 +107,5 @@ Future _doTest() async { } Future main() async { - task(_doTest); + unawaited(task(_doTest)); } diff --git a/dev/devicelab/bin/tasks/flutter_run_test.dart b/dev/devicelab/bin/tasks/flutter_run_test.dart index c05b713ac6b..f80f8f110c3 100644 --- a/dev/devicelab/bin/tasks/flutter_run_test.dart +++ b/dev/devicelab/bin/tasks/flutter_run_test.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -70,7 +71,7 @@ Future createFlutterRunTask() async { } }); await finished.future.timeout(const Duration(minutes: 1)); - subscription.cancel(); + unawaited(subscription.cancel()); run.kill(); }); return passedTest && failedTest && skippedTest && finishedMessage && printMessage && writelnMessage diff --git a/dev/devicelab/bin/tasks/gradle_desugar_classes_test.dart b/dev/devicelab/bin/tasks/gradle_desugar_classes_test.dart index 73e1264f56b..e9c36299825 100644 --- a/dev/devicelab/bin/tasks/gradle_desugar_classes_test.dart +++ b/dev/devicelab/bin/tasks/gradle_desugar_classes_test.dart @@ -4,6 +4,7 @@ import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/apk_utils.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -15,7 +16,7 @@ Future main() async { try { await runProjectTest((FlutterProject flutterProject) async { section('APK contains plugin classes'); - flutterProject.addPlugin('google_maps_flutter', value: '^1.0.10'); + unawaited(flutterProject.addPlugin('google_maps_flutter', value: '^1.0.10')); await inDirectory(flutterProject.rootPath, () async { await flutter('build', options: [ diff --git a/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart b/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart index a61ec2fbe8d..ac918bb6439 100644 --- a/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart +++ b/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart @@ -4,6 +4,7 @@ import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/apk_utils.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -217,7 +218,8 @@ Future main() async { }); section('Configure'); - project.addPlugin('plugin_under_test', value: '$platformLineSep path: ${pluginDir.path}'); + unawaited(project.addPlugin('plugin_under_test', + value: '$platformLineSep path: ${pluginDir.path}')); await project.addCustomBuildType('local', initWith: 'debug'); await project.getPackages(); diff --git a/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart b/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart index ffddd5eb1b4..ad6936be09b 100644 --- a/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart +++ b/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/ios.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -80,7 +81,7 @@ Future main() async { 'EFQRCode.framework', 'EFQRCode', ); - _checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath); + unawaited(_checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath)); section('Clean build'); @@ -100,7 +101,7 @@ Future main() async { checkDirectoryExists(appBundle); await _checkFlutterFrameworkArchs(appFrameworkPath, isSimulator: false); await _checkFlutterFrameworkArchs(flutterFrameworkPath, isSimulator: false); - _checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath); + unawaited(_checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath)); section('Clean build'); diff --git a/dev/devicelab/bin/tasks/ios_content_validation_test.dart b/dev/devicelab/bin/tasks/ios_content_validation_test.dart index 79c6493d3f9..bd0ebaad882 100644 --- a/dev/devicelab/bin/tasks/ios_content_validation_test.dart +++ b/dev/devicelab/bin/tasks/ios_content_validation_test.dart @@ -4,6 +4,7 @@ import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/apk_utils.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -53,7 +54,7 @@ Future main() async { 'Flutter', ); // Exits 0 only if codesigned. - eval('xcrun', ['codesign', '--verify', flutterFramework]); + unawaited(eval('xcrun', ['codesign', '--verify', flutterFramework])); final String appFramework = path.join( appBundle.path, @@ -61,7 +62,7 @@ Future main() async { 'App.framework', 'App', ); - eval('xcrun', ['codesign', '--verify', appFramework]); + unawaited(eval('xcrun', ['codesign', '--verify', appFramework])); }); return TaskResult.success(null); diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 9eedb54555f..b5c0d011b4d 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/host_agent.dart'; import 'package:flutter_devicelab/framework/ios.dart'; @@ -464,7 +465,7 @@ Future main() async { } catch (e) { return TaskResult.failure(e.toString()); } finally { - removeIOSimulator(simulatorDeviceId); + unawaited(removeIOSimulator(simulatorDeviceId)); rmTree(tempDir); } }); diff --git a/dev/devicelab/bin/tasks/routing_test.dart b/dev/devicelab/bin/tasks/routing_test.dart index 4df0ba4e634..4ca9351aa28 100644 --- a/dev/devicelab/bin/tasks/routing_test.dart +++ b/dev/devicelab/bin/tasks/routing_test.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/host_agent.dart'; @@ -68,7 +69,7 @@ void main() { .listen((String line) { stderr.writeln('run:stderr: $line'); }); - run.exitCode.then((int exitCode) { ok = false; }); + unawaited(run.exitCode.then((int exitCode) { ok = false; })); await Future.any(>[ ready.future, run.exitCode ]); if (!ok) throw 'Failed to run test app.'; diff --git a/dev/devicelab/bin/tasks/run_release_test.dart b/dev/devicelab/bin/tasks/run_release_test.dart index f87001221f4..edb63e05d8c 100644 --- a/dev/devicelab/bin/tasks/run_release_test.dart +++ b/dev/devicelab/bin/tasks/run_release_test.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -79,7 +80,7 @@ void main() { print('run:stderr: $line'); stderr.add(line); }); - run.exitCode.then((int exitCode) { runExitCode = exitCode; }); + unawaited(run.exitCode.then((int exitCode) { runExitCode = exitCode; })); await Future.any(>[ ready.future, run.exitCode ]); if (runExitCode != null) { throw 'Failed to run test app; runner unexpected exited, with exit code $runExitCode.'; diff --git a/dev/devicelab/bin/tasks/service_extensions_test.dart b/dev/devicelab/bin/tasks/service_extensions_test.dart index a877d91a2a6..e518114b7df 100644 --- a/dev/devicelab/bin/tasks/service_extensions_test.dart +++ b/dev/devicelab/bin/tasks/service_extensions_test.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -50,7 +51,7 @@ void main() { .listen((String line) { stderr.writeln('run:stderr: $line'); }); - run.exitCode.then((int exitCode) { ok = false; }); + unawaited(run.exitCode.then((int exitCode) { ok = false; })); await Future.any(>[ ready.future, run.exitCode ]); if (!ok) throw 'Failed to run test app.'; @@ -101,7 +102,7 @@ void main() { final Future navigationFuture = navigationEvents.first; // This tap triggers a navigation event. - device.tap(100, 200); + unawaited(device.tap(100, 200)); final Event navigationEvent = await navigationFuture; // validate the fields diff --git a/dev/devicelab/bin/test_runner.dart b/dev/devicelab/bin/test_runner.dart index c069d2b9650..52376cf4f71 100644 --- a/dev/devicelab/bin/test_runner.dart +++ b/dev/devicelab/bin/test_runner.dart @@ -8,6 +8,7 @@ import 'package:args/command_runner.dart'; import 'package:flutter_devicelab/command/test.dart'; import 'package:flutter_devicelab/command/upload_metrics.dart'; +import 'package:flutter_devicelab/common.dart'; final CommandRunner runner = CommandRunner('devicelab_runner', 'DeviceLab test runner for recording performance metrics on applications') @@ -15,10 +16,10 @@ final CommandRunner runner = ..addCommand(UploadMetricsCommand()); Future main(List rawArgs) async { - runner.run(rawArgs).catchError((dynamic error) { + unawaited(runner.run(rawArgs).catchError((dynamic error) { stderr.writeln('$error\n'); stderr.writeln('Usage:\n'); stderr.writeln(runner.usage); exit(64); // Exit code 64 indicates a usage error. - }); + })); } diff --git a/dev/devicelab/lib/common.dart b/dev/devicelab/lib/common.dart new file mode 100644 index 00000000000..3d275c54b76 --- /dev/null +++ b/dev/devicelab/lib/common.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// Indicates to the linter that the given future is intentionally not awaited. +/// +/// Has the same functionality as `unawaited` from `package:pedantic`. +/// +/// In an async context, it is normally expected than all Futures are awaited, +/// and that is the basis of the lint unawaited_futures which is turned on for +/// the flutter_tools package. However, there are times where one or more +/// futures are intentionally not awaited. This function may be used to ignore a +/// particular future. It silences the unawaited_futures lint. +void unawaited(Future future) { } diff --git a/dev/devicelab/lib/framework/adb.dart b/dev/devicelab/lib/framework/adb.dart index 88a66b335d2..d877feae53f 100644 --- a/dev/devicelab/lib/framework/adb.dart +++ b/dev/devicelab/lib/framework/adb.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math' as math; +import 'package:flutter_devicelab/common.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; @@ -591,13 +592,13 @@ class AndroidDevice extends Device { .listen((String line) { print('adb logcat stderr: $line'); }, onDone: () { stderrDone.complete(); }); - process.exitCode.then((int exitCode) { + unawaited(process.exitCode.then((int exitCode) { print('adb logcat process terminated with exit code $exitCode'); if (!aborted) { stream.addError(BuildFailedError('adb logcat failed with exit code $exitCode.\n')); processDone.complete(); } - }); + })); await Future.any(>[ Future.wait(>[ stdoutDone.future, diff --git a/dev/devicelab/lib/framework/browser.dart b/dev/devicelab/lib/framework/browser.dart index df310aec7e4..d0a3f84b244 100644 --- a/dev/devicelab/lib/framework/browser.dart +++ b/dev/devicelab/lib/framework/browser.dart @@ -7,6 +7,7 @@ import 'dart:convert' show json, utf8, LineSplitter, JsonEncoder; import 'dart:io' as io; import 'dart:math' as math; +import 'package:flutter_devicelab/common.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; @@ -625,9 +626,9 @@ Future _spawnChromiumProcess(String executable, List args, { // A precaution that avoids accumulating browser processes, in case the // glibc bug doesn't cause the browser to quit and we keep looping and // launching more processes. - process.exitCode.timeout(const Duration(seconds: 1), onTimeout: () { + unawaited(process.exitCode.timeout(const Duration(seconds: 1), onTimeout: () { process.kill(); return null; - }); + })); } } diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart index e9919c025d9..23a8d7bef2e 100644 --- a/dev/devicelab/lib/framework/runner.dart +++ b/dev/devicelab/lib/framework/runner.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:meta/meta.dart'; import 'package:vm_service/vm_service.dart'; @@ -103,9 +104,9 @@ Future runTask( bool runnerFinished = false; - runner.exitCode.whenComplete(() { + unawaited(runner.exitCode.whenComplete(() { runnerFinished = true; - }); + })); final Completer uri = Completer(); diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart index 77f86f73600..7ba13492066 100644 --- a/dev/devicelab/lib/framework/utils.dart +++ b/dev/devicelab/lib/framework/utils.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math' as math; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; @@ -291,10 +292,10 @@ Future startProcess( final ProcessInfo processInfo = ProcessInfo(command, process); _runningProcesses.add(processInfo); - process.exitCode.then((int exitCode) { + unawaited(process.exitCode.then((int exitCode) { print('"$executable" exit code: $exitCode'); _runningProcesses.remove(processInfo); - }); + })); return process; } diff --git a/dev/devicelab/lib/tasks/build_test_task.dart b/dev/devicelab/lib/tasks/build_test_task.dart index 8d4ad4a1ae9..808512530cb 100644 --- a/dev/devicelab/lib/tasks/build_test_task.dart +++ b/dev/devicelab/lib/tasks/build_test_task.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:args/args.dart'; +import 'package:flutter_devicelab/common.dart'; import '../framework/adb.dart'; import '../framework/task_result.dart'; @@ -106,7 +107,7 @@ abstract class BuildTestTask { } if (!testOnly) { - build(); + unawaited(build()); } if (buildOnly) { diff --git a/dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart b/dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart index 1fa7b8ff85d..cb3cbe942ed 100644 --- a/dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart +++ b/dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; @@ -168,7 +169,7 @@ class PluginPlatformInterfaceMacOS { section('Wait for registry execution after hot restart'); await registryExecutedCompleter.future; - subscription.cancel(); + unawaited(subscription.cancel()); run.kill(); }); return TaskResult.success(null); diff --git a/dev/devicelab/lib/tasks/web_benchmarks.dart b/dev/devicelab/lib/tasks/web_benchmarks.dart index ad0d71001c5..3423db693fb 100644 --- a/dev/devicelab/lib/tasks/web_benchmarks.dart +++ b/dev/devicelab/lib/tasks/web_benchmarks.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert' show json; import 'dart:io' as io; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/browser.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; @@ -58,7 +59,7 @@ Future runWebBenchmark({ @required bool useCanvasKit }) async { 'Requested to run bechmark ${benchmarkIterator.current}, but ' 'got results for $benchmarkName.', )); - server.close(); + unawaited(server.close()); } // Trace data is null when the benchmark is not frame-based, such as RawRecorder. @@ -80,7 +81,7 @@ Future runWebBenchmark({ @required bool useCanvasKit }) async { return Response.ok('Stopped performance tracing'); } else if (request.requestedUri.path.endsWith('/on-error')) { final Map errorDetails = json.decode(await request.readAsString()) as Map; - server.close(); + unawaited(server.close()); // Keep the stack trace as a string. It's thrown in the browser, not this Dart VM. profileData.completeError('${errorDetails['error']}\n${errorDetails['stackTrace']}'); return Response.ok(''); @@ -183,7 +184,7 @@ Future runWebBenchmark({ @required bool useCanvasKit }) async { } return TaskResult.success(taskResult, benchmarkScoreKeys: benchmarkScoreKeys); } finally { - server?.close(); + unawaited(server?.close()); chrome?.stop(); } });