Unverified Commit 08ef7752 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Revert "Migrate core devicelab framework to null safety. (#85993)" (#86269)

This reverts commit 2175e64e.
parent 28cb43e6
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:args/command_runner.dart';
import 'package:flutter_devicelab/framework/runner.dart';
......@@ -62,19 +64,19 @@ class TestCommand extends Command<void> {
@override
Future<void> run() async {
final List<String> taskArgsRaw = argResults!['task-args'] as List<String>;
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?) ?? false,
<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,
);
}
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:args/command_runner.dart';
import '../framework/cocoon.dart';
......@@ -23,8 +25,8 @@ class UploadMetricsCommand extends Command<void> {
@override
Future<void> run() async {
final String resultsPath = argResults!['results-file'] as String;
final String? serviceAccountTokenFile = argResults!['service-account-token-file'] as String?;
final String resultsPath = argResults['results-file'] as String;
final String serviceAccountTokenFile = argResults['service-account-token-file'] as String;
final Cocoon cocoon = Cocoon(serviceAccountTokenPath: serviceAccountTokenFile);
return cocoon.sendResultsPath(resultsPath);
......
......@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math;
import 'package:meta/meta.dart';
import 'task_result.dart';
......@@ -40,8 +43,8 @@ class ABTest {
final String localEngine;
final String taskName;
final DateTime runStart;
DateTime? _runEnd;
DateTime? get runEnd => _runEnd;
DateTime _runEnd;
DateTime get runEnd => _runEnd;
final Map<String, List<double>> _aResults;
final Map<String, List<double>> _bResults;
......@@ -88,15 +91,15 @@ class ABTest {
kLocalEngineKeyName: localEngine,
kTaskNameKeyName: taskName,
kRunStartKeyName: runStart.toIso8601String(),
kRunEndKeyName: runEnd!.toIso8601String(),
kRunEndKeyName: runEnd.toIso8601String(),
kAResultsKeyName: _aResults,
kBResultsKeyName: _bResults,
};
static void updateColumnLengths(List<int> lengths, List<String?> results) {
static void updateColumnLengths(List<int> lengths, List<String> results) {
for (int column = 0; column < lengths.length; column++) {
if (results[column] != null) {
lengths[column] = math.max(lengths[column], results[column]?.length ?? 0);
lengths[column] = math.max(lengths[column], results[column].length);
}
}
}
......@@ -104,10 +107,10 @@ class ABTest {
static void formatResult(StringBuffer buffer,
List<int> lengths,
List<FieldJustification> aligns,
List<String?> values) {
List<String> values) {
for (int column = 0; column < lengths.length; column++) {
final int len = lengths[column];
String? value = values[column];
String value = values[column];
if (value == null) {
value = ''.padRight(len);
} else {
......@@ -139,9 +142,9 @@ class ABTest {
final Map<String, _ScoreSummary> summariesA = _summarize(_aResults);
final Map<String, _ScoreSummary> summariesB = _summarize(_bResults);
final List<List<String?>> tableRows = <List<String?>>[
final List<List<String>> tableRows = <List<String>>[
for (final String scoreKey in <String>{...summariesA.keys, ...summariesB.keys})
<String?>[
<String>[
scoreKey,
summariesA[scoreKey]?.averageString, summariesA[scoreKey]?.noiseString,
summariesB[scoreKey]?.averageString, summariesB[scoreKey]?.noiseString,
......@@ -164,7 +167,7 @@ class ABTest {
final List<int> lengths = List<int>.filled(6, 0);
updateColumnLengths(lengths, titles);
for (final List<String?> row in tableRows) {
for (final List<String> row in tableRows) {
updateColumnLengths(lengths, row);
}
......@@ -174,7 +177,7 @@ class ABTest {
FieldJustification.CENTER,
...alignments.skip(1),
], titles);
for (final List<String?> row in tableRows) {
for (final List<String> row in tableRows) {
formatResult(buffer, lengths, alignments, row);
}
......@@ -189,7 +192,7 @@ class ABTest {
buffer.writeln('$scoreKey:');
buffer.write(' A:\t');
if (_aResults.containsKey(scoreKey)) {
for (final double score in _aResults[scoreKey]!) {
for (final double score in _aResults[scoreKey]) {
buffer.write('${score.toStringAsFixed(2)}\t');
}
} else {
......@@ -199,7 +202,7 @@ class ABTest {
buffer.write(' B:\t');
if (_bResults.containsKey(scoreKey)) {
for (final double score in _bResults[scoreKey]!) {
for (final double score in _bResults[scoreKey]) {
buffer.write('${score.toStringAsFixed(2)}\t');
}
} else {
......@@ -229,8 +232,8 @@ class ABTest {
);
for (final String scoreKey in _allScoreKeys) {
final _ScoreSummary? summaryA = summariesA[scoreKey];
final _ScoreSummary? summaryB = summariesB[scoreKey];
final _ScoreSummary summaryA = summariesA[scoreKey];
final _ScoreSummary summaryB = summariesB[scoreKey];
buffer.write('$scoreKey\t');
if (summaryA != null) {
......@@ -258,8 +261,8 @@ class ABTest {
class _ScoreSummary {
_ScoreSummary({
required this.average,
required this.noise,
@required this.average,
@required this.noise,
});
/// Average (arithmetic mean) of a series of values collected by a benchmark.
......@@ -272,14 +275,14 @@ class _ScoreSummary {
String get averageString => average.toStringAsFixed(2);
String get noiseString => '(${_ratioToPercent(noise)})';
String improvementOver(_ScoreSummary? other) {
String improvementOver(_ScoreSummary other) {
return other == null ? '' : '${(average / other.average).toStringAsFixed(2)}x';
}
}
void _addResult(TaskResult result, Map<String, List<double>> results) {
for (final String scoreKey in result.benchmarkScoreKeys ?? <String>[]) {
final double score = (result.data![scoreKey] as num).toDouble();
for (final String scoreKey in result.benchmarkScoreKeys) {
final double score = (result.data[scoreKey] as num).toDouble();
results.putIfAbsent(scoreKey, () => <double>[]).add(score);
}
}
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:path/path.dart' as path;
......@@ -104,7 +106,7 @@ bool hasMultipleOccurrences(String text, Pattern pattern) {
/// The Android home directory.
String get _androidHome {
final String? androidHome = Platform.environment['ANDROID_HOME'] ??
final String androidHome = Platform.environment['ANDROID_HOME'] ??
Platform.environment['ANDROID_SDK_ROOT'];
if (androidHome == null || androidHome.isEmpty) {
throw Exception('Environment variable `ANDROID_SDK_ROOT` is not set.');
......@@ -116,9 +118,9 @@ String get _androidHome {
Future<String> _evalApkAnalyzer(
List<String> args, {
bool printStdout = false,
String? workingDirectory,
String workingDirectory,
}) async {
final String? javaHome = await findJavaHome();
final String javaHome = await findJavaHome();
if (javaHome == null || javaHome.isEmpty) {
throw Exception('No JAVA_HOME set.');
}
......@@ -257,7 +259,7 @@ class FlutterProject {
String get androidPath => path.join(rootPath, 'android');
String get iosPath => path.join(rootPath, 'ios');
Future<void> addCustomBuildType(String name, {required String initWith}) async {
Future<void> addCustomBuildType(String name, {String initWith}) async {
final File buildScript = File(
path.join(androidPath, 'app', 'build.gradle'),
);
......@@ -274,7 +276,7 @@ android {
''');
}
Future<void> addGlobalBuildType(String name, {required String initWith}) async {
Future<void> addGlobalBuildType(String name, {String initWith}) async {
final File buildScript = File(
path.join(androidPath, 'build.gradle'),
);
......@@ -358,11 +360,11 @@ flutter:
pubspec.writeAsStringSync(newContents);
}
Future<void> runGradleTask(String task, {List<String>? options}) async {
Future<void> runGradleTask(String task, {List<String> options}) async {
return _runGradleTask(workingDirectory: androidPath, task: task, options: options);
}
Future<ProcessResult> resultOfGradleTask(String task, {List<String>? options}) {
Future<ProcessResult> resultOfGradleTask(String task, {List<String> options}) {
return _resultOfGradleTask(workingDirectory: androidPath, task: task, options: options);
}
......@@ -414,11 +416,7 @@ class FlutterModuleProject {
String get rootPath => path.join(parent.path, name);
}
Future<void> _runGradleTask({
required String workingDirectory,
required String task,
List<String>? options,
}) async {
Future<void> _runGradleTask({String workingDirectory, String task, List<String> options}) async {
final ProcessResult result = await _resultOfGradleTask(
workingDirectory: workingDirectory,
task: task,
......@@ -433,13 +431,10 @@ Future<void> _runGradleTask({
throw 'Gradle exited with error';
}
Future<ProcessResult> _resultOfGradleTask({
required String workingDirectory,
required String task,
List<String>? options,
}) async {
Future<ProcessResult> _resultOfGradleTask({String workingDirectory, String task,
List<String> options}) async {
section('Find Java');
final String? javaHome = await findJavaHome();
final String javaHome = await findJavaHome();
if (javaHome == null)
throw TaskResult.failure('Could not find Java');
......@@ -470,7 +465,7 @@ Future<ProcessResult> _resultOfGradleTask({
}
/// Returns [null] if target matches [expectedTarget], otherwise returns an error message.
String? validateSnapshotDependency(FlutterProject project, String expectedTarget) {
String validateSnapshotDependency(FlutterProject project, String expectedTarget) {
final File snapshotBlob = File(
path.join(project.rootPath, 'build', 'app', 'intermediates',
'flutter', 'debug', 'flutter_build.d'));
......
This diff is collapsed.
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert' show Encoding, json;
import 'dart:io';
......@@ -18,12 +20,12 @@ import 'utils.dart';
typedef ProcessRunSync = ProcessResult Function(
String,
List<String>, {
Map<String, String>? environment,
Map<String, String> environment,
bool includeParentEnvironment,
bool runInShell,
Encoding? stderrEncoding,
Encoding? stdoutEncoding,
String? workingDirectory,
Encoding stderrEncoding,
Encoding stdoutEncoding,
String workingDirectory,
});
/// Class for test runner to interact with Flutter's infrastructure service, Cocoon.
......@@ -32,8 +34,8 @@ typedef ProcessRunSync = ProcessResult Function(
/// To retrieve these results, the test runner needs to send results back so the database can be updated.
class Cocoon {
Cocoon({
String? serviceAccountTokenPath,
@visibleForTesting Client? httpClient,
String serviceAccountTokenPath,
@visibleForTesting Client httpClient,
@visibleForTesting this.fs = const LocalFileSystem(),
@visibleForTesting this.processRunSync = Process.runSync,
@visibleForTesting this.requestRetryLimit = 5,
......@@ -56,7 +58,7 @@ class Cocoon {
final int requestRetryLimit;
String get commitSha => _commitSha ?? _readCommitSha();
String? _commitSha;
String _commitSha;
/// Parse the local repo for the current running commit.
String _readCommitSha() {
......@@ -83,9 +85,9 @@ class Cocoon {
/// Send [TaskResult] to Cocoon.
// TODO(chillers): Remove when sendResultsPath is used in prod. https://github.com/flutter/flutter/issues/72457
Future<void> sendTaskResult({
required String builderName,
required TaskResult result,
required String gitBranch,
@required String builderName,
@required TaskResult result,
@required String gitBranch,
}) async {
assert(builderName != null);
assert(gitBranch != null);
......@@ -107,10 +109,10 @@ class Cocoon {
/// Write the given parameters into an update task request and store the JSON in [resultsPath].
Future<void> writeTaskResultToFile({
required String builderName,
required String gitBranch,
required TaskResult result,
required String resultsPath,
@required String builderName,
@required String gitBranch,
@required TaskResult result,
@required String resultsPath,
}) async {
assert(builderName != null);
assert(gitBranch != null);
......@@ -132,9 +134,9 @@ class Cocoon {
}
Map<String, dynamic> _constructUpdateRequest({
String? builderName,
required TaskResult result,
required String gitBranch,
@required String builderName,
@required TaskResult result,
@required String gitBranch,
}) {
final Map<String, dynamic> updateRequest = <String, dynamic>{
'CommitBranch': gitBranch,
......@@ -149,12 +151,12 @@ class Cocoon {
final List<String> validScoreKeys = <String>[];
if (result.benchmarkScoreKeys != null) {
for (final String scoreKey in result.benchmarkScoreKeys!) {
final Object score = result.data![scoreKey] as Object;
for (final String scoreKey in result.benchmarkScoreKeys) {
final Object score = result.data[scoreKey];
if (score is num) {
// Convert all metrics to double, which provide plenty of precision
// without having to add support for multiple numeric types in Cocoon.
result.data![scoreKey] = score.toDouble();
result.data[scoreKey] = score.toDouble();
validScoreKeys.add(scoreKey);
}
}
......@@ -193,15 +195,15 @@ class Cocoon {
class AuthenticatedCocoonClient extends BaseClient {
AuthenticatedCocoonClient(
this._serviceAccountTokenPath, {
@visibleForTesting Client? httpClient,
@visibleForTesting FileSystem? filesystem,
@visibleForTesting Client httpClient,
@visibleForTesting FileSystem filesystem,
}) : _delegate = httpClient ?? Client(),
_fs = filesystem ?? const LocalFileSystem();
/// Authentication token to have the ability to upload and record test results.
///
/// This is intended to only be passed on automated runs on LUCI post-submit.
final String? _serviceAccountTokenPath;
final String _serviceAccountTokenPath;
/// Underlying [HttpClient] to send requests to.
final Client _delegate;
......@@ -211,7 +213,7 @@ class AuthenticatedCocoonClient extends BaseClient {
/// Value contained in the service account token file that can be used in http requests.
String get serviceAccountToken => _serviceAccountToken ?? _readServiceAccountTokenFile();
String? _serviceAccountToken;
String _serviceAccountToken;
/// Get [serviceAccountToken] from the given service account file.
String _readServiceAccountTokenFile() {
......
This diff is collapsed.
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
......@@ -62,8 +64,8 @@ class _TaskRunner {
_TaskRunner(this.task) {
registerExtension('ext.cocoonRunTask',
(String method, Map<String, String> parameters) async {
final Duration? taskTimeout = parameters.containsKey('timeoutInMinutes')
? Duration(minutes: int.parse(parameters['timeoutInMinutes']!))
final Duration taskTimeout = parameters.containsKey('timeoutInMinutes')
? Duration(minutes: int.parse(parameters['timeoutInMinutes']))
: null;
// This is only expected to be passed in unit test runs so they do not
// kill the Dart process that is running them and waste time running config.
......@@ -80,7 +82,7 @@ class _TaskRunner {
final TaskFunction task;
Future<Device?> _getWorkingDeviceIfAvailable() async {
Future<Device/*?*/> _getWorkingDeviceIfAvailable() async {
try {
return await devices.workingDevice;
} on DeviceException {
......@@ -89,8 +91,8 @@ class _TaskRunner {
}
// TODO(ianh): workaround for https://github.com/dart-lang/sdk/issues/23797
RawReceivePort? _keepAlivePort;
Timer? _startTaskTimeout;
RawReceivePort _keepAlivePort;
Timer _startTaskTimeout;
bool _taskStarted = false;
final Completer<TaskResult> _completer = Completer<TaskResult>();
......@@ -100,7 +102,7 @@ class _TaskRunner {
/// Signals that this task runner finished running the task.
Future<TaskResult> get whenDone => _completer.future;
Future<TaskResult> run(Duration? taskTimeout, {
Future<TaskResult> run(Duration taskTimeout, {
bool runFlutterConfig = true,
bool runProcessCleanup = true,
}) async {
......@@ -108,7 +110,7 @@ class _TaskRunner {
_taskStarted = true;
print('Running task with a timeout of $taskTimeout.');
final String exe = Platform.isWindows ? '.exe' : '';
late Set<RunningProcessInfo> beforeRunningDartInstances;
Set<RunningProcessInfo> beforeRunningDartInstances;
if (runProcessCleanup) {
section('Checking running Dart$exe processes');
beforeRunningDartInstances = await getRunningProcesses(
......@@ -134,7 +136,7 @@ class _TaskRunner {
'--enable-windows-desktop',
'--enable-linux-desktop',
'--enable-web',
if (localEngine != null) ...<String>['--local-engine', localEngine!],
if (localEngine != null) ...<String>['--local-engine', localEngine],
], canFail: true);
if (configResult != 0) {
print('Failed to enable configuration, tasks may not run.');
......@@ -143,12 +145,12 @@ class _TaskRunner {
print('Skipping enabling configs for macOS, Linux, Windows, and Web');
}
final Device? device = await _getWorkingDeviceIfAvailable();
late TaskResult result;
IOSink? sink;
final Device/*?*/ device = await _getWorkingDeviceIfAvailable();
/*late*/ TaskResult result;
IOSink/*?*/ sink;
try {
if (device != null && device.canStreamLogs && hostAgent.dumpDirectory != null) {
sink = File(path.join(hostAgent.dumpDirectory!.path, '${device.deviceId}.log')).openWrite();
sink = File(path.join(hostAgent.dumpDirectory.path, '${device.deviceId}.log')).openWrite();
await device.startLoggingToSink(sink);
}
......@@ -210,7 +212,7 @@ class _TaskRunner {
final File rebootFile = _rebootFile();
int runCount;
if (rebootFile.existsSync()) {
runCount = int.tryParse(rebootFile.readAsStringSync().trim()) ?? 0;
runCount = int.tryParse(rebootFile.readAsStringSync().trim());
} else {
runCount = 0;
}
......@@ -281,10 +283,10 @@ class _TaskRunner {
File _rebootFile() {
if (Platform.isLinux || Platform.isMacOS) {
return File(path.join(Platform.environment['HOME']!, '.reboot-count'));
return File(path.join(Platform.environment['HOME'], '.reboot-count'));
}
if (!Platform.isWindows) {
throw StateError('Unexpected platform ${Platform.operatingSystem}');
}
return File(path.join(Platform.environment['USERPROFILE']!, '.reboot-count'));
return File(path.join(Platform.environment['USERPROFILE'], '.reboot-count'));
}
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:convert';
import 'utils.dart';
......@@ -40,10 +42,17 @@ Future<bool> containsBitcode(String pathToBinary) async {
final List<String> lines = LineSplitter.split(loadCommands).toList();
lines.asMap().forEach((int index, String line) {
if (line.contains('segname __LLVM') && lines.length - index - 1 > 3) {
emptyBitcodeMarkerFound |= lines
final String emptyBitcodeMarker = lines
.skip(index - 1)
.take(4)
.any((String line) => line.contains(' size 0x0000000000000001'));
.firstWhere(
(String line) => line.contains(' size 0x0000000000000001'),
orElse: () => null,
);
if (emptyBitcodeMarker != null) {
emptyBitcodeMarkerFound = true;
return;
}
}
});
return !emptyBitcodeMarkerFound;
......@@ -70,16 +79,16 @@ Future<void> testWithNewIOSSimulator(
workingDirectory: flutterDirectory.path,
);
String? iOSSimRuntime;
String iOSSimRuntime;
final RegExp iOSRuntimePattern = RegExp(r'iOS .*\) - (.*)');
for (final String runtime in LineSplitter.split(availableRuntimes)) {
// These seem to be in order, so allow matching multiple lines so it grabs
// the last (hopefully latest) one.
final RegExpMatch? iOSRuntimeMatch = iOSRuntimePattern.firstMatch(runtime);
final RegExpMatch iOSRuntimeMatch = iOSRuntimePattern.firstMatch(runtime);
if (iOSRuntimeMatch != null) {
iOSSimRuntime = iOSRuntimeMatch.group(1)!.trim();
iOSSimRuntime = iOSRuntimeMatch.group(1).trim();
continue;
}
}
......
......@@ -2,14 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:meta/meta.dart';
import 'package:yaml/yaml.dart';
import 'utils.dart';
/// Loads manifest data from `manifest.yaml` file or from [yaml], if present.
Manifest loadTaskManifest([ String? yaml ]) {
Manifest loadTaskManifest([ String yaml ]) {
final dynamic manifestYaml = yaml == null
? loadYaml(file('manifest.yaml').readAsStringSync())
: loadYamlNode(yaml);
......@@ -29,13 +32,13 @@ class Manifest {
/// A CI task.
class ManifestTask {
ManifestTask._({
required this.name,
required this.description,
required this.stage,
required this.requiredAgentCapabilities,
required this.isFlaky,
required this.timeoutInMinutes,
required this.onLuci,
@required this.name,
@required this.description,
@required this.stage,
@required this.requiredAgentCapabilities,
@required this.isFlaky,
@required this.timeoutInMinutes,
@required this.onLuci,
}) {
final String taskName = 'task "$name"';
_checkIsNotBlank(name, 'Task name', taskName);
......@@ -145,9 +148,9 @@ ManifestTask _validateAndParseTask(String taskName, dynamic taskYaml) {
// ignore: avoid_dynamic_calls
stage: taskYaml['stage'] as String,
requiredAgentCapabilities: capabilities as List<String>,
isFlaky: isFlaky as bool,
isFlaky: isFlaky as bool ?? false,
timeoutInMinutes: timeoutInMinutes as int,
onLuci: onLuci as bool,
onLuci: onLuci as bool ?? false,
);
}
......@@ -158,7 +161,7 @@ List<String> _validateAndParseCapabilities(String taskName, dynamic capabilities
final dynamic capability = capabilities[i];
_checkType(capability is String, capability, 'required_agent_capabilities[$i]', 'string');
}
return capabilitiesYaml.cast<String>();
return (capabilitiesYaml as List<dynamic>).cast<String>();
}
void _checkType(bool isValid, dynamic value, String variableName, String typeName) {
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:io';
......@@ -19,13 +21,13 @@ 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,
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"');
......@@ -42,10 +44,10 @@ Future<void> runTasks(
print(const JsonEncoder.withIndent(' ').convert(result));
section('Finished task "$taskName"');
if (resultsPath != null && gitBranch != null) {
if (resultsPath != null) {
final Cocoon cocoon = Cocoon();
await cocoon.writeTaskResultToFile(
builderName: luciBuilder!,
builderName: luciBuilder,
gitBranch: gitBranch,
result: result,
resultsPath: resultsPath,
......@@ -74,11 +76,11 @@ Future<void> runTasks(
Future<TaskResult> runTask(
String taskName, {
bool silent = false,
String? localEngine,
String? localEngineSrcPath,
String? deviceId,
List<String> ?taskArgs,
@visibleForTesting Map<String, String>? isolateParams,
String localEngine,
String localEngineSrcPath,
String deviceId,
List<String> taskArgs,
@visibleForTesting Map<String, String> isolateParams,
}) async {
final String taskExecutable = 'bin/tasks/$taskName.dart';
......@@ -115,7 +117,7 @@ Future<TaskResult> runTask(
.transform<String>(const LineSplitter())
.listen((String line) {
if (!uri.isCompleted) {
final Uri? serviceUri = parseServiceUri(line, prefix: 'Observatory listening on ');
final Uri serviceUri = parseServiceUri(line, prefix: 'Observatory listening on ');
if (serviceUri != null)
uri.complete(serviceUri);
}
......@@ -137,7 +139,7 @@ Future<TaskResult> runTask(
'ext.cocoonRunTask',
args: isolateParams,
isolateId: result.isolate.id,
)).json!;
)).json;
final TaskResult taskResult = TaskResult.fromJson(taskResultJson);
await runner.exitCode;
return taskResult;
......@@ -166,13 +168,13 @@ Future<ConnectionResult> _connectToRunnerIsolate(Uri vmServiceUri) async {
// Look up the isolate.
final VmService client = await vmServiceConnectUri(url);
VM vm = await client.getVM();
while (vm.isolates!.isEmpty) {
while (vm.isolates.isEmpty) {
await Future<void>.delayed(const Duration(seconds: 1));
vm = await client.getVM();
}
final IsolateRef isolate = vm.isolates!.first;
final IsolateRef isolate = vm.isolates.first;
final Response response = await client.callServiceExtension('ext.cocoonRunnerReady', isolateId: isolate.id);
if (response.json!['response'] != 'ready')
if (response.json['response'] != 'ready')
throw 'not ready yet';
return ConnectionResult(client, isolate);
} catch (error) {
......@@ -191,7 +193,7 @@ class ConnectionResult {
}
/// The cocoon client sends an invalid VM service response, we need to intercept it.
Future<VmService> vmServiceConnectUri(String wsUri, {Log? log}) async {
Future<VmService> vmServiceConnectUri(String wsUri, {Log log}) async {
final WebSocket socket = await WebSocket.connect(wsUri);
final StreamController<dynamic> controller = StreamController<dynamic>();
final Completer<dynamic> streamClosedCompleter = Completer<dynamic>();
......@@ -205,7 +207,7 @@ Future<VmService> vmServiceConnectUri(String wsUri, {Log? log}) async {
controller.add(data);
}
},
onError: (Object err, StackTrace stackTrace) => controller.addError(err, stackTrace),
onError: (dynamic err, StackTrace stackTrace) => controller.addError(err, stackTrace),
onDone: () => streamClosedCompleter.complete(),
);
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:meta/meta.dart';
......@@ -34,7 +36,7 @@ class RunningProcessInfo {
}
}
Future<bool> killProcess(String pid, {ProcessManager? processManager}) async {
Future<bool> killProcess(String pid, {ProcessManager processManager}) async {
assert(pid != null, 'Must specify a pid to kill');
processManager ??= const LocalProcessManager();
ProcessResult result;
......@@ -56,8 +58,8 @@ Future<bool> killProcess(String pid, {ProcessManager? processManager}) async {
}
Stream<RunningProcessInfo> getRunningProcesses({
String? processName,
ProcessManager? processManager,
String processName,
ProcessManager processManager,
}) {
processManager ??= const LocalProcessManager();
if (Platform.isWindows) {
......@@ -67,7 +69,7 @@ Stream<RunningProcessInfo> getRunningProcesses({
}
@visibleForTesting
Stream<RunningProcessInfo> windowsRunningProcesses(String? processName) async* {
Stream<RunningProcessInfo> windowsRunningProcesses(String processName) async* {
// PowerShell script to get the command line arguments and create time of
// a process.
// See: https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process
......@@ -105,8 +107,8 @@ Iterable<RunningProcessInfo> processPowershellOutput(String output) sync* {
const int processIdHeaderSize = 'ProcessId'.length;
const int creationDateHeaderStart = processIdHeaderSize + 1;
late int creationDateHeaderEnd;
late int commandLineHeaderStart;
int creationDateHeaderEnd;
int commandLineHeaderStart;
bool inTableBody = false;
for (final String line in output.split('\n')) {
if (line.startsWith('ProcessId')) {
......@@ -158,7 +160,7 @@ Iterable<RunningProcessInfo> processPowershellOutput(String output) sync* {
@visibleForTesting
Stream<RunningProcessInfo> posixRunningProcesses(
String? processName,
String processName,
ProcessManager processManager,
) async* {
// Cirrus is missing this in Linux for some reason.
......@@ -192,7 +194,7 @@ Stream<RunningProcessInfo> posixRunningProcesses(
@visibleForTesting
Iterable<RunningProcessInfo> processPsOutput(
String output,
String? processName,
String processName,
) sync* {
if (output == null) {
return;
......@@ -233,7 +235,7 @@ Iterable<RunningProcessInfo> processPsOutput(
final String rawTime = line.substring(0, 24);
final String year = rawTime.substring(20, 24);
final String month = months[rawTime.substring(4, 7)]!;
final String month = months[rawTime.substring(4, 7)];
final String day = rawTime.substring(8, 10).replaceFirst(' ', '0');
final String time = rawTime.substring(11, 19);
......
......@@ -41,7 +41,7 @@ class TaskResult {
List<String> detailFiles = const <String>[],
}) {
return TaskResult.success(
json.decode(file.readAsStringSync()) as Map<String, dynamic>?,
json.decode(file.readAsStringSync()) as Map<String, dynamic>,
benchmarkScoreKeys: benchmarkScoreKeys,
detailFiles: detailFiles,
);
......@@ -53,14 +53,14 @@ class TaskResult {
if (success) {
final List<String> benchmarkScoreKeys = (json['benchmarkScoreKeys'] as List<dynamic>? ?? <String>[]).cast<String>();
final List<String> detailFiles = (json['detailFiles'] as List<dynamic>? ?? <String>[]).cast<String>();
return TaskResult.success(json['data'] as Map<String, dynamic>?,
return TaskResult.success(json['data'] as Map<String, dynamic>,
benchmarkScoreKeys: benchmarkScoreKeys,
detailFiles: detailFiles,
message: json['reason'] as String?,
message: json['reason'] as String,
);
}
return TaskResult.failure(json['reason'] as String?);
return TaskResult.failure(json['reason'] as String);
}
/// Constructs an unsuccessful result.
......@@ -88,7 +88,7 @@ class TaskResult {
bool get failed => !succeeded;
/// Explains the result in a human-readable format.
final String? message;
final String message;
/// Serializes this task result to JSON format.
///
......@@ -124,7 +124,7 @@ class TaskResult {
}
@override
String toString() => message ?? '';
String toString() => message;
}
class TaskResultCheckProcesses extends TaskResult {
......
This diff is collapsed.
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:io';
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:path/path.dart' as path;
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:args/args.dart';
......@@ -16,9 +18,10 @@ import '../framework/utils.dart';
abstract class BuildTestTask {
BuildTestTask(this.args, {this.workingDirectory, this.runFlutterClean = true,}) {
final ArgResults argResults = argParser.parse(args);
applicationBinaryPath = argResults[kApplicationBinaryPathOption] as String?;
applicationBinaryPath = argResults[kApplicationBinaryPathOption] as String;
buildOnly = argResults[kBuildOnlyFlag] as bool;
testOnly = argResults[kTestOnlyFlag] as bool;
}
static const String kApplicationBinaryPathOption = 'application-binary-path';
......@@ -45,10 +48,10 @@ abstract class BuildTestTask {
/// Path to a built application to use in [test].
///
/// If not given, will default to child's expected location.
String? applicationBinaryPath;
String applicationBinaryPath;
/// Where the test artifacts are stored, such as performance results.
final Directory? workingDirectory;
final Directory workingDirectory;
/// Run Flutter build to create [applicationBinaryPath].
Future<void> build() async {
......@@ -90,7 +93,7 @@ abstract class BuildTestTask {
///
/// Tasks can override to support default values. Otherwise, it will default
/// to needing to be passed as an argument in the test runner.
String? getApplicationBinaryPath() => applicationBinaryPath;
String getApplicationBinaryPath() => applicationBinaryPath;
/// Run this task.
///
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:io';
......@@ -13,8 +15,8 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path;
TaskFunction dartPluginRegistryTest({
String? deviceIdOverride,
Map<String, String>? environment,
String deviceIdOverride,
Map<String, String> environment,
}) {
final Directory tempDir = Directory.systemTemp
.createTempSync('flutter_devicelab_dart_plugin_test.');
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
......@@ -53,9 +55,9 @@ class GalleryTransitionTest {
final bool needFullTimeline;
final String testFile;
final String timelineSummaryFile;
final String? timelineTraceFile;
final String? transitionDurationFile;
final String? driverFile;
final String timelineTraceFile;
final String transitionDurationFile;
final String driverFile;
Future<TaskResult> call() async {
final Device device = await devices.workingDevice;
......@@ -63,7 +65,7 @@ class GalleryTransitionTest {
final String deviceId = device.deviceId;
final Directory galleryDirectory = dir('${flutterDirectory.path}/dev/integration_tests/flutter_gallery');
await inDirectory<void>(galleryDirectory, () async {
String? applicationBinaryPath;
String applicationBinaryPath;
if (deviceOperatingSystem == DeviceOperatingSystem.android) {
section('BUILDING APPLICATION');
await flutter(
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:io';
......@@ -18,7 +20,7 @@ final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'dev/in
const String kSourceLine = 'fontSize: (orientation == Orientation.portrait) ? 32.0 : 24.0';
const String kReplacementLine = 'fontSize: (orientation == Orientation.portrait) ? 34.0 : 24.0';
TaskFunction createHotModeTest({String? deviceIdOverride, Map<String, String>? environment}) {
TaskFunction createHotModeTest({String deviceIdOverride, Map<String, String> environment}) {
// This file is modified during the test and needs to be restored at the end.
final File flutterFrameworkSource = file(path.join(
flutterDirectory.path, 'packages/flutter/lib/src/widgets/framework.dart',
......@@ -33,13 +35,13 @@ TaskFunction createHotModeTest({String? deviceIdOverride, Map<String, String>? e
final File benchmarkFile = file(path.join(_editedFlutterGalleryDir.path, 'hot_benchmark.json'));
rm(benchmarkFile);
final List<String> options = <String>[
'--hot', '-d', deviceIdOverride!, '--benchmark', '--resident', '--no-android-gradle-daemon', '--no-publish-port', '--verbose',
'--hot', '-d', deviceIdOverride, '--benchmark', '--resident', '--no-android-gradle-daemon', '--no-publish-port', '--verbose',
];
int hotReloadCount = 0;
late Map<String, dynamic> smallReloadData;
late Map<String, dynamic> mediumReloadData;
late Map<String, dynamic> largeReloadData;
late Map<String, dynamic> freshRestartReloadsData;
Map<String, dynamic> smallReloadData;
Map<String, dynamic> mediumReloadData;
Map<String, dynamic> largeReloadData;
Map<String, dynamic> freshRestartReloadsData;
await inDirectory<void>(flutterDirectory, () async {
......@@ -215,7 +217,7 @@ TaskFunction createHotModeTest({String? deviceIdOverride, Map<String, String>? e
Future<Map<String, Object>> captureReloadData(
List<String> options,
Map<String, String>? environment,
Map<String, String> environment,
File benchmarkFile,
void Function(String, Process) onLine,
) async {
......@@ -245,7 +247,7 @@ Future<Map<String, Object>> captureReloadData(
await Future.wait<void>(<Future<void>>[stdoutDone.future, stderrDone.future]);
await process.exitCode;
final Map<String, Object> result = json.decode(benchmarkFile.readAsStringSync()) as Map<String, Object>;
final Map<String, dynamic> result = json.decode(benchmarkFile.readAsStringSync()) as Map<String, dynamic>;
benchmarkFile.deleteSync();
return result;
}
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import '../framework/devices.dart';
import '../framework/framework.dart';
import '../framework/task_result.dart';
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:io';
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:flutter_devicelab/tasks/perf_tests.dart';
......
This diff is collapsed.
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io' show Process, Directory;
import 'package:flutter_devicelab/framework/devices.dart' as adb;
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:flutter_devicelab/framework/framework.dart';
......@@ -29,8 +31,8 @@ class PluginTest {
final String buildTarget;
final List<String> options;
final Map<String, String>? pluginCreateEnvironment;
final Map<String, String>? appCreateEnvironment;
final Map<String, String> pluginCreateEnvironment;
final Map<String, String> appCreateEnvironment;
Future<TaskResult> call() async {
final Directory tempDir =
......@@ -75,7 +77,7 @@ class _FlutterProject {
String get rootPath => path.join(parent.path, name);
Future<void> addPlugin(String plugin, {String? pluginPath}) async {
Future<void> addPlugin(String plugin, {String pluginPath}) async {
final File pubspec = File(path.join(rootPath, 'pubspec.yaml'));
String content = await pubspec.readAsString();
final String dependency =
......@@ -98,9 +100,9 @@ class _FlutterProject {
List<String> options,
String target,
{
required String name,
required String template,
Map<String, String>? environment,
String name,
String template,
Map<String, String> environment,
}) async {
await inDirectory(directory, () async {
await flutter(
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert' show json;
import 'dart:io' as io;
......@@ -11,6 +13,7 @@ import 'package:flutter_devicelab/framework/browser.dart';
import 'package:flutter_devicelab/framework/task_result.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:logging/logging.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
......@@ -20,7 +23,7 @@ import 'package:shelf_static/shelf_static.dart';
const int benchmarkServerPort = 9999;
const int chromeDebugPort = 10000;
Future<TaskResult> runWebBenchmark({ required bool useCanvasKit }) async {
Future<TaskResult> runWebBenchmark({ @required bool useCanvasKit }) async {
// Reduce logging level. Otherwise, package:webkit_inspection_protocol is way too spammy.
Logger.root.level = Level.INFO;
final String macrobenchmarksDirectory = path.join(flutterDirectory.path, 'dev', 'benchmarks', 'macrobenchmarks');
......@@ -35,17 +38,17 @@ Future<TaskResult> runWebBenchmark({ required bool useCanvasKit }) async {
]);
final Completer<List<Map<String, dynamic>>> profileData = Completer<List<Map<String, dynamic>>>();
final List<Map<String, dynamic>> collectedProfiles = <Map<String, dynamic>>[];
List<String>? benchmarks;
late Iterator<String> benchmarkIterator;
List<String> benchmarks;
Iterator<String> benchmarkIterator;
// This future fixes a race condition between the web-page loading and
// asking to run a benchmark, and us connecting to Chrome's DevTools port.
// Sometime one wins. Other times, the other wins.
Future<Chrome>? whenChromeIsReady;
Chrome? chrome;
late io.HttpServer server;
Future<Chrome> whenChromeIsReady;
Chrome chrome;
io.HttpServer server;
Cascade cascade = Cascade();
List<Map<String, dynamic>>? latestPerformanceTrace;
List<Map<String, dynamic>> latestPerformanceTrace;
cascade = cascade.add((Request request) async {
try {
chrome ??= await whenChromeIsReady;
......@@ -63,7 +66,7 @@ Future<TaskResult> runWebBenchmark({ required bool useCanvasKit }) async {
// Trace data is null when the benchmark is not frame-based, such as RawRecorder.
if (latestPerformanceTrace != null) {
final BlinkTraceSummary traceSummary = BlinkTraceSummary.fromJson(latestPerformanceTrace!)!;
final BlinkTraceSummary traceSummary = BlinkTraceSummary.fromJson(latestPerformanceTrace);
profile['totalUiFrame.average'] = traceSummary.averageTotalUIFrameTime.inMicroseconds;
profile['scoreKeys'] ??= <dynamic>[]; // using dynamic for consistency with JSON
(profile['scoreKeys'] as List<dynamic>).add('totalUiFrame.average');
......@@ -73,10 +76,10 @@ Future<TaskResult> runWebBenchmark({ required bool useCanvasKit }) async {
return Response.ok('Profile received');
} else if (request.requestedUri.path.endsWith('/start-performance-tracing')) {
latestPerformanceTrace = null;
await chrome!.beginRecordingPerformance(request.requestedUri.queryParameters['label']!);
await chrome.beginRecordingPerformance(request.requestedUri.queryParameters['label']);
return Response.ok('Started performance tracing');
} else if (request.requestedUri.path.endsWith('/stop-performance-tracing')) {
latestPerformanceTrace = await chrome!.endRecordingPerformance();
latestPerformanceTrace = await chrome.endRecordingPerformance();
return Response.ok('Stopped performance tracing');
} else if (request.requestedUri.path.endsWith('/on-error')) {
final Map<String, dynamic> errorDetails = json.decode(await request.readAsString()) as Map<String, dynamic>;
......@@ -87,7 +90,7 @@ Future<TaskResult> runWebBenchmark({ required bool useCanvasKit }) async {
} else if (request.requestedUri.path.endsWith('/next-benchmark')) {
if (benchmarks == null) {
benchmarks = (json.decode(await request.readAsString()) as List<dynamic>).cast<String>();
benchmarkIterator = benchmarks!.iterator;
benchmarkIterator = benchmarks.iterator;
}
if (benchmarkIterator.moveNext()) {
final String nextBenchmark = benchmarkIterator.current;
......@@ -183,7 +186,7 @@ Future<TaskResult> runWebBenchmark({ required bool useCanvasKit }) async {
}
return TaskResult.success(taskResult, benchmarkScoreKeys: benchmarkScoreKeys);
} finally {
unawaited(server.close());
unawaited(server?.close());
chrome?.stop();
}
});
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:io';
......
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