Unverified Commit d3797628 authored by Alexander Aprelev's avatar Alexander Aprelev Committed by GitHub

Run flutter tests in preview-dart-2 mode on travis flutter builds. (#14728)

* Run flutter tests in preview-dart-2 mode on travis flutter builds.

* Run dart2 tests on osx. Run dart tests in dart2.

* Fix name camelCase

* Default options to empty array, rather than null

* Troubleshoot failures

* More logging

* Troubleshoot: run single test

* Troubleshoot: run 15 tests

* Troubleshoot: run 15 tests with fix

* Try limit concurrency to 1

* Limit concurrency for preview-dart-2 tests to 4

* Move dart2 tests to allow_failures section

* Reinstate tests_dart_2 shard

* Raise concurrency to 8

* Reuse compiler across multiple test runs

* Allow to switch entry points when recompiling.

Actually use single compiler to incrementally recompile all tests executed by 'flutter test'.

* Remove leftover commented code

* Fix comment

* Lints
parent e8d5667a
...@@ -6,6 +6,7 @@ osx_image: xcode9.2 ...@@ -6,6 +6,7 @@ osx_image: xcode9.2
env: env:
- SHARD=analyze - SHARD=analyze
- SHARD=tests - SHARD=tests
- SHARD=tests_dart2
- SHARD=docs - SHARD=docs
- SHARD=build_and_deploy_gallery - SHARD=build_and_deploy_gallery
matrix: matrix:
...@@ -14,6 +15,8 @@ matrix: ...@@ -14,6 +15,8 @@ matrix:
env: SHARD=analyze env: SHARD=analyze
- os: osx - os: osx
env: SHARD=docs env: SHARD=docs
allow_failures:
- env: SHARD=tests_dart2
sudo: false sudo: false
filter_secrets: false filter_secrets: false
......
...@@ -29,6 +29,7 @@ const Map<String, ShardRunner> _kShards = const <String, ShardRunner>{ ...@@ -29,6 +29,7 @@ const Map<String, ShardRunner> _kShards = const <String, ShardRunner>{
'docs': _generateDocs, 'docs': _generateDocs,
'analyze': _analyzeRepo, 'analyze': _analyzeRepo,
'tests': _runTests, 'tests': _runTests,
'tests_dart2': _runTestsDart2,
'coverage': _runCoverage, 'coverage': _runCoverage,
}; };
...@@ -129,35 +130,50 @@ Future<Null> _analyzeRepo() async { ...@@ -129,35 +130,50 @@ Future<Null> _analyzeRepo() async {
print('${bold}DONE: Analysis successful.$reset'); print('${bold}DONE: Analysis successful.$reset');
} }
Future<Null> _runTests() async { Future<Null> _runTestsDart2() async {
if (Platform.isWindows) {
// AppVeyor platform is overloaded, won't be able to handle additional
// load of dart2 testing.
return;
}
_runTests(options: <String>['--preview-dart-2']);
}
Future<Null> _runTests({List<String> options: const <String>[]}) async {
// Verify that the tests actually return failure on failure and success on success. // Verify that the tests actually return failure on failure and success on success.
final String automatedTests = path.join(flutterRoot, 'dev', 'automated_tests'); final String automatedTests = path.join(flutterRoot, 'dev', 'automated_tests');
await _runFlutterTest(automatedTests, await _runFlutterTest(automatedTests,
script: path.join('test_smoke_test', 'fail_test.dart'), script: path.join('test_smoke_test', 'fail_test.dart'),
options: options,
expectFailure: true, expectFailure: true,
printOutput: false, printOutput: false,
); );
await _runFlutterTest(automatedTests, await _runFlutterTest(automatedTests,
script: path.join('test_smoke_test', 'pass_test.dart'), script: path.join('test_smoke_test', 'pass_test.dart'),
options: options,
printOutput: false, printOutput: false,
); );
await _runFlutterTest(automatedTests, await _runFlutterTest(automatedTests,
script: path.join('test_smoke_test', 'crash1_test.dart'), script: path.join('test_smoke_test', 'crash1_test.dart'),
options: options,
expectFailure: true, expectFailure: true,
printOutput: false, printOutput: false,
); );
await _runFlutterTest(automatedTests, await _runFlutterTest(automatedTests,
script: path.join('test_smoke_test', 'crash2_test.dart'), script: path.join('test_smoke_test', 'crash2_test.dart'),
options: options,
expectFailure: true, expectFailure: true,
printOutput: false, printOutput: false,
); );
await _runFlutterTest(automatedTests, await _runFlutterTest(automatedTests,
script: path.join('test_smoke_test', 'syntax_error_test.broken_dart'), script: path.join('test_smoke_test', 'syntax_error_test.broken_dart'),
options: options,
expectFailure: true, expectFailure: true,
printOutput: false, printOutput: false,
); );
await _runFlutterTest(automatedTests, await _runFlutterTest(automatedTests,
script: path.join('test_smoke_test', 'missing_import_test.broken_dart'), script: path.join('test_smoke_test', 'missing_import_test.broken_dart'),
options: options,
expectFailure: true, expectFailure: true,
printOutput: false, printOutput: false,
); );
...@@ -171,21 +187,21 @@ Future<Null> _runTests() async { ...@@ -171,21 +187,21 @@ Future<Null> _runTests() async {
await _verifyVersion(path.join(flutterRoot, 'version')); await _verifyVersion(path.join(flutterRoot, 'version'));
// Run tests. // Run tests.
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter')); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations')); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver')); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test')); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), options: options);
await _pubRunTest(path.join(flutterRoot, 'packages', 'flutter_tools')); await _pubRunTest(path.join(flutterRoot, 'packages', 'flutter_tools'));
await _pubRunTest(path.join(flutterRoot, 'dev', 'bots')); await _pubRunTest(path.join(flutterRoot, 'dev', 'bots'));
await _runAllDartTests(path.join(flutterRoot, 'dev', 'devicelab')); await _runAllDartTests(path.join(flutterRoot, 'dev', 'devicelab'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world')); await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers')); await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'examples', 'stocks')); await _runFlutterTest(path.join(flutterRoot, 'examples', 'stocks'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'examples', 'flutter_gallery')); await _runFlutterTest(path.join(flutterRoot, 'examples', 'flutter_gallery'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'examples', 'catalog')); await _runFlutterTest(path.join(flutterRoot, 'examples', 'catalog'), options: options);
print('${bold}DONE: All tests successful.$reset'); print('${bold}DONE: All tests successful.$reset');
} }
...@@ -356,8 +372,13 @@ Future<Null> _runFlutterTest(String workingDirectory, { ...@@ -356,8 +372,13 @@ Future<Null> _runFlutterTest(String workingDirectory, {
Future<Null> _runAllDartTests(String workingDirectory, { Future<Null> _runAllDartTests(String workingDirectory, {
Map<String, String> environment, Map<String, String> environment,
List<String> options,
}) { }) {
final List<String> args = <String>['--checked', path.join('test', 'all.dart')]; final List<String> args = <String>['--checked'];
if (options != null) {
args.addAll(options);
}
args.add(path.join('test', 'all.dart'));
return _runCommand(dart, args, return _runCommand(dart, args,
workingDirectory: workingDirectory, workingDirectory: workingDirectory,
environment: environment, environment: environment,
......
...@@ -125,23 +125,27 @@ Future<String> compile( ...@@ -125,23 +125,27 @@ Future<String> compile(
/// The wrapper is intended to stay resident in memory as user changes, reloads, /// The wrapper is intended to stay resident in memory as user changes, reloads,
/// restarts the Flutter app. /// restarts the Flutter app.
class ResidentCompiler { class ResidentCompiler {
ResidentCompiler(this._sdkRoot, {bool trackWidgetCreation: false}) ResidentCompiler(this._sdkRoot, {bool trackWidgetCreation: false,
String packagesPath})
: assert(_sdkRoot != null), : assert(_sdkRoot != null),
_trackWidgetCreation = trackWidgetCreation { _trackWidgetCreation = trackWidgetCreation,
_packagesPath = packagesPath {
// This is a URI, not a file path, so the forward slash is correct even on Windows. // This is a URI, not a file path, so the forward slash is correct even on Windows.
if (!_sdkRoot.endsWith('/')) if (!_sdkRoot.endsWith('/'))
_sdkRoot = '$_sdkRoot/'; _sdkRoot = '$_sdkRoot/';
} }
final bool _trackWidgetCreation; final bool _trackWidgetCreation;
final String _packagesPath;
String _sdkRoot; String _sdkRoot;
Process _server; Process _server;
final _StdoutHandler stdoutHandler = new _StdoutHandler(); final _StdoutHandler stdoutHandler = new _StdoutHandler();
/// If invoked for the first time, it compiles Dart script identified by /// If invoked for the first time, it compiles Dart script identified by
/// [mainPath], [invalidatedFiles] list is ignored. /// [mainPath], [invalidatedFiles] list is ignored.
/// Otherwise, [mainPath] is ignored, but [invalidatedFiles] is recompiled /// On successive runs [invalidatedFiles] indicates which files need to be
/// into new binary. /// recompiled. If [mainPath] is [null], previously used [mainPath] entry
/// point that is used for recompilation.
/// Binary file name is returned if compilation was successful, otherwise /// Binary file name is returned if compilation was successful, otherwise
/// null is returned. /// null is returned.
Future<String> recompile(String mainPath, List<String> invalidatedFiles, Future<String> recompile(String mainPath, List<String> invalidatedFiles,
...@@ -154,7 +158,7 @@ class ResidentCompiler { ...@@ -154,7 +158,7 @@ class ResidentCompiler {
return _compile(mainPath, outputPath); return _compile(mainPath, outputPath);
final String inputKey = new Uuid().generateV4(); final String inputKey = new Uuid().generateV4();
_server.stdin.writeln('recompile $inputKey'); _server.stdin.writeln('recompile ${mainPath != null ? mainPath + " ": ""}$inputKey');
invalidatedFiles.forEach(_server.stdin.writeln); invalidatedFiles.forEach(_server.stdin.writeln);
_server.stdin.writeln(inputKey); _server.stdin.writeln(inputKey);
...@@ -179,6 +183,9 @@ class ResidentCompiler { ...@@ -179,6 +183,9 @@ class ResidentCompiler {
if (_trackWidgetCreation) { if (_trackWidgetCreation) {
args.add('--track-widget-creation'); args.add('--track-widget-creation');
} }
if (_packagesPath != null) {
args.addAll(<String>['--packages', _packagesPath]);
}
_server = await processManager.start(args); _server = await processManager.start(args);
_server.stdout _server.stdout
.transform(UTF8.decoder) .transform(UTF8.decoder)
......
...@@ -83,6 +83,13 @@ enum _InitialResult { crashed, timedOut, connected } ...@@ -83,6 +83,13 @@ enum _InitialResult { crashed, timedOut, connected }
enum _TestResult { crashed, harnessBailed, testBailed } enum _TestResult { crashed, harnessBailed, testBailed }
typedef Future<Null> _Finalizer(); typedef Future<Null> _Finalizer();
class CompilationRequest {
String path;
Completer<String> result;
CompilationRequest(this.path, this.result);
}
class _FlutterPlatform extends PlatformPlugin { class _FlutterPlatform extends PlatformPlugin {
_FlutterPlatform({ _FlutterPlatform({
@required this.shellPath, @required this.shellPath,
...@@ -93,7 +100,30 @@ class _FlutterPlatform extends PlatformPlugin { ...@@ -93,7 +100,30 @@ class _FlutterPlatform extends PlatformPlugin {
this.explicitObservatoryPort, this.explicitObservatoryPort,
this.host, this.host,
this.previewDart2, this.previewDart2,
}) : assert(shellPath != null); }) : assert(shellPath != null) {
compilerController.stream.listen((CompilationRequest request) async {
final bool isEmpty = compilationQueue.isEmpty;
compilationQueue.add(request);
// Only trigger processing if queue was empty - i.e. no other requests
// are currently being processed. This effectively enforces "one
// compilation request at a time".
if (isEmpty) {
while (compilationQueue.isNotEmpty) {
final CompilationRequest request = compilationQueue.first;
printTrace('Compiling ${request.path}');
final String outputPath = await compiler.recompile(request.path,
<String>[request.path]
);
print('Finished compilation of ${request.path} into $outputPath');
compiler.accept();
compiler.reset();
request.result.complete(outputPath);
// Only remove now when we finished processing the element
compilationQueue.removeAt(0);
}
}
});
}
final String shellPath; final String shellPath;
final TestWatcher watcher; final TestWatcher watcher;
...@@ -103,6 +133,12 @@ class _FlutterPlatform extends PlatformPlugin { ...@@ -103,6 +133,12 @@ class _FlutterPlatform extends PlatformPlugin {
final int explicitObservatoryPort; final int explicitObservatoryPort;
final InternetAddress host; final InternetAddress host;
final bool previewDart2; final bool previewDart2;
final StreamController<CompilationRequest> compilerController =
new StreamController<CompilationRequest>();
ResidentCompiler compiler =
new ResidentCompiler(artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
packagesPath: PackageMap.globalPackagesPath);
final List<CompilationRequest> compilationQueue = <CompilationRequest>[];
// Each time loadChannel() is called, we spin up a local WebSocket server, // Each time loadChannel() is called, we spin up a local WebSocket server,
// then spin up the engine in a subprocess. We pass the engine a Dart file // then spin up the engine in a subprocess. We pass the engine a Dart file
...@@ -203,12 +239,9 @@ class _FlutterPlatform extends PlatformPlugin { ...@@ -203,12 +239,9 @@ class _FlutterPlatform extends PlatformPlugin {
String bundlePath; String bundlePath;
if (previewDart2) { if (previewDart2) {
mainDart = await compile( final Completer<String> completer = new Completer<String>();
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath), compilerController.add(new CompilationRequest(listenerFile.path, completer));
mainPath: listenerFile.path, mainDart = await completer.future;
packagesPath: PackageMap.globalPackagesPath,
linkPlatformKernelIn: true
);
if (mainDart == null) { if (mainDart == null) {
controller.sink.addError(_getErrorMessage('Compilation failed', testPath, shellPath)); controller.sink.addError(_getErrorMessage('Compilation failed', testPath, shellPath));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment