Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1069)

Side by Side Diff: lib/src/backend/invoker.dart

Issue 1372353003: Don't early-exit teardowns after a signal. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Code review changes Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/backend/group.dart ('k') | pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
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.
54 /// 54 ///
55 /// This provides a view into the state of the test being executed. 55 /// This provides a view into the state of the test being executed.
56 LiveTest get liveTest => _controller.liveTest; 56 LiveTest get liveTest => _controller.liveTest;
57 LiveTestController _controller; 57 LiveTestController _controller;
58 58
59 bool get _closable => Zone.current[_closableKey];
60
61 /// An opaque object used as a key in the zone value map to identify
62 /// [_closable].
63 ///
64 /// This is an instance variable to ensure that multiple invokers don't step
65 /// on one anothers' toes.
66 final _closableKey = new Object();
67
59 /// Whether the test has been closed. 68 /// Whether the test has been closed.
60 /// 69 ///
61 /// Once the test is closed, [expect] and [expectAsync] will throw 70 /// Once the test is closed, [expect] and [expectAsync] will throw
62 /// [ClosedException]s whenever accessed to help the test stop executing as 71 /// [ClosedException]s whenever accessed to help the test stop executing as
63 /// soon as possible. 72 /// soon as possible.
64 bool get closed => _onCloseCompleter.isCompleted; 73 bool get closed => _closable && _onCloseCompleter.isCompleted;
65 74
66 /// A future that completes once the test has been closed. 75 /// A future that completes once the test has been closed.
67 Future get onClose => _onCloseCompleter.future; 76 Future get onClose => _closable
77 ? _onCloseCompleter.future
78 // If we're in an unclosable block, return a future that will never
79 // complete.
80 : new Completer().future;
68 final _onCloseCompleter = new Completer(); 81 final _onCloseCompleter = new Completer();
69 82
70 /// The test being run. 83 /// The test being run.
71 LocalTest get _test => liveTest.test as LocalTest; 84 LocalTest get _test => liveTest.test as LocalTest;
72 85
73 /// The test metadata merged with the suite metadata. 86 /// The test metadata merged with the suite metadata.
74 final Metadata metadata; 87 final Metadata metadata;
75 88
76 /// The outstanding callback counter for the current zone. 89 /// The outstanding callback counter for the current zone.
77 OutstandingCallbackCounter get _outstandingCallbacks { 90 OutstandingCallbackCounter get _outstandingCallbacks {
78 var counter = Zone.current[this]; 91 var counter = Zone.current[_counterKey];
79 if (counter != null) return counter; 92 if (counter != null) return counter;
80 throw new StateError("Can't add or remove outstanding callbacks outside " 93 throw new StateError("Can't add or remove outstanding callbacks outside "
81 "of a test body."); 94 "of a test body.");
82 } 95 }
83 96
97 /// An opaque object used as a key in the zone value map to identify
98 /// [_outstandingCallbacks].
99 ///
100 /// This is an instance variable to ensure that multiple invokers don't step
101 /// on one anothers' toes.
102 final _counterKey = new Object();
103
84 /// The current invoker, or `null` if none is defined. 104 /// The current invoker, or `null` if none is defined.
85 /// 105 ///
86 /// An invoker is only set within the zone scope of a running test. 106 /// An invoker is only set within the zone scope of a running test.
87 static Invoker get current { 107 static Invoker get current {
88 // TODO(nweiz): Use a private symbol when dart2js supports it (issue 17526). 108 // TODO(nweiz): Use a private symbol when dart2js supports it (issue 17526).
89 return Zone.current[#test.invoker]; 109 return Zone.current[#test.invoker];
90 } 110 }
91 111
92 /// The zone that the top level of [_test.body] is running in. 112 /// The zone that the top level of [_test.body] is running in.
93 /// 113 ///
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 heartbeat(); 171 heartbeat();
152 172
153 var counter = new OutstandingCallbackCounter(); 173 var counter = new OutstandingCallbackCounter();
154 runZoned(() { 174 runZoned(() {
155 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in 175 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in
156 // two stable versions. 176 // two stable versions.
157 runZoned(() { 177 runZoned(() {
158 new Future.sync(fn).then((_) => counter.removeOutstandingCallback()); 178 new Future.sync(fn).then((_) => counter.removeOutstandingCallback());
159 }, onError: _handleError); 179 }, onError: _handleError);
160 }, zoneValues: { 180 }, zoneValues: {
161 // Use the invoker as a key so that multiple invokers can have different 181 _counterKey: counter
162 // outstanding callback counters at once.
163 this: counter
164 }); 182 });
165 183
166 return counter.noOutstandingCallbacks; 184 return counter.noOutstandingCallbacks;
167 } 185 }
168 186
187 /// Runs [fn] in a zone where [closed] is always `false`.
188 ///
189 /// This is useful for running code that should be able to register callbacks
190 /// and interact with the test framework normally even when the invoker is
191 /// closed, for example cleanup code.
192 unclosable(fn()) {
193 heartbeat();
194
195 return runZoned(fn, zoneValues: {
196 _closableKey: false
197 });
198 }
199
169 /// Notifies the invoker that progress is being made. 200 /// Notifies the invoker that progress is being made.
170 /// 201 ///
171 /// Each heartbeat resets the timeout timer. This helps ensure that 202 /// Each heartbeat resets the timeout timer. This helps ensure that
172 /// long-running tests that still make progress don't time out. 203 /// long-running tests that still make progress don't time out.
173 void heartbeat() { 204 void heartbeat() {
174 if (liveTest.isComplete) return; 205 if (liveTest.isComplete) return;
175 if (_timeoutTimer != null) _timeoutTimer.cancel(); 206 if (_timeoutTimer != null) _timeoutTimer.cancel();
176 207
177 var timeout = metadata.timeout.apply(new Duration(seconds: 30)); 208 var timeout = metadata.timeout.apply(new Duration(seconds: 30));
178 if (timeout == null) return; 209 if (timeout == null) return;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 new State(Status.complete, liveTest.state.result)); 271 new State(Status.complete, liveTest.state.result));
241 272
242 // Use [Timer.run] here to avoid starving the DOM or other 273 // Use [Timer.run] here to avoid starving the DOM or other
243 // non-microtask events. 274 // non-microtask events.
244 Timer.run(_controller.completer.complete); 275 Timer.run(_controller.completer.complete);
245 }); 276 });
246 }, zoneValues: { 277 }, zoneValues: {
247 #test.invoker: this, 278 #test.invoker: this,
248 // Use the invoker as a key so that multiple invokers can have different 279 // Use the invoker as a key so that multiple invokers can have different
249 // outstanding callback counters at once. 280 // outstanding callback counters at once.
250 this: outstandingCallbacksForBody 281 _counterKey: outstandingCallbacksForBody,
282 _closableKey: true
251 }, 283 },
252 zoneSpecification: new ZoneSpecification( 284 zoneSpecification: new ZoneSpecification(
253 print: (self, parent, zone, line) => _controller.print(line)), 285 print: (self, parent, zone, line) => _controller.print(line)),
254 onError: _handleError); 286 onError: _handleError);
255 }); 287 });
256 } 288 }
257 } 289 }
OLDNEW
« no previous file with comments | « lib/src/backend/group.dart ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698