Migrate assemble and integration_test_device to null safety (#96630)

This commit is contained in:
Jenn Magder 2022-01-14 15:50:12 -08:00 committed by GitHub
parent dafda50c6a
commit 219dd6ca38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 67 deletions

View file

@ -2,10 +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 'package:args/args.dart';
import 'package:meta/meta.dart';
import '../artifacts.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../build_info.dart';
@ -88,7 +88,7 @@ List<Target> _kDefaultTargets = <Target>[
/// Assemble provides a low level API to interact with the flutter tool build
/// system.
class AssembleCommand extends FlutterCommand {
AssembleCommand({ bool verboseHelp = false, @required BuildSystem buildSystem })
AssembleCommand({ bool verboseHelp = false, required BuildSystem buildSystem })
: _buildSystem = buildSystem {
argParser.addMultiOption(
'define',
@ -161,13 +161,13 @@ class AssembleCommand extends FlutterCommand {
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async {
final String platform = environment.defines[kTargetPlatform];
final String? platform = environment.defines[kTargetPlatform];
if (platform == null) {
return super.requiredArtifacts;
}
final TargetPlatform targetPlatform = getTargetPlatformForName(platform);
final DevelopmentArtifact artifact = artifactFromTargetPlatform(targetPlatform);
final DevelopmentArtifact? artifact = artifactFromTargetPlatform(targetPlatform);
if (artifact != null) {
return <DevelopmentArtifact>{artifact};
}
@ -176,18 +176,19 @@ class AssembleCommand extends FlutterCommand {
/// The target(s) we are building.
List<Target> createTargets() {
if (argResults.rest.isEmpty) {
final ArgResults argumentResults = argResults!;
if (argumentResults.rest.isEmpty) {
throwToolExit('missing target name for flutter assemble.');
}
final String name = argResults.rest.first;
final String name = argumentResults.rest.first;
final Map<String, Target> targetMap = <String, Target>{
for (final Target target in _kDefaultTargets)
target.name: target
};
final List<Target> results = <Target>[
for (final String targetName in argResults.rest)
for (final String targetName in argumentResults.rest)
if (targetMap.containsKey(targetName))
targetMap[targetName]
targetMap[targetName]!
];
if (results.isEmpty) {
throwToolExit('No target named "$name" defined.');
@ -196,7 +197,7 @@ class AssembleCommand extends FlutterCommand {
}
bool isDeferredComponentsTargets() {
for (final String targetName in argResults.rest) {
for (final String targetName in argResults!.rest) {
if (deferredComponentsTargets.contains(targetName)) {
return true;
}
@ -205,7 +206,7 @@ class AssembleCommand extends FlutterCommand {
}
bool isDebug() {
for (final String targetName in argResults.rest) {
for (final String targetName in argResults!.rest) {
if (targetName.contains('debug')) {
return true;
}
@ -213,13 +214,12 @@ class AssembleCommand extends FlutterCommand {
return false;
}
Environment get environment => _environment ??= createEnvironment();
Environment _environment;
late final Environment environment = createEnvironment();
/// The environmental configuration for a build invocation.
Environment createEnvironment() {
final FlutterProject flutterProject = FlutterProject.current();
String output = stringArg('output');
String? output = stringArg('output');
if (output == null) {
throwToolExit('--output directory is required for assemble.');
}
@ -227,6 +227,7 @@ class AssembleCommand extends FlutterCommand {
if (globals.fs.path.isRelative(output)) {
output = globals.fs.path.join(flutterProject.directory.path, output);
}
final Artifacts artifacts = globals.artifacts!;
final Environment result = Environment(
outputDir: globals.fs.directory(output),
buildDir: flutterProject.directory
@ -237,12 +238,12 @@ class AssembleCommand extends FlutterCommand {
inputs: _parseDefines(stringsArg('input')),
cacheDir: globals.cache.getRoot(),
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
artifacts: globals.artifacts,
artifacts: artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
platform: globals.platform,
engineVersion: globals.artifacts.isLocalEngine
engineVersion: artifacts.isLocalEngine
? null
: globals.flutterVersion.engineRevision,
generateDartPluginRegistry: true,
@ -261,18 +262,19 @@ class AssembleCommand extends FlutterCommand {
final String value = chunk.substring(indexEquals + 1);
results[key] = value;
}
if (argResults.wasParsed(FlutterOptions.kExtraGenSnapshotOptions)) {
results[kExtraGenSnapshotOptions] = (argResults[FlutterOptions.kExtraGenSnapshotOptions] as List<String>).join(',');
final ArgResults argumentResults = argResults!;
if (argumentResults.wasParsed(FlutterOptions.kExtraGenSnapshotOptions)) {
results[kExtraGenSnapshotOptions] = (argumentResults[FlutterOptions.kExtraGenSnapshotOptions] as List<String>).join(',');
}
if (argResults.wasParsed(FlutterOptions.kDartDefinesOption)) {
results[kDartDefines] = (argResults[FlutterOptions.kDartDefinesOption] as List<String>).join(',');
if (argumentResults.wasParsed(FlutterOptions.kDartDefinesOption)) {
results[kDartDefines] = (argumentResults[FlutterOptions.kDartDefinesOption] as List<String>).join(',');
}
results[kDeferredComponents] = 'false';
if (FlutterProject.current().manifest.deferredComponents != null && isDeferredComponentsTargets() && !isDebug()) {
results[kDeferredComponents] = 'true';
}
if (argResults.wasParsed(FlutterOptions.kExtraFrontEndOptions)) {
results[kExtraFrontEndOptions] = (argResults[FlutterOptions.kExtraFrontEndOptions] as List<String>).join(',');
if (argumentResults.wasParsed(FlutterOptions.kExtraFrontEndOptions)) {
results[kExtraFrontEndOptions] = (argumentResults[FlutterOptions.kExtraFrontEndOptions] as List<String>).join(',');
}
return results;
}
@ -289,7 +291,7 @@ class AssembleCommand extends FlutterCommand {
nonDeferredTargets.add(target);
}
}
Target target;
Target? target;
List<String> decodedDefines;
try {
decodedDefines = decodeDartDefines(environment.defines, kDartDefines);
@ -314,12 +316,13 @@ class AssembleCommand extends FlutterCommand {
} else if (targets.isNotEmpty) {
target = targets.single;
}
final ArgResults argumentResults = argResults!;
final BuildResult result = await _buildSystem.build(
target,
target!,
environment,
buildSystemConfig: BuildSystemConfig(
resourcePoolSize: argResults.wasParsed('resource-pool-size')
? int.tryParse(stringArg('resource-pool-size'))
resourcePoolSize: argumentResults.wasParsed('resource-pool-size')
? int.tryParse(stringArg('resource-pool-size')!)
: null,
),
);
@ -335,17 +338,17 @@ class AssembleCommand extends FlutterCommand {
}
globals.printTrace('build succeeded.');
if (argResults.wasParsed('build-inputs')) {
writeListIfChanged(result.inputFiles, stringArg('build-inputs'));
if (argumentResults.wasParsed('build-inputs')) {
writeListIfChanged(result.inputFiles, stringArg('build-inputs')!);
}
if (argResults.wasParsed('build-outputs')) {
writeListIfChanged(result.outputFiles, stringArg('build-outputs'));
if (argumentResults.wasParsed('build-outputs')) {
writeListIfChanged(result.outputFiles, stringArg('build-outputs')!);
}
if (argResults.wasParsed('performance-measurement-file')) {
final File outFile = globals.fs.file(argResults['performance-measurement-file']);
if (argumentResults.wasParsed('performance-measurement-file')) {
final File outFile = globals.fs.file(argumentResults['performance-measurement-file']);
writePerformanceData(result.performance.values, outFile);
}
if (argResults.wasParsed('depfile')) {
if (argumentResults.wasParsed('depfile')) {
final File depfileFile = globals.fs.file(stringArg('depfile'));
final Depfile depfile = Depfile(result.inputFiles, result.outputFiles);
final DepfileService depfileService = DepfileService(

View file

@ -2,11 +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 'package:meta/meta.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
@ -24,10 +21,10 @@ const String kIntegrationTestMethod = 'ext.flutter.integrationTest';
class IntegrationTestTestDevice implements TestDevice {
IntegrationTestTestDevice({
@required this.id,
@required this.device,
@required this.debuggingOptions,
@required this.userIdentifier,
required this.id,
required this.device,
required this.debuggingOptions,
required this.userIdentifier,
});
final int id;
@ -35,7 +32,7 @@ class IntegrationTestTestDevice implements TestDevice {
final DebuggingOptions debuggingOptions;
final String userIdentifier;
ApplicationPackage _applicationPackage;
ApplicationPackage? _applicationPackage;
final Completer<void> _finished = Completer<void>();
final Completer<Uri> _gotProcessObservatoryUri = Completer<Uri>();
@ -45,13 +42,16 @@ class IntegrationTestTestDevice implements TestDevice {
@override
Future<StreamChannel<String>> start(String entrypointPath) async {
final TargetPlatform targetPlatform = await device.targetPlatform;
_applicationPackage = await ApplicationPackageFactory.instance.getPackageForPlatform(
_applicationPackage = await ApplicationPackageFactory.instance?.getPackageForPlatform(
targetPlatform,
buildInfo: debuggingOptions.buildInfo,
);
if (_applicationPackage == null) {
throw TestDeviceException('No application found for $targetPlatform.', StackTrace.current);
}
final LaunchResult launchResult = await device.startApp(
_applicationPackage,
_applicationPackage!,
mainPath: entrypointPath,
platformArgs: <String, dynamic>{},
debuggingOptions: debuggingOptions,
@ -60,17 +60,18 @@ class IntegrationTestTestDevice implements TestDevice {
if (!launchResult.started) {
throw TestDeviceException('Unable to start the app on the device.', StackTrace.current);
}
if (launchResult.observatoryUri == null) {
final Uri? observatoryUri = launchResult.observatoryUri;
if (observatoryUri == null) {
throw TestDeviceException('Observatory is not available on the test device.', StackTrace.current);
}
// No need to set up the log reader because the logs are captured and
// streamed to the package:test_core runner.
_gotProcessObservatoryUri.complete(launchResult.observatoryUri);
_gotProcessObservatoryUri.complete(observatoryUri);
globals.printTrace('test $id: Connecting to vm service');
final FlutterVmService vmService = await connectToVmService(launchResult.observatoryUri, logger: globals.logger).timeout(
final FlutterVmService vmService = await connectToVmService(observatoryUri, logger: globals.logger).timeout(
const Duration(seconds: 5),
onTimeout: () => throw TimeoutException('Connecting to the VM Service timed out.'),
);
@ -83,7 +84,7 @@ class IntegrationTestTestDevice implements TestDevice {
await vmService.service.streamListen(vm_service.EventStreams.kExtension);
final Stream<String> remoteMessages = vmService.service.onExtensionEvent
.where((vm_service.Event e) => e.extensionKind == kIntegrationTestExtension)
.map((vm_service.Event e) => e.extensionData.data[kIntegrationTestData] as String);
.map((vm_service.Event e) => e.extensionData!.data[kIntegrationTestData] as String);
final StreamChannelController<String> controller = StreamChannelController<String>();
@ -113,11 +114,14 @@ class IntegrationTestTestDevice implements TestDevice {
@override
Future<void> kill() async {
if (!await device.stopApp(_applicationPackage, userIdentifier: userIdentifier)) {
globals.printTrace('Could not stop the Integration Test app.');
}
if (!await device.uninstallApp(_applicationPackage, userIdentifier: userIdentifier)) {
globals.printTrace('Could not uninstall the Integration Test app.');
final ApplicationPackage? applicationPackage = _applicationPackage;
if (applicationPackage != null) {
if (!await device.stopApp(applicationPackage, userIdentifier: userIdentifier)) {
globals.printTrace('Could not stop the Integration Test app.');
}
if (!await device.uninstallApp(applicationPackage, userIdentifier: userIdentifier)) {
globals.printTrace('Could not uninstall the Integration Test app.');
}
}
await device.dispose();

View file

@ -750,21 +750,6 @@ class FakeDevice extends Fake implements Device {
}
}
class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFactory {
FakeApplicationPackageFactory(this.applicationPackage);
ApplicationPackage applicationPackage;
@override
Future<ApplicationPackage> getPackageForPlatform(
TargetPlatform platform, {
BuildInfo buildInfo,
File applicationBinary,
}) async => applicationPackage;
}
class FakeApplicationPackage extends Fake implements ApplicationPackage { }
class TestRunCommandWithFakeResidentRunner extends RunCommand {
FakeResidentRunner fakeResidentRunner;

View file

@ -4,6 +4,8 @@
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/io.dart' as io;
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
@ -12,8 +14,10 @@ import 'package:flutter_tools/src/test/integration_test_device.dart';
import 'package:flutter_tools/src/test/test_device.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:test/fake.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import '../src/common.dart';
import '../src/context.dart';
import '../src/fake_devices.dart';
import '../src/fake_vm_services.dart';
@ -121,12 +125,26 @@ void main() {
]);
});
testUsingContext('will not start when package missing', () async {
await expectLater(
testDevice.start('entrypointPath'),
throwsA(
isA<TestDeviceException>().having(
(Exception e) => e.toString(),
'description',
contains('No application found for TargetPlatform.android_arm'),
),
),
);
});
testUsingContext('Can start the entrypoint', () async {
await testDevice.start('entrypointPath');
expect(await testDevice.observatoryUri, observatoryUri);
expect(testDevice.finished, doesNotComplete);
}, overrides: <Type, Generator>{
ApplicationPackageFactory: () => FakeApplicationPackageFactory(),
VMServiceConnector: () => (Uri httpUri, {
ReloadSources reloadSources,
Restart restart,
@ -145,6 +163,7 @@ void main() {
expect(testDevice.finished, completes);
}, overrides: <Type, Generator>{
ApplicationPackageFactory: () => FakeApplicationPackageFactory(),
VMServiceConnector: () => (Uri httpUri, {
ReloadSources reloadSources,
Restart restart,
@ -218,6 +237,7 @@ void main() {
await fakeVmServiceHost.vmService.dispose();
expect(await channel.stream.isEmpty, true);
}, overrides: <Type, Generator>{
ApplicationPackageFactory: () => FakeApplicationPackageFactory(),
VMServiceConnector: () => (Uri httpUri, {
ReloadSources reloadSources,
Restart restart,
@ -230,3 +250,14 @@ void main() {
}) async => fakeVmServiceHost.vmService,
});
}
class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFactory {
@override
Future<ApplicationPackage> getPackageForPlatform(
TargetPlatform platform, {
BuildInfo buildInfo,
File applicationBinary,
}) async => FakeApplicationPackage();
}
class FakeApplicationPackage extends Fake implements ApplicationPackage { }