Implement `flutter test -j` (#20493)
diff --git a/packages/flutter_tools/bin/fuchsia_tester.dart b/packages/flutter_tools/bin/fuchsia_tester.dart
index 10d8aca..b77017d 100644
--- a/packages/flutter_tools/bin/fuchsia_tester.dart
+++ b/packages/flutter_tools/bin/fuchsia_tester.dart
@@ -3,12 +3,14 @@
// found in the LICENSE file.
import 'dart:async';
+import 'dart:math' as math;
import 'package:args/args.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
+import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/dart/package_map.dart';
@@ -121,6 +123,7 @@
enableObservatory: collector != null,
previewDart2: true,
precompiledDillPath: dillFile.path,
+ concurrency: math.max(1, platform.numberOfProcessors - 2),
);
if (collector != null) {
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart
index 1541dfc..ca8c571 100644
--- a/packages/flutter_tools/lib/src/commands/test.dart
+++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -3,9 +3,11 @@
// found in the LICENSE file.
import 'dart:async';
+import 'dart:math' as math;
import '../base/common.dart';
import '../base/file_system.dart';
+import '../base/platform.dart';
import '../cache.dart';
import '../runner/flutter_command.dart';
import '../test/coverage_collector.dart';
@@ -77,7 +79,12 @@
negatable: false,
help: 'Whether matchesGoldenFile() calls within your test methods should\n'
'update the golden files rather than test for an existing match.',
- );
+ )
+ ..addOption('concurrency',
+ abbr: 'j',
+ defaultsTo: math.max<int>(1, platform.numberOfProcessors - 2).toString(),
+ help: 'The number of concurrent test processes to run.',
+ valueHelp: 'jobs');
}
@override
@@ -91,10 +98,10 @@
await super.validateCommand();
if (!fs.isFileSync('pubspec.yaml')) {
throwToolExit(
- 'Error: No pubspec.yaml file found in the current working directory.\n'
- 'Run this command from the root of your project. Test files must be\n'
- 'called *_test.dart and must reside in the package\'s \'test\'\n'
- 'directory (or one of its subdirectories).');
+ 'Error: No pubspec.yaml file found in the current working directory.\n'
+ 'Run this command from the root of your project. Test files must be\n'
+ 'called *_test.dart and must reside in the package\'s \'test\'\n'
+ 'directory (or one of its subdirectories).');
}
}
@@ -108,8 +115,16 @@
final bool startPaused = argResults['start-paused'];
if (startPaused && files.length != 1) {
throwToolExit(
- 'When using --start-paused, you must specify a single test file to run.',
- exitCode: 1);
+ 'When using --start-paused, you must specify a single test file to run.',
+ exitCode: 1,
+ );
+ }
+
+ final int jobs = int.tryParse(argResults['concurrency']);
+ if (jobs == null || jobs <= 0 || !jobs.isFinite) {
+ throwToolExit(
+ 'Could not parse -j/--concurrency argument. It must be an integer greater than zero.'
+ );
}
Directory workDir;
@@ -123,7 +138,7 @@
if (files.isEmpty) {
throwToolExit(
'Test directory "${workDir.path}" does not appear to contain any test files.\n'
- 'Test files must be in that directory and end with the pattern "_test.dart".'
+ 'Test files must be in that directory and end with the pattern "_test.dart".'
);
}
}
@@ -135,8 +150,7 @@
final bool machine = argResults['machine'];
if (collector != null && machine) {
- throwToolExit(
- "The test command doesn't support --machine and coverage together");
+ throwToolExit("The test command doesn't support --machine and coverage together");
}
TestWatcher watcher;
@@ -161,6 +175,7 @@
previewDart2: argResults['preview-dart-2'],
trackWidgetCreation: argResults['track-widget-creation'],
updateGoldens: argResults['update-goldens'],
+ concurrency: jobs,
);
if (collector != null) {
diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart
index bc97ec6..a286df6 100644
--- a/packages/flutter_tools/lib/src/test/runner.dart
+++ b/packages/flutter_tools/lib/src/test/runner.dart
@@ -5,8 +5,8 @@
import 'dart:async';
import 'package:args/command_runner.dart';
-// ignore: implementation_imports
-import 'package:test/src/executable.dart' as test;
+import 'package:meta/meta.dart';
+import 'package:test/src/executable.dart' as test; // ignore: implementation_imports
import '../artifacts.dart';
import '../base/common.dart';
@@ -21,20 +21,21 @@
/// Runs tests using package:test and the Flutter engine.
Future<int> runTests(
- List<String> testFiles, {
- Directory workDir,
- List<String> names = const <String>[],
- List<String> plainNames = const <String>[],
- bool enableObservatory = false,
- bool startPaused = false,
- bool ipv6 = false,
- bool machine = false,
- bool previewDart2 = false,
- String precompiledDillPath,
- bool trackWidgetCreation = false,
- bool updateGoldens = false,
- TestWatcher watcher,
- }) async {
+ List<String> testFiles, {
+ Directory workDir,
+ List<String> names = const <String>[],
+ List<String> plainNames = const <String>[],
+ bool enableObservatory = false,
+ bool startPaused = false,
+ bool ipv6 = false,
+ bool machine = false,
+ bool previewDart2 = false,
+ String precompiledDillPath,
+ bool trackWidgetCreation = false,
+ bool updateGoldens = false,
+ TestWatcher watcher,
+ @required int concurrency,
+}) async {
if (trackWidgetCreation && !previewDart2) {
throw new UsageException(
'--track-widget-creation is valid only when --preview-dart-2 is specified.',
@@ -54,13 +55,7 @@
testArgs.addAll(<String>['-r', 'compact']);
}
- if (enableObservatory) { // (In particular, for collecting code coverage.)
- // Turn on concurrency, but just barely. This is a trade-off between running
- // too many tests such that they all time out, and too few tests such that
- // the tests overall take too much time. The current number is empirically
- // based on what our infrastructure can handle, which isn't ideal...
- testArgs.add('--concurrency=2');
- }
+ testArgs.add('--concurrency=$concurrency');
for (String name in names) {
testArgs..add('--name')..add(name);