smoke test VM service connection before returning VMService object (#12914)
diff --git a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart index 491e2e5..ddb7282 100644 --- a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart +++ b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
@@ -155,11 +155,11 @@ // A cache of VMService connections. final HashMap<int, VMService> _vmServiceCache = new HashMap<int, VMService>(); - VMService _getVMService(int port) { + Future<VMService> _getVMService(int port) async { if (!_vmServiceCache.containsKey(port)) { final String addr = 'http://$ipv4Loopback:$port'; final Uri uri = Uri.parse(addr); - final VMService vmService = VMService.connect(uri); + final VMService vmService = await VMService.connect(uri); _vmServiceCache[port] = vmService; } return _vmServiceCache[port]; @@ -183,7 +183,7 @@ for (int port in ports) { if (!await _checkPort(port)) continue; - final VMService vmService = _getVMService(port); + final VMService vmService = await _getVMService(port); await vmService.getVM(); await vmService.waitForViews(); views.addAll(vmService.vm.views); @@ -283,7 +283,7 @@ Future<Null> _listVMs(List<int> ports) async { for (int port in ports) { - final VMService vmService = _getVMService(port); + final VMService vmService = await _getVMService(port); await vmService.getVM(); await vmService.waitForViews(); printStatus(_vmServiceToString(vmService));
diff --git a/packages/flutter_tools/lib/src/commands/screenshot.dart b/packages/flutter_tools/lib/src/commands/screenshot.dart index 1f7085a..59e56f9 100644 --- a/packages/flutter_tools/lib/src/commands/screenshot.dart +++ b/packages/flutter_tools/lib/src/commands/screenshot.dart
@@ -80,7 +80,7 @@ Future<Null> runSkia(File outputFile) async { final Uri observatoryUri = new Uri(scheme: 'http', host: '127.0.0.1', port: int.parse(argResults[_kSkia])); - final VMService vmService = VMService.connect(observatoryUri); + final VMService vmService = await VMService.connect(observatoryUri); final Map<String, dynamic> skp = await vmService.vm.invokeRpcRaw('_flutter.screenshotSkp'); outputFile ??= getUniqueFile(fs.currentDirectory, 'flutter', 'skp');
diff --git a/packages/flutter_tools/lib/src/commands/trace.dart b/packages/flutter_tools/lib/src/commands/trace.dart index 4674d67..33e88ed 100644 --- a/packages/flutter_tools/lib/src/commands/trace.dart +++ b/packages/flutter_tools/lib/src/commands/trace.dart
@@ -55,7 +55,7 @@ Tracing tracing; try { - tracing = Tracing.connect(observatoryUri); + tracing = await Tracing.connect(observatoryUri); } catch (error) { throwToolExit('Error connecting to observatory: $error'); } @@ -97,8 +97,8 @@ class Tracing { Tracing(this.vmService); - static Tracing connect(Uri uri) { - final VMService observatory = VMService.connect(uri); + static Future<Tracing> connect(Uri uri) async { + final VMService observatory = await VMService.connect(uri); return new Tracing(observatory); }
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 119f3bf..1c7008e 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -53,12 +53,12 @@ /// code of the running application (a.k.a. HotReload). /// This ensures that the reload process follows the normal orchestration of /// the Flutter Tools and not just the VM internal service. - void connect({ReloadSources reloadSources}) { + Future<Null> _connect({ReloadSources reloadSources}) async { if (vmServices != null) return; vmServices = new List<VMService>(observatoryUris.length); for (int i = 0; i < observatoryUris.length; i++) { - vmServices[i] = VMService.connect(observatoryUris[i], + vmServices[i] = await VMService.connect(observatoryUris[i], reloadSources: reloadSources); printTrace('Connected to service protocol: ${observatoryUris[i]}'); } @@ -599,7 +599,7 @@ bool viewFound = false; for (FlutterDevice device in flutterDevices) { device.viewFilter = viewFilter; - device.connect(reloadSources: reloadSources); + await device._connect(reloadSources: reloadSources); await device.getVMs(); await device.waitForViews(); if (device.views == null)
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 7cfab01..3227cc4 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -140,15 +140,19 @@ /// protocol itself. /// /// See: https://github.com/dart-lang/sdk/commit/df8bf384eb815cf38450cb50a0f4b62230fba217 - static VMService connect( + static Future<VMService> connect( Uri httpUri, { Duration requestTimeout: kDefaultRequestTimeout, ReloadSources reloadSources, - }) { + }) async { final Uri wsUri = httpUri.replace(scheme: 'ws', path: fs.path.join(httpUri.path, 'ws')); final StreamChannel<String> channel = _openChannel(wsUri); final rpc.Peer peer = new rpc.Peer.withoutJson(jsonDocument.bind(channel)); - return new VMService._(peer, httpUri, wsUri, requestTimeout, reloadSources); + final VMService service = new VMService._(peer, httpUri, wsUri, requestTimeout, reloadSources); + // This call is to ensure we are able to establish a connection instead of + // keeping on trucking and failing farther down the process. + await service._sendRequest('getVersion', const <String, dynamic>{}); + return service; } final Uri httpAddress;
diff --git a/packages/flutter_tools/test/vmservice_test.dart b/packages/flutter_tools/test/vmservice_test.dart new file mode 100644 index 0000000..6cb0714 --- /dev/null +++ b/packages/flutter_tools/test/vmservice_test.dart
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:test/test.dart'; + +import 'package:flutter_tools/src/base/port_scanner.dart'; +import 'package:flutter_tools/src/vmservice.dart'; + +void main() { + group('VMService', () { + test('fails connection eagerly in the connect() method', () async { + final int port = await const HostPortScanner().findAvailablePort(); + expect( + VMService.connect(Uri.parse('http://localhost:$port')), + throwsA(const isInstanceOf<WebSocketChannelException>()), + ); + }); + }); +}