| 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 library test.backend.invoker; | 5 library test.backend.invoker; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:stack_trace/stack_trace.dart'; | 9 import 'package:stack_trace/stack_trace.dart'; |
| 10 | 10 |
| 11 import '../frontend/expect.dart'; | 11 import '../frontend/expect.dart'; |
| 12 import '../utils.dart'; | 12 import '../utils.dart'; |
| 13 import 'closed_exception.dart'; | 13 import 'closed_exception.dart'; |
| 14 import 'live_test.dart'; | 14 import 'live_test.dart'; |
| 15 import 'live_test_controller.dart'; | 15 import 'live_test_controller.dart'; |
| 16 import 'metadata.dart'; | 16 import 'metadata.dart'; |
| 17 import 'operating_system.dart'; |
| 17 import 'outstanding_callback_counter.dart'; | 18 import 'outstanding_callback_counter.dart'; |
| 18 import 'state.dart'; | 19 import 'state.dart'; |
| 19 import 'suite.dart'; | 20 import 'suite.dart'; |
| 20 import 'test.dart'; | 21 import 'test.dart'; |
| 22 import 'test_platform.dart'; |
| 21 | 23 |
| 22 /// A test in this isolate. | 24 /// A test in this isolate. |
| 23 class LocalTest implements Test { | 25 class LocalTest extends Test { |
| 24 final String name; | 26 final String name; |
| 25 final Metadata metadata; | 27 final Metadata metadata; |
| 26 | 28 |
| 27 /// The test body. | 29 /// The test body. |
| 28 final AsyncFunction _body; | 30 final AsyncFunction _body; |
| 29 | 31 |
| 30 LocalTest(this.name, this.metadata, body()) | 32 LocalTest(this.name, this.metadata, body()) |
| 31 : _body = body; | 33 : _body = body; |
| 32 | 34 |
| 33 /// Loads a single runnable instance of this test. | 35 /// Loads a single runnable instance of this test. |
| 34 LiveTest load(Suite suite) { | 36 LiveTest load(Suite suite) { |
| 35 var invoker = new Invoker._(suite, this); | 37 var invoker = new Invoker._(suite, this); |
| 36 return invoker.liveTest; | 38 return invoker.liveTest; |
| 37 } | 39 } |
| 38 | 40 |
| 39 Test change({String name, Metadata metadata}) { | 41 Test forPlatform(TestPlatform platform, {OperatingSystem os}) { |
| 40 if (name == name && metadata == this.metadata) return this; | 42 if (!metadata.testOn.evaluate(platform, os: os)) return null; |
| 41 if (name == null) name = this.name; | 43 return new LocalTest(name, metadata.forPlatform(platform, os: os), _body); |
| 42 if (metadata == null) metadata = this.metadata; | |
| 43 return new LocalTest(name, metadata, _body); | |
| 44 } | 44 } |
| 45 } | 45 } |
| 46 | 46 |
| 47 /// The class responsible for managing the lifecycle of a single local test. | 47 /// The class responsible for managing the lifecycle of a single local test. |
| 48 /// | 48 /// |
| 49 /// The current invoker is accessible within the zone scope of the running test | 49 /// The current invoker is accessible within the zone scope of the running test |
| 50 /// using [Invoker.current]. It's used to track asynchronous callbacks and | 50 /// using [Invoker.current]. It's used to track asynchronous callbacks and |
| 51 /// report asynchronous errors. | 51 /// report asynchronous errors. |
| 52 class Invoker { | 52 class Invoker { |
| 53 /// The live test being driven by the invoker. | 53 /// The live test being driven by the invoker. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 76 Future get onClose => _closable | 76 Future get onClose => _closable |
| 77 ? _onCloseCompleter.future | 77 ? _onCloseCompleter.future |
| 78 // If we're in an unclosable block, return a future that will never | 78 // If we're in an unclosable block, return a future that will never |
| 79 // complete. | 79 // complete. |
| 80 : new Completer().future; | 80 : new Completer().future; |
| 81 final _onCloseCompleter = new Completer(); | 81 final _onCloseCompleter = new Completer(); |
| 82 | 82 |
| 83 /// The test being run. | 83 /// The test being run. |
| 84 LocalTest get _test => liveTest.test as LocalTest; | 84 LocalTest get _test => liveTest.test as LocalTest; |
| 85 | 85 |
| 86 /// The test metadata merged with the suite metadata. | |
| 87 final Metadata metadata; | |
| 88 | |
| 89 /// The outstanding callback counter for the current zone. | 86 /// The outstanding callback counter for the current zone. |
| 90 OutstandingCallbackCounter get _outstandingCallbacks { | 87 OutstandingCallbackCounter get _outstandingCallbacks { |
| 91 var counter = Zone.current[_counterKey]; | 88 var counter = Zone.current[_counterKey]; |
| 92 if (counter != null) return counter; | 89 if (counter != null) return counter; |
| 93 throw new StateError("Can't add or remove outstanding callbacks outside " | 90 throw new StateError("Can't add or remove outstanding callbacks outside " |
| 94 "of a test body."); | 91 "of a test body."); |
| 95 } | 92 } |
| 96 | 93 |
| 97 /// An opaque object used as a key in the zone value map to identify | 94 /// An opaque object used as a key in the zone value map to identify |
| 98 /// [_outstandingCallbacks]. | 95 /// [_outstandingCallbacks]. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 113 /// | 110 /// |
| 114 /// Tracking this ensures that [_timeoutTimer] isn't created in a | 111 /// Tracking this ensures that [_timeoutTimer] isn't created in a |
| 115 /// timer-mocking zone created by the test. | 112 /// timer-mocking zone created by the test. |
| 116 Zone _invokerZone; | 113 Zone _invokerZone; |
| 117 | 114 |
| 118 /// The timer for tracking timeouts. | 115 /// The timer for tracking timeouts. |
| 119 /// | 116 /// |
| 120 /// This will be `null` until the test starts running. | 117 /// This will be `null` until the test starts running. |
| 121 Timer _timeoutTimer; | 118 Timer _timeoutTimer; |
| 122 | 119 |
| 123 Invoker._(Suite suite, LocalTest test) | 120 Invoker._(Suite suite, LocalTest test) { |
| 124 : metadata = suite.metadata.merge(test.metadata) { | |
| 125 _controller = new LiveTestController( | 121 _controller = new LiveTestController( |
| 126 suite, test, _onRun, _onCloseCompleter.complete); | 122 suite, test, _onRun, _onCloseCompleter.complete); |
| 127 } | 123 } |
| 128 | 124 |
| 129 /// Tells the invoker that there's a callback running that it should wait for | 125 /// Tells the invoker that there's a callback running that it should wait for |
| 130 /// before considering the test successful. | 126 /// before considering the test successful. |
| 131 /// | 127 /// |
| 132 /// Each call to [addOutstandingCallback] should be followed by a call to | 128 /// Each call to [addOutstandingCallback] should be followed by a call to |
| 133 /// [removeOutstandingCallback] once the callbak is no longer running. Note | 129 /// [removeOutstandingCallback] once the callbak is no longer running. Note |
| 134 /// that only successful tests wait for outstanding callbacks; as soon as a | 130 /// that only successful tests wait for outstanding callbacks; as soon as a |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 } | 194 } |
| 199 | 195 |
| 200 /// Notifies the invoker that progress is being made. | 196 /// Notifies the invoker that progress is being made. |
| 201 /// | 197 /// |
| 202 /// Each heartbeat resets the timeout timer. This helps ensure that | 198 /// Each heartbeat resets the timeout timer. This helps ensure that |
| 203 /// long-running tests that still make progress don't time out. | 199 /// long-running tests that still make progress don't time out. |
| 204 void heartbeat() { | 200 void heartbeat() { |
| 205 if (liveTest.isComplete) return; | 201 if (liveTest.isComplete) return; |
| 206 if (_timeoutTimer != null) _timeoutTimer.cancel(); | 202 if (_timeoutTimer != null) _timeoutTimer.cancel(); |
| 207 | 203 |
| 208 var timeout = metadata.timeout.apply(new Duration(seconds: 30)); | 204 var timeout = liveTest.test.metadata.timeout |
| 205 .apply(new Duration(seconds: 30)); |
| 209 if (timeout == null) return; | 206 if (timeout == null) return; |
| 210 _timeoutTimer = _invokerZone.createTimer(timeout, | 207 _timeoutTimer = _invokerZone.createTimer(timeout, |
| 211 Zone.current.bindCallback(() { | 208 Zone.current.bindCallback(() { |
| 212 if (liveTest.isComplete) return; | 209 if (liveTest.isComplete) return; |
| 213 _handleError( | 210 _handleError( |
| 214 new TimeoutException( | 211 new TimeoutException( |
| 215 "Test timed out after ${niceDuration(timeout)}.", timeout)); | 212 "Test timed out after ${niceDuration(timeout)}.", timeout)); |
| 216 })); | 213 })); |
| 217 } | 214 } |
| 218 | 215 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 // outstanding callback counters at once. | 277 // outstanding callback counters at once. |
| 281 _counterKey: outstandingCallbacksForBody, | 278 _counterKey: outstandingCallbacksForBody, |
| 282 _closableKey: true | 279 _closableKey: true |
| 283 }, | 280 }, |
| 284 zoneSpecification: new ZoneSpecification( | 281 zoneSpecification: new ZoneSpecification( |
| 285 print: (self, parent, zone, line) => _controller.print(line)), | 282 print: (self, parent, zone, line) => _controller.print(line)), |
| 286 onError: _handleError); | 283 onError: _handleError); |
| 287 }); | 284 }); |
| 288 } | 285 } |
| 289 } | 286 } |
| OLD | NEW |