| // Copyright 2019 The Chromium 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 'package:file/file.dart'; |
| import 'package:path/path.dart' as p; |
| import 'package:platform/platform.dart'; |
| import 'common.dart'; |
| |
| class DriveExamplesCommand extends PluginCommand { |
| DriveExamplesCommand( |
| Directory packagesDir, |
| FileSystem fileSystem, { |
| ProcessRunner processRunner = const ProcessRunner(), |
| }) : super(packagesDir, fileSystem, processRunner: processRunner) { |
| argParser.addFlag(kLinux, |
| help: 'Runs the Linux implementation of the examples'); |
| argParser.addFlag(kMacos, |
| help: 'Runs the macOS implementation of the examples'); |
| argParser.addFlag(kWindows, |
| help: 'Runs the Windows implementation of the examples'); |
| argParser.addFlag(kIos, |
| help: 'Runs the iOS implementation of the examples'); |
| argParser.addFlag(kAndroid, |
| help: 'Runs the Android implementation of the examples'); |
| argParser.addOption( |
| kEnableExperiment, |
| defaultsTo: '', |
| help: |
| 'Runs the driver tests in Dart VM with the given experiments enabled.', |
| ); |
| } |
| |
| @override |
| final String name = 'drive-examples'; |
| |
| @override |
| final String description = 'Runs driver tests for plugin example apps.\n\n' |
| 'For each *_test.dart in test_driver/ it drives an application with a ' |
| 'corresponding name in the test/ or test_driver/ directories.\n\n' |
| 'For example, test_driver/app_test.dart would match test/app.dart.\n\n' |
| 'This command requires "flutter" to be in your path.\n\n' |
| 'If a file with a corresponding name cannot be found, this driver file' |
| 'will be used to drive the tests that match ' |
| 'integration_test/*_test.dart.'; |
| |
| @override |
| Future<Null> run() async { |
| checkSharding(); |
| final List<String> failingTests = <String>[]; |
| final bool isLinux = argResults[kLinux]; |
| final bool isMacos = argResults[kMacos]; |
| final bool isWindows = argResults[kWindows]; |
| await for (Directory plugin in getPlugins()) { |
| final String flutterCommand = |
| LocalPlatform().isWindows ? 'flutter.bat' : 'flutter'; |
| for (Directory example in getExamplesForPlugin(plugin)) { |
| final String packageName = |
| p.relative(example.path, from: packagesDir.path); |
| if (!(await pluginSupportedOnCurrentPlatform(plugin, fileSystem))) { |
| continue; |
| } |
| final Directory driverTests = |
| fileSystem.directory(p.join(example.path, 'test_driver')); |
| if (!driverTests.existsSync()) { |
| // No driver tests available for this example |
| continue; |
| } |
| // Look for driver tests ending in _test.dart in test_driver/ |
| await for (FileSystemEntity test in driverTests.list()) { |
| final String driverTestName = |
| p.relative(test.path, from: driverTests.path); |
| if (!driverTestName.endsWith('_test.dart')) { |
| continue; |
| } |
| // Try to find a matching app to drive without the _test.dart |
| final String deviceTestName = driverTestName.replaceAll( |
| RegExp(r'_test.dart$'), |
| '.dart', |
| ); |
| String deviceTestPath = p.join('test', deviceTestName); |
| if (!fileSystem |
| .file(p.join(example.path, deviceTestPath)) |
| .existsSync()) { |
| // If the app isn't in test/ folder, look in test_driver/ instead. |
| deviceTestPath = p.join('test_driver', deviceTestName); |
| } |
| |
| final List<String> targetPaths = <String>[]; |
| if (fileSystem |
| .file(p.join(example.path, deviceTestPath)) |
| .existsSync()) { |
| targetPaths.add(deviceTestPath); |
| } else { |
| final Directory integrationTests = |
| fileSystem.directory(p.join(example.path, 'integration_test')); |
| |
| if (await integrationTests.exists()) { |
| await for (FileSystemEntity integration_test |
| in integrationTests.list()) { |
| if (!integration_test.basename.endsWith('_test.dart')) { |
| continue; |
| } |
| targetPaths |
| .add(p.relative(integration_test.path, from: example.path)); |
| } |
| } |
| |
| if (targetPaths.isEmpty) { |
| print(''' |
| Unable to infer a target application for $driverTestName to drive. |
| Tried searching for the following: |
| 1. test/$deviceTestName |
| 2. test_driver/$deviceTestName |
| 3. test_driver/*_test.dart |
| '''); |
| failingTests.add(p.relative(test.path, from: example.path)); |
| continue; |
| } |
| } |
| |
| final List<String> driveArgs = <String>['drive']; |
| |
| final String enableExperiment = argResults[kEnableExperiment]; |
| if (enableExperiment.isNotEmpty) { |
| driveArgs.add('--enable-experiment=$enableExperiment'); |
| } |
| |
| if (isLinux && isLinuxPlugin(plugin, fileSystem)) { |
| driveArgs.addAll(<String>[ |
| '-d', |
| 'linux', |
| ]); |
| } |
| if (isMacos && isMacOsPlugin(plugin, fileSystem)) { |
| driveArgs.addAll(<String>[ |
| '-d', |
| 'macos', |
| ]); |
| } |
| if (isWindows && isWindowsPlugin(plugin, fileSystem)) { |
| driveArgs.addAll(<String>[ |
| '-d', |
| 'windows', |
| ]); |
| } |
| |
| for (final targetPath in targetPaths) { |
| final int exitCode = await processRunner.runAndStream( |
| flutterCommand, |
| [ |
| ...driveArgs, |
| '--driver', |
| p.join('test_driver', driverTestName), |
| '--target', |
| targetPath, |
| ], |
| workingDir: example, |
| exitOnError: true); |
| if (exitCode != 0) { |
| failingTests.add(p.join(packageName, deviceTestPath)); |
| } |
| } |
| } |
| } |
| } |
| print('\n\n'); |
| |
| if (failingTests.isNotEmpty) { |
| print('The following driver tests are failing (see above for details):'); |
| for (String test in failingTests) { |
| print(' * $test'); |
| } |
| throw ToolExit(1); |
| } |
| |
| print('All driver tests successful!'); |
| } |
| |
| Future<bool> pluginSupportedOnCurrentPlatform( |
| FileSystemEntity plugin, FileSystem fileSystem) async { |
| final bool isLinux = argResults[kLinux]; |
| final bool isMacos = argResults[kMacos]; |
| final bool isWindows = argResults[kWindows]; |
| final bool isIOS = argResults[kIos]; |
| final bool isAndroid = argResults[kAndroid]; |
| if (isLinux) { |
| return isLinuxPlugin(plugin, fileSystem); |
| } |
| if (isMacos) { |
| return isMacOsPlugin(plugin, fileSystem); |
| } |
| if (isWindows) { |
| return isWindowsPlugin(plugin, fileSystem); |
| } |
| if (isIOS) { |
| return isIosPlugin(plugin, fileSystem); |
| } |
| if (isAndroid) { |
| return (isAndroidPlugin(plugin, fileSystem)); |
| } |
| // When we are here, no flags are specified. Only return true if the plugin |
| // supports Android for legacy command support. TODO(cyanglaz): Make Android |
| // flag also required like other platforms (breaking change). |
| // https://github.com/flutter/flutter/issues/58285 |
| return isAndroidPlugin(plugin, fileSystem); |
| } |
| } |