Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 library observatory_tester; | |
| 6 | |
| 7 // Minimal dependency Observatory heartbeat test. | |
| 8 | |
| 9 import 'dart:async'; | |
| 10 import 'dart:convert'; | |
| 11 import 'dart:io'; | |
| 12 | |
| 13 class Expect { | |
| 14 static equals(a, b) { | |
| 15 if (a != b) { | |
| 16 throw 'Expected $a == $b'; | |
| 17 } | |
| 18 } | |
| 19 | |
| 20 static isMap(a) { | |
| 21 if (a is! Map) { | |
| 22 throw 'Expected $a to be a Map'; | |
| 23 } | |
| 24 } | |
| 25 | |
| 26 static notExecuted() { | |
| 27 throw 'Should not have hit'; | |
| 28 } | |
| 29 | |
| 30 static isNotNull(a) { | |
| 31 if (a == null) { | |
| 32 throw 'Expected $a to not be null.'; | |
| 33 } | |
| 34 } | |
| 35 } | |
| 36 | |
| 37 class Launch { | |
| 38 Launch(this.executable, this.arguments, this.process, this.port); | |
| 39 | |
| 40 void kill() { | |
| 41 process.kill(); | |
| 42 } | |
| 43 | |
| 44 final String executable; | |
| 45 final String arguments; | |
| 46 final Process process; | |
| 47 final int port; | |
| 48 } | |
| 49 | |
| 50 class Launcher { | |
| 51 /// Launch [executable] with [arguments]. Returns a future to a [Launch] | |
| 52 /// which includes the process and port where Observatory is running. | |
| 53 static Future<Launch> launch(String executable, | |
| 54 List<String> arguments) async { | |
| 55 var process = await Process.start(executable, arguments); | |
| 56 | |
| 57 // Completer completes once 'Observatory listening on' message has been | |
| 58 // scraped and we know the port number. | |
| 59 var completer = new Completer(); | |
| 60 | |
| 61 process.stdout.transform(UTF8.decoder) | |
| 62 .transform(new LineSplitter()).listen((line) { | |
| 63 if (line.startsWith('Observatory listening on http://')) { | |
| 64 RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); | |
| 65 var port = portExp.firstMatch(line).group(1); | |
| 66 var portNumber = int.parse(port); | |
| 67 completer.complete(portNumber); | |
| 68 } else { | |
| 69 print(line); | |
| 70 } | |
| 71 }); | |
| 72 | |
| 73 process.stderr.transform(UTF8.decoder) | |
| 74 .transform(new LineSplitter()).listen((line) { | |
| 75 print(line); | |
| 76 }); | |
| 77 | |
|
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.
| |
| 78 var port = await completer.future; | |
| 79 return new Launch(executable, arguments, process, port); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 class ServiceHelper { | |
| 84 ServiceHelper(this.client) { | |
| 85 client.listen(_onData, | |
| 86 onError: _onError, | |
| 87 cancelOnError: true); | |
| 88 } | |
| 89 | |
| 90 Future<Map> invokeRPC(String method, [Map params]) async { | |
| 91 var key = _createKey(); | |
| 92 var request = JSON.encode({ | |
| 93 'jsonrpc': '2.0', | |
| 94 'method': method, | |
| 95 'params': params == null ? {} : params, | |
| 96 'id': key, | |
| 97 }); | |
| 98 client.add(request); | |
| 99 var completer = new Completer(); | |
| 100 _outstanding_requests[key] = completer; | |
| 101 print('-> $key ($method)'); | |
| 102 return completer.future; | |
| 103 } | |
| 104 | |
| 105 String _createKey() { | |
| 106 var key = '$_id'; | |
| 107 _id++; | |
| 108 return key; | |
| 109 } | |
| 110 | |
| 111 void _onData(String message) { | |
| 112 var response = JSON.decode(message); | |
| 113 var key = response['id']; | |
| 114 print('<- $key'); | |
| 115 var completer = _outstanding_requests.remove(key); | |
| 116 assert(completer != null); | |
| 117 var result = response['result']; | |
| 118 var error = response['error']; | |
| 119 if (error != null) { | |
| 120 assert(result == null); | |
| 121 completer.completeError(error); | |
| 122 } else { | |
| 123 assert(result != null); | |
| 124 completer.complete(result); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void _onError(error) { | |
| 129 print('WebSocket error: $error'); | |
| 130 } | |
| 131 | |
| 132 final WebSocket client; | |
| 133 final Map<String, Completer> _outstanding_requests = <String, Completer>{}; | |
| 134 var _id = 1; | |
| 135 } | |
| 136 | |
| 137 main(List<String> args) async { | |
| 138 var executable = args[0]; | |
| 139 var arguments = args.sublist(1); | |
| 140 | |
| 141 print('Launching $executable with $arguments'); | |
| 142 | |
| 143 var launch = await Launcher.launch(executable, arguments); | |
| 144 | |
| 145 print('Observatory is on port ${launch.port}'); | |
| 146 var serviceUrl = 'ws://127.0.0.1:${launch.port}/ws'; | |
| 147 | |
| 148 var client = await WebSocket.connect(serviceUrl); | |
| 149 print('Connected to $serviceUrl'); | |
| 150 | |
| 151 var helper = new ServiceHelper(client); | |
| 152 | |
| 153 // Invoke getVM RPC. Verify a valid repsonse. | |
| 154 var vm = await helper.invokeRPC('getVM'); | |
| 155 Expect.equals(vm['type'], 'VM'); | |
| 156 | |
| 157 // Invoke a bogus RPC. Expect an error. | |
| 158 bool errorCaught = false; | |
| 159 try { | |
| 160 var bad = await helper.invokeRPC('BARTSIMPSON'); | |
| 161 Expect.notExecuted(); | |
| 162 } catch (e) { | |
| 163 errorCaught = true; | |
| 164 // Map. | |
| 165 Expect.isMap(e); | |
| 166 // Has an error code. | |
| 167 Expect.isNotNull(e['code']); | |
| 168 } | |
| 169 Expect.equals(errorCaught, true); | |
| 170 | |
| 171 await client.close(); | |
| 172 print('Closed connection'); | |
| 173 | |
| 174 print('Finished.'); | |
| 175 launch.kill(); | |
| 176 } | |
| OLD | NEW |