OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 | 6 |
7 import 'package:async/async.dart'; | 7 import 'package:async/async.dart'; |
| 8 import 'package:json_rpc_2/json_rpc_2.dart' as rpc; |
8 import 'package:test/test.dart'; | 9 import 'package:test/test.dart'; |
9 import 'package:vm_service_client/vm_service_client.dart'; | 10 import 'package:vm_service_client/vm_service_client.dart'; |
10 | 11 |
11 import 'utils.dart'; | 12 import 'utils.dart'; |
12 | 13 |
13 VMServiceClient client; | 14 VMServiceClient client; |
14 | 15 |
15 void main() { | 16 void main() { |
16 tearDown(() { | 17 tearDown(() { |
17 if (client != null) client.close(); | 18 if (client != null) client.close(); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 try { | 159 try { |
159 await other.load(); | 160 await other.load(); |
160 } on VMSentinelException catch (_) { | 161 } on VMSentinelException catch (_) { |
161 break; | 162 break; |
162 } | 163 } |
163 } | 164 } |
164 | 165 |
165 expect(other.onExit, completes); | 166 expect(other.onExit, completes); |
166 }); | 167 }); |
167 }); | 168 }); |
| 169 |
| 170 test("onServiceExtensionAdded fires when an extension is added", () async { |
| 171 client = await runAndConnect(main: """ |
| 172 registerExtension('ext.test', (_, __) {}); |
| 173 """, flags: ["--pause-isolates-on-start"]); |
| 174 |
| 175 var isolate = await (await client.getVM()).isolates.first.loadRunnable(); |
| 176 await isolate.waitUntilPaused(); |
| 177 await isolate.resume(); |
| 178 |
| 179 String ext = await isolate.onServiceExtensionAdded.first; |
| 180 expect(ext, 'ext.test'); |
| 181 }); |
| 182 |
| 183 group("onExtensionEvent", () { |
| 184 test("emits extension events", () async { |
| 185 client = await runAndConnect(main: """ |
| 186 postEvent('foo', {'bar': 'baz'}); |
| 187 """, flags: ["--pause-isolates-on-start"]); |
| 188 |
| 189 var isolate = await (await client.getVM()).isolates.first.load(); |
| 190 await isolate.waitUntilPaused(); |
| 191 var eventFuture = _onlyEvent(isolate.onExtensionEvent); |
| 192 await isolate.resume(); |
| 193 |
| 194 var event = await eventFuture; |
| 195 expect(event.kind, 'foo'); |
| 196 expect(event.data, {'bar': 'baz'}); |
| 197 }); |
| 198 }); |
| 199 |
| 200 group("selectExtensionEvents", () { |
| 201 test("chooses by extension kind", () async { |
| 202 client = await runAndConnect(main: """ |
| 203 postEvent('foo', {'prefixed': false}); |
| 204 postEvent('bar.baz', {'prefixed': true}); |
| 205 postEvent('not.captured', {}); |
| 206 """, flags: ["--pause-isolates-on-start"]); |
| 207 |
| 208 var isolate = await (await client.getVM()).isolates.first.load(); |
| 209 |
| 210 var unprefixedEvent = _onlyEvent(isolate.selectExtensionEvents('foo')); |
| 211 var prefixedEvent = |
| 212 _onlyEvent(isolate.selectExtensionEvents('bar.', prefix: true)); |
| 213 |
| 214 await isolate.waitUntilPaused(); |
| 215 await isolate.resume(); |
| 216 |
| 217 expect((await unprefixedEvent).kind, 'foo'); |
| 218 expect((await prefixedEvent).kind, 'bar.baz'); |
| 219 }); |
| 220 }); |
168 }); | 221 }); |
169 | 222 |
| 223 group("waitForExtension", () { |
| 224 test("notifies when the extension is already registered", () async { |
| 225 client = await runAndConnect(main: """ |
| 226 registerExtension('ext.test', (_, __) {}); |
| 227 postEvent('registered', {}); |
| 228 """, flags: ["--pause-isolates-on-start"]); |
| 229 |
| 230 var isolate = await (await client.getVM()).isolates.first.load(); |
| 231 await isolate.waitUntilPaused(); |
| 232 var whenRegistered = isolate.selectExtensionEvents('registered').first; |
| 233 await isolate.resume(); |
| 234 await whenRegistered; |
| 235 expect(isolate.waitForExtension('ext.test'), completes); |
| 236 }); |
| 237 |
| 238 test("notifies when the extension is registered later", () async { |
| 239 client = await runAndConnect(main: """ |
| 240 registerExtension('ext.one', (_, __) { |
| 241 registerExtension('ext.two', (_, __) { |
| 242 return new ServiceExtensionResponse.result('''{ |
| 243 "ext.two": "is ok" |
| 244 }'''); |
| 245 }); |
| 246 }); |
| 247 """); |
| 248 |
| 249 var isolate = await (await client.getVM()).isolates.first.load(); |
| 250 isolate.waitForExtension('ext.two').then(expectAsync((_) async { |
| 251 expect(await isolate.invokeExtension('ext.two'), { |
| 252 'ext.two': 'is ok', |
| 253 }); |
| 254 })); |
| 255 |
| 256 await isolate.waitForExtension('ext.one'); |
| 257 isolate.invokeExtension('ext.one'); |
| 258 }); |
| 259 }); |
| 260 |
| 261 group("load", () { |
| 262 test("loads extensionRpcs", () async { |
| 263 client = await runAndConnect(main: """ |
| 264 registerExtension('ext.foo', (_, __) {}); |
| 265 registerExtension('ext.bar', (_, __) {}); |
| 266 """); |
| 267 |
| 268 var isolate = await (await client.getVM()).isolates.first.load(); |
| 269 expect(isolate.extensionRpcs, unorderedEquals(['ext.foo', 'ext.bar'])); |
| 270 }); |
| 271 }); |
| 272 |
170 group("loadRunnable", () { | 273 group("loadRunnable", () { |
171 test("for an unrunnable isolate", () async { | 274 test("for an unrunnable isolate", () async { |
172 client = await runAndConnect(flags: ["--pause-isolates-on-start"]); | 275 client = await runAndConnect(flags: ["--pause-isolates-on-start"]); |
173 | 276 |
174 var isolate = (await client.getVM()).isolates.first; | 277 var isolate = (await client.getVM()).isolates.first; |
175 expect(isolate, isNot(new isInstanceOf<VMRunnableIsolate>())); | 278 expect(isolate, isNot(new isInstanceOf<VMRunnableIsolate>())); |
176 | 279 |
177 isolate = await isolate.loadRunnable(); | 280 isolate = await isolate.loadRunnable(); |
178 expect(isolate.rootLibrary, isNotNull); | 281 expect(isolate.rootLibrary, isNotNull); |
179 }); | 282 }); |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 test("works before the isolate is runnable", () async { | 471 test("works before the isolate is runnable", () async { |
369 client = await runAndConnect(flags: ['--pause-isolates-on-start']); | 472 client = await runAndConnect(flags: ['--pause-isolates-on-start']); |
370 | 473 |
371 // We should be able to set a breakpoint before the relevant library is | 474 // We should be able to set a breakpoint before the relevant library is |
372 // loaded, although it may fail to resolve if the line number is bogus. | 475 // loaded, although it may fail to resolve if the line number is bogus. |
373 var isolate = (await client.getVM()).isolates.first; | 476 var isolate = (await client.getVM()).isolates.first; |
374 var breakpoint = await isolate.addBreakpoint('my/script.dart', 0); | 477 var breakpoint = await isolate.addBreakpoint('my/script.dart', 0); |
375 expect(breakpoint.number, equals(1)); | 478 expect(breakpoint.number, equals(1)); |
376 }); | 479 }); |
377 }); | 480 }); |
| 481 |
| 482 group("invokeExtension", () { |
| 483 test("enforces ext. prefix", () async { |
| 484 var client = await runAndConnect(); |
| 485 var isolate = await (await client.getVM()).isolates.first.loadRunnable(); |
| 486 expect(() => isolate.invokeExtension('noprefix'), throwsArgumentError); |
| 487 }); |
| 488 |
| 489 test("invokes extension", () async { |
| 490 var client = await runAndConnect(main: r""" |
| 491 registerExtension('ext.ping', (_, __) async { |
| 492 return new ServiceExtensionResponse.result('{"type": "pong"}'); |
| 493 }); |
| 494 """); |
| 495 |
| 496 var isolate = await (await client.getVM()).isolates.first.loadRunnable(); |
| 497 var response = await isolate.invokeExtension('ext.ping'); |
| 498 expect(response, {'type': 'pong'}); |
| 499 }); |
| 500 |
| 501 test("passes parameters", () async { |
| 502 var client = await runAndConnect(main: r""" |
| 503 registerExtension('ext.params', (_, params) async { |
| 504 return new ServiceExtensionResponse.result('''{ |
| 505 "foo": "${params['foo']}" |
| 506 }'''); |
| 507 }); |
| 508 """); |
| 509 |
| 510 var isolate = await (await client.getVM()).isolates.first.loadRunnable(); |
| 511 var response = await isolate.invokeExtension('ext.params', { |
| 512 'foo': 'bar', |
| 513 }); |
| 514 expect(response, { |
| 515 'foo': 'bar', |
| 516 }); |
| 517 }); |
| 518 |
| 519 test("returns errors", () async { |
| 520 var client = await runAndConnect(main: r""" |
| 521 registerExtension('ext.error', (_, __) async { |
| 522 return new ServiceExtensionResponse.error(-32013, 'some error'); |
| 523 }); |
| 524 """); |
| 525 |
| 526 var isolate = await (await client.getVM()).isolates.first.loadRunnable(); |
| 527 await isolate.invokeExtension('ext.error') |
| 528 .then(expectAsync((_) {}, count: 0)) |
| 529 .catchError(expectAsync((rpc.RpcException error) { |
| 530 expect(error.code, -32013); |
| 531 expect(error.data, {'details': 'some error'}); |
| 532 })); |
| 533 }); |
| 534 }); |
378 } | 535 } |
379 | 536 |
380 /// Starts a client with two unpaused empty isolates. | 537 /// Starts a client with two unpaused empty isolates. |
381 Future<List<VMRunnableIsolate>> _twoIsolates() async { | 538 Future<List<VMRunnableIsolate>> _twoIsolates() async { |
382 client = await runAndConnect(topLevel: r""" | 539 client = await runAndConnect(topLevel: r""" |
383 void otherIsolate(_) {} | 540 void otherIsolate(_) {} |
384 """, main: r""" | 541 """, main: r""" |
385 Isolate.spawn(otherIsolate, null); | 542 Isolate.spawn(otherIsolate, null); |
386 """, flags: ["--pause-isolates-on-start", "--pause-isolates-on-exit"]); | 543 """, flags: ["--pause-isolates-on-start", "--pause-isolates-on-exit"]); |
387 | 544 |
388 var vm = await client.getVM(); | 545 var vm = await client.getVM(); |
389 var main = vm.isolates.first; | 546 var main = vm.isolates.first; |
390 | 547 |
391 var otherFuture = client.onIsolateRunnable.first; | 548 var otherFuture = client.onIsolateRunnable.first; |
392 await main.resume(); | 549 await main.resume(); |
393 var other = await otherFuture; | 550 var other = await otherFuture; |
394 await other.resume(); | 551 await other.resume(); |
395 | 552 |
396 return [main, other]; | 553 return [main, other]; |
397 } | 554 } |
| 555 |
| 556 Future _onlyEvent(Stream stream) { |
| 557 var completer = new Completer.sync(); |
| 558 stream.listen(expectAsync(completer.complete, count: 1), |
| 559 onError: registerException, |
| 560 onDone: () { |
| 561 if (completer.isCompleted) return; |
| 562 throw "Expected an event."; |
| 563 }); |
| 564 |
| 565 // Hack to cause the test to stick around long enough to receive all events |
| 566 // from the VM service. |
| 567 expect(new Future.delayed(new Duration(milliseconds: 200)), completes); |
| 568 return completer.future; |
| 569 } |
OLD | NEW |