Unverified Commit a204f038 authored by Dan Field's avatar Dan Field Committed by GitHub

Null safe migration for fuchsia_remote_debug_protocol (#74762)

parent d546e1d3
...@@ -10,14 +10,13 @@ import 'package:vm_service/vm_service.dart' as vms; ...@@ -10,14 +10,13 @@ import 'package:vm_service/vm_service.dart' as vms;
import '../common/logging.dart'; import '../common/logging.dart';
const Duration _kConnectTimeout = Duration(seconds: 3); const Duration _kConnectTimeout = Duration(seconds: 3);
const Duration _kRpcTimeout = Duration(seconds: 5);
final Logger _log = Logger('DartVm'); final Logger _log = Logger('DartVm');
/// Signature of an asynchronous function for establishing a [vms.VmService] /// Signature of an asynchronous function for establishing a [vms.VmService]
/// connection to a [Uri]. /// connection to a [Uri].
typedef RpcPeerConnectionFunction = Future<vms.VmService> Function( typedef RpcPeerConnectionFunction = Future<vms.VmService> Function(
Uri uri, { Uri uri, {
Duration timeout, required Duration timeout,
}); });
/// [DartVm] uses this function to connect to the Dart VM on Fuchsia. /// [DartVm] uses this function to connect to the Dart VM on Fuchsia.
...@@ -34,7 +33,7 @@ Future<vms.VmService> _waitAndConnect( ...@@ -34,7 +33,7 @@ Future<vms.VmService> _waitAndConnect(
Duration timeout = _kConnectTimeout, Duration timeout = _kConnectTimeout,
}) async { }) async {
int attempts = 0; int attempts = 0;
WebSocket socket; late WebSocket socket;
while (true) { while (true) {
try { try {
socket = await WebSocket.connect(uri.toString()); socket = await WebSocket.connect(uri.toString());
...@@ -56,7 +55,7 @@ Future<vms.VmService> _waitAndConnect( ...@@ -56,7 +55,7 @@ Future<vms.VmService> _waitAndConnect(
await service.getVersion(); await service.getVersion();
return service; return service;
} catch (e) { } catch (e) {
await socket?.close(); await socket.close();
if (attempts > 5) { if (attempts > 5) {
_log.warning('It is taking an unusually long time to connect to the VM...'); _log.warning('It is taking an unusually long time to connect to the VM...');
} }
...@@ -112,9 +111,6 @@ class DartVm { ...@@ -112,9 +111,6 @@ class DartVm {
} }
final vms.VmService service = await fuchsiaVmServiceConnectionFunction(uri, timeout: timeout); final vms.VmService service = await fuchsiaVmServiceConnectionFunction(uri, timeout: timeout);
if (service == null) {
return null;
}
return DartVm._(service, uri); return DartVm._(service, uri);
} }
...@@ -123,16 +119,13 @@ class DartVm { ...@@ -123,16 +119,13 @@ class DartVm {
/// This is not limited to Isolates running Flutter, but to any Isolate on the /// This is not limited to Isolates running Flutter, but to any Isolate on the
/// VM. Therefore, the [pattern] argument should be written to exclude /// VM. Therefore, the [pattern] argument should be written to exclude
/// matching unintended isolates. /// matching unintended isolates.
Future<List<IsolateRef>> getMainIsolatesByPattern( Future<List<IsolateRef>> getMainIsolatesByPattern(Pattern pattern) async {
Pattern pattern, {
Duration timeout = _kRpcTimeout,
}) async {
final vms.VM vmRef = await _vmService.getVM(); final vms.VM vmRef = await _vmService.getVM();
final List<IsolateRef> result = <IsolateRef>[]; final List<IsolateRef> result = <IsolateRef>[];
for (final vms.IsolateRef isolateRef in vmRef.isolates) { for (final vms.IsolateRef isolateRef in vmRef.isolates!) {
if (pattern.matchAsPrefix(isolateRef.name) != null) { if (pattern.matchAsPrefix(isolateRef.name!) != null) {
_log.fine('Found Isolate matching "$pattern": "${isolateRef.name}"'); _log.fine('Found Isolate matching "$pattern": "${isolateRef.name}"');
result.add(IsolateRef._fromJson(isolateRef.json, this)); result.add(IsolateRef._fromJson(isolateRef.json!, this));
} }
} }
return result; return result;
...@@ -145,16 +138,11 @@ class DartVm { ...@@ -145,16 +138,11 @@ class DartVm {
/// the flutter view's name), then the flutter view's ID will be added /// the flutter view's name), then the flutter view's ID will be added
/// instead. If none of these things can be found (isolate has no name or the /// instead. If none of these things can be found (isolate has no name or the
/// flutter view has no ID), then the result will not be added to the list. /// flutter view has no ID), then the result will not be added to the list.
Future<List<FlutterView>> getAllFlutterViews({ Future<List<FlutterView>> getAllFlutterViews() async {
Duration timeout = _kRpcTimeout,
}) async {
final List<FlutterView> views = <FlutterView>[]; final List<FlutterView> views = <FlutterView>[];
final vms.Response rpcResponse = await _vmService.callMethod('_flutter.listViews'); final vms.Response rpcResponse = await _vmService.callMethod('_flutter.listViews');
for (final Map<String, dynamic> jsonView in (rpcResponse.json['views'] as List<dynamic>).cast<Map<String, dynamic>>()) { for (final Map<String, dynamic> jsonView in (rpcResponse.json!['views'] as List<dynamic>).cast<Map<String, dynamic>>()) {
final FlutterView flutterView = FlutterView._fromJson(jsonView); views.add(FlutterView._fromJson(jsonView));
if (flutterView != null) {
views.add(flutterView);
}
} }
return views; return views;
} }
...@@ -190,25 +178,25 @@ class FlutterView { ...@@ -190,25 +178,25 @@ class FlutterView {
/// All other cases return a [FlutterView] instance. The name of the /// All other cases return a [FlutterView] instance. The name of the
/// view may be null, but the id will always be set. /// view may be null, but the id will always be set.
factory FlutterView._fromJson(Map<String, dynamic> json) { factory FlutterView._fromJson(Map<String, dynamic> json) {
final Map<String, dynamic> isolate = json['isolate'] as Map<String, dynamic>; final Map<String, dynamic>? isolate = json['isolate'] as Map<String, dynamic>?;
final String id = json['id'] as String; final String? id = json['id'] as String?;
String name; String? name;
if (id == null) {
throw RpcFormatError(
'Unable to find view name for the following JSON structure "$json"');
}
if (isolate != null) { if (isolate != null) {
name = isolate['name'] as String; name = isolate['name'] as String?;
if (name == null) { if (name == null) {
throw RpcFormatError('Unable to find name for isolate "$isolate"'); throw RpcFormatError('Unable to find name for isolate "$isolate"');
} }
} }
if (id == null) {
throw RpcFormatError(
'Unable to find view name for the following JSON structure "$json"');
}
return FlutterView._(name, id); return FlutterView._(name, id);
} }
/// Determines the name of the isolate associated with this view. If there is /// Determines the name of the isolate associated with this view. If there is
/// no associated isolate, this will be set to the view's ID. /// no associated isolate, this will be set to the view's ID.
final String _name; final String? _name;
/// The ID of the Flutter view. /// The ID of the Flutter view.
final String _id; final String _id;
...@@ -219,7 +207,7 @@ class FlutterView { ...@@ -219,7 +207,7 @@ class FlutterView {
/// Returns the name of the [FlutterView]. /// Returns the name of the [FlutterView].
/// ///
/// May be null if there is no associated isolate. /// May be null if there is no associated isolate.
String get name => _name; String? get name => _name;
} }
/// This is a wrapper class for the `@Isolate` RPC object. /// This is a wrapper class for the `@Isolate` RPC object.
...@@ -233,9 +221,9 @@ class IsolateRef { ...@@ -233,9 +221,9 @@ class IsolateRef {
IsolateRef._(this.name, this.number, this.dartVm); IsolateRef._(this.name, this.number, this.dartVm);
factory IsolateRef._fromJson(Map<String, dynamic> json, DartVm dartVm) { factory IsolateRef._fromJson(Map<String, dynamic> json, DartVm dartVm) {
final String number = json['number'] as String; final String? number = json['number'] as String?;
final String name = json['name'] as String; final String? name = json['name'] as String?;
final String type = json['type'] as String; final String? type = json['type'] as String?;
if (type == null) { if (type == null) {
throw RpcFormatError('Unable to find type within JSON "$json"'); throw RpcFormatError('Unable to find type within JSON "$json"');
} }
......
...@@ -34,8 +34,8 @@ final Logger _log = Logger('FuchsiaRemoteConnection'); ...@@ -34,8 +34,8 @@ final Logger _log = Logger('FuchsiaRemoteConnection');
typedef PortForwardingFunction = Future<PortForwarder> Function( typedef PortForwardingFunction = Future<PortForwarder> Function(
String address, String address,
int remotePort, [ int remotePort, [
String interface, String? interface,
String configFile, String? configFile,
]); ]);
/// The function for forwarding the local machine's ports to a remote Fuchsia /// The function for forwarding the local machine's ports to a remote Fuchsia
...@@ -83,7 +83,7 @@ enum DartVmEventType { ...@@ -83,7 +83,7 @@ enum DartVmEventType {
/// Specifies the type of the event (whether the VM has started or has stopped), /// Specifies the type of the event (whether the VM has started or has stopped),
/// and contains the service port of the VM as well as a URL to connect to it. /// and contains the service port of the VM as well as a URL to connect to it.
class DartVmEvent { class DartVmEvent {
DartVmEvent._({this.eventType, this.servicePort, this.uri}); DartVmEvent._({required this.eventType, required this.servicePort, required this.uri});
/// The URL used to connect to the Dart VM. /// The URL used to connect to the Dart VM.
final Uri uri; final Uri uri;
...@@ -121,13 +121,13 @@ class FuchsiaRemoteConnection { ...@@ -121,13 +121,13 @@ class FuchsiaRemoteConnection {
/// A broadcast stream that emits events relating to Dart VM's as they update. /// A broadcast stream that emits events relating to Dart VM's as they update.
Stream<DartVmEvent> get onDartVmEvent => _onDartVmEvent; Stream<DartVmEvent> get onDartVmEvent => _onDartVmEvent;
Stream<DartVmEvent> _onDartVmEvent; late Stream<DartVmEvent> _onDartVmEvent;
final StreamController<DartVmEvent> _dartVmEventController = final StreamController<DartVmEvent> _dartVmEventController =
StreamController<DartVmEvent>(); StreamController<DartVmEvent>();
/// VM service cache to avoid repeating handshakes across function /// VM service cache to avoid repeating handshakes across function
/// calls. Keys a URI to a DartVm connection instance. /// calls. Keys a URI to a DartVm connection instance.
final Map<Uri, DartVm> _dartVmCache = <Uri, DartVm>{}; final Map<Uri, DartVm?> _dartVmCache = <Uri, DartVm?>{};
/// Same as [FuchsiaRemoteConnection.connect] albeit with a provided /// Same as [FuchsiaRemoteConnection.connect] albeit with a provided
/// [SshCommandRunner] instance. /// [SshCommandRunner] instance.
...@@ -188,9 +188,9 @@ class FuchsiaRemoteConnection { ...@@ -188,9 +188,9 @@ class FuchsiaRemoteConnection {
/// In the event that `FUCHSIA_SSH_CONFIG` is set in the environment, that /// In the event that `FUCHSIA_SSH_CONFIG` is set in the environment, that
/// will be used when `sshConfigPath` isn't supplied. /// will be used when `sshConfigPath` isn't supplied.
static Future<FuchsiaRemoteConnection> connect([ static Future<FuchsiaRemoteConnection> connect([
String address, String? address,
String interface = '', String interface = '',
String sshConfigPath, String? sshConfigPath,
]) async { ]) async {
address ??= Platform.environment['FUCHSIA_DEVICE_URL']; address ??= Platform.environment['FUCHSIA_DEVICE_URL'];
sshConfigPath ??= Platform.environment['FUCHSIA_SSH_CONFIG']; sshConfigPath ??= Platform.environment['FUCHSIA_SSH_CONFIG'];
...@@ -210,7 +210,7 @@ class FuchsiaRemoteConnection { ...@@ -210,7 +210,7 @@ class FuchsiaRemoteConnection {
SshCommandRunner( SshCommandRunner(
address: address, address: address,
interface: interface, interface: interface,
sshConfigPath: sshConfigPath, sshConfigPath: sshConfigPath!,
), ),
); );
} }
...@@ -225,14 +225,14 @@ class FuchsiaRemoteConnection { ...@@ -225,14 +225,14 @@ class FuchsiaRemoteConnection {
// Closes VM service first to ensure that the connection is closed cleanly // Closes VM service first to ensure that the connection is closed cleanly
// on the target before shutting down the forwarding itself. // on the target before shutting down the forwarding itself.
final Uri uri = _getDartVmUri(pf); final Uri uri = _getDartVmUri(pf);
final DartVm vmService = _dartVmCache[uri]; final DartVm? vmService = _dartVmCache[uri];
_dartVmCache[uri] = null; _dartVmCache[uri] = null;
await vmService?.stop(); await vmService?.stop();
await pf.stop(); await pf.stop();
} }
for (final PortForwarder pf in _dartVmPortMap.values) { for (final PortForwarder pf in _dartVmPortMap.values) {
final Uri uri = _getDartVmUri(pf); final Uri uri = _getDartVmUri(pf);
final DartVm vmService = _dartVmCache[uri]; final DartVm? vmService = _dartVmCache[uri];
_dartVmCache[uri] = null; _dartVmCache[uri] = null;
await vmService?.stop(); await vmService?.stop();
await pf.stop(); await pf.stop();
...@@ -250,7 +250,7 @@ class FuchsiaRemoteConnection { ...@@ -250,7 +250,7 @@ class FuchsiaRemoteConnection {
/// (possible when the Isolate we're attempting to connect to is in the only /// (possible when the Isolate we're attempting to connect to is in the only
/// instance of the Dart VM and its service port has not yet opened). /// instance of the Dart VM and its service port has not yet opened).
Future<List<IsolateRef>> _waitForMainIsolatesByPattern([ Future<List<IsolateRef>> _waitForMainIsolatesByPattern([
Pattern pattern, Pattern? pattern,
Duration timeout = _kIsolateFindTimeout, Duration timeout = _kIsolateFindTimeout,
Duration vmConnectionTimeout = _kDartVmConnectionTimeout, Duration vmConnectionTimeout = _kDartVmConnectionTimeout,
]) async { ]) async {
...@@ -260,12 +260,10 @@ class FuchsiaRemoteConnection { ...@@ -260,12 +260,10 @@ class FuchsiaRemoteConnection {
if (event.eventType == DartVmEventType.started) { if (event.eventType == DartVmEventType.started) {
_log.fine('New VM found on port: ${event.servicePort}. Searching ' _log.fine('New VM found on port: ${event.servicePort}. Searching '
'for Isolate: $pattern'); 'for Isolate: $pattern');
final DartVm vmService = await _getDartVm(event.uri, final DartVm? vmService = await _getDartVm(event.uri,
timeout: _kDartVmConnectionTimeout); timeout: _kDartVmConnectionTimeout);
// If the VM service is null, set the result to the empty list. // If the VM service is null, set the result to the empty list.
final List<IsolateRef> result = await vmService final List<IsolateRef> result = await vmService?.getMainIsolatesByPattern(pattern!) ?? <IsolateRef>[];
?.getMainIsolatesByPattern(pattern, timeout: timeout) ??
<IsolateRef>[];
if (result.isNotEmpty) { if (result.isNotEmpty) {
if (!completer.isCompleted) { if (!completer.isCompleted) {
completer.complete(result); completer.complete(result);
...@@ -308,7 +306,7 @@ class FuchsiaRemoteConnection { ...@@ -308,7 +306,7 @@ class FuchsiaRemoteConnection {
final List<Future<List<IsolateRef>>> isolates = final List<Future<List<IsolateRef>>> isolates =
<Future<List<IsolateRef>>>[]; <Future<List<IsolateRef>>>[];
for (final PortForwarder fp in _dartVmPortMap.values) { for (final PortForwarder fp in _dartVmPortMap.values) {
final DartVm vmService = final DartVm? vmService =
await _getDartVm(_getDartVmUri(fp), timeout: vmConnectionTimeout); await _getDartVm(_getDartVmUri(fp), timeout: vmConnectionTimeout);
if (vmService == null) { if (vmService == null) {
continue; continue;
...@@ -393,7 +391,7 @@ class FuchsiaRemoteConnection { ...@@ -393,7 +391,7 @@ class FuchsiaRemoteConnection {
} }
for (final PortForwarder pf in _dartVmPortMap.values) { for (final PortForwarder pf in _dartVmPortMap.values) {
final DartVm service = await _getDartVm(_getDartVmUri(pf)); final DartVm? service = await _getDartVm(_getDartVmUri(pf));
if (service == null) { if (service == null) {
await shutDownPortForwarder(pf); await shutDownPortForwarder(pf);
} else { } else {
...@@ -405,11 +403,11 @@ class FuchsiaRemoteConnection { ...@@ -405,11 +403,11 @@ class FuchsiaRemoteConnection {
} }
Uri _getDartVmUri(PortForwarder pf) { Uri _getDartVmUri(PortForwarder pf) {
String addr; String? addr;
if (pf.openPortAddress == null) { if (pf.openPortAddress == null) {
addr = _useIpV6 ? '[$_ipv6Loopback]' : _ipv4Loopback; addr = _useIpV6 ? '[$_ipv6Loopback]' : _ipv4Loopback;
} else { } else {
addr = isIpV6Address(pf.openPortAddress) addr = isIpV6Address(pf.openPortAddress!)
? '[${pf.openPortAddress}]' ? '[${pf.openPortAddress}]'
: pf.openPortAddress; : pf.openPortAddress;
} }
...@@ -421,7 +419,7 @@ class FuchsiaRemoteConnection { ...@@ -421,7 +419,7 @@ class FuchsiaRemoteConnection {
/// ///
/// Returns null if either there is an [HttpException] or a /// Returns null if either there is an [HttpException] or a
/// [TimeoutException], else a [DartVm] instance. /// [TimeoutException], else a [DartVm] instance.
Future<DartVm> _getDartVm( Future<DartVm?> _getDartVm(
Uri uri, { Uri uri, {
Duration timeout = _kDartVmConnectionTimeout, Duration timeout = _kDartVmConnectionTimeout,
}) async { }) async {
...@@ -462,7 +460,7 @@ class FuchsiaRemoteConnection { ...@@ -462,7 +460,7 @@ class FuchsiaRemoteConnection {
_dartVmEventController.add(DartVmEvent._( _dartVmEventController.add(DartVmEvent._(
eventType: DartVmEventType.started, eventType: DartVmEventType.started,
servicePort: servicePort, servicePort: servicePort,
uri: _getDartVmUri(_dartVmPortMap[servicePort]), uri: _getDartVmUri(_dartVmPortMap[servicePort]!),
)); ));
} }
} }
...@@ -488,9 +486,9 @@ class FuchsiaRemoteConnection { ...@@ -488,9 +486,9 @@ class FuchsiaRemoteConnection {
Future<void> _forwardOpenPortsToDeviceServicePorts() async { Future<void> _forwardOpenPortsToDeviceServicePorts() async {
await stop(); await stop();
final List<int> servicePorts = await getDeviceServicePorts(); final List<int> servicePorts = await getDeviceServicePorts();
final List<PortForwarder> forwardedVmServicePorts = final List<PortForwarder?> forwardedVmServicePorts =
await Future.wait<PortForwarder>( await Future.wait<PortForwarder?>(
servicePorts.map<Future<PortForwarder>>((int deviceServicePort) { servicePorts.map<Future<PortForwarder?>>((int deviceServicePort) {
return fuchsiaPortForwardingFunction( return fuchsiaPortForwardingFunction(
_sshCommandRunner.address, _sshCommandRunner.address,
deviceServicePort, deviceServicePort,
...@@ -498,9 +496,9 @@ class FuchsiaRemoteConnection { ...@@ -498,9 +496,9 @@ class FuchsiaRemoteConnection {
_sshCommandRunner.sshConfigPath); _sshCommandRunner.sshConfigPath);
})); }));
for (final PortForwarder pf in forwardedVmServicePorts) { for (final PortForwarder? pf in forwardedVmServicePorts) {
// TODO(awdavies): Handle duplicates. // TODO(awdavies): Handle duplicates.
_dartVmPortMap[pf.remotePort] = pf; _dartVmPortMap[pf!.remotePort] = pf;
} }
// Don't queue events, since this is the initial forwarding. // Don't queue events, since this is the initial forwarding.
...@@ -530,7 +528,7 @@ class FuchsiaRemoteConnection { ...@@ -530,7 +528,7 @@ class FuchsiaRemoteConnection {
if (line == '') { if (line == '') {
continue; continue;
} }
final int port = int.tryParse(line); final int? port = int.tryParse(line);
if (port != null) { if (port != null) {
ports.add(port); ports.add(port);
} }
...@@ -552,7 +550,7 @@ abstract class PortForwarder { ...@@ -552,7 +550,7 @@ abstract class PortForwarder {
/// The address on which the open port is accessible. Defaults to null to /// The address on which the open port is accessible. Defaults to null to
/// indicate local loopback. /// indicate local loopback.
String get openPortAddress => null; String? get openPortAddress => null;
/// The destination port on the other end of the port forwarding tunnel. /// The destination port on the other end of the port forwarding tunnel.
int get remotePort; int get remotePort;
...@@ -577,8 +575,8 @@ class _SshPortForwarder implements PortForwarder { ...@@ -577,8 +575,8 @@ class _SshPortForwarder implements PortForwarder {
final String _remoteAddress; final String _remoteAddress;
final int _remotePort; final int _remotePort;
final ServerSocket _localSocket; final ServerSocket _localSocket;
final String _sshConfigPath; final String? _sshConfigPath;
final String _interface; final String? _interface;
final bool _ipV6; final bool _ipV6;
@override @override
...@@ -595,15 +593,15 @@ class _SshPortForwarder implements PortForwarder { ...@@ -595,15 +593,15 @@ class _SshPortForwarder implements PortForwarder {
static Future<_SshPortForwarder> start( static Future<_SshPortForwarder> start(
String address, String address,
int remotePort, [ int remotePort, [
String interface, String? interface,
String sshConfigPath, String? sshConfigPath,
]) async { ]) async {
final bool isIpV6 = isIpV6Address(address); final bool isIpV6 = isIpV6Address(address);
final ServerSocket localSocket = await _createLocalSocket(); final ServerSocket? localSocket = await _createLocalSocket();
if (localSocket == null || localSocket.port == 0) { if (localSocket == null || localSocket.port == 0) {
_log.warning('_SshPortForwarder failed to find a local port for ' _log.warning('_SshPortForwarder failed to find a local port for '
'$address:$remotePort'); '$address:$remotePort');
return null; throw StateError('Unable to create a socket or no available ports.');
} }
// TODO(awdavies): The square-bracket enclosure for using the IPv6 loopback // TODO(awdavies): The square-bracket enclosure for using the IPv6 loopback
// didn't appear to work, but when assigning to the IPv4 loopback device, // didn't appear to work, but when assigning to the IPv4 loopback device,
...@@ -614,7 +612,7 @@ class _SshPortForwarder implements PortForwarder { ...@@ -614,7 +612,7 @@ class _SshPortForwarder implements PortForwarder {
final String formattedForwardingUrl = final String formattedForwardingUrl =
'${localSocket.port}:$_ipv4Loopback:$remotePort'; '${localSocket.port}:$_ipv4Loopback:$remotePort';
final String targetAddress = final String targetAddress =
isIpV6 && interface.isNotEmpty ? '$address%$interface' : address; isIpV6 && interface!.isNotEmpty ? '$address%$interface' : address;
const String dummyRemoteCommand = 'true'; const String dummyRemoteCommand = 'true';
final List<String> command = <String>[ final List<String> command = <String>[
'ssh', 'ssh',
...@@ -636,7 +634,7 @@ class _SshPortForwarder implements PortForwarder { ...@@ -636,7 +634,7 @@ class _SshPortForwarder implements PortForwarder {
_log.fine("'${command.join(' ')}' exited with exit code " _log.fine("'${command.join(' ')}' exited with exit code "
'${processResult.exitCode}'); '${processResult.exitCode}');
if (processResult.exitCode != 0) { if (processResult.exitCode != 0) {
return null; throw StateError('Unable to start port forwarding');
} }
final _SshPortForwarder result = _SshPortForwarder._( final _SshPortForwarder result = _SshPortForwarder._(
address, remotePort, localSocket, interface, sshConfigPath, isIpV6); address, remotePort, localSocket, interface, sshConfigPath, isIpV6);
...@@ -653,13 +651,13 @@ class _SshPortForwarder implements PortForwarder { ...@@ -653,13 +651,13 @@ class _SshPortForwarder implements PortForwarder {
// uses the IPv4 loopback. // uses the IPv4 loopback.
final String formattedForwardingUrl = final String formattedForwardingUrl =
'${_localSocket.port}:$_ipv4Loopback:$_remotePort'; '${_localSocket.port}:$_ipv4Loopback:$_remotePort';
final String targetAddress = _ipV6 && _interface.isNotEmpty final String targetAddress = _ipV6 && _interface!.isNotEmpty
? '$_remoteAddress%$_interface' ? '$_remoteAddress%$_interface'
: _remoteAddress; : _remoteAddress;
final List<String> command = <String>[ final List<String?> command = <String?>[
'ssh', 'ssh',
if (_sshConfigPath != null) if (_sshConfigPath != null)
...<String>['-F', _sshConfigPath], ...<String?>['-F', _sshConfigPath],
'-O', '-O',
'cancel', 'cancel',
'-L', '-L',
...@@ -680,7 +678,7 @@ class _SshPortForwarder implements PortForwarder { ...@@ -680,7 +678,7 @@ class _SshPortForwarder implements PortForwarder {
/// ///
/// If successful returns a valid [ServerSocket] (which must be disconnected /// If successful returns a valid [ServerSocket] (which must be disconnected
/// later). /// later).
static Future<ServerSocket> _createLocalSocket() async { static Future<ServerSocket?> _createLocalSocket() async {
ServerSocket s; ServerSocket s;
try { try {
s = await ServerSocket.bind(_ipv4Loopback, 0); s = await ServerSocket.bind(_ipv4Loopback, 0);
......
...@@ -44,7 +44,7 @@ class SshCommandRunner { ...@@ -44,7 +44,7 @@ class SshCommandRunner {
/// IPv4 nor IPv6. When connecting to a link local address (`fe80::` is /// IPv4 nor IPv6. When connecting to a link local address (`fe80::` is
/// usually at the start of the address), an interface should be supplied. /// usually at the start of the address), an interface should be supplied.
SshCommandRunner({ SshCommandRunner({
this.address, required this.address,
this.interface = '', this.interface = '',
this.sshConfigPath, this.sshConfigPath,
}) : _processManager = const LocalProcessManager() { }) : _processManager = const LocalProcessManager() {
...@@ -55,7 +55,7 @@ class SshCommandRunner { ...@@ -55,7 +55,7 @@ class SshCommandRunner {
@visibleForTesting @visibleForTesting
SshCommandRunner.withProcessManager( SshCommandRunner.withProcessManager(
this._processManager, { this._processManager, {
this.address, required this.address,
this.interface = '', this.interface = '',
this.sshConfigPath, this.sshConfigPath,
}) { }) {
...@@ -70,7 +70,7 @@ class SshCommandRunner { ...@@ -70,7 +70,7 @@ class SshCommandRunner {
final String address; final String address;
/// The path to the SSH config (optional). /// The path to the SSH config (optional).
final String sshConfigPath; final String? sshConfigPath;
/// The name of the machine's network interface (for use with IPv6 /// The name of the machine's network interface (for use with IPv6
/// connections. Ignored otherwise). /// connections. Ignored otherwise).
...@@ -84,7 +84,7 @@ class SshCommandRunner { ...@@ -84,7 +84,7 @@ class SshCommandRunner {
final List<String> args = <String>[ final List<String> args = <String>[
'ssh', 'ssh',
if (sshConfigPath != null) if (sshConfigPath != null)
...<String>['-F', sshConfigPath], ...<String>['-F', sshConfigPath!],
if (isIpV6Address(address)) if (isIpV6Address(address))
...<String>['-6', if (interface.isEmpty) address else '$address%$interface'] ...<String>['-6', if (interface.isEmpty) address else '$address%$interface']
else else
......
...@@ -5,7 +5,7 @@ homepage: http://flutter.dev ...@@ -5,7 +5,7 @@ homepage: http://flutter.dev
author: Flutter Authors <flutter-dev@googlegroups.com> author: Flutter Authors <flutter-dev@googlegroups.com>
environment: environment:
sdk: ">=2.2.2 <3.0.0" sdk: '>=2.12.0-0 <3.0.0'
dependencies: dependencies:
process: 4.0.0-nullsafety.4 process: 4.0.0-nullsafety.4
......
...@@ -11,9 +11,9 @@ import 'common.dart'; ...@@ -11,9 +11,9 @@ import 'common.dart';
void main() { void main() {
group('FuchsiaRemoteConnection.connect', () { group('FuchsiaRemoteConnection.connect', () {
List<FakePortForwarder> forwardedPorts; late List<FakePortForwarder> forwardedPorts;
List<FakeVmService> fakeVmServices; List<FakeVmService> fakeVmServices;
List<Uri> uriConnections; late List<Uri> uriConnections;
setUp(() { setUp(() {
final List<Map<String, dynamic>> flutterViewCannedResponses = final List<Map<String, dynamic>> flutterViewCannedResponses =
...@@ -63,7 +63,7 @@ void main() { ...@@ -63,7 +63,7 @@ void main() {
uriConnections = <Uri>[]; uriConnections = <Uri>[];
Future<vms.VmService> fakeVmConnectionFunction( Future<vms.VmService> fakeVmConnectionFunction(
Uri uri, { Uri uri, {
Duration timeout, Duration? timeout,
}) { }) {
return Future<vms.VmService>(() async { return Future<vms.VmService>(() async {
final FakeVmService service = FakeVmService(); final FakeVmService service = FakeVmService();
...@@ -89,8 +89,8 @@ void main() { ...@@ -89,8 +89,8 @@ void main() {
Future<PortForwarder> fakePortForwardingFunction( Future<PortForwarder> fakePortForwardingFunction(
String address, String address,
int remotePort, [ int remotePort, [
String interface = '', String? interface = '',
String configFile, String? configFile,
]) { ]) {
return Future<PortForwarder>(() { return Future<PortForwarder>(() {
final FakePortForwarder pf = FakePortForwarder(); final FakePortForwarder pf = FakePortForwarder();
...@@ -156,8 +156,8 @@ void main() { ...@@ -156,8 +156,8 @@ void main() {
Future<PortForwarder> fakePortForwardingFunction( Future<PortForwarder> fakePortForwardingFunction(
String address, String address,
int remotePort, [ int remotePort, [
String interface = '', String? interface = '',
String configFile, String? configFile,
]) { ]) {
return Future<PortForwarder>(() { return Future<PortForwarder>(() {
final FakePortForwarder pf = FakePortForwarder(); final FakePortForwarder pf = FakePortForwarder();
...@@ -223,8 +223,8 @@ void main() { ...@@ -223,8 +223,8 @@ void main() {
Future<PortForwarder> fakePortForwardingFunction( Future<PortForwarder> fakePortForwardingFunction(
String address, String address,
int remotePort, [ int remotePort, [
String interface = '', String? interface = '',
String configFile, String? configFile,
]) { ]) {
return Future<PortForwarder>(() { return Future<PortForwarder>(() {
final FakePortForwarder pf = FakePortForwarder(); final FakePortForwarder pf = FakePortForwarder();
...@@ -296,24 +296,24 @@ void main() { ...@@ -296,24 +296,24 @@ void main() {
} }
class FakeSshCommandRunner extends Fake implements SshCommandRunner { class FakeSshCommandRunner extends Fake implements SshCommandRunner {
List<String> findResponse; List<String>? findResponse;
List<String> lsResponse; List<String>? lsResponse;
@override @override
Future<List<String>> run(String command) async { Future<List<String>> run(String command) async {
if (command.startsWith('/bin/find')) { if (command.startsWith('/bin/find')) {
return findResponse; return findResponse!;
} }
if (command.startsWith('/bin/ls')) { if (command.startsWith('/bin/ls')) {
return lsResponse; return lsResponse!;
} }
throw UnimplementedError(command); throw UnimplementedError(command);
} }
@override @override
String interface; String interface = '';
@override @override
String address; String address = '';
@override @override
String get sshConfigPath => '~/.ssh'; String get sshConfigPath => '~/.ssh';
...@@ -321,13 +321,13 @@ class FakeSshCommandRunner extends Fake implements SshCommandRunner { ...@@ -321,13 +321,13 @@ class FakeSshCommandRunner extends Fake implements SshCommandRunner {
class FakePortForwarder extends Fake implements PortForwarder { class FakePortForwarder extends Fake implements PortForwarder {
@override @override
int port; int port = 0;
@override @override
int remotePort; int remotePort = 0;
@override @override
String openPortAddress; String? openPortAddress;
bool stopped = false; bool stopped = false;
@override @override
...@@ -338,7 +338,7 @@ class FakePortForwarder extends Fake implements PortForwarder { ...@@ -338,7 +338,7 @@ class FakePortForwarder extends Fake implements PortForwarder {
class FakeVmService extends Fake implements vms.VmService { class FakeVmService extends Fake implements vms.VmService {
bool disposed = false; bool disposed = false;
vms.Response flutterListViews; vms.Response? flutterListViews;
@override @override
Future<void> dispose() async { Future<void> dispose() async {
...@@ -346,15 +346,15 @@ class FakeVmService extends Fake implements vms.VmService { ...@@ -346,15 +346,15 @@ class FakeVmService extends Fake implements vms.VmService {
} }
@override @override
Future<vms.Response> callMethod(String method, {String isolateId, Map<String, dynamic> args}) async { Future<vms.Response> callMethod(String method, {String? isolateId, Map<String, dynamic>? args}) async {
if (method == '_flutter.listViews') { if (method == '_flutter.listViews') {
return flutterListViews; return flutterListViews!;
} }
throw UnimplementedError(method); throw UnimplementedError(method);
} }
@override @override
Future<void> onDone; Future<void> onDone = Future<void>.value();
@override @override
Future<vms.Version> getVersion() async { Future<vms.Version> getVersion() async {
......
...@@ -16,24 +16,11 @@ void main() { ...@@ -16,24 +16,11 @@ void main() {
restoreVmServiceConnectionFunction(); restoreVmServiceConnectionFunction();
}); });
test('null connector', () async {
Future<vms.VmService> fakeServiceFunction(
Uri uri, {
Duration timeout,
}) {
return Future<vms.VmService>(() => null);
}
fuchsiaVmServiceConnectionFunction = fakeServiceFunction;
expect(await DartVm.connect(Uri.parse('http://this.whatever/ws')),
equals(null));
});
test('disconnect closes peer', () async { test('disconnect closes peer', () async {
final FakeVmService service = FakeVmService(); final FakeVmService service = FakeVmService();
Future<vms.VmService> fakeServiceFunction( Future<vms.VmService> fakeServiceFunction(
Uri uri, { Uri uri, {
Duration timeout, Duration? timeout,
}) { }) {
return Future<vms.VmService>(() => service); return Future<vms.VmService>(() => service);
} }
...@@ -47,7 +34,7 @@ void main() { ...@@ -47,7 +34,7 @@ void main() {
}); });
group('DartVm.getAllFlutterViews', () { group('DartVm.getAllFlutterViews', () {
FakeVmService fakeService; late FakeVmService fakeService;
setUp(() { setUp(() {
fakeService = FakeVmService(); fakeService = FakeVmService();
...@@ -91,7 +78,7 @@ void main() { ...@@ -91,7 +78,7 @@ void main() {
Future<vms.VmService> fakeVmConnectionFunction( Future<vms.VmService> fakeVmConnectionFunction(
Uri uri, { Uri uri, {
Duration timeout, Duration? timeout,
}) { }) {
fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponses); fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponses);
return Future<vms.VmService>(() => fakeService); return Future<vms.VmService>(() => fakeService);
...@@ -147,7 +134,7 @@ void main() { ...@@ -147,7 +134,7 @@ void main() {
Future<vms.VmService> fakeVmConnectionFunction( Future<vms.VmService> fakeVmConnectionFunction(
Uri uri, { Uri uri, {
Duration timeout, Duration? timeout,
}) { }) {
fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponses); fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponses);
return Future<vms.VmService>(() => fakeService); return Future<vms.VmService>(() => fakeService);
...@@ -194,7 +181,7 @@ void main() { ...@@ -194,7 +181,7 @@ void main() {
Future<vms.VmService> fakeVmConnectionFunction( Future<vms.VmService> fakeVmConnectionFunction(
Uri uri, { Uri uri, {
Duration timeout, Duration? timeout,
}) { }) {
fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponseMissingId); fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponseMissingId);
return Future<vms.VmService>(() => fakeService); return Future<vms.VmService>(() => fakeService);
...@@ -219,33 +206,33 @@ void main() { ...@@ -219,33 +206,33 @@ void main() {
'id': 'isolates/1', 'id': 'isolates/1',
'name': 'file://thingThatWillNotMatch:main()', 'name': 'file://thingThatWillNotMatch:main()',
'number': '1', 'number': '1',
}), })!,
vms.IsolateRef.parse(<String, dynamic>{ vms.IsolateRef.parse(<String, dynamic>{
'type': '@Isolate', 'type': '@Isolate',
'fixedId': 'true', 'fixedId': 'true',
'id': 'isolates/2', 'id': 'isolates/2',
'name': '0:dart_name_pattern()', 'name': '0:dart_name_pattern()',
'number': '2', 'number': '2',
}), })!,
vms.IsolateRef.parse(<String, dynamic>{ vms.IsolateRef.parse(<String, dynamic>{
'type': '@Isolate', 'type': '@Isolate',
'fixedId': 'true', 'fixedId': 'true',
'id': 'isolates/3', 'id': 'isolates/3',
'name': 'flutterBinary.cmx', 'name': 'flutterBinary.cmx',
'number': '3', 'number': '3',
}), })!,
vms.IsolateRef.parse(<String, dynamic>{ vms.IsolateRef.parse(<String, dynamic>{
'type': '@Isolate', 'type': '@Isolate',
'fixedId': 'true', 'fixedId': 'true',
'id': 'isolates/4', 'id': 'isolates/4',
'name': '0:some_other_dart_name_pattern()', 'name': '0:some_other_dart_name_pattern()',
'number': '4', 'number': '4',
}), })!,
]; ];
Future<vms.VmService> fakeVmConnectionFunction( Future<vms.VmService> fakeVmConnectionFunction(
Uri uri, { Uri uri, {
Duration timeout, Duration? timeout,
}) { }) {
fakeService.vm = FakeVM(isolates: isolates); fakeService.vm = FakeVM(isolates: isolates);
return Future<vms.VmService>(() => fakeService); return Future<vms.VmService>(() => fakeService);
...@@ -279,7 +266,7 @@ void main() { ...@@ -279,7 +266,7 @@ void main() {
Future<vms.VmService> fakeVmConnectionFunction( Future<vms.VmService> fakeVmConnectionFunction(
Uri uri, { Uri uri, {
Duration timeout, Duration? timeout,
}) { }) {
fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponseMissingIsolateName); fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponseMissingIsolateName);
return Future<vms.VmService>(() => fakeService); return Future<vms.VmService>(() => fakeService);
...@@ -300,11 +287,11 @@ void main() { ...@@ -300,11 +287,11 @@ void main() {
class FakeVmService extends Fake implements vms.VmService { class FakeVmService extends Fake implements vms.VmService {
bool disposed = false; bool disposed = false;
vms.Response flutterListViews; vms.Response? flutterListViews;
vms.VM vm; vms.VM? vm;
@override @override
Future<vms.VM> getVM() async => vm; Future<vms.VM> getVM() async => vm!;
@override @override
Future<void> dispose() async { Future<void> dispose() async {
...@@ -312,15 +299,15 @@ class FakeVmService extends Fake implements vms.VmService { ...@@ -312,15 +299,15 @@ class FakeVmService extends Fake implements vms.VmService {
} }
@override @override
Future<vms.Response> callMethod(String method, {String isolateId, Map<String, dynamic> args}) async { Future<vms.Response> callMethod(String method, {String? isolateId, Map<String, dynamic>? args}) async {
if (method == '_flutter.listViews') { if (method == '_flutter.listViews') {
return flutterListViews; return flutterListViews!;
} }
throw UnimplementedError(method); throw UnimplementedError(method);
} }
@override @override
Future<void> onDone; Future<void> onDone = Future<void>.value();
} }
class FakeVM extends Fake implements vms.VM { class FakeVM extends Fake implements vms.VM {
...@@ -329,5 +316,5 @@ class FakeVM extends Fake implements vms.VM { ...@@ -329,5 +316,5 @@ class FakeVM extends Fake implements vms.VM {
}); });
@override @override
List<vms.IsolateRef> isolates; List<vms.IsolateRef>? isolates;
} }
...@@ -33,8 +33,8 @@ void main() { ...@@ -33,8 +33,8 @@ void main() {
}); });
group('SshCommandRunner.run', () { group('SshCommandRunner.run', () {
FakeProcessManager fakeProcessManager; late FakeProcessManager fakeProcessManager;
FakeProcessResult fakeProcessResult; late FakeProcessResult fakeProcessResult;
SshCommandRunner runner; SshCommandRunner runner;
setUp(() { setUp(() {
...@@ -103,10 +103,10 @@ void main() { ...@@ -103,10 +103,10 @@ void main() {
); );
fakeProcessResult.stdout = 'somestuff'; fakeProcessResult.stdout = 'somestuff';
await runner.run('ls /whatever'); await runner.run('ls /whatever');
final List<String> passedCommand = fakeProcessManager.runCommands.single as List<String>; final List<String?> passedCommand = fakeProcessManager.runCommands.single as List<String?>;
expect(passedCommand, contains('-F')); expect(passedCommand, contains('-F'));
final int indexOfFlag = passedCommand.indexOf('-F'); final int indexOfFlag = passedCommand.indexOf('-F');
final String passedConfig = passedCommand[indexOfFlag + 1]; final String? passedConfig = passedCommand[indexOfFlag + 1];
expect(passedConfig, config); expect(passedConfig, config);
}); });
...@@ -118,7 +118,7 @@ void main() { ...@@ -118,7 +118,7 @@ void main() {
); );
fakeProcessResult.stdout = 'somestuff'; fakeProcessResult.stdout = 'somestuff';
await runner.run('ls /whatever'); await runner.run('ls /whatever');
final List<String> passedCommand = fakeProcessManager.runCommands.single as List<String>; final List<String?> passedCommand = fakeProcessManager.runCommands.single as List<String?>;
final int indexOfFlag = passedCommand.indexOf('-F'); final int indexOfFlag = passedCommand.indexOf('-F');
expect(indexOfFlag, equals(-1)); expect(indexOfFlag, equals(-1));
}); });
...@@ -126,21 +126,21 @@ void main() { ...@@ -126,21 +126,21 @@ void main() {
} }
class FakeProcessManager extends Fake implements ProcessManager { class FakeProcessManager extends Fake implements ProcessManager {
FakeProcessResult fakeResult; FakeProcessResult? fakeResult;
List<List<dynamic>> runCommands = <List<dynamic>>[]; List<List<dynamic>> runCommands = <List<dynamic>>[];
@override @override
Future<ProcessResult> run(List<dynamic> command, { Future<ProcessResult> run(List<dynamic> command, {
String workingDirectory, String? workingDirectory,
Map<String, String> environment, Map<String, String>? environment,
bool includeParentEnvironment = true, bool includeParentEnvironment = true,
bool runInShell = false, bool runInShell = false,
Encoding stdoutEncoding = systemEncoding, Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding, Encoding stderrEncoding = systemEncoding,
}) async { }) async {
runCommands.add(command); runCommands.add(command);
return fakeResult; return fakeResult!;
} }
} }
......
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