Refactor devicelab logic to use TaskResult instead of JSON (#67550)
This commit is contained in:
parent
b851f99794
commit
9e206a0c93
@ -11,6 +11,7 @@ import 'package:path/path.dart' as path;
|
||||
import 'package:flutter_devicelab/framework/ab.dart';
|
||||
import 'package:flutter_devicelab/framework/manifest.dart';
|
||||
import 'package:flutter_devicelab/framework/runner.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
ArgResults args;
|
||||
@ -89,7 +90,7 @@ Future<void> main(List<String> rawArgs) async {
|
||||
Future<void> _runTasks() async {
|
||||
for (final String taskName in _taskNames) {
|
||||
section('Running task "$taskName"');
|
||||
final Map<String, dynamic> result = await runTask(
|
||||
final TaskResult result = await runTask(
|
||||
taskName,
|
||||
silent: silent,
|
||||
localEngine: localEngine,
|
||||
@ -101,7 +102,7 @@ Future<void> _runTasks() async {
|
||||
print(const JsonEncoder.withIndent(' ').convert(result));
|
||||
section('Finished task "$taskName"');
|
||||
|
||||
if (!(result['success'] as bool)) {
|
||||
if (!result.succeeded) {
|
||||
exitCode = 1;
|
||||
if (exitOnFirstTestFailure) {
|
||||
return;
|
||||
@ -134,7 +135,7 @@ Future<void> _runABTest() async {
|
||||
section('Run #$i');
|
||||
|
||||
print('Running with the default engine (A)');
|
||||
final Map<String, dynamic> defaultEngineResult = await runTask(
|
||||
final TaskResult defaultEngineResult = await runTask(
|
||||
taskName,
|
||||
silent: silent,
|
||||
deviceId: deviceId,
|
||||
@ -143,7 +144,7 @@ Future<void> _runABTest() async {
|
||||
print('Default engine result:');
|
||||
print(const JsonEncoder.withIndent(' ').convert(defaultEngineResult));
|
||||
|
||||
if (!(defaultEngineResult['success'] as bool)) {
|
||||
if (!defaultEngineResult.succeeded) {
|
||||
stderr.writeln('Task failed on the default engine.');
|
||||
exit(1);
|
||||
}
|
||||
@ -151,7 +152,7 @@ Future<void> _runABTest() async {
|
||||
abTest.addAResult(defaultEngineResult);
|
||||
|
||||
print('Running with the local engine (B)');
|
||||
final Map<String, dynamic> localEngineResult = await runTask(
|
||||
final TaskResult localEngineResult = await runTask(
|
||||
taskName,
|
||||
silent: silent,
|
||||
localEngine: localEngine,
|
||||
@ -162,7 +163,7 @@ Future<void> _runABTest() async {
|
||||
print('Task localEngineResult:');
|
||||
print(const JsonEncoder.withIndent(' ').convert(localEngineResult));
|
||||
|
||||
if (!(localEngineResult['success'] as bool)) {
|
||||
if (!localEngineResult.succeeded) {
|
||||
stderr.writeln('Task failed on the local engine.');
|
||||
exit(1);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/ios.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
Future<String> runFlutterAndQuit(List<String> args, Device device) async {
|
||||
|
@ -11,6 +11,7 @@ import 'package:vm_service_client/vm_service_client.dart';
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
Future<String> _runWithMode(String mode, String deviceId) async {
|
||||
|
@ -10,6 +10,7 @@ import 'dart:math';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
void generateMain(Directory appDir, String sentinel) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'package:flutter_devicelab/tasks/gallery.dart';
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
// This test runs "//dev/integration_tests/flutter_gallery/test/live_smoketest.dart", which communicates
|
||||
|
@ -9,6 +9,7 @@ import 'dart:io';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:flutter_devicelab/versions/gallery.dart' show galleryVersion;
|
||||
|
||||
|
@ -7,6 +7,7 @@ import 'dart:io';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:flutter_devicelab/versions/gallery.dart' show galleryVersion;
|
||||
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'examples/hello_world'));
|
||||
|
@ -21,6 +21,7 @@ import 'dart:io';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
// Matches the output of the "test" package, e.g.: "00:01 +1 loading foo"
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -7,6 +7,7 @@ import 'dart:io';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -7,6 +7,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/ios.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:meta/meta.dart';
|
||||
|
@ -7,6 +7,7 @@ import 'dart:io';
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/ios.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/apk_utils.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/ios.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -8,6 +8,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:vm_service_client/vm_service_client.dart';
|
||||
|
@ -2,8 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
|
||||
/// Smoke test of a successful task.
|
||||
Future<void> main() async {
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
|
||||
/// Smoke test of a task that fails by returning an unsuccessful response.
|
||||
Future<void> main() async {
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
|
||||
/// Smoke test of a successful task.
|
||||
Future<void> main() async {
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
import 'service_extensions_test.dart';
|
||||
|
@ -6,6 +6,7 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -7,6 +7,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
import 'dart:math' as math;
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'task_result.dart';
|
||||
|
||||
const String kBenchmarkTypeKeyName = 'benchmark_type';
|
||||
const String kBenchmarkVersionKeyName = 'version';
|
||||
const String kLocalEngineKeyName = 'local_engine';
|
||||
@ -58,7 +60,7 @@ class ABTest {
|
||||
/// The result may contain multiple score keys.
|
||||
///
|
||||
/// [result] is expected to be a serialization of [TaskResult].
|
||||
void addAResult(Map<String, dynamic> result) {
|
||||
void addAResult(TaskResult result) {
|
||||
if (_runEnd != null) {
|
||||
throw StateError('Cannot add results to ABTest after it is finalized');
|
||||
}
|
||||
@ -70,7 +72,7 @@ class ABTest {
|
||||
/// The result may contain multiple score keys.
|
||||
///
|
||||
/// [result] is expected to be a serialization of [TaskResult].
|
||||
void addBResult(Map<String, dynamic> result) {
|
||||
void addBResult(TaskResult result) {
|
||||
if (_runEnd != null) {
|
||||
throw StateError('Cannot add results to ABTest after it is finalized');
|
||||
}
|
||||
@ -276,11 +278,9 @@ class _ScoreSummary {
|
||||
}
|
||||
}
|
||||
|
||||
void _addResult(Map<String, dynamic> result, Map<String, List<double>> results) {
|
||||
final List<String> scoreKeys = (result['benchmarkScoreKeys'] as List<dynamic>).cast<String>();
|
||||
final Map<String, dynamic> data = result['data'] as Map<String, dynamic>;
|
||||
for (final String scoreKey in scoreKeys) {
|
||||
final double score = (data[scoreKey] as num).toDouble();
|
||||
void _addResult(TaskResult result, Map<String, List<double>> results) {
|
||||
for (final String scoreKey in result.benchmarkScoreKeys) {
|
||||
final double score = (result.data[scoreKey] as num).toDouble();
|
||||
results.putIfAbsent(scoreKey, () => <double>[]).add(score);
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
import 'task_result.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
final String platformLineSep = Platform.isWindows ? '\r\n' : '\n';
|
||||
|
||||
|
@ -13,6 +13,7 @@ import 'package:logging/logging.dart';
|
||||
import 'package:stack_trace/stack_trace.dart';
|
||||
|
||||
import 'running_processes.dart';
|
||||
import 'task_result.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
/// Represents a unit of work performed in the CI environment that can
|
||||
@ -185,102 +186,3 @@ class _TaskRunner {
|
||||
return completer.future;
|
||||
}
|
||||
}
|
||||
|
||||
/// A result of running a single task.
|
||||
class TaskResult {
|
||||
/// Constructs a successful result.
|
||||
TaskResult.success(this.data, {
|
||||
this.benchmarkScoreKeys = const <String>[],
|
||||
this.detailFiles,
|
||||
})
|
||||
: succeeded = true,
|
||||
message = 'success' {
|
||||
const JsonEncoder prettyJson = JsonEncoder.withIndent(' ');
|
||||
if (benchmarkScoreKeys != null) {
|
||||
for (final String key in benchmarkScoreKeys) {
|
||||
if (!data.containsKey(key)) {
|
||||
throw 'Invalid benchmark score key "$key". It does not exist in task '
|
||||
'result data ${prettyJson.convert(data)}';
|
||||
} else if (data[key] is! num) {
|
||||
throw 'Invalid benchmark score for key "$key". It is expected to be a num '
|
||||
'but was ${data[key].runtimeType}: ${prettyJson.convert(data[key])}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a successful result using JSON data stored in a file.
|
||||
factory TaskResult.successFromFile(File file,
|
||||
{List<String> benchmarkScoreKeys}) {
|
||||
return TaskResult.success(
|
||||
json.decode(file.readAsStringSync()) as Map<String, dynamic>,
|
||||
benchmarkScoreKeys: benchmarkScoreKeys,
|
||||
);
|
||||
}
|
||||
|
||||
/// Constructs an unsuccessful result.
|
||||
TaskResult.failure(this.message)
|
||||
: succeeded = false,
|
||||
data = null,
|
||||
detailFiles = null,
|
||||
benchmarkScoreKeys = const <String>[];
|
||||
|
||||
/// Whether the task succeeded.
|
||||
final bool succeeded;
|
||||
|
||||
/// Task-specific JSON data
|
||||
final Map<String, dynamic> data;
|
||||
|
||||
/// Files containing detail on the run (e.g. timeline trace files)
|
||||
final List<String> detailFiles;
|
||||
|
||||
/// Keys in [data] that store scores that will be submitted to Cocoon.
|
||||
///
|
||||
/// Each key is also part of a benchmark's name tracked by Cocoon.
|
||||
final List<String> benchmarkScoreKeys;
|
||||
|
||||
/// Whether the task failed.
|
||||
bool get failed => !succeeded;
|
||||
|
||||
/// Explains the result in a human-readable format.
|
||||
final String message;
|
||||
|
||||
/// Serializes this task result to JSON format.
|
||||
///
|
||||
/// The JSON format is as follows:
|
||||
///
|
||||
/// {
|
||||
/// "success": true|false,
|
||||
/// "data": arbitrary JSON data valid only for successful results,
|
||||
/// "detailFiles": list of filenames containing detail on the run
|
||||
/// "benchmarkScoreKeys": [
|
||||
/// contains keys into "data" that represent benchmarks scores, which
|
||||
/// can be uploaded, for example. to golem, valid only for successful
|
||||
/// results
|
||||
/// ],
|
||||
/// "reason": failure reason string valid only for unsuccessful results
|
||||
/// }
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> json = <String, dynamic>{
|
||||
'success': succeeded,
|
||||
};
|
||||
|
||||
if (succeeded) {
|
||||
json['data'] = data;
|
||||
if (detailFiles != null)
|
||||
json['detailFiles'] = detailFiles;
|
||||
json['benchmarkScoreKeys'] = benchmarkScoreKeys;
|
||||
} else {
|
||||
json['reason'] = message;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
class TaskResultCheckProcesses extends TaskResult {
|
||||
TaskResultCheckProcesses() : super.success(null);
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ import 'package:vm_service_client/vm_service_client.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
|
||||
import 'task_result.dart';
|
||||
|
||||
/// Runs a task in a separate Dart VM and collects the result using the VM
|
||||
/// service protocol.
|
||||
///
|
||||
@ -20,7 +22,7 @@ import 'package:flutter_devicelab/framework/adb.dart';
|
||||
///
|
||||
/// Running the task in [silent] mode will suppress standard output from task
|
||||
/// processes and only print standard errors.
|
||||
Future<Map<String, dynamic>> runTask(
|
||||
Future<TaskResult> runTask(
|
||||
String taskName, {
|
||||
bool silent = false,
|
||||
String localEngine,
|
||||
@ -79,7 +81,8 @@ Future<Map<String, dynamic>> runTask(
|
||||
|
||||
try {
|
||||
final VMIsolateRef isolate = await _connectToRunnerIsolate(await uri.future);
|
||||
final Map<String, dynamic> taskResult = await isolate.invokeExtension('ext.cocoonRunTask') as Map<String, dynamic>;
|
||||
final Map<String, dynamic> taskResultJson = await isolate.invokeExtension('ext.cocoonRunTask') as Map<String, dynamic>;
|
||||
final TaskResult taskResult = TaskResult.fromJson(taskResultJson);
|
||||
await runner.exitCode;
|
||||
return taskResult;
|
||||
} finally {
|
||||
|
117
dev/devicelab/lib/framework/task_result.dart
Normal file
117
dev/devicelab/lib/framework/task_result.dart
Normal file
@ -0,0 +1,117 @@
|
||||
// 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 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
/// A result of running a single task.
|
||||
class TaskResult {
|
||||
/// Constructs a successful result.
|
||||
TaskResult.success(this.data, {
|
||||
this.benchmarkScoreKeys = const <String>[],
|
||||
this.detailFiles,
|
||||
})
|
||||
: succeeded = true,
|
||||
message = 'success' {
|
||||
const JsonEncoder prettyJson = JsonEncoder.withIndent(' ');
|
||||
if (benchmarkScoreKeys != null) {
|
||||
for (final String key in benchmarkScoreKeys) {
|
||||
if (!data.containsKey(key)) {
|
||||
throw 'Invalid benchmark score key "$key". It does not exist in task '
|
||||
'result data ${prettyJson.convert(data)}';
|
||||
} else if (data[key] is! num) {
|
||||
throw 'Invalid benchmark score for key "$key". It is expected to be a num '
|
||||
'but was ${data[key].runtimeType}: ${prettyJson.convert(data[key])}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a successful result using JSON data stored in a file.
|
||||
factory TaskResult.successFromFile(File file,
|
||||
{List<String> benchmarkScoreKeys}) {
|
||||
return TaskResult.success(
|
||||
json.decode(file.readAsStringSync()) as Map<String, dynamic>,
|
||||
benchmarkScoreKeys: benchmarkScoreKeys,
|
||||
);
|
||||
}
|
||||
|
||||
/// Constructs a [TaskResult] from JSON.
|
||||
factory TaskResult.fromJson(Map<String, dynamic> json) {
|
||||
final bool success = json['success'] as bool;
|
||||
if (success) {
|
||||
final List<String> benchmarkScoreKeys = (json['benchmarkScoreKeys'] as List<dynamic> ?? <String>[]).cast<String>();
|
||||
return TaskResult.success(json['data'] as Map<String, dynamic>,
|
||||
benchmarkScoreKeys: benchmarkScoreKeys);
|
||||
}
|
||||
|
||||
return TaskResult.failure(json['reason'] as String);
|
||||
}
|
||||
|
||||
/// Constructs an unsuccessful result.
|
||||
TaskResult.failure(this.message)
|
||||
: succeeded = false,
|
||||
data = null,
|
||||
detailFiles = null,
|
||||
benchmarkScoreKeys = const <String>[];
|
||||
|
||||
/// Whether the task succeeded.
|
||||
final bool succeeded;
|
||||
|
||||
/// Task-specific JSON data
|
||||
final Map<String, dynamic> data;
|
||||
|
||||
/// Files containing detail on the run (e.g. timeline trace files)
|
||||
final List<String> detailFiles;
|
||||
|
||||
/// Keys in [data] that store scores that will be submitted to Cocoon.
|
||||
///
|
||||
/// Each key is also part of a benchmark's name tracked by Cocoon.
|
||||
final List<String> benchmarkScoreKeys;
|
||||
|
||||
/// Whether the task failed.
|
||||
bool get failed => !succeeded;
|
||||
|
||||
/// Explains the result in a human-readable format.
|
||||
final String message;
|
||||
|
||||
/// Serializes this task result to JSON format.
|
||||
///
|
||||
/// The JSON format is as follows:
|
||||
///
|
||||
/// {
|
||||
/// "success": true|false,
|
||||
/// "data": arbitrary JSON data valid only for successful results,
|
||||
/// "detailFiles": list of filenames containing detail on the run
|
||||
/// "benchmarkScoreKeys": [
|
||||
/// contains keys into "data" that represent benchmarks scores, which
|
||||
/// can be uploaded, for example. to golem, valid only for successful
|
||||
/// results
|
||||
/// ],
|
||||
/// "reason": failure reason string valid only for unsuccessful results
|
||||
/// }
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> json = <String, dynamic>{
|
||||
'success': succeeded,
|
||||
};
|
||||
|
||||
if (succeeded) {
|
||||
json['data'] = data;
|
||||
if (detailFiles != null)
|
||||
json['detailFiles'] = detailFiles;
|
||||
json['benchmarkScoreKeys'] = benchmarkScoreKeys;
|
||||
} else {
|
||||
json['reason'] = message;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
class TaskResultCheckProcesses extends TaskResult {
|
||||
TaskResultCheckProcesses() : super.success(null);
|
||||
}
|
@ -12,7 +12,7 @@ import 'package:path/path.dart' as path;
|
||||
import 'package:process/process.dart';
|
||||
import 'package:stack_trace/stack_trace.dart';
|
||||
|
||||
import 'framework.dart';
|
||||
import 'task_result.dart';
|
||||
|
||||
/// Virtual current working directory, which affect functions, such as [exec].
|
||||
String cwd = Directory.current.path;
|
||||
|
@ -6,7 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
/// Run each benchmark this many times and compute average, min, max.
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import '../framework/adb.dart';
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
Future<TaskResult> runDartDefinesTask() async {
|
||||
|
@ -6,8 +6,10 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
|
||||
|
||||
import '../framework/adb.dart';
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
TaskFunction createGalleryTransitionTest({bool semanticsEnabled = false}) {
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import '../framework/adb.dart';
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
final Directory _editedFlutterGalleryDir = dir(path.join(Directory.systemTemp.path, 'edited_flutter_gallery'));
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import '../framework/adb.dart';
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
TaskFunction createChannelsIntegrationTest() {
|
||||
|
@ -5,7 +5,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import '../framework/adb.dart';
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
Future<TaskResult> runEndToEndTests() async {
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
/// Creates a device lab task that runs benchmarks in
|
||||
|
@ -7,7 +7,7 @@ import 'dart:io';
|
||||
import 'package:flutter_devicelab/tasks/perf_tests.dart';
|
||||
|
||||
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
import '../versions/gallery.dart' show galleryVersion;
|
||||
|
||||
|
@ -12,6 +12,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:flutter_devicelab/tasks/track_widget_creation_enabled_task.dart';
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
/// Combines several TaskFunctions with trivial success value into one.
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
|
||||
import '../framework/adb.dart';
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
TaskFunction createRunWithoutLeakTest(dynamic dir) {
|
||||
|
@ -9,7 +9,7 @@ import 'package:vm_service/vm_service.dart';
|
||||
import 'package:vm_service/vm_service_io.dart';
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
final Directory integrationTestDir = Directory(
|
||||
|
@ -14,7 +14,7 @@ import 'package:shelf/shelf_io.dart' as shelf_io;
|
||||
import 'package:shelf_static/shelf_static.dart';
|
||||
|
||||
import 'package:flutter_devicelab/framework/browser.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
|
||||
/// The port number used by the local benchmark server.
|
||||
|
@ -9,6 +9,7 @@ import 'dart:io';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import '../framework/framework.dart';
|
||||
import '../framework/task_result.dart';
|
||||
import '../framework/utils.dart';
|
||||
|
||||
final Directory _editedFlutterGalleryDir = dir(path.join(Directory.systemTemp.path, 'edited_flutter_gallery'));
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_devicelab/framework/ab.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
@ -11,7 +12,8 @@ void main() {
|
||||
final ABTest ab = ABTest('engine', 'test');
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ab.addAResult(<String, dynamic>{
|
||||
final TaskResult aResult = TaskResult.fromJson(<String, dynamic>{
|
||||
'success': true,
|
||||
'data': <String, dynamic>{
|
||||
'i': i,
|
||||
'j': 10 * i,
|
||||
@ -19,14 +21,16 @@ void main() {
|
||||
},
|
||||
'benchmarkScoreKeys': <String>['i', 'j'],
|
||||
});
|
||||
|
||||
ab.addBResult(<String, dynamic>{
|
||||
ab.addAResult(aResult);
|
||||
final TaskResult bResult = TaskResult.fromJson(<String, dynamic>{
|
||||
'success': true,
|
||||
'data': <String, dynamic>{
|
||||
'i': i + 1,
|
||||
'k': 10 * i + 1,
|
||||
},
|
||||
'benchmarkScoreKeys': <String>['i', 'k'],
|
||||
});
|
||||
ab.addBResult(bResult);
|
||||
}
|
||||
ab.finalize();
|
||||
|
||||
|
46
dev/devicelab/test/task_result_test.dart
Normal file
46
dev/devicelab/test/task_result_test.dart
Normal file
@ -0,0 +1,46 @@
|
||||
// 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:flutter_devicelab/framework/task_result.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
void main() {
|
||||
group('TaskResult fromJson', () {
|
||||
test('succeeded', () {
|
||||
final Map<String, dynamic> expectedJson = <String, dynamic>{
|
||||
'success': true,
|
||||
'data': <String, dynamic>{
|
||||
'i': 5,
|
||||
'j': 10,
|
||||
'not_a_metric': 'something',
|
||||
},
|
||||
'benchmarkScoreKeys': <String>['i', 'j'],
|
||||
};
|
||||
final TaskResult result = TaskResult.fromJson(expectedJson);
|
||||
expect(result.toJson(), expectedJson);
|
||||
});
|
||||
|
||||
test('succeeded with empty data', () {
|
||||
final TaskResult result = TaskResult.fromJson(<String, dynamic>{
|
||||
'success': true,
|
||||
});
|
||||
final Map<String, dynamic> expectedJson = <String, dynamic>{
|
||||
'success': true,
|
||||
'data': null,
|
||||
'benchmarkScoreKeys': <String>[],
|
||||
};
|
||||
expect(result.toJson(), expectedJson);
|
||||
});
|
||||
|
||||
test('failed', () {
|
||||
final Map<String, dynamic> expectedJson = <String, dynamic>{
|
||||
'success': false,
|
||||
'reason': 'failure message',
|
||||
};
|
||||
final TaskResult result = TaskResult.fromJson(expectedJson);
|
||||
expect(result.toJson(), expectedJson);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user