Unverified Commit c8c681f6 authored by Casey Hillers's avatar Casey Hillers Committed by GitHub

[devicelab] Create test command to pass task args (#77110)

parent 9397c374
...@@ -9,7 +9,6 @@ import 'package:args/args.dart'; ...@@ -9,7 +9,6 @@ import 'package:args/args.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:flutter_devicelab/framework/ab.dart'; import 'package:flutter_devicelab/framework/ab.dart';
import 'package:flutter_devicelab/framework/cocoon.dart';
import 'package:flutter_devicelab/framework/manifest.dart'; import 'package:flutter_devicelab/framework/manifest.dart';
import 'package:flutter_devicelab/framework/runner.dart'; import 'package:flutter_devicelab/framework/runner.dart';
import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/task_result.dart';
...@@ -105,46 +104,14 @@ Future<void> main(List<String> rawArgs) async { ...@@ -105,46 +104,14 @@ Future<void> main(List<String> rawArgs) async {
if (args.wasParsed('ab')) { if (args.wasParsed('ab')) {
await _runABTest(); await _runABTest();
} else { } else {
await _runTasks(); await runTasks(_taskNames,
}
}
Future<void> _runTasks() async {
for (final String taskName in _taskNames) {
section('Running task "$taskName"');
final TaskResult result = await runTask(
taskName,
silent: silent, silent: silent,
localEngine: localEngine,
localEngineSrcPath: localEngineSrcPath,
deviceId: deviceId, deviceId: deviceId,
); exitOnFirstTestFailure: exitOnFirstTestFailure,
print('Task result:');
print(const JsonEncoder.withIndent(' ').convert(result));
section('Finished task "$taskName"');
if (resultsPath != null) {
final Cocoon cocoon = Cocoon();
await cocoon.writeTaskResultToFile(
builderName: luciBuilder,
gitBranch: gitBranch, gitBranch: gitBranch,
result: result, luciBuilder: luciBuilder,
resultsPath: resultsPath, resultsPath: resultsPath,
); );
} else if (serviceAccountTokenFile != null) {
final Cocoon cocoon = Cocoon(serviceAccountTokenPath: serviceAccountTokenFile);
/// Cocoon references LUCI tasks by the [luciBuilder] instead of [taskName].
await cocoon.sendTaskResult(builderName: luciBuilder, result: result, gitBranch: gitBranch);
}
if (!result.succeeded) {
exitCode = 1;
if (exitOnFirstTestFailure) {
return;
}
}
} }
} }
......
...@@ -5,10 +5,13 @@ ...@@ -5,10 +5,13 @@
import 'dart:io'; import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:flutter_devicelab/command/test.dart';
import 'package:flutter_devicelab/command/upload_metrics.dart'; import 'package:flutter_devicelab/command/upload_metrics.dart';
final CommandRunner<void> runner = final CommandRunner<void> runner =
CommandRunner<void>('devicelab_runner', 'DeviceLab test runner for recording performance metrics on applications') CommandRunner<void>('devicelab_runner', 'DeviceLab test runner for recording performance metrics on applications')
..addCommand(TestCommand())
..addCommand(UploadMetricsCommand()); ..addCommand(UploadMetricsCommand());
Future<void> main(List<String> rawArgs) async { Future<void> main(List<String> rawArgs) async {
......
// 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 'package:args/command_runner.dart';
import 'package:flutter_devicelab/framework/runner.dart';
class TestCommand extends Command<void> {
TestCommand() {
argParser.addOption('task',
abbr: 't',
help: 'The name of a task listed under bin/tasks.\n'
' Example: complex_layout__start_up.\n');
argParser.addMultiOption('task-args',
help: 'The name of a task listed under bin/tasks.\n'
'For example, "--task-args build" is passed as "bin/task/task.dart --build"');
argParser.addOption(
'device-id',
abbr: 'd',
help: 'Target device id (prefixes are allowed, names are not supported).\n'
'The option will be ignored if the test target does not run on a\n'
'mobile device. This still respects the device operating system\n'
'settings in the test case, and will results in error if no device\n'
'with given ID/ID prefix is found.',
);
argParser.addOption(
'git-branch',
help: '[Flutter infrastructure] Git branch of the current commit. LUCI\n'
'checkouts run in detached HEAD state, so the branch must be passed.',
);
argParser.addOption(
'local-engine',
help: 'Name of a build output within the engine out directory, if you\n'
'are building Flutter locally. Use this to select a specific\n'
'version of the engine if you have built multiple engine targets.\n'
'This path is relative to --local-engine-src-path/out. This option\n'
'is required when running an A/B test (see the --ab option).',
);
argParser.addOption(
'local-engine-src-path',
help: 'Path to your engine src directory, if you are building Flutter\n'
'locally. Defaults to \$FLUTTER_ENGINE if set, or tries to guess at\n'
'the location based on the value of the --flutter-root option.',
);
argParser.addOption('luci-builder', help: '[Flutter infrastructure] Name of the LUCI builder being run on.');
argParser.addOption('results-file',
help: '[Flutter infrastructure] File path for test results. If passed with\n'
'task, will write test results to the file.');
argParser.addFlag(
'silent',
negatable: true,
defaultsTo: false,
);
}
@override
String get name => 'test';
@override
String get description => 'Run Flutter DeviceLab test';
@override
Future<void> run() async {
final List<String> taskArgsRaw = argResults['task-args'] as List<String>;
// Prepend '--' to convert args to options when passed to task
final List<String> taskArgs = taskArgsRaw.map((String taskArg) => '--$taskArg').toList();
print(taskArgs);
await runTasks(
<String>[argResults['task'] as String],
deviceId: argResults['device-id'] as String,
gitBranch: argResults['git-branch'] as String,
localEngine: argResults['local-engine'] as String,
localEngineSrcPath: argResults['local-engine-src-path'] as String,
luciBuilder: argResults['luci-builder'] as String,
resultsPath: argResults['results-file'] as String,
silent: argResults['silent'] as bool,
taskArgs: taskArgs,
);
}
}
\ No newline at end of file
...@@ -8,10 +8,56 @@ import 'dart:io'; ...@@ -8,10 +8,56 @@ import 'dart:io';
import 'package:vm_service_client/vm_service_client.dart'; import 'package:vm_service_client/vm_service_client.dart';
import 'package:flutter_devicelab/framework/utils.dart'; import 'adb.dart';
import 'package:flutter_devicelab/framework/adb.dart'; import 'cocoon.dart';
import 'task_result.dart'; import 'task_result.dart';
import 'utils.dart';
Future<void> runTasks(
List<String> taskNames, {
bool exitOnFirstTestFailure = false,
bool silent = false,
String deviceId,
String gitBranch,
String localEngine,
String localEngineSrcPath,
String luciBuilder,
String resultsPath,
List<String> taskArgs,
}) async {
for (final String taskName in taskNames) {
section('Running task "$taskName"');
final TaskResult result = await runTask(
taskName,
deviceId: deviceId,
localEngine: localEngine,
localEngineSrcPath: localEngineSrcPath,
silent: silent,
taskArgs: taskArgs,
);
print('Task result:');
print(const JsonEncoder.withIndent(' ').convert(result));
section('Finished task "$taskName"');
if (resultsPath != null) {
final Cocoon cocoon = Cocoon();
await cocoon.writeTaskResultToFile(
builderName: luciBuilder,
gitBranch: gitBranch,
result: result,
resultsPath: resultsPath,
);
}
if (!result.succeeded) {
exitCode = 1;
if (exitOnFirstTestFailure) {
return;
}
}
}
}
/// Runs a task in a separate Dart VM and collects the result using the VM /// Runs a task in a separate Dart VM and collects the result using the VM
/// service protocol. /// service protocol.
...@@ -21,12 +67,15 @@ import 'task_result.dart'; ...@@ -21,12 +67,15 @@ import 'task_result.dart';
/// ///
/// Running the task in [silent] mode will suppress standard output from task /// Running the task in [silent] mode will suppress standard output from task
/// processes and only print standard errors. /// processes and only print standard errors.
///
/// [taskArgs] are passed to the task executable for additional configuration.
Future<TaskResult> runTask( Future<TaskResult> runTask(
String taskName, { String taskName, {
bool silent = false, bool silent = false,
String localEngine, String localEngine,
String localEngineSrcPath, String localEngineSrcPath,
String deviceId, String deviceId,
List<String> taskArgs,
}) async { }) async {
final String taskExecutable = 'bin/tasks/$taskName.dart'; final String taskExecutable = 'bin/tasks/$taskName.dart';
...@@ -42,6 +91,7 @@ Future<TaskResult> runTask( ...@@ -42,6 +91,7 @@ Future<TaskResult> runTask(
if (localEngine != null) '-DlocalEngine=$localEngine', if (localEngine != null) '-DlocalEngine=$localEngine',
if (localEngineSrcPath != null) '-DlocalEngineSrcPath=$localEngineSrcPath', if (localEngineSrcPath != null) '-DlocalEngineSrcPath=$localEngineSrcPath',
taskExecutable, taskExecutable,
...?taskArgs,
], ],
environment: <String, String>{ environment: <String, String>{
if (deviceId != null) if (deviceId != null)
......
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