Unverified Commit 124aa6f8 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] use package:test for coverage and remove build_runner test precompilation (#51966)

parent 75932286
...@@ -39,8 +39,6 @@ final List<String> flutterTestArgs = <String>[]; ...@@ -39,8 +39,6 @@ final List<String> flutterTestArgs = <String>[];
final bool useFlutterTestFormatter = Platform.environment['FLUTTER_TEST_FORMATTER'] == 'true'; final bool useFlutterTestFormatter = Platform.environment['FLUTTER_TEST_FORMATTER'] == 'true';
final bool canUseBuildRunner = Platform.environment['FLUTTER_TEST_NO_BUILD_RUNNER'] != 'true';
/// The number of Cirrus jobs that run host-only devicelab tests in parallel. /// The number of Cirrus jobs that run host-only devicelab tests in parallel.
/// ///
/// WARNING: if you change this number, also change .cirrus.yml /// WARNING: if you change this number, also change .cirrus.yml
...@@ -236,18 +234,18 @@ Future<bq.BigqueryApi> _getBigqueryApi() async { ...@@ -236,18 +234,18 @@ Future<bq.BigqueryApi> _getBigqueryApi() async {
} }
Future<void> _runToolCoverage() async { Future<void> _runToolCoverage() async {
await runCommand( // Precompile tests to speed up subsequent runs. await _pubRunTest(
pub, toolRoot,
<String>['run', 'build_runner', 'build'], testPaths: <String>[
workingDirectory: toolRoot, path.join('test', 'general.shard'),
path.join('test', 'commands.shard', 'hermetic'),
],
coverage: 'coverage',
); );
await runCommand( await runCommand(pub,
dart, <String>['run', 'coverage:format_coverage', '--lcov', '--in=coverage', '--out=coverage/lcov.info'],
<String>[path.join('tool', 'tool_coverage.dart')],
workingDirectory: toolRoot, workingDirectory: toolRoot,
environment: <String, String>{ outputMode: OutputMode.discard,
'FLUTTER_ROOT': flutterRoot,
}
); );
} }
...@@ -273,8 +271,7 @@ Future<void> _runToolTests() async { ...@@ -273,8 +271,7 @@ Future<void> _runToolTests() async {
: ''; : '';
await _pubRunTest( await _pubRunTest(
toolsPath, toolsPath,
testPath: path.join(kTest, '$subshard$kDotShard', suffix), testPaths: <String>[path.join(kTest, '$subshard$kDotShard', suffix)],
useBuildRunner: canUseBuildRunner,
tableData: bigqueryApi?.tabledata, tableData: bigqueryApi?.tabledata,
enableFlutterToolAsserts: true, enableFlutterToolAsserts: true,
); );
...@@ -706,25 +703,12 @@ Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) asy ...@@ -706,25 +703,12 @@ Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) asy
} }
Future<void> _pubRunTest(String workingDirectory, { Future<void> _pubRunTest(String workingDirectory, {
String testPath, List<String> testPaths,
bool enableFlutterToolAsserts = true, bool enableFlutterToolAsserts = true,
bool useBuildRunner = false, bool useBuildRunner = false,
String coverage,
bq.TabledataResourceApi tableData, bq.TabledataResourceApi tableData,
}) async { }) async {
final List<String> args = <String>['run'];
if (useBuildRunner) {
final String posixTestPath = path.posix.joinAll(path.split(testPath));
args.addAll(<String>[
'build_runner',
'test',
'--build-filter=$posixTestPath/*.dill',
'--build-filter=$posixTestPath/**/*.dill',
'--',
]);
} else {
args.add('test');
}
args.add(useFlutterTestFormatter ? '-rjson' : '-rcompact');
int cpus; int cpus;
final String cpuVariable = Platform.environment['CPU']; // CPU is set in cirrus.yml final String cpuVariable = Platform.environment['CPU']; // CPU is set in cirrus.yml
if (cpuVariable != null) { if (cpuVariable != null) {
...@@ -737,11 +721,23 @@ Future<void> _pubRunTest(String workingDirectory, { ...@@ -737,11 +721,23 @@ Future<void> _pubRunTest(String workingDirectory, {
} else { } else {
cpus = 2; // Don't default to 1, otherwise we won't catch race conditions. cpus = 2; // Don't default to 1, otherwise we won't catch race conditions.
} }
args.add('-j$cpus');
if (!hasColor) final List<String> args = <String>[
args.add('--no-color'); 'run',
if (testPath != null) 'test',
args.add(testPath); if (useFlutterTestFormatter)
'-rjson'
else
'-rcompact',
'-j$cpus',
if (!hasColor)
'--no-color',
if (coverage != null)
'--coverage=$coverage',
if (testPaths != null)
for (final String testPath in testPaths)
testPath,
];
final Map<String, String> pubEnvironment = <String, String>{ final Map<String, String> pubEnvironment = <String, String>{
'FLUTTER_ROOT': flutterRoot, 'FLUTTER_ROOT': flutterRoot,
}; };
......
...@@ -98,30 +98,15 @@ dev_dependencies: ...@@ -98,30 +98,15 @@ dev_dependencies:
mockito: 4.1.1 mockito: 4.1.1
file_testing: 2.1.0 file_testing: 2.1.0
test: 1.14.1 test: 1.14.1
build_runner: 1.7.4 pubspec_parse: 0.1.5
build_vm_compilers: 1.0.4
build_test: 0.10.12+1
bazel_worker: 0.1.23+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
build: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
build_config: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
build_modules: 2.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
build_resolvers: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
build_runner_core: 4.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
checked_yaml: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" checked_yaml: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
code_builder: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dart_style: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
graphs: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_annotation: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_annotation: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble: 1.4.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 1.4.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
protobuf: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pubspec_parse: 0.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
scratch_space: 0.0.4+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
timing: 0.1.1+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dartdoc: dartdoc:
# Exclude this package from the hosted API docs. # Exclude this package from the hosted API docs.
nodoc: true nodoc: true
# PUBSPEC CHECKSUM: 193b # PUBSPEC CHECKSUM: 86fe
// 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.
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'dart:isolate';
import 'package:coverage/coverage.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/test/test_wrapper.dart';
import 'package:path/path.dart' as path;
import 'package:stream_channel/isolate_channel.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/test/coverage_collector.dart';
/// Generates an lcov report for the flutter tool unit tests.
///
/// Example invocation:
///
/// dart tool/tool_coverage.dart
Future<void> main(List<String> arguments) async {
return runInContext(() async {
final VMPlatform vmPlatform = VMPlatform();
const TestWrapper test = TestWrapper();
test.registerPlatformPlugin(
<Runtime>[Runtime.vm],
() => vmPlatform,
);
if (arguments.isEmpty) {
arguments = <String>[
path.join('test', 'general.shard'),
path.join('test', 'commands.shard', 'hermetic'),
];
}
await test.main(<String>[
'--no-color',
'-r', 'compact',
'-j', '1',
...arguments
]);
exit(exitCode);
});
}
/// A platform that loads tests in isolates spawned within this Dart process.
class VMPlatform extends PlatformPlugin {
final CoverageCollector coverageCollector = CoverageCollector(
libraryPredicate: (String libraryName) => libraryName.contains(FlutterProject.current().manifest.appName),
);
final Map<String, Future<void>> _pending = <String, Future<void>>{};
final String precompiledPath = path.join('.dart_tool', 'build', 'generated', 'flutter_tools');
@override
StreamChannel<void> loadChannel(String codePath, SuitePlatform platform) =>
throw UnimplementedError();
@override
Future<RunnerSuite> load(
String codePath,
SuitePlatform platform,
SuiteConfiguration suiteConfig,
Object message,
) async {
final ReceivePort receivePort = ReceivePort();
Isolate isolate;
try {
isolate = await _spawnIsolate(codePath, receivePort.sendPort);
} catch (error) {
receivePort.close();
rethrow;
}
final Completer<void> completer = Completer<void>();
// When this is completed we remove it from the map of pending so we can
// log the futures that get "stuck".
unawaited(completer.future.whenComplete(() {
_pending.remove(codePath);
}));
final ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
final StreamChannel<Object> channel = IsolateChannel<Object>.connectReceive(receivePort)
.transformStream(StreamTransformer<Object, Object>.fromHandlers(
handleDone: (EventSink<Object> sink) async {
try {
// this will throw if collection fails.
await coverageCollector.collectCoverageIsolate(info.serverUri);
} finally {
isolate.kill(priority: Isolate.immediate);
isolate = null;
sink.close();
completer.complete();
}
},
handleError: (dynamic error, StackTrace stackTrace, EventSink<Object> sink) {
isolate.kill(priority: Isolate.immediate);
isolate = null;
sink.close();
completer.complete();
},
));
final RunnerSuiteController controller = deserializeSuite(
codePath,
platform,
suiteConfig,
null,
channel,
message,
);
_pending[codePath] = completer.future;
return await controller.suite;
}
/// Spawns an isolate and passes it [message].
///
/// This isolate connects an [IsolateChannel] to [message] and sends the
/// serialized tests over that channel.
Future<Isolate> _spawnIsolate(String codePath, SendPort message) async {
String testPath = path.absolute(path.join(precompiledPath, codePath) + '.vm_test.dart');
testPath = testPath.substring(0, testPath.length - '.dart'.length) + '.vm.app.dill';
return await Isolate.spawnUri(path.toUri(testPath), <String>[], message,
packageConfig: path.toUri('.packages'),
checked: true,
);
}
@override
Future<void> close() async {
try {
await Future.wait(_pending.values).timeout(const Duration(minutes: 1));
} on TimeoutException {
// TODO(jonahwilliams): resolve whether there are any specific tests that
// get stuck or if it is a general infra issue with how we are collecting
// coverage.
// Log tests that are "Stuck" waiting for coverage.
print('The following tests timed out waiting for coverage:');
print(_pending.keys.join(', '));
}
final String packagePath = Directory.current.path;
final Resolver resolver = Resolver(packagesPath: '.packages');
final Formatter formatter = LcovFormatter(resolver, reportOn: <String>[
'lib',
], basePath: packagePath);
final String result = await coverageCollector.finalizeCoverage(
formatter: formatter,
);
final String outputLcovPath = path.join('coverage', 'lcov.info');
File(outputLcovPath)
..createSync(recursive: true)
..writeAsStringSync(result);
}
}
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