| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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 schedule; | 5 library schedule; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 import 'package:stack_trace/stack_trace.dart'; | 10 import 'package:stack_trace/stack_trace.dart'; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 Duration get timeout => _timeout; | 104 Duration get timeout => _timeout; |
| 105 Duration _timeout = new Duration(seconds: 5); | 105 Duration _timeout = new Duration(seconds: 5); |
| 106 set timeout(Duration duration) { | 106 set timeout(Duration duration) { |
| 107 _timeout = duration; | 107 _timeout = duration; |
| 108 heartbeat(); | 108 heartbeat(); |
| 109 } | 109 } |
| 110 | 110 |
| 111 /// The timer for keeping track of task timeouts. This may be null. | 111 /// The timer for keeping track of task timeouts. This may be null. |
| 112 Timer _timeoutTimer; | 112 Timer _timeoutTimer; |
| 113 | 113 |
| 114 /// If `true`, then new [Task]s will capture the current stack trace before | |
| 115 /// running. This can be set to `false` to speed up running tests since | |
| 116 /// capturing stack traces is currently quite slow. Even when set to `false`, | |
| 117 /// stack traces from *thrown* exceptions will be caught. This only disables | |
| 118 /// the eager collection of stack traces *before* an error occurs. Defaults | |
| 119 /// to `true`. | |
| 120 bool captureStackTraces = true; | |
| 121 | |
| 122 /// Creates a new schedule with empty task queues. | 114 /// Creates a new schedule with empty task queues. |
| 123 Schedule() { | 115 Schedule() { |
| 124 _tasks = new TaskQueue._("tasks", this); | 116 _tasks = new TaskQueue._("tasks", this); |
| 125 _onComplete = new TaskQueue._("onComplete", this); | 117 _onComplete = new TaskQueue._("onComplete", this); |
| 126 _onException = new TaskQueue._("onException", this); | 118 _onException = new TaskQueue._("onException", this); |
| 127 _currentQueue = _tasks; | 119 _currentQueue = _tasks; |
| 128 | 120 |
| 129 heartbeat(); | 121 heartbeat(); |
| 130 } | 122 } |
| 131 | 123 |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 | 339 |
| 348 /// A queue of asynchronous tasks to execute in order. | 340 /// A queue of asynchronous tasks to execute in order. |
| 349 class TaskQueue { | 341 class TaskQueue { |
| 350 /// The tasks in the queue. | 342 /// The tasks in the queue. |
| 351 List<Task> get contents => new UnmodifiableListView<Task>(_contents); | 343 List<Task> get contents => new UnmodifiableListView<Task>(_contents); |
| 352 final _contents = new Queue<Task>(); | 344 final _contents = new Queue<Task>(); |
| 353 | 345 |
| 354 /// The name of the queue, for debugging purposes. | 346 /// The name of the queue, for debugging purposes. |
| 355 final String name; | 347 final String name; |
| 356 | 348 |
| 357 /// If `true`, then new [Task]s in this queue will capture the current stack | |
| 358 /// trace before running. | |
| 359 bool get captureStackTraces => _schedule.captureStackTraces; | |
| 360 | |
| 361 /// The [Schedule] that created this queue. | 349 /// The [Schedule] that created this queue. |
| 362 final Schedule _schedule; | 350 final Schedule _schedule; |
| 363 | 351 |
| 364 /// An out-of-band error signaled by [_schedule]. If this is non-null, it | 352 /// An out-of-band error signaled by [_schedule]. If this is non-null, it |
| 365 /// indicates that the queue should stop as soon as possible and re-throw this | 353 /// indicates that the queue should stop as soon as possible and re-throw this |
| 366 /// error. | 354 /// error. |
| 367 ScheduleError _error; | 355 ScheduleError _error; |
| 368 | 356 |
| 369 /// The [SubstituteFuture] for the currently-running task in the queue, or | 357 /// The [SubstituteFuture] for the currently-running task in the queue, or |
| 370 /// null if no task is currently running. | 358 /// null if no task is currently running. |
| 371 SubstituteFuture _taskFuture; | 359 SubstituteFuture _taskFuture; |
| 372 | 360 |
| 373 /// The toal number of out-of-band callbacks that have been registered on | 361 /// The toal number of out-of-band callbacks that have been registered on |
| 374 /// [this]. | 362 /// [this]. |
| 375 int _totalCallbacks = 0; | 363 int _totalCallbacks = 0; |
| 376 | 364 |
| 377 /// Whether to stop running after the current task. | 365 /// Whether to stop running after the current task. |
| 378 bool _aborted = false; | 366 bool _aborted = false; |
| 379 | 367 |
| 380 /// The descriptions of all callbacks that are blocking the completion of | 368 /// The descriptions of all callbacks that are blocking the completion of |
| 381 /// [this]. | 369 /// [this]. |
| 382 List<String> get pendingCallbacks => | 370 List<PendingCallback> get pendingCallbacks => |
| 383 new UnmodifiableListView<String>(_pendingCallbacks); | 371 new UnmodifiableListView<PendingCallback>(_pendingCallbacks); |
| 384 final _pendingCallbacks = new Queue<String>(); | 372 final _pendingCallbacks = new Queue<PendingCallback>(); |
| 385 | 373 |
| 386 /// A completer that will be completed once [_pendingCallbacks] becomes empty | 374 /// A completer that will be completed once [_pendingCallbacks] becomes empty |
| 387 /// after the queue finishes running its tasks. | 375 /// after the queue finishes running its tasks. |
| 388 Future get _noPendingCallbacks => _noPendingCallbacksCompleter.future; | 376 Future get _noPendingCallbacks => _noPendingCallbacksCompleter.future; |
| 389 final Completer _noPendingCallbacksCompleter = new Completer(); | 377 final Completer _noPendingCallbacksCompleter = new Completer(); |
| 390 | 378 |
| 391 /// A [Future] that completes when the tasks in [this] are all complete. If an | 379 /// A [Future] that completes when the tasks in [this] are all complete. If an |
| 392 /// error occurs while running this queue, the returned [Future] will complete | 380 /// error occurs while running this queue, the returned [Future] will complete |
| 393 /// with that error. | 381 /// with that error. |
| 394 /// | 382 /// |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 /// chain. This will also block [this] from completing until the returned | 486 /// chain. This will also block [this] from completing until the returned |
| 499 /// function has been called. It's used to ensure that out-of-band callbacks | 487 /// function has been called. It's used to ensure that out-of-band callbacks |
| 500 /// are properly handled by the scheduled test. | 488 /// are properly handled by the scheduled test. |
| 501 Function _wrapAsync(fn(arg), String description) { | 489 Function _wrapAsync(fn(arg), String description) { |
| 502 assert(_schedule.state == ScheduleState.SET_UP || isRunning); | 490 assert(_schedule.state == ScheduleState.SET_UP || isRunning); |
| 503 | 491 |
| 504 // It's possible that the queue timed out before [fn] finished. | 492 // It's possible that the queue timed out before [fn] finished. |
| 505 bool _timedOut() => | 493 bool _timedOut() => |
| 506 _schedule.currentQueue != this || pendingCallbacks.isEmpty; | 494 _schedule.currentQueue != this || pendingCallbacks.isEmpty; |
| 507 | 495 |
| 508 if (description == null) { | 496 _totalCallbacks++; |
| 509 description = "Out-of-band operation #${_totalCallbacks}"; | 497 var trace = new Trace.current(); |
| 510 } | 498 var pendingCallback = new PendingCallback._(() { |
| 499 var fullDescription = description; |
| 500 if (fullDescription == null) { |
| 501 fullDescription = "Out-of-band operation #${_totalCallbacks}"; |
| 502 } |
| 511 | 503 |
| 512 if (captureStackTraces) { | 504 var stackString = prefixLines(terseTraceString(trace)); |
| 513 var stackString = prefixLines(terseTraceString(new Trace.current())); | 505 fullDescription += "\n\nStack trace:\n$stackString"; |
| 514 description += "\n\nStack trace:\n$stackString"; | 506 }); |
| 515 } | 507 _pendingCallbacks.add(pendingCallback); |
| 516 | 508 |
| 517 _totalCallbacks++; | |
| 518 | |
| 519 _pendingCallbacks.add(description); | |
| 520 return (arg) { | 509 return (arg) { |
| 521 try { | 510 try { |
| 522 return fn(arg); | 511 return fn(arg); |
| 523 } catch (e, stackTrace) { | 512 } catch (e, stackTrace) { |
| 524 var error = new ScheduleError.from( | 513 var error = new ScheduleError.from( |
| 525 _schedule, e, stackTrace: stackTrace); | 514 _schedule, e, stackTrace: stackTrace); |
| 526 if (_timedOut()) { | 515 if (_timedOut()) { |
| 527 _schedule._signalPostTimeoutError(error); | 516 _schedule._signalPostTimeoutError(error); |
| 528 } else { | 517 } else { |
| 529 _schedule.signalError(error); | 518 _schedule.signalError(error); |
| 530 } | 519 } |
| 531 } finally { | 520 } finally { |
| 532 if (_timedOut()) return; | 521 if (_timedOut()) return; |
| 533 | 522 |
| 534 _pendingCallbacks.remove(description); | 523 _pendingCallbacks.remove(pendingCallback); |
| 535 if (_pendingCallbacks.isEmpty && !isRunningTasks) { | 524 if (_pendingCallbacks.isEmpty && !isRunningTasks) { |
| 536 _noPendingCallbacksCompleter.complete(); | 525 _noPendingCallbacksCompleter.complete(); |
| 537 } | 526 } |
| 538 } | 527 } |
| 539 }; | 528 }; |
| 540 } | 529 } |
| 541 | 530 |
| 542 /// Signals that an out-of-band error has been detected and the queue should | 531 /// Signals that an out-of-band error has been detected and the queue should |
| 543 /// stop running as soon as possible. | 532 /// stop running as soon as possible. |
| 544 void _signalError(ScheduleError error) { | 533 void _signalError(ScheduleError error) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 return prefixLines(childString, | 587 return prefixLines(childString, |
| 599 firstPrefix: " $prefix ", prefix: " | "); | 588 firstPrefix: " $prefix ", prefix: " | "); |
| 600 }).join('\n'); | 589 }).join('\n'); |
| 601 taskString = '$taskString\n$childrenString'; | 590 taskString = '$taskString\n$childrenString'; |
| 602 } | 591 } |
| 603 | 592 |
| 604 return taskString; | 593 return taskString; |
| 605 }).join("\n"); | 594 }).join("\n"); |
| 606 } | 595 } |
| 607 } | 596 } |
| 597 |
| 598 /// A thunk for lazily resolving the description of a [PendingCallback]. |
| 599 typedef String _DescriptionThunk(); |
| 600 |
| 601 /// An identifier for an out-of-band callback running during a schedule. |
| 602 class PendingCallback { |
| 603 final _DescriptionThunk _thunk; |
| 604 String _description; |
| 605 |
| 606 /// The string description of the callback. |
| 607 String get description { |
| 608 if (_description == null) _description = _thunk(); |
| 609 return _description; |
| 610 } |
| 611 |
| 612 String toString() => description; |
| 613 |
| 614 PendingCallback._(this._thunk); |
| 615 } |
| OLD | NEW |