| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library vmservice_test_helper; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 import 'dart:convert'; | |
| 9 import 'dart:io'; | |
| 10 import 'package:expect/expect.dart'; | |
| 11 | |
| 12 abstract class ServiceWebSocketRequestHelper { | |
| 13 final String url; | |
| 14 final Completer _completer = new Completer(); | |
| 15 WebSocket _socket; | |
| 16 | |
| 17 ServiceWebSocketRequestHelper(this.url); | |
| 18 | |
| 19 // Returns [this] when connected. | |
| 20 Future connect() { | |
| 21 return WebSocket.connect(url).then((ws) { | |
| 22 _socket = ws; | |
| 23 _socket.listen((message) { | |
| 24 var map = JSON.decode(message); | |
| 25 var response = JSON.decode(map['response']); | |
| 26 onResponse(map['seq'], response); | |
| 27 }); | |
| 28 return this; | |
| 29 }); | |
| 30 } | |
| 31 | |
| 32 void complete() { | |
| 33 _completer.complete(this); | |
| 34 } | |
| 35 | |
| 36 Future get completed => _completer.future; | |
| 37 | |
| 38 // Must call complete. | |
| 39 void onResponse(var seq, Map response); | |
| 40 void runTest(); | |
| 41 | |
| 42 Future sendMessage(var seq, String request) { | |
| 43 var map = { | |
| 44 'seq': seq, | |
| 45 'request': request | |
| 46 }; | |
| 47 var message = JSON.encode(map); | |
| 48 _socket.add(message); | |
| 49 return _completer.future; | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 abstract class VmServiceRequestHelper { | |
| 54 final Uri uri; | |
| 55 final HttpClient client; | |
| 56 | |
| 57 VmServiceRequestHelper(String url) : | |
| 58 uri = Uri.parse(url), | |
| 59 client = new HttpClient(); | |
| 60 | |
| 61 Future makeRequest() { | |
| 62 print('** GET: $uri'); | |
| 63 return client.getUrl(uri) | |
| 64 .then((HttpClientRequest request) => request.close()) | |
| 65 .then((HttpClientResponse response) { | |
| 66 return response | |
| 67 .fold(new BytesBuilder(), (b, d) => b..add(d)) | |
| 68 .then((builder) { | |
| 69 return _requestCompleted(builder.takeBytes(), response); | |
| 70 }); | |
| 71 }).catchError((error) { | |
| 72 onRequestFailed(error); | |
| 73 }); | |
| 74 } | |
| 75 | |
| 76 Future _requestCompleted(List<int> data, HttpClientResponse response) { | |
| 77 Expect.equals(200, response.statusCode, 'Invalid HTTP Status Code'); | |
| 78 var replyAsString; | |
| 79 try { | |
| 80 replyAsString = UTF8.decode(data); | |
| 81 } catch (e) { | |
| 82 onRequestFailed(e); | |
| 83 return null; | |
| 84 } | |
| 85 print('** Response: $replyAsString'); | |
| 86 var reply; | |
| 87 try { | |
| 88 reply = JSON.decode(replyAsString); | |
| 89 } catch (e, trace) { | |
| 90 onRequestFailed(e); | |
| 91 return null; | |
| 92 } | |
| 93 if (reply is! Map) { | |
| 94 onRequestFailed('Reply was not a map: $reply'); | |
| 95 return null; | |
| 96 } | |
| 97 if (reply['type'] == null) { | |
| 98 onRequestFailed('Reply does not contain a type key: $reply'); | |
| 99 return null; | |
| 100 } | |
| 101 var r; | |
| 102 try { | |
| 103 r = onRequestCompleted(reply); | |
| 104 } catch (e) { | |
| 105 r = onRequestFailed('Test callback failed: $e'); | |
| 106 } | |
| 107 return r; | |
| 108 } | |
| 109 | |
| 110 Future onRequestFailed(dynamic error) { | |
| 111 Expect.fail('Failed to make request: $error'); | |
| 112 } | |
| 113 | |
| 114 Future onRequestCompleted(Map response); | |
| 115 } | |
| 116 | |
| 117 class TestLauncher { | |
| 118 final String script; | |
| 119 Process process; | |
| 120 | |
| 121 TestLauncher(this.script); | |
| 122 | |
| 123 String get scriptPath { | |
| 124 var dartScript = Platform.script.toFilePath(); | |
| 125 var splitPoint = dartScript.lastIndexOf(Platform.pathSeparator); | |
| 126 var scriptDirectory = dartScript.substring(0, splitPoint); | |
| 127 return scriptDirectory + Platform.pathSeparator + script; | |
| 128 } | |
| 129 | |
| 130 Future<int> launch() { | |
| 131 String dartExecutable = Platform.executable; | |
| 132 print('** Launching $scriptPath'); | |
| 133 return Process.start(dartExecutable, | |
| 134 ['--enable-vm-service:0', scriptPath]).then((p) { | |
| 135 | |
| 136 Completer completer = new Completer(); | |
| 137 process = p; | |
| 138 var portNumber; | |
| 139 var blank; | |
| 140 var first = true; | |
| 141 process.stdout.transform(UTF8.decoder) | |
| 142 .transform(new LineSplitter()).listen((line) { | |
| 143 if (line.startsWith('Observatory listening on http://')) { | |
| 144 RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); | |
| 145 var port = portExp.firstMatch(line).group(1); | |
| 146 portNumber = int.parse(port); | |
| 147 } | |
| 148 if (line == '') { | |
| 149 // Received blank line. | |
| 150 blank = true; | |
| 151 } | |
| 152 if (portNumber != null && blank == true && first == true) { | |
| 153 completer.complete(portNumber); | |
| 154 // Stop repeat completions. | |
| 155 first = false; | |
| 156 print('** Signaled to run test queries on $portNumber'); | |
| 157 } | |
| 158 }); | |
| 159 process.stderr.transform(UTF8.decoder) | |
| 160 .transform(new LineSplitter()).listen((line) { | |
| 161 print(line); | |
| 162 }); | |
| 163 process.exitCode.then((code) { | |
| 164 Expect.equals(0, code, 'Launched dart executable exited with error.'); | |
| 165 }); | |
| 166 return completer.future; | |
| 167 }); | |
| 168 } | |
| 169 | |
| 170 void requestExit() { | |
| 171 print('** Requesting script to exit.'); | |
| 172 process.stdin.add([32, 13, 10]); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 class VMTester { | |
| 177 final Map vm; | |
| 178 | |
| 179 VMTester(this.vm) { | |
| 180 // The reply is a VM. | |
| 181 Expect.equals('VM', vm['type'], 'Not an VM.'); | |
| 182 } | |
| 183 | |
| 184 void checkIsolateCount(int n) { | |
| 185 Expect.equals(n, vm['isolates'].length, 'Isolate count not $n'); | |
| 186 } | |
| 187 | |
| 188 void checkIsolateIdExists(String id) { | |
| 189 var exists = false; | |
| 190 vm['isolates'].forEach((isolate) { | |
| 191 if (isolate['id'] == id) { | |
| 192 exists = true; | |
| 193 } | |
| 194 }); | |
| 195 Expect.isTrue(exists, 'No isolate with id: $id'); | |
| 196 } | |
| 197 | |
| 198 String getIsolateId(int index) { | |
| 199 return vm['isolates'][index]['id']; | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 class ClassTableHelper { | |
| 204 final Map classTable; | |
| 205 | |
| 206 ClassTableHelper(this.classTable) { | |
| 207 Expect.equals('ClassList', classTable['type'], 'Not a ClassTable.'); | |
| 208 } | |
| 209 | |
| 210 bool classExists(String name) { | |
| 211 List members = classTable['members']; | |
| 212 for (var i = 0; i < members.length; i++) { | |
| 213 Map klass = members[i]; | |
| 214 if (klass['name'] == name) { | |
| 215 return true; | |
| 216 } | |
| 217 } | |
| 218 return false; | |
| 219 } | |
| 220 | |
| 221 String classId(String name) { | |
| 222 List members = classTable['members']; | |
| 223 for (var i = 0; i < members.length; i++) { | |
| 224 Map klass = members[i]; | |
| 225 if (klass['name'] == name) { | |
| 226 return klass['id']; | |
| 227 } | |
| 228 } | |
| 229 return null; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 class FieldRequestHelper extends VmServiceRequestHelper { | |
| 234 FieldRequestHelper(port, isolate_id, field_id) : | |
| 235 super('http://127.0.0.1:$port/$isolate_id/$field_id'); | |
| 236 Map field; | |
| 237 onRequestCompleted(Map reply) { | |
| 238 Expect.equals('Field', reply['type']); | |
| 239 field = reply; | |
| 240 return new Future.value(this); | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 class ClassFieldRequestHelper extends VmServiceRequestHelper { | |
| 245 final List<String> fieldNames; | |
| 246 int port_; | |
| 247 String isolate_id_; | |
| 248 ClassFieldRequestHelper(port, isolate_id, class_id, this.fieldNames) : | |
| 249 super('http://127.0.0.1:$port/$isolate_id/$class_id') { | |
| 250 port_ = port; | |
| 251 isolate_id_ = isolate_id; | |
| 252 } | |
| 253 final Map<String, Map> fields = new Map<String, Map>(); | |
| 254 | |
| 255 onRequestCompleted(Map reply) { | |
| 256 Expect.equals('Class', reply['type']); | |
| 257 List<Map> class_fields = reply['fields']; | |
| 258 List<Future> requests = new List<Future>(); | |
| 259 fieldNames.forEach((fn) { | |
| 260 class_fields.forEach((f) { | |
| 261 if (f['name'] == fn) { | |
| 262 var request = new FieldRequestHelper(port_, isolate_id_, f['id']); | |
| 263 requests.add(request.makeRequest()); | |
| 264 } | |
| 265 }); | |
| 266 }); | |
| 267 return Future.wait(requests).then((a) { | |
| 268 a.forEach((FieldRequestHelper field) { | |
| 269 fields[field.field['name']] = field.field; | |
| 270 }); | |
| 271 return this; | |
| 272 }); | |
| 273 } | |
| 274 } | |
| OLD | NEW |