use vm_service_client to talk to Observatory
diff --git a/pkgs/coverage/lib/src/collect.dart b/pkgs/coverage/lib/src/collect.dart
index c4a850a..6d84e16 100644
--- a/pkgs/coverage/lib/src/collect.dart
+++ b/pkgs/coverage/lib/src/collect.dart
@@ -6,15 +6,17 @@
import 'dart:async';
-import 'devtools.dart';
+import 'vm_service_client.dart';
import 'util.dart';
const _retryInterval = const Duration(milliseconds: 200);
Future<Map> collect(String host, int port, bool resume, bool waitPaused,
{Duration timeout}) async {
+ var uri = 'ws://$host:$port/ws';
+
var vmService = await retry(
- () => VMService.connect(host, port), _retryInterval,
+ () => VMServiceClient.connect(uri), _retryInterval,
timeout: timeout);
try {
if (waitPaused) {
@@ -30,30 +32,34 @@
}
}
-Future<Map> _getAllCoverage(VMService service) async {
+Future<Map> _getAllCoverage(VMServiceClient service) async {
var vm = await service.getVM();
var allCoverage = [];
for (var isolateRef in vm.isolates) {
- var coverage = await service.getCoverage(isolateRef.id);
+ var isolate = await isolateRef.load();
+ var coverage = await service.getCoverage(isolate);
allCoverage.addAll(coverage.coverage);
}
return {'type': 'CodeCoverage', 'coverage': allCoverage};
}
-Future _resumeIsolates(VMService service) async {
+Future _resumeIsolates(VMServiceClient service) async {
var vm = await service.getVM();
for (var isolateRef in vm.isolates) {
- await service.resume(isolateRef.id);
+ var isolate = await isolateRef.load();
+ if (isolate.isPaused) {
+ await isolateRef.resume();
+ }
}
}
-Future _waitIsolatesPaused(VMService service, {Duration timeout}) async {
+Future _waitIsolatesPaused(VMServiceClient service, {Duration timeout}) async {
allPaused() async {
var vm = await service.getVM();
for (var isolateRef in vm.isolates) {
- var isolate = await service.getIsolate(isolateRef.id);
- if (!isolate.paused) throw "Unpaused isolates remaining.";
+ var isolate = await isolateRef.load();
+ if (!isolate.isPaused) throw "Unpaused isolates remaining.";
}
}
return retry(allPaused, _retryInterval, timeout: timeout);
diff --git a/pkgs/coverage/lib/src/devtools.dart b/pkgs/coverage/lib/src/devtools.dart
deleted file mode 100644
index 1c2f534..0000000
--- a/pkgs/coverage/lib/src/devtools.dart
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library coverage.src.devtools;
-
-import 'dart:async';
-import 'dart:convert' show JSON;
-import 'dart:io';
-import 'package:logging/logging.dart';
-
-final Logger _log = new Logger('coverage.src.devtools');
-
-class VMService {
- final _Connection _connection;
-
- VMService._(this._connection);
-
- Future<VM> getVM() async {
- var response = await _connection.request('getVM');
- return new VM.fromJson(response);
- }
-
- Future<Isolate> getIsolate(String isolateId) async {
- var response =
- await _connection.request('getIsolate', {'isolateId': isolateId});
- return new Isolate.fromJson(response);
- }
-
- //TODO(kevmoo): Test this - https://github.com/dart-lang/coverage/issues/90
- Future<AllocationProfile> getAllocationProfile(String isolateId,
- {bool reset, bool gc}) async {
- var params = {'isolateId': isolateId};
- if (reset != null) {
- params['reset'] = reset;
- }
- if (gc != null) {
- params['gc'] = 'full';
- }
-
- // TODO(kevmoo) Remove fallback logic once 1.11 is stable
- // https://github.com/dart-lang/coverage/issues/91
- var response;
- try {
- // For Dart >=1.11.0-dev.3.0 - _getAllocationProfile is considered private
- response = await _connection.request('_getAllocationProfile', params);
- } on ServiceProtocolErrorBase catch (error) {
- if (error.isMethodNotFound) {
- // For Dart <1.11.0-dev.3.0 - getAllocationProfile is considered public
- response = await _connection.request('getAllocationProfile', params);
- } else {
- rethrow;
- }
- }
-
- return new AllocationProfile.fromJson(response);
- }
-
- Future<CodeCoverage> getCoverage(String isolateId, {String targetId}) async {
- var params = {'isolateId': isolateId};
- if (targetId != null) {
- params['targetId'] = targetId;
- }
-
- var response;
-
- // TODO(kevmoo) Remove fallback logic once 1.11 is stable
- // https://github.com/dart-lang/coverage/issues/91
- try {
- // For Dart >=1.11.0-dev.3.0 - _getCoverage is considered private
- response = await _connection.request('_getCoverage', params);
- } on ServiceProtocolErrorBase catch (error) {
- if (error.isMethodNotFound) {
- // For Dart <1.11.0-dev.3.0 - getCoverage is considered public
- response = await _connection.request('getCoverage', params);
- } else {
- rethrow;
- }
- }
- return new CodeCoverage.fromJson(response);
- }
-
- Future resume(String isolateId) =>
- _connection.request('resume', {'isolateId': isolateId});
-
- static Future<VMService> connect(String host, int port) async {
- _log.fine('Connecting to host $host on port $port');
-
- return connectToVMWebsocket(host, port);
- }
-
- static Future<VMService> connectToVMWebsocket(String host, int port) async {
- var connection = await _Connection.connect(host, port);
- return new VMService._(connection);
- }
-
- Future close() => _connection.close();
-}
-
-class VM {
- final String id;
- final String targetCPU;
- final String hostCPU;
- final String version;
- final String pid;
- final List<IsolateRef> isolates;
-
- VM(this.id, this.targetCPU, this.hostCPU, this.version, this.pid,
- this.isolates);
-
- factory VM.fromJson(json) => new VM(
- json['id'],
- json['targetCPU'],
- json['hostCPU'],
- json['version'],
- json['pid'],
- json['isolates'].map((i) => new IsolateRef.fromJson(i)).toList());
-}
-
-class IsolateRef {
- final String id;
- final String name;
-
- IsolateRef(this.id, this.name);
-
- factory IsolateRef.fromJson(json) => new IsolateRef(json['id'], json['name']);
-}
-
-class Isolate {
- final String id;
- final String name;
- final bool pauseOnExit;
- final ServiceEvent pauseEvent;
- bool get paused =>
- pauseOnExit && pauseEvent != null && pauseEvent.kind == 'PauseExit';
-
- Isolate(this.id, this.name, this.pauseOnExit, this.pauseEvent);
-
- factory Isolate.fromJson(json) => new Isolate(json['id'], json['name'],
- json['pauseOnExit'], new ServiceEvent.fromJson(json['pauseEvent']));
-}
-
-class ServiceEvent {
- final String kind;
- final IsolateRef isolate;
-
- @Deprecated('Will be removed in 0.8')
- String get eventType => kind;
-
- ServiceEvent(this.kind, this.isolate);
-
- factory ServiceEvent.fromJson(Map json) {
- // TODO(kevmoo) Keep around until 1.11 is stable
- // https://github.com/dart-lang/coverage/issues/91
- // 'kind' is the key for >= 1.11-dev.5.0.
- // 'eventType' is for older versions
- var kind = json.containsKey('kind') ? json['kind'] : json['eventType'];
-
- return new ServiceEvent(kind, new IsolateRef.fromJson(json['isolate']));
- }
-}
-
-class CodeCoverage {
- final String id;
- final List coverage;
-
- CodeCoverage(this.id, this.coverage);
-
- factory CodeCoverage.fromJson(json) =>
- new CodeCoverage(json['id'], json['coverage']);
-}
-
-class AllocationProfile {
- final String id;
-
- AllocationProfile(this.id);
-
- factory AllocationProfile.fromJson(json) => new AllocationProfile(json['id']);
-}
-
-/// Observatory connection via websocket.
-class _Connection {
- final WebSocket _socket;
- final Map<int, Completer> _pendingRequests = {};
- int _requestId = 1;
-
- _Connection(this._socket) {
- _socket.listen(_handleResponse);
- }
-
- static Future<_Connection> connect(String host, int port) async {
- _log.fine('Connecting to VM via HTTP websocket protocol');
- var uri = 'ws://$host:$port/ws';
- var socket = await WebSocket.connect(uri);
- return new _Connection(socket);
- }
-
- Future<Map> request(String method, [Map params = const {}]) {
- _pendingRequests[_requestId] = new Completer();
- var message =
- JSON.encode({'id': _requestId, 'method': method, 'params': params,});
- _log.fine('Send> $message');
- _socket.add(message);
- return _pendingRequests[_requestId++].future;
- }
-
- Future close() => _socket.close();
-
- void _handleResponse(String response) {
- _log.fine('Recv< $response');
- var json = JSON.decode(response);
- var id = json['id'];
- if (id is String) {
- // Support for vm version >= 1.11.0
- id = int.parse(id);
- }
- if (id == null || !_pendingRequests.keys.contains(id)) {
- // Suppress unloved messages.
- return;
- }
-
- var completer = _pendingRequests.remove(id);
- if (completer == null) {
- _log.severe('Failed to pair response with request');
- }
-
- // Behavior >= Dart 1.11-dev.3
- var error = json['error'];
- if (error != null) {
- var errorObj = new JsonRpcError.fromJson(error);
- completer.completeError(errorObj);
- return;
- }
-
- var innerResponse = json['result'];
- if (innerResponse == null) {
- // Support for 1.9.0 <= vm version < 1.10.0.
- innerResponse = json['response'];
- }
- if (innerResponse == null) {
- completer.completeError('Failed to get JSON response for message $id');
- return;
- }
- var message;
- if (innerResponse != null) {
- if (innerResponse is Map) {
- // Support for vm version >= 1.11.0
- message = innerResponse;
- } else {
- message = JSON.decode(innerResponse);
- }
- }
-
- // need to check this for errors in the Dart 1.10 version
- var type = message['type'];
- if (type == 'Error') {
- var errorObj = new Dart_1_10_RpcError.fromJson(message);
- completer.completeError(errorObj);
- return;
- }
-
- completer.complete(message);
- }
-}
-
-abstract class ServiceProtocolErrorBase extends Error {
- String get message;
- bool get isMethodNotFound;
-}
-
-// TODO(kevmoo) Remove this logic once 1.11 is stable
-// https://github.com/dart-lang/coverage/issues/91
-class Dart_1_10_RpcError extends ServiceProtocolErrorBase {
- final String message;
- final bool isMethodNotFound;
-
- Dart_1_10_RpcError(this.message, this.isMethodNotFound);
-
- factory Dart_1_10_RpcError.fromJson(Map<String, dynamic> json) {
- assert(json['type'] == 'Error');
- var message = json['message'];
-
- var isMethodNotFound = message.startsWith('unrecognized method:');
-
- return new Dart_1_10_RpcError(message, isMethodNotFound);
- }
-}
-
-class JsonRpcError extends ServiceProtocolErrorBase {
- final int code;
- final String message;
- final data;
-
- // http://www.jsonrpc.org/specification
- // -32601 Method not found The method does not exist / is not available.
- bool get isMethodNotFound => code == -32601;
-
- JsonRpcError(this.code, this.message, this.data);
-
- factory JsonRpcError.fromJson(Map<String, dynamic> json) =>
- new JsonRpcError(json['code'], json['message'], json['data']);
-
- String toString() {
- var msg = 'JsonRpcError: $message';
- if (isMethodNotFound) {
- if (data is Map) {
- var request = data['request'];
- if (request is Map) {
- var method = request['method'];
- if (method != null) {
- msg = '$msg - "$method"';
- }
- }
- }
- }
-
- return '$msg ($code)';
- }
-}
diff --git a/pkgs/coverage/lib/src/vm_service_client.dart b/pkgs/coverage/lib/src/vm_service_client.dart
new file mode 100644
index 0000000..8bd676d
--- /dev/null
+++ b/pkgs/coverage/lib/src/vm_service_client.dart
@@ -0,0 +1,218 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Contents of this file are mostly copied from
+// https://github.com/dart-lang/vm_service_client/blob/master/lib/vm_service_client.dart
+// At or about commit
+// https://github.com/dart-lang/vm_service_client/commit/a5d18cf62777d850b6e4505205f7b254679446ef
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:async/async.dart';
+import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
+
+import 'package:vm_service_client/src/exceptions.dart';
+import 'package:vm_service_client/src/flag.dart';
+import 'package:vm_service_client/src/isolate.dart';
+import 'package:vm_service_client/src/service_version.dart';
+import 'package:vm_service_client/src/stream_manager.dart';
+import 'package:vm_service_client/src/utils.dart';
+import 'package:vm_service_client/src/v1_compatibility.dart';
+import 'package:vm_service_client/src/vm.dart';
+
+/// A [StreamSinkTransformer] that converts encodes JSON messages.
+///
+/// We can't use fromStreamTransformer with JSON.encoder because it isn't
+/// guaranteed to emit the entire object as a single message, and the WebSocket
+/// protocol cares about that.
+final _jsonSinkEncoder = new StreamSinkTransformer.fromHandlers(
+ handleData: (data, sink) => sink.add(JSON.encode(data)));
+
+/// A client for the [Dart VM service protocol][service api].
+///
+/// [service api]: https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md
+///
+/// Connect to a VM service endpoint using [connect], and use [getVM] to load
+/// information about the VM itself.
+///
+/// The client supports VM service versions 1.x (which first shipped with Dart
+/// 1.11), 2.x (which first shipped with Dart 1.12), and 3.x (which first
+/// shipped with Dart 1.13). Some functionality may be unavailable in older VM
+/// service versions; those places will be clearly documented. You can check the
+/// version of the VM service you're connected to using [getVersion].
+///
+/// Because it takes an extra RPC call to verify compatibility with the protocol
+/// version, the client doesn't do so by default. Users who want to be sure
+/// they're talking to a supported protocol version can call [validateVersion].
+class VMServiceClient {
+ /// The underlying JSON-RPC peer used to communicate with the VM service.
+ final rpc.Peer _peer;
+
+ /// The streams shared among the entire service protocol client.
+ final StreamManager _streams;
+
+ /// A broadcast stream that emits every isolate as it starts.
+ Stream<VMIsolateRef> get onIsolateStart => _onIsolateStart;
+ Stream<VMIsolateRef> _onIsolateStart;
+
+ /// A broadcast stream that emits every isolate as it becomes runnable.
+ ///
+ /// These isolates are guaranteed to return a [VMRunnableIsolate] from
+ /// [VMIsolateRef.load].
+ ///
+ /// This is only supported on the VM service protocol version 3.0 and greater.
+ Stream<VMIsolateRef> get onIsolateRunnable => _onIsolateRunnable;
+ Stream<VMIsolateRef> _onIsolateRunnable;
+
+ /// A future that fires when the underlying connection has been closed.
+ ///
+ /// Any connection-level errors will also be emitted through this future.
+ final Future done;
+
+ /// Connects to the VM service protocol at [url].
+ ///
+ /// [url] may be a `ws://` or a `http://` URL. If it's `ws://`, it's
+ /// interpreted as the URL to connect to directly. If it's `http://`, it's
+ /// interpreted as the URL for the Dart observatory, and the corresponding
+ /// WebSocket URL is determined based on that. It may be either a [String] or
+ /// a [Uri].
+ static Future<VMServiceClient> connect(url) async {
+ if (url is! Uri && url is! String) {
+ throw new ArgumentError.value(url, "url", "must be a String or a Uri");
+ }
+
+ var uri = url is String ? Uri.parse(url) : url;
+ if (uri.scheme == 'http') uri = uri.replace(scheme: 'ws', path: '/ws');
+
+ return new VMServiceClient(await WebSocket.connect(uri.toString()));
+ }
+
+ /// Creates a client that reads incoming messages from [incoming] and writes
+ /// outgoing messages to [outgoing].
+ ///
+ /// If [incoming] is a [StreamSink] as well as a [Stream] (for example, a
+ /// [WebSocket]), [outgoing] may be omitted.
+ ///
+ /// This is useful when using the client over a pre-existing connection. To
+ /// establish a connection from scratch, use [connect].
+ factory VMServiceClient(Stream<String> incoming,
+ [StreamSink<String> outgoing]) {
+ if (outgoing == null) outgoing = incoming as StreamSink;
+
+ var incomingEncoded =
+ incoming.map(JSON.decode).transform(v1CompatibilityTransformer);
+ var outgoingEncoded = _jsonSinkEncoder.bind(outgoing);
+ return new VMServiceClient._(
+ new rpc.Peer.withoutJson(incomingEncoded, outgoingEncoded));
+ }
+
+ /// Creates a client that reads incoming decoded messages from [incoming] and
+ /// writes outgoing decoded messages to [outgoing].
+ ///
+ /// Unlike [new VMServiceClient], this doesn't read or write JSON strings.
+ /// Instead, it reads and writes decoded maps.
+ ///
+ /// If [incoming] is a [StreamSink] as well as a [Stream], [outgoing] may be
+ /// omitted.
+ ///
+ /// This is useful when using the client over a pre-existing connection. To
+ /// establish a connection from scratch, use [connect].
+ factory VMServiceClient.withoutJson(Stream incoming, [StreamSink outgoing]) {
+ if (outgoing == null) outgoing = incoming as StreamSink;
+
+ incoming = incoming.transform(v1CompatibilityTransformer);
+ return new VMServiceClient._(new rpc.Peer.withoutJson(incoming, outgoing));
+ }
+
+ VMServiceClient._(rpc.Peer peer)
+ : _peer = peer,
+ _streams = new StreamManager(peer),
+ done = peer.listen() {
+ _onIsolateStart = transform(_streams.isolate, (json, sink) {
+ if (json["kind"] != "IsolateStart") return;
+ sink.add(newVMIsolateRef(_peer, _streams, json["isolate"]));
+ });
+
+ _onIsolateRunnable = transform(_streams.isolate, (json, sink) {
+ if (json["kind"] != "IsolateRunnable") return;
+ sink.add(newVMIsolateRef(_peer, _streams, json["isolate"]));
+ });
+ }
+
+ /// Checks the VM service protocol version and throws a
+ /// [VMUnsupportedVersionException] if it's not a supported version.
+ ///
+ /// Because it's possible the VM service protocol doesn't speak JSON-RPC 2.0
+ /// at all, by default this will also throw a [VMUnsupportedVersionException]
+ /// if a reply isn't received within two seconds. This timeout can be
+ /// controlled with [timeout], or `null` can be passed to use no timeout.
+ Future validateVersion({Duration timeout: const Duration(seconds: 2)}) {
+ var future = _peer.sendRequest("getVersion", {}).then((json) {
+ var version;
+ try {
+ version = newVMServiceVersion(json);
+ } catch (_) {
+ throw new VMUnsupportedVersionException();
+ }
+
+ if (version.major < 2 || version.major > 3) {
+ throw new VMUnsupportedVersionException(version);
+ }
+ });
+
+ if (timeout == null) return future;
+
+ return future.timeout(timeout, onTimeout: () {
+ throw new VMUnsupportedVersionException();
+ });
+ }
+
+ /// Closes the underlying connection to the VM service.
+ ///
+ /// Returns a [Future] that fires once the connection has been closed.
+ Future close() => _peer.close();
+
+ /// Returns a list of flags that were passed to the VM.
+ ///
+ /// As of VM service version 3.0, this only includes VM-internal flags.
+ Future<List<VMFlag>> getFlags() async =>
+ newVMFlagList(await _peer.sendRequest("getFlagList", {}));
+
+ /// Returns the version of the VM service protocol that this client is
+ /// communicating with.
+ ///
+ /// Note that this is distinct from the version of Dart, which is accessible
+ /// via [VM.version].
+ Future<VMServiceVersion> getVersion() async =>
+ newVMServiceVersion(await _peer.sendRequest("getVersion", {}));
+
+ /// Returns information about the Dart VM.
+ Future<VM> getVM() async =>
+ newVM(_peer, _streams, await _peer.sendRequest("getVM", {}));
+
+ // Function added to original VmServiceClient class to enable coverage access
+ Future<CodeCoverage> getCoverage(VMIsolate isolate) async {
+ var json = await _peer.sendRequest(
+ '_getCoverage', {'isolateId': 'isolates/${isolate.numberAsString}'})
+ as Map;
+
+ if (json['type'] == 'Error') {
+ throw json;
+ }
+
+ return new CodeCoverage.fromJson(json);
+ }
+}
+
+class CodeCoverage {
+ final String id;
+ final List coverage;
+
+ CodeCoverage(this.id, this.coverage);
+
+ factory CodeCoverage.fromJson(json) =>
+ new CodeCoverage(json['id'], json['coverage']);
+}
diff --git a/pkgs/coverage/pubspec.yaml b/pkgs/coverage/pubspec.yaml
index 58b906b..48ede69 100644
--- a/pkgs/coverage/pubspec.yaml
+++ b/pkgs/coverage/pubspec.yaml
@@ -7,9 +7,12 @@
sdk: '>=1.12.0 <2.0.0'
dependencies:
args: '>=0.12.1 <1.0.0'
+ async: ^1.8.0
+ json_rpc_2: ^1.2.0
logging: '>=0.9.0 <0.12.0'
path: '>=0.9.0 <2.0.0'
stack_trace: ^1.3.0
+ vm_service_client: ^0.1.1+1
dev_dependencies:
test: '>=0.12.0 <0.13.0'
executables:
diff --git a/pkgs/coverage/test/collect_coverage_api_test.dart b/pkgs/coverage/test/collect_coverage_api_test.dart
index 43f2eff..14c8976 100644
--- a/pkgs/coverage/test/collect_coverage_api_test.dart
+++ b/pkgs/coverage/test/collect_coverage_api_test.dart
@@ -5,7 +5,6 @@
library coverage.test.collect_coverage_api_test;
import 'dart:async';
-import 'dart:io';
import 'package:coverage/coverage.dart';
import 'package:coverage/src/util.dart';
@@ -19,8 +18,6 @@
final _sampleAppFileUri = p.toUri(p.absolute(testAppPath)).toString();
final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
-const _timeout = const Duration(seconds: 5);
-
void main() {
test('collect_coverage_api', () async {
var json = await _getCoverageResult();
@@ -40,8 +37,8 @@
return map;
});
- for (var sampleCoverageData in sources[_sampleAppFileUri]) {
- expect(sampleCoverageData['hits'], isNotEmpty);
+ for (Map sampleCoverageData in sources[_sampleAppFileUri]) {
+ expect(sampleCoverageData['hits'], isNotNull);
}
for (var sampleCoverageData in sources[_isolateLibFileUri]) {
@@ -63,15 +60,9 @@
var openPort = await getOpenPort();
// run the sample app, with the right flags
- var sampleProcFuture = Process.run('dart', [
- '--enable-vm-service=$openPort',
- '--pause_isolates_on_exit',
- testAppPath
- ]).timeout(_timeout, onTimeout: () {
- throw 'We timed out waiting for the sample app to finish.';
- });
+ var sampleProcFuture = runTestApp(openPort);
- var result = collect('127.0.0.1', openPort, true, false, timeout: _timeout);
+ var result = collect('127.0.0.1', openPort, true, false, timeout: timeout);
await sampleProcFuture;
return result;
diff --git a/pkgs/coverage/test/collect_coverage_test.dart b/pkgs/coverage/test/collect_coverage_test.dart
index 3f1ad31..9a8ba28 100644
--- a/pkgs/coverage/test/collect_coverage_test.dart
+++ b/pkgs/coverage/test/collect_coverage_test.dart
@@ -21,8 +21,6 @@
final _sampleAppFileUri = p.toUri(p.absolute(testAppPath)).toString();
final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
-const _timeout = const Duration(seconds: 5);
-
void main() {
test('collect_coverage', () async {
var resultString = await _getCoverageResult();
@@ -46,7 +44,7 @@
});
for (var sampleCoverageData in sources[_sampleAppFileUri]) {
- expect(sampleCoverageData['hits'], isNotEmpty);
+ expect(sampleCoverageData['hits'], isNotNull);
}
for (var sampleCoverageData in sources[_isolateLibFileUri]) {
@@ -67,7 +65,7 @@
var isolateFile = hitMap[_isolateLibFileUri];
- expect(isolateFile, {11: 1, 12: 1, 14: 1, 16: 3, 18: 1});
+ expect(isolateFile, {12: 1, 14: 1, 16: 3, 18: 1});
});
test('parseCoverage', () async {
@@ -104,13 +102,7 @@
var openPort = await getOpenPort();
// run the sample app, with the right flags
- var sampleProcFuture = Process.run('dart', [
- '--enable-vm-service=$openPort',
- '--pause_isolates_on_exit',
- testAppPath
- ]).timeout(_timeout, onTimeout: () {
- throw 'We timed out waiting for the sample app to finish.';
- });
+ var sampleProcFuture = runTestApp(openPort);
// run the tool with the right flags
// TODO: need to get all of this functionality in the lib
@@ -120,7 +112,7 @@
openPort.toString(),
'--resume-isolates',
'--wait-paused'
- ]).timeout(_timeout, onTimeout: () {
+ ]).timeout(timeout, onTimeout: () {
throw 'We timed out waiting for the tool to finish.';
});
diff --git a/pkgs/coverage/test/lcov_test.dart b/pkgs/coverage/test/lcov_test.dart
index 06ee63e..033f0d6 100644
--- a/pkgs/coverage/test/lcov_test.dart
+++ b/pkgs/coverage/test/lcov_test.dart
@@ -95,7 +95,7 @@
// be very careful if you change the test file
expect(res, contains(" 0| return a - b;"));
- expect(res, contains(' 1| return _withTimeout(() async {'),
+ expect(res, contains('| return _withTimeout(() async {'),
reason: 'be careful if you change lib/src/util.dart');
var hitLineRegexp = new RegExp(r'\s+(\d+)\| return a \+ b;');
diff --git a/pkgs/coverage/test/run_and_collect_test.dart b/pkgs/coverage/test/run_and_collect_test.dart
index c73001c..c1ca14a 100644
--- a/pkgs/coverage/test/run_and_collect_test.dart
+++ b/pkgs/coverage/test/run_and_collect_test.dart
@@ -37,7 +37,7 @@
});
for (var sampleCoverageData in sources[_sampleAppFileUri]) {
- expect(sampleCoverageData['hits'], isNotEmpty);
+ expect(sampleCoverageData['hits'], isNotNull);
}
for (var sampleCoverageData in sources[_isolateLibFileUri]) {
@@ -50,6 +50,6 @@
var isolateFile = hitMap[_isolateLibFileUri];
- expect(isolateFile, {11: 1, 12: 1, 14: 1, 16: 3, 18: 1});
+ expect(isolateFile, {12: 1, 14: 1, 16: 3, 18: 1});
});
}
diff --git a/pkgs/coverage/test/test_util.dart b/pkgs/coverage/test/test_util.dart
index 8e94121..8909238 100644
--- a/pkgs/coverage/test/test_util.dart
+++ b/pkgs/coverage/test/test_util.dart
@@ -4,6 +4,38 @@
library coverage.test.util;
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
import 'package:path/path.dart' as p;
final testAppPath = p.join('test', 'test_files', 'test_app.dart');
+
+const timeout = const Duration(seconds: 10);
+
+Future runTestApp(int openPort) async {
+ var proc = await Process.start('dart', [
+ '--enable-vm-service=$openPort',
+ '--pause_isolates_on_exit',
+ testAppPath
+ ]);
+
+ return Future.wait([
+ _transformStd(proc.stdout),
+ _transformStd(proc.stderr),
+ proc.exitCode
+ ]).timeout(timeout, onTimeout: () {
+ throw 'We timed out waiting for the sample app to finish.';
+ });
+}
+
+Future<Null> _transformStd(Stream<List<int>> source) {
+ return source
+ .transform(SYSTEM_ENCODING.decoder)
+ .transform(const LineSplitter())
+ .forEach((line) {
+ // Uncomment to debug output from `testApp`
+ // print(line);
+ });
+}