| 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 _killRequested = false; |
| 40 this.process.exitCode.then(_checkKill); |
| 41 } |
| 42 |
| 43 void kill() { |
| 44 _killRequested = true; |
| 45 process.kill(); |
| 46 } |
| 47 |
| 48 void _checkKill(int exitCode) { |
| 49 if (!_killRequested) { |
| 50 throw 'Unexpected exit of testee. (exitCode = $exitCode)'; |
| 51 } |
| 52 } |
| 53 |
| 54 final String executable; |
| 55 final String arguments; |
| 56 final Process process; |
| 57 final int port; |
| 58 bool _killRequested; |
| 59 } |
| 60 |
| 61 class Launcher { |
| 62 /// Launch [executable] with [arguments]. Returns a future to a [Launch] |
| 63 /// which includes the process and port where Observatory is running. |
| 64 static Future<Launch> launch(String executable, |
| 65 List<String> arguments) async { |
| 66 var process = await Process.start(executable, arguments); |
| 67 |
| 68 // Completer completes once 'Observatory listening on' message has been |
| 69 // scraped and we know the port number. |
| 70 var completer = new Completer(); |
| 71 |
| 72 process.stdout.transform(UTF8.decoder) |
| 73 .transform(new LineSplitter()).listen((line) { |
| 74 if (line.startsWith('Observatory listening on http://')) { |
| 75 RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); |
| 76 var port = portExp.firstMatch(line).group(1); |
| 77 var portNumber = int.parse(port); |
| 78 completer.complete(portNumber); |
| 79 } else { |
| 80 print(line); |
| 81 } |
| 82 }); |
| 83 |
| 84 process.stderr.transform(UTF8.decoder) |
| 85 .transform(new LineSplitter()).listen((line) { |
| 86 print(line); |
| 87 }); |
| 88 |
| 89 var port = await completer.future; |
| 90 return new Launch(executable, arguments, process, port); |
| 91 } |
| 92 } |
| 93 |
| 94 class ServiceHelper { |
| 95 ServiceHelper(this.client) { |
| 96 client.listen(_onData, |
| 97 onError: _onError, |
| 98 cancelOnError: true); |
| 99 } |
| 100 |
| 101 Future<Map> invokeRPC(String method, [Map params]) async { |
| 102 var key = _createKey(); |
| 103 var request = JSON.encode({ |
| 104 'jsonrpc': '2.0', |
| 105 'method': method, |
| 106 'params': params == null ? {} : params, |
| 107 'id': key, |
| 108 }); |
| 109 client.add(request); |
| 110 var completer = new Completer(); |
| 111 _outstanding_requests[key] = completer; |
| 112 print('-> $key ($method)'); |
| 113 return completer.future; |
| 114 } |
| 115 |
| 116 String _createKey() { |
| 117 var key = '$_id'; |
| 118 _id++; |
| 119 return key; |
| 120 } |
| 121 |
| 122 void _onData(String message) { |
| 123 var response = JSON.decode(message); |
| 124 var key = response['id']; |
| 125 print('<- $key'); |
| 126 var completer = _outstanding_requests.remove(key); |
| 127 assert(completer != null); |
| 128 var result = response['result']; |
| 129 var error = response['error']; |
| 130 if (error != null) { |
| 131 assert(result == null); |
| 132 completer.completeError(error); |
| 133 } else { |
| 134 assert(result != null); |
| 135 completer.complete(result); |
| 136 } |
| 137 } |
| 138 |
| 139 void _onError(error) { |
| 140 print('WebSocket error: $error'); |
| 141 } |
| 142 |
| 143 final WebSocket client; |
| 144 final Map<String, Completer> _outstanding_requests = <String, Completer>{}; |
| 145 var _id = 1; |
| 146 } |
| 147 |
| 148 main(List<String> args) async { |
| 149 var executable = args[0]; |
| 150 var arguments = args.sublist(1); |
| 151 |
| 152 print('Launching $executable with $arguments'); |
| 153 |
| 154 var launch = await Launcher.launch(executable, arguments); |
| 155 |
| 156 print('Observatory is on port ${launch.port}'); |
| 157 var serviceUrl = 'ws://127.0.0.1:${launch.port}/ws'; |
| 158 |
| 159 var client = await WebSocket.connect(serviceUrl); |
| 160 print('Connected to $serviceUrl'); |
| 161 |
| 162 var helper = new ServiceHelper(client); |
| 163 |
| 164 // Invoke getVM RPC. Verify a valid repsonse. |
| 165 var vm = await helper.invokeRPC('getVM'); |
| 166 Expect.equals(vm['type'], 'VM'); |
| 167 |
| 168 // Invoke a bogus RPC. Expect an error. |
| 169 bool errorCaught = false; |
| 170 try { |
| 171 var bad = await helper.invokeRPC('BARTSIMPSON'); |
| 172 Expect.notExecuted(); |
| 173 } catch (e) { |
| 174 errorCaught = true; |
| 175 // Map. |
| 176 Expect.isMap(e); |
| 177 // Has an error code. |
| 178 Expect.isNotNull(e['code']); |
| 179 } |
| 180 Expect.equals(errorCaught, true); |
| 181 |
| 182 await client.close(); |
| 183 print('Closed connection'); |
| 184 |
| 185 print('Finished.'); |
| 186 launch.kill(); |
| 187 } |
| OLD | NEW |