Unverified Commit 1371b8dc authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] Fix null check errors in attach command (#107864)

parent 8dfad230
......@@ -215,7 +215,11 @@ known, it can be explicitly provided to attach via the command-line, e.g.
Future<FlutterCommandResult> runCommand() async {
await _validateArguments();
final Device device = await (findTargetDevice() as FutureOr<Device>);
final Device? device = await findTargetDevice();
if (device == null) {
throwToolExit('Did not find any valid target devices.');
}
final Artifacts? overrideArtifacts = device.artifactOverrides ?? globals.artifacts;
await context.run<void>(
......@@ -272,7 +276,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
} else if ((device is IOSDevice) || (device is IOSSimulator) || (device is MacOSDesignedForIPadDevice)) {
final Uri? uriFromMdns =
await MDnsObservatoryDiscovery.instance!.getObservatoryUri(
appId!,
appId,
device,
usesIpv6: usesIpv6,
deviceVmservicePort: deviceVmservicePort,
......@@ -317,12 +321,12 @@ known, it can be explicitly provided to attach via the command-line, e.g.
try {
int? result;
if (daemon != null) {
final ResidentRunner runner = await (createResidentRunner(
final ResidentRunner runner = await createResidentRunner(
observatoryUris: observatoryUri,
device: device,
flutterProject: flutterProject,
usesIpv6: usesIpv6,
) as FutureOr<ResidentRunner>);
);
late AppInstance app;
try {
app = await daemon.appDomain.launch(
......@@ -351,12 +355,12 @@ known, it can be explicitly provided to attach via the command-line, e.g.
return;
}
while (true) {
final ResidentRunner runner = await (createResidentRunner(
final ResidentRunner runner = await createResidentRunner(
observatoryUris: observatoryUri,
device: device,
flutterProject: flutterProject,
usesIpv6: usesIpv6,
) as FutureOr<ResidentRunner>);
);
final Completer<void> onAppStart = Completer<void>.sync();
TerminalHandler? terminalHandler;
unawaited(onAppStart.future.whenComplete(() {
......@@ -400,7 +404,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
}
}
Future<ResidentRunner?> createResidentRunner({
Future<ResidentRunner> createResidentRunner({
required Stream<Uri> observatoryUris,
required Device device,
required FlutterProject flutterProject,
......@@ -452,7 +456,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
}
class HotRunnerFactory {
HotRunner? build(
HotRunner build(
List<FlutterDevice> devices, {
required String target,
required DebuggingOptions debuggingOptions,
......
......@@ -145,7 +145,7 @@ class MDnsObservatoryDiscovery {
}
}
Future<Uri?> getObservatoryUri(String applicationId, Device device, {
Future<Uri?> getObservatoryUri(String? applicationId, Device device, {
bool usesIpv6 = false,
int? hostVmservicePort,
int? deviceVmservicePort,
......
......@@ -2,8 +2,6 @@
// 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:file/memory.dart';
......@@ -13,6 +11,7 @@ import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/dds.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart';
......@@ -24,11 +23,13 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/application_package.dart';
import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/macos/macos_ipad_device.dart';
import 'package:flutter_tools/src/mdns_discovery.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/run_hot.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:meta/meta.dart';
import 'package:multicast_dns/multicast_dns.dart';
import 'package:test/fake.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
......@@ -43,8 +44,8 @@ void main() {
});
group('attach', () {
StreamLogger logger;
FileSystem testFileSystem;
late StreamLogger logger;
late FileSystem testFileSystem;
setUp(() {
Cache.disableLocking();
......@@ -62,10 +63,10 @@ void main() {
const int devicePort = 499;
const int hostPort = 42;
FakeDeviceLogReader fakeLogReader;
RecordingPortForwarder portForwarder;
FakeDartDevelopmentService fakeDds;
FakeAndroidDevice device;
late FakeDeviceLogReader fakeLogReader;
late RecordingPortForwarder portForwarder;
late FakeDartDevelopmentService fakeDds;
late FakeAndroidDevice device;
setUp(() {
fakeLogReader = FakeDeviceLogReader();
......@@ -80,6 +81,45 @@ void main() {
fakeLogReader.dispose();
});
testUsingContext('succeeds with iOS device', () async {
final FakeIOSDevice device = FakeIOSDevice(
logReader: fakeLogReader,
portForwarder: portForwarder,
onGetLogReader: () {
fakeLogReader.addLine('Foo');
fakeLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:$devicePort');
return fakeLogReader;
},
);
testDeviceManager.addDevice(device);
final Completer<void> completer = Completer<void>();
final StreamSubscription<String> loggerSubscription = logger.stream.listen((String message) {
if (message == '[verbose] Observatory URL on device: http://127.0.0.1:$devicePort') {
// The "Observatory URL on device" message is output by the ProtocolDiscovery when it found the observatory.
completer.complete();
}
});
final Future<void> task = createTestCommandRunner(AttachCommand()).run(<String>['attach']);
await completer.future;
expect(portForwarder.devicePort, devicePort);
expect(portForwarder.hostPort, hostPort);
await fakeLogReader.dispose();
await expectLoggerInterruptEndsTask(task, logger);
await loggerSubscription.cancel();
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
ProcessManager: () => FakeProcessManager.any(),
Logger: () => logger,
MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(
mdnsClient: FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}),
logger: logger,
flutterUsage: TestUsage(),
),
});
testUsingContext('finds observatory port and forwards', () async {
device.onGetLogReader = () {
fakeLogReader.addLine('Foo');
......@@ -139,8 +179,8 @@ void main() {
final FakeHotRunner hotRunner = FakeHotRunner();
hotRunner.onAttach = (
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void>? appStartedCompleter,
bool allowExistingDdsInstance,
bool enableDevTools,
) async => 0;
......@@ -224,8 +264,8 @@ void main() {
group('forwarding to given port', () {
const int devicePort = 499;
const int hostPort = 42;
RecordingPortForwarder portForwarder;
FakeAndroidDevice device;
late RecordingPortForwarder portForwarder;
late FakeAndroidDevice device;
setUp(() {
final FakeDartDevelopmentService fakeDds = FakeDartDevelopmentService();
......@@ -408,8 +448,8 @@ void main() {
final FakeHotRunnerFactory hotRunnerFactory = FakeHotRunnerFactory()
..hotRunner = hotRunner;
hotRunner.onAttach = (
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void>? appStartedCompleter,
bool allowExistingDdsInstance,
bool enableDevTools,
) async {
......@@ -438,8 +478,8 @@ void main() {
..hotRunner = hotRunner;
hotRunner.onAttach = (
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void>? appStartedCompleter,
bool allowExistingDdsInstance,
bool enableDevTools,
) async {
......@@ -447,7 +487,6 @@ void main() {
throw vm_service.RPCError('flutter._listViews', RPCErrorCodes.kInvalidParams, '');
};
testDeviceManager.addDevice(device);
testFileSystem.file('lib/main.dart').createSync();
......@@ -463,7 +502,7 @@ void main() {
}
class FakeHotRunner extends Fake implements HotRunner {
Future<int> Function(Completer<DebugConnectionInfo>, Completer<void>, bool, bool) onAttach;
late Future<int> Function(Completer<DebugConnectionInfo>?, Completer<void>?, bool, bool) onAttach;
@override
bool exited = false;
......@@ -473,8 +512,8 @@ class FakeHotRunner extends Fake implements HotRunner {
@override
Future<int> attach({
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void>? appStartedCompleter,
bool allowExistingDdsInstance = false,
bool enableDevTools = false,
bool needsFullRestart = true,
......@@ -484,25 +523,25 @@ class FakeHotRunner extends Fake implements HotRunner {
}
class FakeHotRunnerFactory extends Fake implements HotRunnerFactory {
HotRunner hotRunner;
String dillOutputPath;
String projectRootPath;
List<FlutterDevice> devices;
late HotRunner hotRunner;
String? dillOutputPath;
String? projectRootPath;
late List<FlutterDevice> devices;
@override
HotRunner build(
List<FlutterDevice> devices, {
String target,
DebuggingOptions debuggingOptions,
required String target,
required DebuggingOptions debuggingOptions,
bool benchmarkMode = false,
File applicationBinary,
File? applicationBinary,
bool hostIsIde = false,
String projectRootPath,
String packagesFilePath,
String dillOutputPath,
String? projectRootPath,
String? packagesFilePath,
String? dillOutputPath,
bool stayResident = true,
bool ipv6 = false,
FlutterProject flutterProject,
FlutterProject? flutterProject,
}) {
this.devices = devices;
this.dillOutputPath = dillOutputPath;
......@@ -514,17 +553,17 @@ class FakeHotRunnerFactory extends Fake implements HotRunnerFactory {
class RecordingPortForwarder implements DevicePortForwarder {
RecordingPortForwarder([this.hostPort]);
int devicePort;
int hostPort;
int? devicePort;
int? hostPort;
@override
Future<void> dispose() async { }
@override
Future<int> forward(int devicePort, {int hostPort}) async {
Future<int> forward(int devicePort, {int? hostPort}) async {
this.devicePort = devicePort;
this.hostPort ??= hostPort;
return this.hostPort;
return this.hostPort!;
}
@override
......@@ -541,12 +580,12 @@ class StreamLogger extends Logger {
@override
void printError(
String message, {
StackTrace stackTrace,
bool emphasis,
TerminalColor color,
int indent,
int hangingIndent,
bool wrap,
StackTrace? stackTrace,
bool? emphasis,
TerminalColor? color,
int? indent,
int? hangingIndent,
bool? wrap,
}) {
hadErrorOutput = true;
_log('[stderr] $message');
......@@ -555,11 +594,11 @@ class StreamLogger extends Logger {
@override
void printWarning(
String message, {
bool emphasis,
TerminalColor color,
int indent,
int hangingIndent,
bool wrap,
bool? emphasis,
TerminalColor? color,
int? indent,
int? hangingIndent,
bool? wrap,
}) {
hadWarningOutput = true;
_log('[stderr] $message');
......@@ -568,12 +607,12 @@ class StreamLogger extends Logger {
@override
void printStatus(
String message, {
bool emphasis,
TerminalColor color,
bool newline,
int indent,
int hangingIndent,
bool wrap,
bool? emphasis,
TerminalColor? color,
bool? newline,
int? indent,
int? hangingIndent,
bool? wrap,
}) {
_log('[stdout] $message');
}
......@@ -581,7 +620,7 @@ class StreamLogger extends Logger {
@override
void printBox(
String message, {
String title,
String? title,
}) {
if (title == null) {
_log('[stdout] $message');
......@@ -598,8 +637,8 @@ class StreamLogger extends Logger {
@override
Status startProgress(
String message, {
@required Duration timeout,
String progressId,
Duration? timeout,
String? progressId,
bool multilineOutput = false,
bool includeTiming = true,
int progressIndicatorPadding = kDefaultStatusPadding,
......@@ -612,9 +651,9 @@ class StreamLogger extends Logger {
@override
Status startSpinner({
VoidCallback onFinish,
Duration timeout,
SlowWarningCallback slowWarningCallback,
VoidCallback? onFinish,
Duration? timeout,
SlowWarningCallback? slowWarningCallback,
}) {
return SilentStatus(
stopwatch: Stopwatch(),
......@@ -641,7 +680,7 @@ class StreamLogger extends Logger {
Stream<String> get stream => _controller.stream;
@override
void sendEvent(String name, [Map<String, dynamic> args]) { }
void sendEvent(String name, [Map<String, dynamic>? args]) { }
@override
bool get supportsColor => throw UnimplementedError();
......@@ -676,10 +715,10 @@ class FakeDartDevelopmentService extends Fake implements DartDevelopmentService
@override
Future<void> startDartDevelopmentService(
Uri observatoryUri, {
@required Logger logger,
int hostPort,
bool ipv6,
bool disableServiceAuthCodes,
required Logger logger,
int? hostPort,
bool? ipv6,
bool? disableServiceAuthCodes,
bool cacheStartupProfile = false,
}) async {}
......@@ -691,10 +730,10 @@ class FakeDartDevelopmentService extends Fake implements DartDevelopmentService
// Until we fix that, we have to also ignore related lints here.
// ignore: avoid_implementing_value_types
class FakeAndroidDevice extends Fake implements AndroidDevice {
FakeAndroidDevice({@required this.id});
FakeAndroidDevice({required this.id});
@override
DartDevelopmentService dds;
late DartDevelopmentService dds;
@override
final String id;
......@@ -727,20 +766,25 @@ class FakeAndroidDevice extends Fake implements AndroidDevice {
bool isSupportedForProject(FlutterProject flutterProject) => true;
@override
DevicePortForwarder portForwarder;
DevicePortForwarder? portForwarder;
DeviceLogReader Function() onGetLogReader;
DeviceLogReader Function()? onGetLogReader;
@override
FutureOr<DeviceLogReader> getLogReader({
AndroidApk app,
AndroidApk? app,
bool includePastLogs = false,
}) {
return onGetLogReader();
if (onGetLogReader == null) {
throw UnimplementedError(
'Called getLogReader but no onGetLogReader callback was supplied in the constructor to FakeAndroidDevice.',
);
}
return onGetLogReader!();
}
@override
OverrideArtifacts get artifactOverrides => null;
OverrideArtifacts? get artifactOverrides => null;
@override
final PlatformType platformType = PlatformType.android;
......@@ -753,24 +797,40 @@ class FakeAndroidDevice extends Fake implements AndroidDevice {
// Until we fix that, we have to also ignore related lints here.
// ignore: avoid_implementing_value_types
class FakeIOSDevice extends Fake implements IOSDevice {
FakeIOSDevice({this.dds, this.portForwarder, this.logReader});
FakeIOSDevice({
DevicePortForwarder? portForwarder,
DeviceLogReader? logReader,
this.onGetLogReader,
}) : _portForwarder = portForwarder, _logReader = logReader;
final DevicePortForwarder? _portForwarder;
@override
final DevicePortForwarder portForwarder;
DevicePortForwarder get portForwarder => _portForwarder!;
@override
final DartDevelopmentService dds;
DartDevelopmentService get dds => throw UnimplementedError('getter dds not implemented');
final DeviceLogReader? _logReader;
DeviceLogReader get logReader => _logReader!;
final DeviceLogReader logReader;
final DeviceLogReader Function()? onGetLogReader;
@override
DeviceLogReader getLogReader({
IOSApp app,
IOSApp? app,
bool includePastLogs = false,
}) => logReader;
}) {
if (onGetLogReader == null) {
throw UnimplementedError(
'Called getLogReader but no onGetLogReader callback was supplied in the constructor to FakeIOSDevice',
);
}
return onGetLogReader!();
}
@override
OverrideArtifacts get artifactOverrides => null;
OverrideArtifacts? get artifactOverrides => null;
@override
final String name = 'name';
......@@ -781,3 +841,49 @@ class FakeIOSDevice extends Fake implements IOSDevice {
@override
final PlatformType platformType = PlatformType.ios;
}
class FakeMDnsClient extends Fake implements MDnsClient {
FakeMDnsClient(this.ptrRecords, this.srvResponse, {
this.txtResponse = const <String, List<TxtResourceRecord>>{},
this.osErrorOnStart = false,
});
final List<PtrResourceRecord> ptrRecords;
final Map<String, List<SrvResourceRecord>> srvResponse;
final Map<String, List<TxtResourceRecord>> txtResponse;
final bool osErrorOnStart;
@override
Future<void> start({
InternetAddress? listenAddress,
NetworkInterfacesFactory? interfacesFactory,
int mDnsPort = 5353,
InternetAddress? mDnsAddress,
}) async {
if (osErrorOnStart) {
throw const OSError('Operation not supported on socket', 102);
}
}
@override
Stream<T> lookup<T extends ResourceRecord>(
ResourceRecordQuery query, {
Duration timeout = const Duration(seconds: 5),
}) {
if (T == PtrResourceRecord && query.fullyQualifiedName == MDnsObservatoryDiscovery.dartObservatoryName) {
return Stream<PtrResourceRecord>.fromIterable(ptrRecords) as Stream<T>;
}
if (T == SrvResourceRecord) {
final String key = query.fullyQualifiedName;
return Stream<SrvResourceRecord>.fromIterable(srvResponse[key] ?? <SrvResourceRecord>[]) as Stream<T>;
}
if (T == TxtResourceRecord) {
final String key = query.fullyQualifiedName;
return Stream<TxtResourceRecord>.fromIterable(txtResponse[key] ?? <TxtResourceRecord>[]) as Stream<T>;
}
throw UnsupportedError('Unsupported query type $T');
}
@override
void stop() {}
}
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