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>()),
+      );
+    });
+  });
+}