Chromium Code Reviews| Index: mojo/dart/observatory_tester/tester.dart |
| diff --git a/mojo/dart/observatory_tester/tester.dart b/mojo/dart/observatory_tester/tester.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..18326742e455d0ee5554e54b09bc8c85be311223 |
| --- /dev/null |
| +++ b/mojo/dart/observatory_tester/tester.dart |
| @@ -0,0 +1,176 @@ |
| +// Copyright 2015 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. |
| + |
| +library observatory_tester; |
| + |
| +// Minimal dependency Observatory heartbeat test. |
| + |
| +import 'dart:async'; |
| +import 'dart:convert'; |
| +import 'dart:io'; |
| + |
| +class Expect { |
| + static equals(a, b) { |
| + if (a != b) { |
| + throw 'Expected $a == $b'; |
| + } |
| + } |
| + |
| + static isMap(a) { |
| + if (a is! Map) { |
| + throw 'Expected $a to be a Map'; |
| + } |
| + } |
| + |
| + static notExecuted() { |
| + throw 'Should not have hit'; |
| + } |
| + |
| + static isNotNull(a) { |
| + if (a == null) { |
| + throw 'Expected $a to not be null.'; |
| + } |
| + } |
| +} |
| + |
| +class Launch { |
| + Launch(this.executable, this.arguments, this.process, this.port); |
| + |
| + void kill() { |
| + process.kill(); |
| + } |
| + |
| + final String executable; |
| + final String arguments; |
| + final Process process; |
| + final int port; |
| +} |
| + |
| +class Launcher { |
| + /// Launch [executable] with [arguments]. Returns a future to a [Launch] |
| + /// which includes the process and port where Observatory is running. |
| + static Future<Launch> launch(String executable, |
| + List<String> arguments) async { |
| + var process = await Process.start(executable, arguments); |
| + |
| + // Completer completes once 'Observatory listening on' message has been |
| + // scraped and we know the port number. |
| + var completer = new Completer(); |
| + |
| + process.stdout.transform(UTF8.decoder) |
| + .transform(new LineSplitter()).listen((line) { |
| + if (line.startsWith('Observatory listening on http://')) { |
| + RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); |
| + var port = portExp.firstMatch(line).group(1); |
| + var portNumber = int.parse(port); |
| + completer.complete(portNumber); |
| + } else { |
| + print(line); |
| + } |
| + }); |
| + |
| + process.stderr.transform(UTF8.decoder) |
| + .transform(new LineSplitter()).listen((line) { |
| + print(line); |
| + }); |
| + |
|
rmacnak
2015/06/22 20:03:37
Check process doesn't exit with non-zero before we
Cutch
2015/06/22 20:15:24
Done.
|
| + var port = await completer.future; |
| + return new Launch(executable, arguments, process, port); |
| + } |
| +} |
| + |
| +class ServiceHelper { |
| + ServiceHelper(this.client) { |
| + client.listen(_onData, |
| + onError: _onError, |
| + cancelOnError: true); |
| + } |
| + |
| + Future<Map> invokeRPC(String method, [Map params]) async { |
| + var key = _createKey(); |
| + var request = JSON.encode({ |
| + 'jsonrpc': '2.0', |
| + 'method': method, |
| + 'params': params == null ? {} : params, |
| + 'id': key, |
| + }); |
| + client.add(request); |
| + var completer = new Completer(); |
| + _outstanding_requests[key] = completer; |
| + print('-> $key ($method)'); |
| + return completer.future; |
| + } |
| + |
| + String _createKey() { |
| + var key = '$_id'; |
| + _id++; |
| + return key; |
| + } |
| + |
| + void _onData(String message) { |
| + var response = JSON.decode(message); |
| + var key = response['id']; |
| + print('<- $key'); |
| + var completer = _outstanding_requests.remove(key); |
| + assert(completer != null); |
| + var result = response['result']; |
| + var error = response['error']; |
| + if (error != null) { |
| + assert(result == null); |
| + completer.completeError(error); |
| + } else { |
| + assert(result != null); |
| + completer.complete(result); |
| + } |
| + } |
| + |
| + void _onError(error) { |
| + print('WebSocket error: $error'); |
| + } |
| + |
| + final WebSocket client; |
| + final Map<String, Completer> _outstanding_requests = <String, Completer>{}; |
| + var _id = 1; |
| +} |
| + |
| +main(List<String> args) async { |
| + var executable = args[0]; |
| + var arguments = args.sublist(1); |
| + |
| + print('Launching $executable with $arguments'); |
| + |
| + var launch = await Launcher.launch(executable, arguments); |
| + |
| + print('Observatory is on port ${launch.port}'); |
| + var serviceUrl = 'ws://127.0.0.1:${launch.port}/ws'; |
| + |
| + var client = await WebSocket.connect(serviceUrl); |
| + print('Connected to $serviceUrl'); |
| + |
| + var helper = new ServiceHelper(client); |
| + |
| + // Invoke getVM RPC. Verify a valid repsonse. |
| + var vm = await helper.invokeRPC('getVM'); |
| + Expect.equals(vm['type'], 'VM'); |
| + |
| + // Invoke a bogus RPC. Expect an error. |
| + bool errorCaught = false; |
| + try { |
| + var bad = await helper.invokeRPC('BARTSIMPSON'); |
| + Expect.notExecuted(); |
| + } catch (e) { |
| + errorCaught = true; |
| + // Map. |
| + Expect.isMap(e); |
| + // Has an error code. |
| + Expect.isNotNull(e['code']); |
| + } |
| + Expect.equals(errorCaught, true); |
| + |
| + await client.close(); |
| + print('Closed connection'); |
| + |
| + print('Finished.'); |
| + launch.kill(); |
| +} |