| // Copyright 2013 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 'package:engine_build_configs/engine_build_configs.dart'; |
| |
| import '../build_plan.dart'; |
| import '../build_utils.dart'; |
| import '../gn.dart'; |
| import '../label.dart'; |
| import '../proc_utils.dart'; |
| import '../worker_pool.dart'; |
| import 'command.dart'; |
| |
| /// The root 'test' command. |
| final class TestCommand extends CommandBase { |
| /// Constructs the 'test' command. |
| TestCommand({ |
| required super.environment, |
| required Map<String, BuilderConfig> configs, |
| super.help = false, |
| super.usageLineLength, |
| }) { |
| builds = BuildPlan.configureArgParser( |
| argParser, |
| environment, |
| configs: configs, |
| help: help, |
| ); |
| } |
| |
| /// List of compatible builds. |
| late final List<Build> builds; |
| |
| @override |
| String get name => 'test'; |
| |
| @override |
| String get description => ''' |
| Runs a test target |
| et test //flutter/fml/... # Run all test targets in `//flutter/fml` and its subdirectories. |
| et test //flutter/fml:all # Run all test targets in `//flutter/fml`. |
| et test //flutter/fml:fml_benchmarks # Run a single test target in `//flutter/fml`. |
| '''; |
| |
| @override |
| Future<int> run() async { |
| final plan = BuildPlan.fromArgResults( |
| argResults!, |
| environment, |
| builds: builds, |
| ); |
| |
| if (!await ensureBuildDir( |
| environment, |
| plan.build, |
| enableRbe: plan.useRbe, |
| extraGnArgs: plan.toGnArgs(), |
| )) { |
| return 1; |
| } |
| |
| // Builds only accept labels as arguments, so convert patterns to labels. |
| final gn = Gn.fromEnvironment(environment); |
| |
| // Figure out what targets the user wants to build. |
| final buildTargets = <BuildTarget>{}; |
| for (final pattern in argResults!.rest) { |
| final target = TargetPattern.parse(pattern); |
| final found = await gn.desc( |
| 'out/${plan.build.ninja.config}', |
| target, |
| ); |
| buildTargets.addAll(found); |
| } |
| |
| if (buildTargets.isEmpty) { |
| environment.logger.error('No targets found, nothing to test.'); |
| return 1; |
| } |
| |
| // Make sure there is at least one test target. |
| final testTargets = buildTargets |
| .whereType<ExecutableBuildTarget>() |
| .where((ExecutableBuildTarget t) => t.testOnly) |
| .toList(); |
| |
| if (testTargets.isEmpty) { |
| environment.logger.error('No test targets found'); |
| return 1; |
| } |
| |
| final buildExitCode = await runBuild( |
| environment, |
| plan.build, |
| concurrency: plan.concurrency ?? 0, |
| targets: testTargets.map((target) => target.label).toList(), |
| enableRbe: plan.useRbe, |
| rbeConfig: plan.toRbeConfig(), |
| extraGnArgs: plan.toGnArgs(), |
| ); |
| if (buildExitCode != 0) { |
| return buildExitCode; |
| } |
| final workerPool = WorkerPool( |
| environment, |
| ProcessTaskProgressReporter(environment), |
| ); |
| final tasks = <ProcessTask>{}; |
| for (final target in testTargets) { |
| final commandLine = <String>[target.executable]; |
| tasks.add(ProcessTask( |
| target.label.toString(), |
| environment, |
| environment.engine.srcDir, |
| commandLine, |
| )); |
| } |
| return await workerPool.run(tasks) ? 0 : 1; |
| } |
| } |