blob: 0a3fe3bbff31bb1b371c15d3a0d0eb27b618ca1b [file] [log] [blame]
Ian Hickson449f4a62019-11-27 15:04:02 -08001// Copyright 2014 The Flutter Authors. All rights reserved.
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alexander Apreleve2e24132018-09-08 17:53:40 -07005import 'dart:convert' show json;
Ian Hickson98c117b2018-08-15 12:22:30 -07006import 'dart:math' as math;
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -07007
8import 'package:args/args.dart';
Alexandre Ardhuin06135292018-03-22 07:56:18 +01009import 'package:flutter_tools/src/base/common.dart';
Todd Volkert6258f322018-07-24 16:33:49 -070010import 'package:flutter_tools/src/base/context.dart';
Alexandre Ardhuin06135292018-03-22 07:56:18 +010011import 'package:flutter_tools/src/base/file_system.dart';
12import 'package:flutter_tools/src/base/io.dart';
Jonah Williamsee7a37f2020-01-06 11:04:20 -080013
Ryan Macnakb7773da2019-10-14 15:26:14 -070014import 'package:flutter_tools/src/build_info.dart';
Alexandre Ardhuin06135292018-03-22 07:56:18 +010015import 'package:flutter_tools/src/cache.dart';
Todd Volkert8d11f5c2018-03-28 10:58:28 -070016import 'package:flutter_tools/src/context_runner.dart';
Gary Miguel35f37402018-07-13 10:37:44 -070017import 'package:flutter_tools/src/artifacts.dart';
Jonah Williamsee7a37f2020-01-06 11:04:20 -080018import 'package:flutter_tools/src/globals.dart' as globals;
Jonah Williams301eaa82019-04-15 08:59:28 -070019import 'package:flutter_tools/src/project.dart';
Zachary Andersonef146f62019-07-29 07:24:02 -070020import 'package:flutter_tools/src/reporting/reporting.dart';
Gary Miguel35f37402018-07-13 10:37:44 -070021import 'package:flutter_tools/src/test/coverage_collector.dart';
22import 'package:flutter_tools/src/test/runner.dart';
Dan Fieldb2323882019-12-18 13:58:01 -080023import 'package:flutter_tools/src/test/test_wrapper.dart';
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070024
Alexandre Ardhuin1fce14a2017-10-22 18:11:36 +020025const String _kOptionPackages = 'packages';
26const String _kOptionShell = 'shell';
27const String _kOptionTestDirectory = 'test-directory';
Todd Volkert5d8771d2018-08-10 21:18:10 -070028const String _kOptionSdkRoot = 'sdk-root';
Todd Volkertf8a5c862018-08-14 20:06:07 -070029const String _kOptionIcudtl = 'icudtl';
Alexander Apreleve2e24132018-09-08 17:53:40 -070030const String _kOptionTests = 'tests';
Jonah Williams63f2fb92018-09-26 13:17:20 -070031const String _kOptionCoverageDirectory = 'coverage-directory';
Alexandre Ardhuineda03e22018-08-02 12:02:32 +020032const List<String> _kRequiredOptions = <String>[
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070033 _kOptionPackages,
34 _kOptionShell,
Todd Volkert5d8771d2018-08-10 21:18:10 -070035 _kOptionSdkRoot,
Alexander Apreleve2e24132018-09-08 17:53:40 -070036 _kOptionIcudtl,
37 _kOptionTests,
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070038];
Gary Miguel35f37402018-07-13 10:37:44 -070039const String _kOptionCoverage = 'coverage';
40const String _kOptionCoveragePath = 'coverage-path';
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070041
Gary Miguel35f37402018-07-13 10:37:44 -070042void main(List<String> args) {
Alexandre Ardhuin2d3ff102018-10-05 07:54:56 +020043 runInContext<void>(() => run(args), overrides: <Type, Generator>{
Alexandre Ardhuind927c932018-09-12 08:29:29 +020044 Usage: () => DisabledUsage(),
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070045 });
46}
47
Alexandre Ardhuin2d3ff102018-10-05 07:54:56 +020048Future<void> run(List<String> args) async {
Alexandre Ardhuind927c932018-09-12 08:29:29 +020049 final ArgParser parser = ArgParser()
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070050 ..addOption(_kOptionPackages, help: 'The .packages file')
51 ..addOption(_kOptionShell, help: 'The Flutter shell binary')
Gary Miguel35f37402018-07-13 10:37:44 -070052 ..addOption(_kOptionTestDirectory, help: 'Directory containing the tests')
Todd Volkert5d8771d2018-08-10 21:18:10 -070053 ..addOption(_kOptionSdkRoot, help: 'Path to the SDK platform files')
Todd Volkertf8a5c862018-08-14 20:06:07 -070054 ..addOption(_kOptionIcudtl, help: 'Path to the ICU data file')
Alexander Apreleve2e24132018-09-08 17:53:40 -070055 ..addOption(_kOptionTests, help: 'Path to json file that maps Dart test files to precompiled dill files')
Jonah Williams63f2fb92018-09-26 13:17:20 -070056 ..addOption(_kOptionCoverageDirectory, help: 'The path to the directory that will have coverage collected')
Gary Miguel35f37402018-07-13 10:37:44 -070057 ..addFlag(_kOptionCoverage,
58 defaultsTo: false,
59 negatable: false,
60 help: 'Whether to collect coverage information.',
61 )
62 ..addOption(_kOptionCoveragePath,
63 defaultsTo: 'coverage/lcov.info',
64 help: 'Where to store coverage information (if coverage is enabled).',
65 );
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070066 final ArgResults argResults = parser.parse(args);
67 if (_kRequiredOptions
68 .any((String option) => !argResults.options.contains(option))) {
Gary Miguel35f37402018-07-13 10:37:44 -070069 throwToolExit('Missing option! All options must be specified.');
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070070 }
Ian Hickson3dec6a62018-08-17 13:17:23 -070071 final Directory tempDir =
Jonah Williamsee7a37f2020-01-06 11:04:20 -080072 globals.fs.systemTempDirectory.createTempSync('flutter_fuchsia_tester.');
P.Y. Laligandd2c6b0a2017-04-27 09:10:48 -070073 try {
Ian Hickson3dec6a62018-08-17 13:17:23 -070074 Cache.flutterRoot = tempDir.path;
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -070075
Jonah Williamsee7a37f2020-01-06 11:04:20 -080076 final String shellPath = globals.fs.file(argResults[_kOptionShell]).resolveSymbolicLinksSync();
77 if (!globals.fs.isFileSync(shellPath)) {
P.Y. Laligandd2c6b0a2017-04-27 09:10:48 -070078 throwToolExit('Cannot find Flutter shell at $shellPath');
79 }
Todd Volkert5d8771d2018-08-10 21:18:10 -070080
Jonah Williamsee7a37f2020-01-06 11:04:20 -080081 final Directory sdkRootSrc = globals.fs.directory(argResults[_kOptionSdkRoot]);
82 if (!globals.fs.isDirectorySync(sdkRootSrc.path)) {
Todd Volkert5d8771d2018-08-10 21:18:10 -070083 throwToolExit('Cannot find SDK files at ${sdkRootSrc.path}');
84 }
Jonah Williams63f2fb92018-09-26 13:17:20 -070085 Directory coverageDirectory;
Alexandre Ardhuinadc73512019-11-19 07:57:42 +010086 final String coverageDirectoryPath = argResults[_kOptionCoverageDirectory] as String;
Jonah Williams63f2fb92018-09-26 13:17:20 -070087 if (coverageDirectoryPath != null) {
Jonah Williamsee7a37f2020-01-06 11:04:20 -080088 if (!globals.fs.isDirectorySync(coverageDirectoryPath)) {
Jonah Williams63f2fb92018-09-26 13:17:20 -070089 throwToolExit('Cannot find coverage directory at $coverageDirectoryPath');
90 }
Jonah Williamsee7a37f2020-01-06 11:04:20 -080091 coverageDirectory = globals.fs.directory(coverageDirectoryPath);
Jonah Williams63f2fb92018-09-26 13:17:20 -070092 }
Todd Volkert5d8771d2018-08-10 21:18:10 -070093
Gary Miguel35f37402018-07-13 10:37:44 -070094 // Put the tester shell where runTests expects it.
Alexandre Ardhuin79b5e5b2018-11-19 10:37:55 +010095 // TODO(garymm): Switch to a Fuchsia-specific Artifacts impl.
Gary Miguel35f37402018-07-13 10:37:44 -070096 final Link testerDestLink =
Jonah Williamsee7a37f2020-01-06 11:04:20 -080097 globals.fs.link(globals.artifacts.getArtifactPath(Artifact.flutterTester));
Gary Miguel35f37402018-07-13 10:37:44 -070098 testerDestLink.parent.createSync(recursive: true);
Jonah Williamsee7a37f2020-01-06 11:04:20 -080099 testerDestLink.createSync(globals.fs.path.absolute(shellPath));
Zachary Anderson61b5caf2019-04-01 07:48:50 -0700100
Todd Volkert5d8771d2018-08-10 21:18:10 -0700101 final Directory sdkRootDest =
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800102 globals.fs.directory(globals.artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath));
Todd Volkert5d8771d2018-08-10 21:18:10 -0700103 sdkRootDest.createSync(recursive: true);
Alexandre Ardhuin4f9b6cf2020-01-07 16:32:04 +0100104 for (final FileSystemEntity artifact in sdkRootSrc.listSync()) {
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800105 globals.fs.link(sdkRootDest.childFile(artifact.basename).path).createSync(artifact.path);
Todd Volkert5d8771d2018-08-10 21:18:10 -0700106 }
107 // TODO(tvolkert): Remove once flutter_tester no longer looks for this.
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800108 globals.fs.link(sdkRootDest.childFile('platform.dill').path).createSync('platform_strong.dill');
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -0700109
Zachary Andersondf1462f2019-02-26 11:35:28 -0800110 Directory testDirectory;
Gary Miguel35f37402018-07-13 10:37:44 -0700111 CoverageCollector collector;
Alexandre Ardhuinadc73512019-11-19 07:57:42 +0100112 if (argResults['coverage'] as bool) {
Jonah Williams28cb5892019-04-15 12:26:43 -0700113 collector = CoverageCollector(
Jonah Williamsa40ee8a2020-11-11 13:50:41 -0800114 packagesPath: globals.fs.path.normalize(globals.fs.path.absolute(argResults[_kOptionPackages] as String)),
Jiahao4de9b442019-07-24 10:58:37 -0700115 libraryPredicate: (String libraryName) {
116 // If we have a specified coverage directory then accept all libraries.
117 if (coverageDirectory != null) {
118 return true;
119 }
120 final String projectName = FlutterProject.current().manifest.appName;
121 return libraryName.contains(projectName);
122 });
Zachary Andersondf1462f2019-02-26 11:35:28 -0800123 if (!argResults.options.contains(_kOptionTestDirectory)) {
124 throwToolExit('Use of --coverage requires setting --test-directory');
125 }
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800126 testDirectory = globals.fs.directory(argResults[_kOptionTestDirectory]);
Gary Miguel35f37402018-07-13 10:37:44 -0700127 }
128
Alexander Apreleve2e24132018-09-08 17:53:40 -0700129
130 final Map<String, String> tests = <String, String>{};
131 final List<Map<String, dynamic>> jsonList = List<Map<String, dynamic>>.from(
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800132 (json.decode(globals.fs.file(argResults[_kOptionTests]).readAsStringSync()) as List<dynamic>).cast<Map<String, dynamic>>());
Alexandre Ardhuin4f9b6cf2020-01-07 16:32:04 +0100133 for (final Map<String, dynamic> map in jsonList) {
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800134 final String source = globals.fs.file(map['source']).resolveSymbolicLinksSync();
135 final String dill = globals.fs.file(map['dill']).resolveSymbolicLinksSync();
Joshua Seaton1ffd5f02019-03-04 10:52:58 -0800136 tests[source] = dill;
Alexander Apreleve2e24132018-09-08 17:53:40 -0700137 }
138
Dan Field24f8f792020-02-12 14:52:09 -0800139 // TODO(dnfield): This should be injected.
140 exitCode = await const FlutterTestRunner().runTests(
Dan Fieldb2323882019-12-18 13:58:01 -0800141 const TestWrapper(),
Alexander Apreleve2e24132018-09-08 17:53:40 -0700142 tests.keys.toList(),
Gary Miguel35f37402018-07-13 10:37:44 -0700143 workDir: testDirectory,
144 watcher: collector,
Todd Volkert5d8771d2018-08-10 21:18:10 -0700145 ipv6: false,
Gary Miguel35f37402018-07-13 10:37:44 -0700146 enableObservatory: collector != null,
Jonah Williamsa40ee8a2020-11-11 13:50:41 -0800147 buildInfo: BuildInfo(
148 BuildMode.debug,
149 '',
150 treeShakeIcons: false,
151 packagesPath: globals.fs.path.normalize(globals.fs.path.absolute(argResults[_kOptionPackages] as String),
152 )),
Alexander Apreleve2e24132018-09-08 17:53:40 -0700153 precompiledDillFiles: tests,
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800154 concurrency: math.max(1, globals.platform.numberOfProcessors - 2),
155 icudtlPath: globals.fs.path.absolute(argResults[_kOptionIcudtl] as String),
Jonah Williams301eaa82019-04-15 08:59:28 -0700156 coverageDirectory: coverageDirectory,
Gary Miguel35f37402018-07-13 10:37:44 -0700157 );
158
159 if (collector != null) {
160 // collector expects currentDirectory to be the root of the dart
Jonah Williams63f2fb92018-09-26 13:17:20 -0700161 // package (i.e. contains lib/ and test/ sub-dirs). In some cases,
162 // test files may appear to be in the root directory.
163 if (coverageDirectory == null) {
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800164 globals.fs.currentDirectory = testDirectory.parent;
Jonah Williams63f2fb92018-09-26 13:17:20 -0700165 } else {
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800166 globals.fs.currentDirectory = testDirectory;
Jonah Williams63f2fb92018-09-26 13:17:20 -0700167 }
Alexandre Ardhuinadc73512019-11-19 07:57:42 +0100168 if (!await collector.collectCoverageData(argResults[_kOptionCoveragePath] as String, coverageDirectory: coverageDirectory)) {
Gary Miguel35f37402018-07-13 10:37:44 -0700169 throwToolExit('Failed to collect coverage data');
Zachary Andersone2340c62019-09-13 14:51:35 -0700170 }
Gary Miguel35f37402018-07-13 10:37:44 -0700171 }
P.Y. Laligandd2c6b0a2017-04-27 09:10:48 -0700172 } finally {
Ian Hickson3dec6a62018-08-17 13:17:23 -0700173 tempDir.deleteSync(recursive: true);
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -0700174 }
Ian Hickson3dec6a62018-08-17 13:17:23 -0700175 // TODO(ianh): There's apparently some sort of lost async task keeping the
176 // process open. Remove the next line once that's been resolved.
Gary Miguel35f37402018-07-13 10:37:44 -0700177 exit(exitCode);
P.Y. Laligand5b02aaa2017-04-20 14:18:24 -0700178}