From 13bf341584aa191ca940259a817cbddfa5a44e4d Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 7 Oct 2020 08:46:11 -0700 Subject: [PATCH] [flutter_tools] update build rules to depend on subset of package_config contents (#67165) Split from #66776 Even if pub does not change the packge_config contents, it will still update a timestamp in one of the fields. This causes unnecessary rebuilds. To fix this, generate an additional file when running pub get that only contains the relevant fields and then update the KernelSnapshot rule to depend on it only. --- .../lib/src/build_system/targets/android.dart | 1 - .../lib/src/build_system/targets/common.dart | 16 +- packages/flutter_tools/lib/src/dart/pub.dart | 55 +++++-- .../hermetic/analyze_continuously_test.dart | 1 - .../{dart_test.dart => common_test.dart} | 42 ++++-- .../test/general.shard/dart/pub_get_test.dart | 46 ++++++ .../test_test.dart | 137 ++++++++---------- 7 files changed, 189 insertions(+), 109 deletions(-) rename packages/flutter_tools/test/general.shard/build_system/targets/{dart_test.dart => common_test.dart} (94%) rename packages/flutter_tools/test/{commands.shard/permeable => integration.shard}/test_test.dart (69%) diff --git a/packages/flutter_tools/lib/src/build_system/targets/android.dart b/packages/flutter_tools/lib/src/build_system/targets/android.dart index dfdb85cc979..82713a6885a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/android.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/android.dart @@ -192,7 +192,6 @@ class AndroidAot extends AotElfBase { List get inputs => [ const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/android.dart'), const Source.pattern('{BUILD_DIR}/app.dill'), - const Source.pattern('{PROJECT_DIR}/.packages'), const Source.artifact(Artifact.engineDartBinary), const Source.artifact(Artifact.skyEnginePath), Source.artifact(Artifact.genSnapshot, diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 7c978656cd7..b4612fc466d 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -161,8 +161,12 @@ class ReleaseCopyFlutterBundle extends CopyFlutterBundle { List get dependencies => const []; } - /// Generate a snapshot of the dart code used in the program. +/// +/// Note that this target depends on the `.dart_tool/package_config.json` file +/// even though it is not listed as an input. Pub inserts a timestamp into +/// the file which causes unecessary rebuilds, so instead a subset of the contents +/// are used an input instead. class KernelSnapshot extends Target { const KernelSnapshot(); @@ -171,7 +175,7 @@ class KernelSnapshot extends Target { @override List get inputs => const [ - Source.pattern('{PROJECT_DIR}/.packages'), + Source.pattern('{PROJECT_DIR}/.dart_tool/package_config_subset'), Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), Source.artifact(Artifact.platformKernelDill), Source.artifact(Artifact.engineDartBinary), @@ -209,7 +213,9 @@ class KernelSnapshot extends Target { } final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final String targetFile = environment.defines[kTargetFile] ?? environment.fileSystem.path.join('lib', 'main.dart'); - final File packagesFile = environment.projectDir.childFile('.packages'); + final File packagesFile = environment.projectDir + .childDirectory('.dart_tool') + .childFile('package_config.json'); final String targetFileAbsolute = environment.fileSystem.file(targetFile).absolute.path; // everything besides 'false' is considered to be enabled. final bool trackWidgetCreation = environment.defines[kTrackWidgetCreation] != 'false'; @@ -240,7 +246,7 @@ class KernelSnapshot extends Target { } final PackageConfig packageConfig = await loadPackageConfigWithLogging( - environment.projectDir.childFile('.packages'), + packagesFile, logger: environment.logger, ); @@ -341,7 +347,6 @@ class AotElfProfile extends AotElfBase { List get inputs => [ const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), const Source.pattern('{BUILD_DIR}/app.dill'), - const Source.pattern('{PROJECT_DIR}/.packages'), const Source.artifact(Artifact.engineDartBinary), const Source.artifact(Artifact.skyEnginePath), Source.artifact(Artifact.genSnapshot, @@ -374,7 +379,6 @@ class AotElfRelease extends AotElfBase { List get inputs => [ const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), const Source.pattern('{BUILD_DIR}/app.dill'), - const Source.pattern('{PROJECT_DIR}/.packages'), const Source.artifact(Artifact.engineDartBinary), const Source.artifact(Artifact.skyEnginePath), Source.artifact(Artifact.genSnapshot, diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index 9bff641361c..9830ff414d5 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart @@ -250,10 +250,11 @@ class _DefaultPub implements Pub { 'The time now is: $now' ); } - // Insert references to synthetic flutter package. - if (generateSyntheticPackage) { - await _updatePackageConfig(packageConfigFile, generatedDirectory); - } + await _updatePackageConfig( + packageConfigFile, + generatedDirectory, + generateSyntheticPackage, + ); } @override @@ -458,13 +459,35 @@ class _DefaultPub implements Pub { return environment; } - /// Insert the flutter_gen synthetic package into the package configuration file if - /// there is an l10n.yaml. - Future _updatePackageConfig(File packageConfigFile, Directory generatedDirectory) async { - if (!packageConfigFile.existsSync()) { + /// Update the package configuration file. + /// + /// Creates a corresponding `package_config_subset` file that is used by the build + /// system to avoid rebuilds caused by an updated pub timestamp. + /// + /// if [generateSyntheticPackage] is true then insert flutter_gen synthetic + /// package into the package configuration. This is used by the l10n localization + /// tooling to insert a new reference into the package_config file, allowing the import + /// of a package URI that is not specified in the pubspec.yaml + /// + /// For more information, see: + /// * [generateLocalizations], `in lib/src/localizations/gen_l10n.dart` + Future _updatePackageConfig( + File packageConfigFile, + Directory generatedDirectory, + bool generateSyntheticPackage, + ) async { + final PackageConfig packageConfig = await loadPackageConfigWithLogging(packageConfigFile, logger: _logger); + + packageConfigFile.parent + .childFile('package_config_subset') + .writeAsStringSync(_computePackageConfigSubset( + packageConfig, + _fileSystem, + )); + + if (!generateSyntheticPackage) { return; } - final PackageConfig packageConfig = await loadPackageConfigWithLogging(packageConfigFile, logger: _logger); final Package flutterGen = Package('flutter_gen', generatedDirectory.uri, languageVersion: LanguageVersion(2, 8)); if (packageConfig.packages.any((Package package) => package.name == 'flutter_gen')) { return; @@ -480,4 +503,18 @@ class _DefaultPub implements Pub { await savePackageConfig(newPackageConfig, packageConfigFile.parent.parent); } } + + // Subset the package config file to only the parts that are relevant for + // rerunning the dart compiler. + String _computePackageConfigSubset(PackageConfig packageConfig, FileSystem fileSystem) { + final StringBuffer buffer = StringBuffer(); + for (final Package package in packageConfig.packages) { + buffer.writeln(package.name); + buffer.writeln(package.languageVersion); + buffer.writeln(package.root); + buffer.writeln(package.packageUriRoot); + } + buffer.writeln(packageConfig.version); + return buffer.toString(); + } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart index badc6932cbd..16fa0e02591 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart @@ -117,7 +117,6 @@ void main() { platform: const LocalPlatform(), usage: globals.flutterUsage, botDetector: globals.botDetector, - toolStampFile: () => globals.fs.file('test'), ); await pub.get( context: PubContext.flutterTests, diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart similarity index 94% rename from packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart rename to packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 36d61222300..c5d88a195f2 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -72,7 +72,9 @@ void main() { }); testWithoutContext('KernelSnapshot handles null result from kernel compilation', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -91,7 +93,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -106,7 +108,9 @@ void main() { }); testWithoutContext('KernelSnapshot does not use track widget creation on profile builds', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -125,7 +129,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -140,7 +144,9 @@ void main() { }); testWithoutContext('KernelSnapshot correctly handles an empty string in ExtraFrontEndOptions', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -159,7 +165,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -175,7 +181,9 @@ void main() { }); testWithoutContext('KernelSnapshot correctly forwards ExtraFrontEndOptions', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -194,7 +202,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -212,7 +220,9 @@ void main() { }); testWithoutContext('KernelSnapshot can disable track-widget-creation on debug builds', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -230,7 +240,7 @@ void main() { ...buildModeOptions(BuildMode.debug), '--no-link-platform', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -247,7 +257,9 @@ void main() { }); testWithoutContext('KernelSnapshot forces platform linking on debug for darwin target platforms', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -264,7 +276,7 @@ void main() { '-Ddart.developer.causal_async_stacks=true', ...buildModeOptions(BuildMode.debug), '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -283,7 +295,9 @@ void main() { }); testWithoutContext('KernelSnapshot does use track widget creation on debug builds', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final Environment testEnvironment = Environment.test( fileSystem.currentDirectory, defines: { @@ -313,7 +327,7 @@ void main() { '--track-widget-creation', '--no-link-platform', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', diff --git a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart index 26ea2f0ff02..1b76f9d8e8e 100644 --- a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart +++ b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart @@ -223,6 +223,52 @@ void main() { verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1); }); + testWithoutContext('package_config_subset file is generated from packages and not timestamp', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final MockUsage usage = MockUsage(); + final Pub pub = Pub( + fileSystem: fileSystem, + logger: BufferLogger.test(), + processManager: MockProcessManager(0), + botDetector: const BotDetectorAlwaysNo(), + usage: usage, + platform: FakePlatform( + environment: const { + 'PUB_CACHE': 'custom/pub-cache/path', + } + ), + ); + fileSystem.file('pubspec.yaml').createSync(); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync(''' + {"configVersion": 2,"packages": [ + { + "name": "flutter_tools", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "2.7" + } + ],"generated":"some-time"} +'''); + + await pub.get( + context: PubContext.flutterTests, + generateSyntheticPackage: true, + checkLastModified: false, + ); + + expect( + fileSystem.file('.dart_tool/package_config_subset').readAsStringSync(), + 'flutter_tools\n' + '2.7\n' + 'file:///\n' + 'file:///lib/\n' + '2\n', + ); + }); + + testWithoutContext('analytics sent on failure', () async { MockDirectory.findCache = true; final MockUsage usage = MockUsage(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/test_test.dart b/packages/flutter_tools/test/integration.shard/test_test.dart similarity index 69% rename from packages/flutter_tools/test/commands.shard/permeable/test_test.dart rename to packages/flutter_tools/test/integration.shard/test_test.dart index 87796974475..15aab8af2aa 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/test_test.dart +++ b/packages/flutter_tools/test/integration.shard/test_test.dart @@ -5,79 +5,84 @@ import 'dart:async'; import 'dart:convert'; -import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; -import '../../src/common.dart'; -import '../../src/context.dart'; +import '../src/common.dart'; +import 'test_utils.dart'; // This test depends on some files in ///dev/automated_tests/flutter_test/* -Future _testExclusionLock; +final String automatedTestsDirectory = fileSystem.path.join('..', '..', 'dev', 'automated_tests'); +final String missingDependencyDirectory = fileSystem.path.join('..', '..', 'dev', 'missing_dependency_tests'); +final String flutterTestDirectory = fileSystem.path.join(automatedTestsDirectory, 'flutter_test'); +final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'flutter.bat' : 'flutter'); void main() { - final String automatedTestsDirectory = globals.fs.path.join('..', '..', 'dev', 'automated_tests'); - final String flutterTestDirectory = globals.fs.path.join(automatedTestsDirectory, 'flutter_test'); + setUpAll(() async { + await processManager.run( + [ + flutterBin, + 'pub', + 'get' + ], + workingDirectory: flutterTestDirectory + ); + await processManager.run( + [ + flutterBin, + 'pub', + 'get' + ], + workingDirectory: missingDependencyDirectory + ); + }); - testUsingContext('flutter test should not have extraneous error messages', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should not have extraneous error messages', () async { return _testFile('trivial_widget', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero); }); - testUsingContext('flutter test should report nice errors for exceptions thrown within testWidgets()', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report nice errors for exceptions thrown within testWidgets()', () async { return _testFile('exception_handling', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when a guarded function was called without await', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when a guarded function was called without await', () async { return _testFile('test_async_utils_guarded', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when an async function was called without await', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when an async function was called without await', () async { return _testFile('test_async_utils_unguarded', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when a Ticker is left running', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when a Ticker is left running', () async { return _testFile('ticker', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when a pubspec.yaml is missing a flutter_test dependency', () async { - final String missingDependencyTests = globals.fs.path.join('..', '..', 'dev', 'missing_dependency_tests'); - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when a pubspec.yaml is missing a flutter_test dependency', () async { + final String missingDependencyTests = fileSystem.path.join('..', '..', 'dev', 'missing_dependency_tests'); return _testFile('trivial', missingDependencyTests, missingDependencyTests); }); - testUsingContext('flutter test should report which user-created widget caused the error', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report which user-created widget caused the error', () async { return _testFile('print_user_created_ancestor', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--track-widget-creation']); }); - testUsingContext('flutter test should report which user-created widget caused the error - no flag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report which user-created widget caused the error - no flag', () async { return _testFile('print_user_created_ancestor_no_flag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--no-track-widget-creation']); }); - testUsingContext('flutter test should report the correct user-created widget that caused the error', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report the correct user-created widget that caused the error', () async { return _testFile('print_correct_local_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--track-widget-creation']); }); - testUsingContext('flutter test should can load assets within its own package', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should can load assets within its own package', () async { return _testFile('package_assets', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero); }); - testUsingContext('flutter test should run a test when its name matches a regexp', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a test when its name matches a regexp', () async { final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--name', 'inc.*de']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -86,8 +91,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run a test when its name contains a string', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a test when its name contains a string', () async { final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--plain-name', 'include']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -96,8 +100,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run a test with a given tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a test with a given tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--tags', 'include-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -106,8 +109,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should not run a test with excluded tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should not run a test with excluded tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--exclude-tags', 'exclude-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -116,8 +118,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run all tests when tags are unspecified', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run all tests when tags are unspecified', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory); if (!(result.stdout as String).contains('+1 -1: Some tests failed')) { fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); @@ -125,8 +126,7 @@ void main() { expect(result.exitCode, 1); }); - testUsingContext('flutter test should run a widgetTest with a given tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a widgetTest with a given tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--tags', 'include-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -135,8 +135,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should not run a widgetTest with excluded tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should not run a widgetTest with excluded tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--exclude-tags', 'exclude-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -145,8 +144,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run all widgetTest when tags are unspecified', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run all widgetTest when tags are unspecified', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory); if (!(result.stdout as String).contains('+1 -1: Some tests failed')) { fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); @@ -154,8 +152,7 @@ void main() { expect(result.exitCode, 1); }); - testUsingContext('flutter test should test runs to completion', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should test runs to completion', () async { final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--verbose']); final String stdout = result.stdout as String; @@ -172,8 +169,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run all tests inside of a directory with no trailing slash', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run all tests inside of a directory with no trailing slash', () async { final ProcessResult result = await _runFlutterTest(null, automatedTestsDirectory, flutterTestDirectory + '/child_directory', extraArguments: const ['--verbose']); final String stdout = result.stdout as String; @@ -199,16 +195,12 @@ Future _testFile( List extraArguments = const [], }) async { exitCode ??= isNonZero; - final String fullTestExpectation = globals.fs.path.join(testDirectory, '${testName}_expectation.txt'); - final File expectationFile = globals.fs.file(fullTestExpectation); + final String fullTestExpectation = fileSystem.path.join(testDirectory, '${testName}_expectation.txt'); + final File expectationFile = fileSystem.file(fullTestExpectation); if (!expectationFile.existsSync()) { fail('missing expectation file: $expectationFile'); } - while (_testExclusionLock != null) { - await _testExclusionLock; - } - final ProcessResult exec = await _runFlutterTest( testName, workingDirectory, @@ -226,7 +218,7 @@ Future _testFile( } output.add('<>'); output.addAll((exec.stderr as String).split('\n')); - final List expectations = globals.fs.file(fullTestExpectation).readAsLinesSync(); + final List expectations = fileSystem.file(fullTestExpectation).readAsLinesSync(); bool allowSkip = false; int expectationLineNumber = 0; int outputLineNumber = 0; @@ -288,44 +280,33 @@ Future _runFlutterTest( if (testName == null) { // Test everything in the directory. testPath = testDirectory; - final Directory directoryToTest = globals.fs.directory(testPath); + final Directory directoryToTest = fileSystem.directory(testPath); if (!directoryToTest.existsSync()) { fail('missing test directory: $directoryToTest'); } } else { // Test just a specific test file. - testPath = globals.fs.path.join(testDirectory, '${testName}_test.dart'); - final File testFile = globals.fs.file(testPath); + testPath = fileSystem.path.join(testDirectory, '${testName}_test.dart'); + final File testFile = fileSystem.file(testPath); if (!testFile.existsSync()) { fail('missing test file: $testFile'); } } final List args = [ - globals.fs.path.absolute(globals.fs.path.join('bin', 'flutter_tools.dart')), 'test', '--no-color', '--no-version-check', + '--no-pub', ...extraArguments, testPath, ]; - while (_testExclusionLock != null) { - await _testExclusionLock; - } - - final Completer testExclusionCompleter = Completer(); - _testExclusionLock = testExclusionCompleter.future; - try { - return await Process.run( - globals.artifacts.getArtifactPath(Artifact.engineDartBinary), - args, - workingDirectory: workingDirectory, - stdoutEncoding: utf8, - stderrEncoding: utf8, - ); - } finally { - _testExclusionLock = null; - testExclusionCompleter.complete(); - } + return Process.run( + flutterBin, // Uses the precompiled flutter tool for faster tests, + args, + workingDirectory: workingDirectory, + stdoutEncoding: utf8, + stderrEncoding: utf8, + ); }