add an --enable-vmservice flag (#50663)
diff --git a/packages/flutter_tools/bin/fuchsia_tester.dart b/packages/flutter_tools/bin/fuchsia_tester.dart index 0e60a96..0fc00e5 100644 --- a/packages/flutter_tools/bin/fuchsia_tester.dart +++ b/packages/flutter_tools/bin/fuchsia_tester.dart
@@ -142,7 +142,8 @@ tests[source] = dill; } - exitCode = await runTests( + // TODO(dnfield): This should be injected. + exitCode = await const FlutterTestRunner().runTests( const TestWrapper(), tests.keys.toList(), workDir: testDirectory,
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index 101b142..a4a26f7 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -27,6 +27,7 @@ TestCommand({ bool verboseHelp = false, this.testWrapper = const TestWrapper(), + this.testRunner = const FlutterTestRunner(), }) : assert(testWrapper != null) { requiresPubspecYaml(); usesPubOption(); @@ -110,6 +111,15 @@ 'test cases (must be a 32bit unsigned integer).\n' 'If "random", pick a random seed to use.\n' 'If 0 or not set, do not randomize test case execution order.', + ) + ..addFlag('enable-vmservice', + defaultsTo: false, + hide: !verboseHelp, + help: 'Enables the vmservice without --start-paused. This flag is ' + 'intended for use with tests that will use dart:developer to ' + 'interact with the vmservice at runtime.\n' + 'This flag is ignored if --start-paused or coverage are requested. ' + 'The vmservice will be enabled no matter what in those cases.' ); usesTrackWidgetCreation(verboseHelp: verboseHelp); } @@ -117,6 +127,9 @@ /// The interface for starting and configuring the tester. final TestWrapper testWrapper; + /// Interface for running the tester process. + final FlutterTestRunner testRunner; + @override Future<Set<DevelopmentArtifact>> get requiredArtifacts async { final Set<DevelopmentArtifact> results = <DevelopmentArtifact>{}; @@ -235,14 +248,14 @@ final bool disableServiceAuthCodes = boolArg('disable-service-auth-codes'); - final int result = await runTests( + final int result = await testRunner.runTests( testWrapper, files, workDir: workDir, names: names, plainNames: plainNames, watcher: watcher, - enableObservatory: collector != null || startPaused, + enableObservatory: collector != null || startPaused || boolArg('enable-vmservice'), startPaused: startPaused, disableServiceAuthCodes: disableServiceAuthCodes, ipv6: boolArg('ipv6'),
diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index 1577d1c..6f1b095 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart
@@ -20,141 +20,177 @@ import 'test_wrapper.dart'; import 'watcher.dart'; -/// Runs tests using package:test and the Flutter engine. -Future<int> runTests( - TestWrapper testWrapper, - List<String> testFiles, { - Directory workDir, - List<String> names = const <String>[], - List<String> plainNames = const <String>[], - bool enableObservatory = false, - bool startPaused = false, - bool disableServiceAuthCodes = false, - bool ipv6 = false, - bool machine = false, - String precompiledDillPath, - Map<String, String> precompiledDillFiles, - @required BuildMode buildMode, - bool trackWidgetCreation = false, - bool updateGoldens = false, - TestWatcher watcher, - @required int concurrency, - bool buildTestAssets = false, - FlutterProject flutterProject, - String icudtlPath, - Directory coverageDirectory, - bool web = false, - String randomSeed = '0', -}) async { - // Configure package:test to use the Flutter engine for child processes. - final String shellPath = globals.artifacts.getArtifactPath(Artifact.flutterTester); - if (!globals.processManager.canRun(shellPath)) { - throwToolExit('Cannot execute Flutter tester at $shellPath'); - } +/// A class that abstracts launching the test process from the test runner. +abstract class FlutterTestRunner { + const factory FlutterTestRunner() = _FlutterTestRunnerImpl; - // Compute the command-line arguments for package:test. - final List<String> testArgs = <String>[ - if (!globals.terminal.supportsColor) - '--no-color', - if (startPaused) - '--pause-after-load', - if (machine) - ...<String>['-r', 'json'] - else - ...<String>['-r', 'compact'], - '--concurrency=$concurrency', - for (final String name in names) - ...<String>['--name', name], - for (final String plainName in plainNames) - ...<String>['--plain-name', plainName], - '--test-randomize-ordering-seed=$randomSeed', - ]; - if (web) { - final String tempBuildDir = globals.fs.systemTempDirectory - .createTempSync('flutter_test.') - .absolute - .uri - .toFilePath(); - final bool result = await webCompilationProxy.initialize( - projectDirectory: flutterProject.directory, - testOutputDir: tempBuildDir, - testFiles: testFiles, - projectName: flutterProject.manifest.appName, - initializePlatform: true, - ); - if (!result) { - throwToolExit('Failed to compile tests'); + /// Runs tests using package:test and the Flutter engine. + Future<int> runTests( + TestWrapper testWrapper, + List<String> testFiles, { + Directory workDir, + List<String> names = const <String>[], + List<String> plainNames = const <String>[], + bool enableObservatory = false, + bool startPaused = false, + bool disableServiceAuthCodes = false, + bool ipv6 = false, + bool machine = false, + String precompiledDillPath, + Map<String, String> precompiledDillFiles, + @required BuildMode buildMode, + bool trackWidgetCreation = false, + bool updateGoldens = false, + TestWatcher watcher, + @required int concurrency, + bool buildTestAssets = false, + FlutterProject flutterProject, + String icudtlPath, + Directory coverageDirectory, + bool web = false, + String randomSeed = '0', + }); +} + +class _FlutterTestRunnerImpl implements FlutterTestRunner { + const _FlutterTestRunnerImpl(); + + @override + Future<int> runTests( + TestWrapper testWrapper, + List<String> testFiles, { + Directory workDir, + List<String> names = const <String>[], + List<String> plainNames = const <String>[], + bool enableObservatory = false, + bool startPaused = false, + bool disableServiceAuthCodes = false, + bool ipv6 = false, + bool machine = false, + String precompiledDillPath, + Map<String, String> precompiledDillFiles, + @required BuildMode buildMode, + bool trackWidgetCreation = false, + bool updateGoldens = false, + TestWatcher watcher, + @required int concurrency, + bool buildTestAssets = false, + FlutterProject flutterProject, + String icudtlPath, + Directory coverageDirectory, + bool web = false, + String randomSeed = '0', + }) async { + // Configure package:test to use the Flutter engine for child processes. + final String shellPath = globals.artifacts.getArtifactPath(Artifact.flutterTester); + if (!globals.processManager.canRun(shellPath)) { + throwToolExit('Cannot execute Flutter tester at $shellPath'); } + + // Compute the command-line arguments for package:test. + final List<String> testArgs = <String>[ + if (!globals.terminal.supportsColor) + '--no-color', + if (startPaused) + '--pause-after-load', + if (machine) + ...<String>['-r', 'json'] + else + ...<String>['-r', 'compact'], + '--concurrency=$concurrency', + for (final String name in names) + ...<String>['--name', name], + for (final String plainName in plainNames) + ...<String>['--plain-name', plainName], + '--test-randomize-ordering-seed=$randomSeed', + ]; + if (web) { + final String tempBuildDir = globals.fs.systemTempDirectory + .createTempSync('flutter_test.') + .absolute + .uri + .toFilePath(); + final bool result = await webCompilationProxy.initialize( + projectDirectory: flutterProject.directory, + testOutputDir: tempBuildDir, + testFiles: testFiles, + projectName: flutterProject.manifest.appName, + initializePlatform: true, + ); + if (!result) { + throwToolExit('Failed to compile tests'); + } + testArgs + ..add('--platform=chrome') + ..add('--precompiled=$tempBuildDir') + ..add('--') + ..addAll(testFiles); + testWrapper.registerPlatformPlugin( + <Runtime>[Runtime.chrome], + () { + return FlutterWebPlatform.start( + flutterProject.directory.path, + updateGoldens: updateGoldens, + shellPath: shellPath, + flutterProject: flutterProject, + pauseAfterLoad: startPaused, + ); + }, + ); + await testWrapper.main(testArgs); + return exitCode; + } + testArgs - ..add('--platform=chrome') - ..add('--precompiled=$tempBuildDir') ..add('--') ..addAll(testFiles); - testWrapper.registerPlatformPlugin( - <Runtime>[Runtime.chrome], - () { - return FlutterWebPlatform.start( - flutterProject.directory.path, - updateGoldens: updateGoldens, - shellPath: shellPath, - flutterProject: flutterProject, - pauseAfterLoad: startPaused, - ); - }, + + final InternetAddressType serverType = + ipv6 ? InternetAddressType.IPv6 : InternetAddressType.IPv4; + + final loader.FlutterPlatform platform = loader.installHook( + testWrapper: testWrapper, + shellPath: shellPath, + watcher: watcher, + enableObservatory: enableObservatory, + machine: machine, + startPaused: startPaused, + disableServiceAuthCodes: disableServiceAuthCodes, + serverType: serverType, + precompiledDillPath: precompiledDillPath, + precompiledDillFiles: precompiledDillFiles, + buildMode: buildMode, + trackWidgetCreation: trackWidgetCreation, + updateGoldens: updateGoldens, + buildTestAssets: buildTestAssets, + projectRootDirectory: globals.fs.currentDirectory.uri, + flutterProject: flutterProject, + icudtlPath: icudtlPath, ); - await testWrapper.main(testArgs); - return exitCode; - } - testArgs - ..add('--') - ..addAll(testFiles); + // Make the global packages path absolute. + // (Makes sure it still works after we change the current directory.) + PackageMap.globalPackagesPath = + globals.fs.path.normalize(globals.fs.path.absolute(PackageMap.globalPackagesPath)); - final InternetAddressType serverType = - ipv6 ? InternetAddressType.IPv6 : InternetAddressType.IPv4; + // Call package:test's main method in the appropriate directory. + final Directory saved = globals.fs.currentDirectory; + try { + if (workDir != null) { + globals.printTrace('switching to directory $workDir to run tests'); + globals.fs.currentDirectory = workDir; + } - final loader.FlutterPlatform platform = loader.installHook( - testWrapper: testWrapper, - shellPath: shellPath, - watcher: watcher, - enableObservatory: enableObservatory, - machine: machine, - startPaused: startPaused, - disableServiceAuthCodes: disableServiceAuthCodes, - serverType: serverType, - precompiledDillPath: precompiledDillPath, - precompiledDillFiles: precompiledDillFiles, - buildMode: buildMode, - trackWidgetCreation: trackWidgetCreation, - updateGoldens: updateGoldens, - buildTestAssets: buildTestAssets, - projectRootDirectory: globals.fs.currentDirectory.uri, - flutterProject: flutterProject, - icudtlPath: icudtlPath, - ); + globals.printTrace('running test package with arguments: $testArgs'); + await testWrapper.main(testArgs); - // Make the global packages path absolute. - // (Makes sure it still works after we change the current directory.) - PackageMap.globalPackagesPath = - globals.fs.path.normalize(globals.fs.path.absolute(PackageMap.globalPackagesPath)); + // test.main() sets dart:io's exitCode global. + globals.printTrace('test package returned with exit code $exitCode'); - // Call package:test's main method in the appropriate directory. - final Directory saved = globals.fs.currentDirectory; - try { - if (workDir != null) { - globals.printTrace('switching to directory $workDir to run tests'); - globals.fs.currentDirectory = workDir; + return exitCode; + } finally { + globals.fs.currentDirectory = saved; + await platform.close(); } - - globals.printTrace('running test package with arguments: $testArgs'); - await testWrapper.main(testArgs); - - // test.main() sets dart:io's exitCode global. - globals.printTrace('test package returned with exit code $exitCode'); - - return exitCode; - } finally { - globals.fs.currentDirectory = saved; - await platform.close(); } }
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart index b8145cf..792a0c8 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart
@@ -7,9 +7,13 @@ import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/test.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/test/runner.dart'; import 'package:flutter_tools/src/test/test_wrapper.dart'; +import 'package:flutter_tools/src/test/watcher.dart'; import 'package:process/process.dart'; import '../../src/common.dart'; @@ -73,6 +77,92 @@ ProcessManager: () => FakeProcessManager.any(), Cache: () => FakeCache(), }); + + testUsingContext('Pipes enable-observatory', () async { + final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); + + final TestCommand testCommand = TestCommand(testRunner: testRunner); + final CommandRunner<void> commandRunner = + createTestCommandRunner(testCommand); + + await commandRunner.run(const <String>[ + 'test', + '--no-pub', + '--enable-vmservice', + '--', + 'test/fake_test.dart', + ]); + expect( + testRunner.lastEnableObservatoryValue, + true, + ); + + await commandRunner.run(const <String>[ + 'test', + '--no-pub', + '--start-paused', + '--no-enable-vmservice', + '--', + 'test/fake_test.dart', + ]); + expect( + testRunner.lastEnableObservatoryValue, + true, + ); + + await commandRunner.run(const <String>[ + 'test', + '--no-pub', + '--', + 'test/fake_test.dart', + ]); + expect( + testRunner.lastEnableObservatoryValue, + false, + ); + }, overrides: <Type, Generator>{ + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + Cache: () => FakeCache(), + }); +} + +class FakeFlutterTestRunner implements FlutterTestRunner { + FakeFlutterTestRunner(this.exitCode); + + int exitCode; + bool lastEnableObservatoryValue; + + @override + Future<int> runTests( + TestWrapper testWrapper, + List<String> testFiles, { + Directory workDir, + List<String> names = const <String>[], + List<String> plainNames = const <String>[], + bool enableObservatory = false, + bool startPaused = false, + bool disableServiceAuthCodes = false, + bool ipv6 = false, + bool machine = false, + String precompiledDillPath, + Map<String, String> precompiledDillFiles, + BuildMode buildMode, + bool trackWidgetCreation = false, + bool updateGoldens = false, + TestWatcher watcher, + int concurrency, + bool buildTestAssets = false, + FlutterProject flutterProject, + String icudtlPath, + Directory coverageDirectory, + bool web = false, + String randomSeed = '0', + }) async { + lastEnableObservatoryValue = enableObservatory; + return exitCode; + } + } class FakePackageTest implements TestWrapper {