From 9cb7001a3911575c6b4e5db4c5f19d080bae6047 Mon Sep 17 00:00:00 2001 From: John McCutchan Date: Fri, 4 Mar 2016 15:01:26 -0800 Subject: [PATCH] Add ServiceProtocolDiscovery --- .../lib/src/service_protocol.dart | 52 +++++++++++++++++++ .../test/service_protocol_test.dart | 47 +++++++++++++++++ packages/flutter_tools/test/src/mocks.dart | 34 ++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 packages/flutter_tools/lib/src/service_protocol.dart create mode 100644 packages/flutter_tools/test/service_protocol_test.dart diff --git a/packages/flutter_tools/lib/src/service_protocol.dart b/packages/flutter_tools/lib/src/service_protocol.dart new file mode 100644 index 0000000000..ffbbdfa144 --- /dev/null +++ b/packages/flutter_tools/lib/src/service_protocol.dart @@ -0,0 +1,52 @@ +// Copyright 2016 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 'dart:async'; + +import 'device.dart'; + +/// Discover service protocol ports on devices. +class ServiceProtocolDiscovery { + /// [logReader] A [DeviceLogReader] to look for Observatory messages in. + ServiceProtocolDiscovery(DeviceLogReader logReader) + : _logReader = logReader { + assert(_logReader != null); + if (!_logReader.isReading) + _logReader.start(); + + _logReader.lines.listen(_onLine); + } + + final DeviceLogReader _logReader; + Completer _completer = new Completer(); + + /// The [Future] returned by this function will complete when the next + /// service protocol port is found. + Future nextPort() { + return _completer.future; + } + + void _onLine(String line) { + int portNumber = 0; + if (line.startsWith('Observatory listening on http://')) { + try { + RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); + var port = portExp.firstMatch(line).group(1); + portNumber = int.parse(port); + } catch (_) { + // Ignore errors. + } + } + if (portNumber != 0) { + _located(portNumber); + } + } + + void _located(int port) { + assert(_completer != null); + assert(!_completer.isCompleted); + _completer.complete(port); + _completer = new Completer(); + } +} diff --git a/packages/flutter_tools/test/service_protocol_test.dart b/packages/flutter_tools/test/service_protocol_test.dart new file mode 100644 index 0000000000..7c62e57011 --- /dev/null +++ b/packages/flutter_tools/test/service_protocol_test.dart @@ -0,0 +1,47 @@ +// Copyright 2016 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 'dart:async'; +import 'package:test/test.dart'; + +import 'package:flutter_tools/src/service_protocol.dart'; + +import 'src/mocks.dart'; + +main() => defineTests(); + +defineTests() { + group('service_protocol', () { + test('Discovery Heartbeat', () async { + MockDeviceLogReader logReader = new MockDeviceLogReader(); + ServiceProtocolDiscovery discoverer = + new ServiceProtocolDiscovery(logReader); + // Get next port future. + Future nextPort = discoverer.nextPort(); + expect(nextPort, isNotNull); + // Inject some lines. + logReader.addLine('HELLO WORLD'); + logReader.addLine( + 'Observatory listening on http://127.0.0.1:9999'); + // Await the port. + expect(await nextPort, 9999); + // Get next port future. + nextPort = discoverer.nextPort(); + logReader.addLine( + 'Observatory listening on http://127.0.0.1:3333'); + expect(await nextPort, 3333); + // Get next port future. + nextPort = discoverer.nextPort(); + // Inject some bad lines. + logReader.addLine('Observatory listening on http://127.0.0.1'); + logReader.addLine('Observatory listening on http://127.0.0.1:'); + logReader.addLine( + 'Observatory listening on http://127.0.0.1:apple'); + int port = await nextPort.timeout( + const Duration(milliseconds: 100), onTimeout: () => 77); + // Expect the timeout port. + expect(port, 77); + }); + }); +} diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart index 38a4610bcf..1d7b81925f 100644 --- a/packages/flutter_tools/test/src/mocks.dart +++ b/packages/flutter_tools/test/src/mocks.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; import 'package:flutter_tools/src/android/android_device.dart'; import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/build_configuration.dart'; @@ -51,6 +52,39 @@ class MockDeviceStore extends DeviceStore { iOSSimulator: new MockIOSSimulator()); } +class MockDeviceLogReader extends DeviceLogReader { + String get name => 'MockLogReader'; + + final StreamController _linesStreamController = + new StreamController.broadcast(); + + final Completer _finishedCompleter = new Completer(); + + Stream get lines => _linesStreamController.stream; + + void addLine(String line) { + _linesStreamController.add(line); + } + + bool _started = false; + + Future start() { + assert(!_started); + _started = true; + return new Future.value(this); + } + + bool get isReading => _started; + + Future stop() { + assert(_started); + _started = false; + return new Future.value(this); + } + + Future get finished => _finishedCompleter.future; +} + void applyMocksToCommand(FlutterCommand command) { command ..applicationPackages = new MockApplicationPackageStore()