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.runner.engine; | 5 library test.runner.engine; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 | 9 |
10 import 'package:async/async.dart' hide Result; | 10 import 'package:async/async.dart' hide Result; |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 if (suite is LoadSuite) { | 198 if (suite is LoadSuite) { |
199 suite = await _addLoadSuite(suite); | 199 suite = await _addLoadSuite(suite); |
200 if (suite == null) { | 200 if (suite == null) { |
201 loadResource.release(); | 201 loadResource.release(); |
202 return; | 202 return; |
203 } | 203 } |
204 } | 204 } |
205 | 205 |
206 await _runPool.withResource(() async { | 206 await _runPool.withResource(() async { |
207 if (_closed) return; | 207 if (_closed) return; |
208 await _runGroup(suite, suite.group); | 208 await _runGroup(suite, suite.group, []); |
209 loadResource.allowRelease(() => suite.close()); | 209 loadResource.allowRelease(() => suite.close()); |
210 }); | 210 }); |
211 })); | 211 })); |
212 }, onDone: _group.close); | 212 }, onDone: _group.close); |
213 | 213 |
214 return success; | 214 return success; |
215 } | 215 } |
216 | 216 |
217 /// Runs all the entries in [entries] in sequence. | 217 /// Runs all the entries in [entries] in sequence. |
218 Future _runGroup(RunnerSuite suite, Group group) async { | 218 /// |
| 219 /// [parents] is a list of groups that contain [group]. It may be modified, |
| 220 /// but it's guaranteed to be in its original state once this function has |
| 221 /// finished. |
| 222 Future _runGroup(RunnerSuite suite, Group group, List<Group> parents) async { |
219 if (group.metadata.skip) { | 223 if (group.metadata.skip) { |
220 await _runLiveTest(_skippedTest(suite, group)); | 224 await _runLiveTest(_skippedTest(suite, group, parents)); |
221 return; | 225 return; |
222 } | 226 } |
223 | 227 |
224 var setUpAllSucceeded = true; | 228 var setUpAllSucceeded = true; |
225 if (group.setUpAll != null) { | 229 if (group.setUpAll != null) { |
226 var liveTest = group.setUpAll.load(suite); | 230 var liveTest = group.setUpAll.load(suite, groups: parents); |
227 await _runLiveTest(liveTest, countSuccess: false); | 231 await _runLiveTest(liveTest, countSuccess: false); |
228 setUpAllSucceeded = liveTest.state.result == Result.success; | 232 setUpAllSucceeded = liveTest.state.result == Result.success; |
229 } | 233 } |
230 | 234 |
231 if (!_closed && setUpAllSucceeded) { | 235 if (!_closed && setUpAllSucceeded) { |
232 for (var entry in group.entries) { | 236 parents.add(group); |
233 if (_closed) return; | 237 try { |
| 238 for (var entry in group.entries) { |
| 239 if (_closed) return; |
234 | 240 |
235 if (entry is Group) { | 241 if (entry is Group) { |
236 await _runGroup(suite, entry); | 242 await _runGroup(suite, entry, parents); |
237 } else if (entry.metadata.skip) { | 243 } else if (entry.metadata.skip) { |
238 await _runLiveTest(_skippedTest(suite, entry)); | 244 await _runLiveTest(_skippedTest(suite, entry, parents)); |
239 } else { | 245 } else { |
240 var test = entry as Test; | 246 var test = entry as Test; |
241 await _runLiveTest(test.load(suite)); | 247 await _runLiveTest(test.load(suite, groups: parents)); |
| 248 } |
242 } | 249 } |
| 250 } finally { |
| 251 parents.remove(group); |
243 } | 252 } |
244 } | 253 } |
245 | 254 |
246 // Even if we're closed or setUpAll failed, we want to run all the teardowns | 255 // Even if we're closed or setUpAll failed, we want to run all the teardowns |
247 // to ensure that any state is properly cleaned up. | 256 // to ensure that any state is properly cleaned up. |
248 if (group.tearDownAll != null) { | 257 if (group.tearDownAll != null) { |
249 var liveTest = group.tearDownAll.load(suite); | 258 var liveTest = group.tearDownAll.load(suite, groups: parents); |
250 await _runLiveTest(liveTest, countSuccess: false); | 259 await _runLiveTest(liveTest, countSuccess: false); |
251 if (_closed) await liveTest.close(); | 260 if (_closed) await liveTest.close(); |
252 } | 261 } |
253 } | 262 } |
254 | 263 |
255 /// Returns a dummy [LiveTest] for a test or group marked as "skip". | 264 /// Returns a dummy [LiveTest] for a test or group marked as "skip". |
256 LiveTest _skippedTest(RunnerSuite suite, GroupEntry entry) { | 265 /// |
| 266 /// [parents] is a list of groups that contain [entry]. |
| 267 LiveTest _skippedTest(RunnerSuite suite, GroupEntry entry, |
| 268 List<Group> parents) { |
257 // The netry name will be `null` for the root group. | 269 // The netry name will be `null` for the root group. |
258 var test = new LocalTest(entry.name ?? "(suite)", entry.metadata, () {}); | 270 var test = new LocalTest(entry.name ?? "(suite)", entry.metadata, () {}); |
259 | 271 |
260 var controller; | 272 var controller; |
261 controller = new LiveTestController(suite, test, () { | 273 controller = new LiveTestController(suite, test, () { |
262 controller.setState(const State(Status.running, Result.success)); | 274 controller.setState(const State(Status.running, Result.success)); |
263 controller.setState(const State(Status.complete, Result.success)); | 275 controller.setState(const State(Status.complete, Result.success)); |
264 controller.completer.complete(); | 276 controller.completer.complete(); |
265 }, () {}); | 277 }, () {}, groups: parents); |
266 return controller.liveTest; | 278 return controller.liveTest; |
267 } | 279 } |
268 | 280 |
269 /// Runs [liveTest]. | 281 /// Runs [liveTest]. |
270 /// | 282 /// |
271 /// If [countSuccess] is `true` (the default), the test is put into [passed] | 283 /// If [countSuccess] is `true` (the default), the test is put into [passed] |
272 /// if it succeeds. Otherwise, it's removed from [liveTests] entirely. | 284 /// if it succeeds. Otherwise, it's removed from [liveTests] entirely. |
273 Future _runLiveTest(LiveTest liveTest, {bool countSuccess: true}) async { | 285 Future _runLiveTest(LiveTest liveTest, {bool countSuccess: true}) async { |
274 _liveTests.add(liveTest); | 286 _liveTests.add(liveTest); |
275 _active.add(liveTest); | 287 _active.add(liveTest); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 var futures = allLiveTests.map((liveTest) => liveTest.close()).toList(); | 397 var futures = allLiveTests.map((liveTest) => liveTest.close()).toList(); |
386 | 398 |
387 // Closing the load pool will close the test suites as soon as their tests | 399 // Closing the load pool will close the test suites as soon as their tests |
388 // are done. For browser suites this is effectively immediate since their | 400 // are done. For browser suites this is effectively immediate since their |
389 // tests shut down as soon as they're closed, but for VM suites we may need | 401 // tests shut down as soon as they're closed, but for VM suites we may need |
390 // to wait for tearDowns or tearDownAlls to run. | 402 // to wait for tearDowns or tearDownAlls to run. |
391 futures.add(_loadPool.close()); | 403 futures.add(_loadPool.close()); |
392 await Future.wait(futures, eagerError: true); | 404 await Future.wait(futures, eagerError: true); |
393 } | 405 } |
394 } | 406 } |
OLD | NEW |