| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library service_test_common; | 5 library service_test_common; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'package:observatory/models.dart' as M; | 8 import 'package:observatory/models.dart' as M; |
| 9 import 'package:observatory/service_common.dart'; | 9 import 'package:observatory/service_common.dart'; |
| 10 import 'package:unittest/unittest.dart'; | 10 import 'package:unittest/unittest.dart'; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 completeError(e); | 92 completeError(e); |
| 93 return pausedAtSyntheticBreakpoint.future; | 93 return pausedAtSyntheticBreakpoint.future; |
| 94 } | 94 } |
| 95 | 95 |
| 96 Breakpoint syntheticBreakpoint; | 96 Breakpoint syntheticBreakpoint; |
| 97 | 97 |
| 98 subscription = stream.listen((ServiceEvent event) async { | 98 subscription = stream.listen((ServiceEvent event) async { |
| 99 // Synthetic breakpoint add event. This is the first event we will | 99 // Synthetic breakpoint add event. This is the first event we will |
| 100 // receive. | 100 // receive. |
| 101 bool isAdd = (event.kind == ServiceEvent.kBreakpointAdded) && | 101 bool isAdd = (event.kind == ServiceEvent.kBreakpointAdded) && |
| 102 (event.breakpoint.isSyntheticAsyncContinuation) && | 102 (event.breakpoint.isSyntheticAsyncContinuation) && |
| 103 (event.owner == isolate); | 103 (event.owner == isolate); |
| 104 // Resume after synthetic breakpoint added. This is the second event | 104 // Resume after synthetic breakpoint added. This is the second event |
| 105 // we will recieve. | 105 // we will recieve. |
| 106 bool isResume = (event.kind == ServiceEvent.kResume) && | 106 bool isResume = (event.kind == ServiceEvent.kResume) && |
| 107 (syntheticBreakpoint != null) && | 107 (syntheticBreakpoint != null) && |
| 108 (event.owner == isolate); | 108 (event.owner == isolate); |
| 109 // Paused at synthetic breakpoint. This is the third event we will | 109 // Paused at synthetic breakpoint. This is the third event we will |
| 110 // receive. | 110 // receive. |
| 111 bool isPaused = (event.kind == ServiceEvent.kPauseBreakpoint) && | 111 bool isPaused = (event.kind == ServiceEvent.kPauseBreakpoint) && |
| 112 (syntheticBreakpoint != null) && | 112 (syntheticBreakpoint != null) && |
| 113 (event.breakpoint == syntheticBreakpoint); | 113 (event.breakpoint == syntheticBreakpoint); |
| 114 if (isAdd) { | 114 if (isAdd) { |
| 115 syntheticBreakpoint = event.breakpoint; | 115 syntheticBreakpoint = event.breakpoint; |
| 116 } else if (isResume) { | 116 } else if (isResume) {} else if (isPaused) { |
| 117 } else if (isPaused) { | |
| 118 pausedAtSyntheticBreakpoint.complete(isolate); | 117 pausedAtSyntheticBreakpoint.complete(isolate); |
| 119 syntheticBreakpoint = null; | 118 syntheticBreakpoint = null; |
| 120 cancelSubscription(); | 119 cancelSubscription(); |
| 121 } | 120 } |
| 122 }); | 121 }); |
| 123 | 122 |
| 124 // Issue the step OverAwait command. | 123 // Issue the step OverAwait command. |
| 125 try { | 124 try { |
| 126 await isolate.stepOverAsyncSuspension(); | 125 await isolate.stepOverAsyncSuspension(); |
| 127 } catch (e) { | 126 } catch (e) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 150 return false; | 149 return false; |
| 151 } | 150 } |
| 152 } | 151 } |
| 153 | 152 |
| 154 Future<Isolate> hasPausedFor(Isolate isolate, String kind) { | 153 Future<Isolate> hasPausedFor(Isolate isolate, String kind) { |
| 155 // Set up a listener to wait for breakpoint events. | 154 // Set up a listener to wait for breakpoint events. |
| 156 Completer completer = new Completer(); | 155 Completer completer = new Completer(); |
| 157 isolate.vm.getEventStream(VM.kDebugStream).then((stream) { | 156 isolate.vm.getEventStream(VM.kDebugStream).then((stream) { |
| 158 var subscription; | 157 var subscription; |
| 159 subscription = stream.listen((ServiceEvent event) { | 158 subscription = stream.listen((ServiceEvent event) { |
| 160 if ((isolate == event.isolate) && (event.kind == kind)) { | 159 if ((isolate == event.isolate) && (event.kind == kind)) { |
| 161 if (completer != null) { | 160 if (completer != null) { |
| 162 // Reload to update isolate.pauseEvent. | 161 // Reload to update isolate.pauseEvent. |
| 163 print('Paused with $kind'); | 162 print('Paused with $kind'); |
| 164 subscription.cancel(); | 163 subscription.cancel(); |
| 165 completer.complete(isolate.reload()); | 164 completer.complete(isolate.reload()); |
| 166 completer = null; | 165 completer = null; |
| 167 } | |
| 168 } | 166 } |
| 167 } |
| 169 }); | 168 }); |
| 170 | 169 |
| 171 // Pause may have happened before we subscribed. | 170 // Pause may have happened before we subscribed. |
| 172 isolate.reload().then((_) { | 171 isolate.reload().then((_) { |
| 173 if ((isolate.pauseEvent != null) && | 172 if ((isolate.pauseEvent != null) && |
| 174 isEventOfKind(isolate.pauseEvent, kind)) { | 173 isEventOfKind(isolate.pauseEvent, kind)) { |
| 175 // Already waiting at a breakpoint. | 174 // Already waiting at a breakpoint. |
| 176 if (completer != null) { | 175 if (completer != null) { |
| 177 print('Paused with $kind'); | 176 print('Paused with $kind'); |
| 178 subscription.cancel(); | 177 subscription.cancel(); |
| 179 completer.complete(isolate); | 178 completer.complete(isolate); |
| 180 completer = null; | 179 completer = null; |
| 181 } | 180 } |
| 182 } | 181 } |
| 183 }); | 182 }); |
| 184 }); | 183 }); |
| 185 | 184 |
| 186 return completer.future; // Will complete when breakpoint hit. | 185 return completer.future; // Will complete when breakpoint hit. |
| 187 } | 186 } |
| 188 | 187 |
| 189 Future<Isolate> hasStoppedAtBreakpoint(Isolate isolate) { | 188 Future<Isolate> hasStoppedAtBreakpoint(Isolate isolate) { |
| 190 return hasPausedFor(isolate, ServiceEvent.kPauseBreakpoint); | 189 return hasPausedFor(isolate, ServiceEvent.kPauseBreakpoint); |
| 191 } | 190 } |
| 192 | 191 |
| 193 Future<Isolate> hasStoppedPostRequest(Isolate isolate) { | 192 Future<Isolate> hasStoppedPostRequest(Isolate isolate) { |
| 194 return hasPausedFor(isolate, ServiceEvent.kPausePostRequest); | 193 return hasPausedFor(isolate, ServiceEvent.kPausePostRequest); |
| 195 } | 194 } |
| 196 | 195 |
| 197 Future<Isolate> hasStoppedWithUnhandledException(Isolate isolate) { | 196 Future<Isolate> hasStoppedWithUnhandledException(Isolate isolate) { |
| 198 return hasPausedFor(isolate, ServiceEvent.kPauseException); | 197 return hasPausedFor(isolate, ServiceEvent.kPauseException); |
| 199 } | 198 } |
| 200 | 199 |
| 201 Future<Isolate> hasStoppedAtExit(Isolate isolate) { | 200 Future<Isolate> hasStoppedAtExit(Isolate isolate) { |
| 202 return hasPausedFor(isolate, ServiceEvent.kPauseExit); | 201 return hasPausedFor(isolate, ServiceEvent.kPauseExit); |
| 203 } | 202 } |
| 204 | 203 |
| 205 Future<Isolate> hasPausedAtStart(Isolate isolate) { | 204 Future<Isolate> hasPausedAtStart(Isolate isolate) { |
| 206 return hasPausedFor(isolate, ServiceEvent.kPauseStart); | 205 return hasPausedFor(isolate, ServiceEvent.kPauseStart); |
| 207 } | 206 } |
| 208 | 207 |
| 209 Future<Isolate> markDartColonLibrariesDebuggable(Isolate isolate) async { | 208 Future<Isolate> markDartColonLibrariesDebuggable(Isolate isolate) async { |
| 210 await isolate.reload(); | 209 await isolate.reload(); |
| 211 for (Library lib in isolate.libraries) { | 210 for (Library lib in isolate.libraries) { |
| 212 await lib.load(); | 211 await lib.load(); |
| 213 if (lib.uri.startsWith('dart:') && | 212 if (lib.uri.startsWith('dart:') && !lib.uri.startsWith('dart:_')) { |
| 214 !lib.uri.startsWith('dart:_')) { | |
| 215 var setDebugParams = { | 213 var setDebugParams = { |
| 216 'libraryId': lib.id, | 214 'libraryId': lib.id, |
| 217 'isDebuggable': true, | 215 'isDebuggable': true, |
| 218 }; | 216 }; |
| 219 Map<String, dynamic> result = | 217 Map<String, dynamic> result = await isolate.invokeRpcNoUpgrade( |
| 220 await isolate.invokeRpcNoUpgrade('setLibraryDebuggable', | 218 'setLibraryDebuggable', setDebugParams); |
| 221 setDebugParams); | |
| 222 } | 219 } |
| 223 } | 220 } |
| 224 return isolate; | 221 return isolate; |
| 225 } | 222 } |
| 226 | 223 |
| 227 IsolateTest reloadSources([bool pause = false]) { | 224 IsolateTest reloadSources([bool pause = false]) { |
| 228 return (Isolate isolate) async { | 225 return (Isolate isolate) async { |
| 229 Map<String, dynamic> params = <String, dynamic>{ }; | 226 Map<String, dynamic> params = <String, dynamic>{}; |
| 230 if (pause == true) { | 227 if (pause == true) { |
| 231 params['pause'] = pause; | 228 params['pause'] = pause; |
| 232 } | 229 } |
| 233 return isolate.invokeRpc('reloadSources', params); | 230 return isolate.invokeRpc('reloadSources', params); |
| 234 }; | 231 }; |
| 235 } | 232 } |
| 236 | 233 |
| 237 // Currying is your friend. | 234 // Currying is your friend. |
| 238 IsolateTest setBreakpointAtLine(int line) { | 235 IsolateTest setBreakpointAtLine(int line) { |
| 239 return (Isolate isolate) async { | 236 return (Isolate isolate) async { |
| 240 print("Setting breakpoint for line $line"); | 237 print("Setting breakpoint for line $line"); |
| 241 Library lib = await isolate.rootLibrary.load(); | 238 Library lib = await isolate.rootLibrary.load(); |
| 242 Script script = lib.scripts.single; | 239 Script script = lib.scripts.single; |
| 243 | 240 |
| 244 Breakpoint bpt = await isolate.addBreakpoint(script, line); | 241 Breakpoint bpt = await isolate.addBreakpoint(script, line); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 272 for (Frame f in stack['frames']) { | 269 for (Frame f in stack['frames']) { |
| 273 sb.write(" $f [${await f.location.getLine()}]\n"); | 270 sb.write(" $f [${await f.location.getLine()}]\n"); |
| 274 } | 271 } |
| 275 throw sb.toString(); | 272 throw sb.toString(); |
| 276 } else { | 273 } else { |
| 277 print('Program is stopped at line: $line'); | 274 print('Program is stopped at line: $line'); |
| 278 } | 275 } |
| 279 }; | 276 }; |
| 280 } | 277 } |
| 281 | 278 |
| 282 | |
| 283 IsolateTest stoppedInFunction(String functionName, {bool contains: false}) { | 279 IsolateTest stoppedInFunction(String functionName, {bool contains: false}) { |
| 284 return (Isolate isolate) async { | 280 return (Isolate isolate) async { |
| 285 print("Checking we are in function: $functionName"); | 281 print("Checking we are in function: $functionName"); |
| 286 | 282 |
| 287 ServiceMap stack = await isolate.getStack(); | 283 ServiceMap stack = await isolate.getStack(); |
| 288 expect(stack.type, equals('Stack')); | 284 expect(stack.type, equals('Stack')); |
| 289 | 285 |
| 290 List<Frame> frames = stack['frames']; | 286 List<Frame> frames = stack['frames']; |
| 291 expect(frames.length, greaterThanOrEqualTo(1)); | 287 expect(frames.length, greaterThanOrEqualTo(1)); |
| 292 | 288 |
| 293 Frame topFrame = stack['frames'][0]; | 289 Frame topFrame = stack['frames'][0]; |
| 294 ServiceFunction function = await topFrame.function.load(); | 290 ServiceFunction function = await topFrame.function.load(); |
| 295 final bool matches = | 291 final bool matches = contains |
| 296 contains ? function.name.contains(functionName) : | 292 ? function.name.contains(functionName) |
| 297 function.name == functionName; | 293 : function.name == functionName; |
| 298 if (!matches) { | 294 if (!matches) { |
| 299 StringBuffer sb = new StringBuffer(); | 295 StringBuffer sb = new StringBuffer(); |
| 300 sb.write("Expected to be in function $functionName but " | 296 sb.write("Expected to be in function $functionName but " |
| 301 "actually in function ${function.name}"); | 297 "actually in function ${function.name}"); |
| 302 sb.write("\nFull stack trace:\n"); | 298 sb.write("\nFull stack trace:\n"); |
| 303 for (Frame f in stack['frames']) { | 299 for (Frame f in stack['frames']) { |
| 304 await f.function.load(); | 300 await f.function.load(); |
| 305 await (f.function.dartOwner as ServiceObject).load(); | 301 await (f.function.dartOwner as ServiceObject).load(); |
| 306 String name = f.function.name; | 302 String name = f.function.name; |
| 307 String ownerName = (f.function.dartOwner as ServiceObject).name; | 303 String ownerName = (f.function.dartOwner as ServiceObject).name; |
| 308 sb.write(" $f [$name] [$ownerName]\n"); | 304 sb.write(" $f [$name] [$ownerName]\n"); |
| 309 } | 305 } |
| 310 throw sb.toString(); | 306 throw sb.toString(); |
| 311 } else { | 307 } else { |
| 312 print('Program is stopped in function: $functionName'); | 308 print('Program is stopped in function: $functionName'); |
| 313 } | 309 } |
| 314 }; | 310 }; |
| 315 } | 311 } |
| 316 | 312 |
| 317 | |
| 318 Future<Isolate> resumeIsolate(Isolate isolate) { | 313 Future<Isolate> resumeIsolate(Isolate isolate) { |
| 319 Completer completer = new Completer(); | 314 Completer completer = new Completer(); |
| 320 isolate.vm.getEventStream(VM.kDebugStream).then((stream) { | 315 isolate.vm.getEventStream(VM.kDebugStream).then((stream) { |
| 321 var subscription; | 316 var subscription; |
| 322 subscription = stream.listen((ServiceEvent event) { | 317 subscription = stream.listen((ServiceEvent event) { |
| 323 if (event.kind == ServiceEvent.kResume) { | 318 if (event.kind == ServiceEvent.kResume) { |
| 324 subscription.cancel(); | 319 subscription.cancel(); |
| 325 completer.complete(); | 320 completer.complete(); |
| 326 } | 321 } |
| 327 }); | 322 }); |
| 328 }); | 323 }); |
| 329 isolate.resume(); | 324 isolate.resume(); |
| 330 return completer.future; | 325 return completer.future; |
| 331 } | 326 } |
| 332 | 327 |
| 333 | |
| 334 Future resumeAndAwaitEvent(Isolate isolate, stream, onEvent) async { | 328 Future resumeAndAwaitEvent(Isolate isolate, stream, onEvent) async { |
| 335 Completer completer = new Completer(); | 329 Completer completer = new Completer(); |
| 336 var sub; | 330 var sub; |
| 337 sub = await isolate.vm.listenEventStream( | 331 sub = await isolate.vm.listenEventStream(stream, (ServiceEvent event) { |
| 338 stream, | 332 var r = onEvent(event); |
| 339 (ServiceEvent event) { | 333 if (r is! Future) { |
| 340 var r = onEvent(event); | 334 r = new Future.value(r); |
| 341 if (r is! Future) { | 335 } |
| 342 r = new Future.value(r); | 336 r.then((x) => sub.cancel().then((_) { |
| 343 } | 337 completer.complete(); |
| 344 r.then((x) => sub.cancel().then((_) { | 338 })); |
| 345 completer.complete(); | 339 }); |
| 346 })); | |
| 347 }); | |
| 348 await isolate.resume(); | 340 await isolate.resume(); |
| 349 return completer.future; | 341 return completer.future; |
| 350 } | 342 } |
| 351 | 343 |
| 352 IsolateTest resumeIsolateAndAwaitEvent(stream, onEvent) { | 344 IsolateTest resumeIsolateAndAwaitEvent(stream, onEvent) { |
| 353 return (Isolate isolate) async => | 345 return (Isolate isolate) async => |
| 354 resumeAndAwaitEvent(isolate, stream, onEvent); | 346 resumeAndAwaitEvent(isolate, stream, onEvent); |
| 355 } | 347 } |
| 356 | 348 |
| 357 | |
| 358 Future<Isolate> stepOver(Isolate isolate) async { | 349 Future<Isolate> stepOver(Isolate isolate) async { |
| 359 await isolate.stepOver(); | 350 await isolate.stepOver(); |
| 360 return hasStoppedAtBreakpoint(isolate); | 351 return hasStoppedAtBreakpoint(isolate); |
| 361 } | 352 } |
| 362 | 353 |
| 363 Future<Isolate> stepInto(Isolate isolate) async { | 354 Future<Isolate> stepInto(Isolate isolate) async { |
| 364 await isolate.stepInto(); | 355 await isolate.stepInto(); |
| 365 return hasStoppedAtBreakpoint(isolate); | 356 return hasStoppedAtBreakpoint(isolate); |
| 366 } | 357 } |
| 367 | 358 |
| 368 Future<Isolate> stepOut(Isolate isolate) async { | 359 Future<Isolate> stepOut(Isolate isolate) async { |
| 369 await isolate.stepOut(); | 360 await isolate.stepOut(); |
| 370 return hasStoppedAtBreakpoint(isolate); | 361 return hasStoppedAtBreakpoint(isolate); |
| 371 } | 362 } |
| 372 | 363 |
| 373 | |
| 374 Future isolateIsRunning(Isolate isolate) async { | 364 Future isolateIsRunning(Isolate isolate) async { |
| 375 await isolate.reload(); | 365 await isolate.reload(); |
| 376 expect(isolate.running, true); | 366 expect(isolate.running, true); |
| 377 } | 367 } |
| 378 | 368 |
| 379 Future<Class> getClassFromRootLib(Isolate isolate, String className) async { | 369 Future<Class> getClassFromRootLib(Isolate isolate, String className) async { |
| 380 Library rootLib = await isolate.rootLibrary.load(); | 370 Library rootLib = await isolate.rootLibrary.load(); |
| 381 for (var i = 0; i < rootLib.classes.length; i++) { | 371 for (var i = 0; i < rootLib.classes.length; i++) { |
| 382 Class cls = rootLib.classes[i]; | 372 Class cls = rootLib.classes[i]; |
| 383 if (cls.name == className) { | 373 if (cls.name == className) { |
| 384 return cls; | 374 return cls; |
| 385 } | 375 } |
| 386 } | 376 } |
| 387 return null; | 377 return null; |
| 388 } | 378 } |
| 389 | 379 |
| 390 | 380 Future<Instance> rootLibraryFieldValue( |
| 391 Future<Instance> rootLibraryFieldValue(Isolate isolate, | 381 Isolate isolate, String fieldName) async { |
| 392 String fieldName) async { | |
| 393 Library rootLib = await isolate.rootLibrary.load(); | 382 Library rootLib = await isolate.rootLibrary.load(); |
| 394 Field field = rootLib.variables.singleWhere((v) => v.name == fieldName); | 383 Field field = rootLib.variables.singleWhere((v) => v.name == fieldName); |
| 395 await field.load(); | 384 await field.load(); |
| 396 Instance value = field.staticValue; | 385 Instance value = field.staticValue; |
| 397 await value.load(); | 386 await value.load(); |
| 398 return value; | 387 return value; |
| 399 } | 388 } |
| 400 | 389 |
| 401 IsolateTest runStepThroughProgramRecordingStops(List<String> recordStops) { | 390 IsolateTest runStepThroughProgramRecordingStops(List<String> recordStops) { |
| 402 return (Isolate isolate) async { | 391 return (Isolate isolate) async { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 432 ? recordStops.length | 421 ? recordStops.length |
| 433 : expectedStops.length; | 422 : expectedStops.length; |
| 434 for (int i = 0; i < end; ++i) { | 423 for (int i = 0; i < end; ++i) { |
| 435 expect(recordStops[i], expectedStops[i]); | 424 expect(recordStops[i], expectedStops[i]); |
| 436 } | 425 } |
| 437 | 426 |
| 438 expect(recordStops.length >= expectedStops.length, true, | 427 expect(recordStops.length >= expectedStops.length, true, |
| 439 reason: "Expects at least ${expectedStops.length} breaks."); | 428 reason: "Expects at least ${expectedStops.length} breaks."); |
| 440 }; | 429 }; |
| 441 } | 430 } |
| OLD | NEW |