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

Side by Side Diff: lib/src/runner/engine.dart

Issue 2099553002: Add an option to run skipped tests. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Code review changes Created 4 years, 5 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/runner/configuration/load.dart ('k') | lib/src/runner/loader.dart » ('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 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:collection'; 6 import 'dart:collection';
7 7
8 import 'package:async/async.dart' hide Result; 8 import 'package:async/async.dart' hide Result;
9 import 'package:collection/collection.dart'; 9 import 'package:collection/collection.dart';
10 import 'package:pool/pool.dart'; 10 import 'package:pool/pool.dart';
11 11
12 import '../backend/group.dart'; 12 import '../backend/group.dart';
13 import '../backend/group_entry.dart';
14 import '../backend/invoker.dart'; 13 import '../backend/invoker.dart';
15 import '../backend/live_test.dart'; 14 import '../backend/live_test.dart';
16 import '../backend/live_test_controller.dart'; 15 import '../backend/live_test_controller.dart';
17 import '../backend/message.dart'; 16 import '../backend/message.dart';
18 import '../backend/state.dart'; 17 import '../backend/state.dart';
19 import '../backend/test.dart'; 18 import '../backend/test.dart';
20 import '../util/iterable_set.dart'; 19 import '../util/iterable_set.dart';
21 import 'live_suite.dart'; 20 import 'live_suite.dart';
22 import 'live_suite_controller.dart'; 21 import 'live_suite_controller.dart';
23 import 'load_suite.dart'; 22 import 'load_suite.dart';
(...skipping 21 matching lines...) Expand all
45 /// and [liveTests]. If this test passes, it will be removed from both [active] 44 /// and [liveTests]. If this test passes, it will be removed from both [active]
46 /// and [liveTests] and *will not* be added to [passed]. If at any point a load 45 /// and [liveTests] and *will not* be added to [passed]. If at any point a load
47 /// test fails, it will be added to [failed] and [liveTests]. 46 /// test fails, it will be added to [failed] and [liveTests].
48 /// 47 ///
49 /// The test suite loaded by a load suite will be automatically be run by the 48 /// The test suite loaded by a load suite will be automatically be run by the
50 /// engine; it doesn't need to be added to [suiteSink] manually. 49 /// engine; it doesn't need to be added to [suiteSink] manually.
51 /// 50 ///
52 /// Load tests will always be emitted through [onTestStarted] so users can watch 51 /// Load tests will always be emitted through [onTestStarted] so users can watch
53 /// their event streams once they start running. 52 /// their event streams once they start running.
54 class Engine { 53 class Engine {
54 /// Whether to run skipped tests.
55 final bool _runSkipped;
56
55 /// Whether [run] has been called yet. 57 /// Whether [run] has been called yet.
56 var _runCalled = false; 58 var _runCalled = false;
57 59
58 /// Whether [close] has been called. 60 /// Whether [close] has been called.
59 var _closed = false; 61 var _closed = false;
60 62
61 /// Whether [close] was called before all the tests finished running. 63 /// Whether [close] was called before all the tests finished running.
62 /// 64 ///
63 /// This is `null` if close hasn't been called and the tests are still 65 /// This is `null` if close hasn't been called and the tests are still
64 /// running, `true` if close was called before the tests finished running, and 66 /// running, `true` if close was called before the tests finished running, and
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 /// This is separate from [active] because load tests aren't always surfaced. 184 /// This is separate from [active] because load tests aren't always surfaced.
183 final _activeLoadTests = new List<LiveTest>(); 185 final _activeLoadTests = new List<LiveTest>();
184 186
185 /// Whether this engine is idle—that is, not currently executing a test. 187 /// Whether this engine is idle—that is, not currently executing a test.
186 bool get isIdle => _group.isIdle; 188 bool get isIdle => _group.isIdle;
187 189
188 /// A broadcast stream that fires an event whenever [isIdle] switches from 190 /// A broadcast stream that fires an event whenever [isIdle] switches from
189 /// `false` to `true`. 191 /// `false` to `true`.
190 Stream get onIdle => _group.onIdle; 192 Stream get onIdle => _group.onIdle;
191 193
194 // TODO(nweiz): Use interface libraries to take a Configuration even when
195 // dart:io is unavailable.
192 /// Creates an [Engine] that will run all tests provided via [suiteSink]. 196 /// Creates an [Engine] that will run all tests provided via [suiteSink].
193 /// 197 ///
194 /// [concurrency] controls how many suites are run at once, and defaults to 1. 198 /// [concurrency] controls how many suites are run at once, and defaults to 1.
195 /// [maxSuites] controls how many suites are *loaded* at once, and defaults to 199 /// [maxSuites] controls how many suites are *loaded* at once, and defaults to
196 /// four times [concurrency]. 200 /// four times [concurrency]. If [runSkipped] is `true`, skipped tests will be
197 Engine({int concurrency, int maxSuites}) 201 /// run as though they weren't skipped.
198 : _runPool = new Pool(concurrency == null ? 1 : concurrency), 202 Engine({int concurrency, int maxSuites, bool runSkipped: false})
199 _loadPool = new Pool(maxSuites == null 203 : _runPool = new Pool(concurrency ?? 1),
200 ? (concurrency == null ? 2 : concurrency * 2) 204 _loadPool = new Pool(maxSuites ?? (concurrency ?? 1) * 2),
201 : maxSuites) { 205 _runSkipped = runSkipped {
202 _group.future.then((_) { 206 _group.future.then((_) {
203 _onTestStartedGroup.close(); 207 _onTestStartedGroup.close();
204 _onSuiteStartedController.close(); 208 _onSuiteStartedController.close();
205 if (_closedBeforeDone == null) _closedBeforeDone = false; 209 if (_closedBeforeDone == null) _closedBeforeDone = false;
206 }).catchError((_) { 210 }).catchError((_) {
207 // Don't top-level errors. They'll be thrown via [success] anyway. 211 // Don't top-level errors. They'll be thrown via [success] anyway.
208 }); 212 });
209 } 213 }
210 214
211 /// Creates an [Engine] that will run all tests in [suites]. 215 /// Creates an [Engine] that will run all tests in [suites].
212 /// 216 ///
213 /// [concurrency] controls how many suites are run at once. An engine 217 /// An engine constructed this way will automatically close its [suiteSink],
214 /// constructed this way will automatically close its [suiteSink], meaning 218 /// meaning that no further suites may be provided.
215 /// that no further suites may be provided. 219 ///
216 factory Engine.withSuites(List<RunnerSuite> suites, {int concurrency}) { 220 /// [concurrency] controls how many suites are run at once. If [runSkipped] is
217 var engine = new Engine(concurrency: concurrency); 221 /// `true`, skipped tests will be run as though they weren't skipped.
222 factory Engine.withSuites(List<RunnerSuite> suites, {int concurrency,
223 bool runSkipped: false}) {
224 var engine = new Engine(concurrency: concurrency, runSkipped: runSkipped);
218 for (var suite in suites) engine.suiteSink.add(suite); 225 for (var suite in suites) engine.suiteSink.add(suite);
219 engine.suiteSink.close(); 226 engine.suiteSink.close();
220 return engine; 227 return engine;
221 } 228 }
222 229
223 /// Runs all tests in all suites defined by this engine. 230 /// Runs all tests in all suites defined by this engine.
224 /// 231 ///
225 /// This returns `true` if all tests succeed, and `false` otherwise. It will 232 /// This returns `true` if all tests succeed, and `false` otherwise. It will
226 /// only return once all tests have finished running and [suiteSink] has been 233 /// only return once all tests have finished running and [suiteSink] has been
227 /// closed. 234 /// closed.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 /// Runs all the entries in [group] in sequence. 276 /// Runs all the entries in [group] in sequence.
270 /// 277 ///
271 /// [suiteController] is the controller fo the suite that contains [group]. 278 /// [suiteController] is the controller fo the suite that contains [group].
272 /// [parents] is a list of groups that contain [group]. It may be modified, 279 /// [parents] is a list of groups that contain [group]. It may be modified,
273 /// but it's guaranteed to be in its original state once this function has 280 /// but it's guaranteed to be in its original state once this function has
274 /// finished. 281 /// finished.
275 Future _runGroup(LiveSuiteController suiteController, Group group, 282 Future _runGroup(LiveSuiteController suiteController, Group group,
276 List<Group> parents) async { 283 List<Group> parents) async {
277 parents.add(group); 284 parents.add(group);
278 try { 285 try {
279 if (group.metadata.skip) { 286 var skipGroup = !_runSkipped && group.metadata.skip;
280 await _runSkippedTest(suiteController, group, parents);
281 return;
282 }
283
284 var setUpAllSucceeded = true; 287 var setUpAllSucceeded = true;
285 if (group.setUpAll != null) { 288 if (!skipGroup && group.setUpAll != null) {
286 var liveTest = group.setUpAll.load(suiteController.liveSuite.suite, 289 var liveTest = group.setUpAll.load(suiteController.liveSuite.suite,
287 groups: parents); 290 groups: parents);
288 await _runLiveTest(suiteController, liveTest, countSuccess: false); 291 await _runLiveTest(suiteController, liveTest, countSuccess: false);
289 setUpAllSucceeded = liveTest.state.result.isPassing; 292 setUpAllSucceeded = liveTest.state.result.isPassing;
290 } 293 }
291 294
292 if (!_closed && setUpAllSucceeded) { 295 if (!_closed && setUpAllSucceeded) {
293 for (var entry in group.entries) { 296 for (var entry in group.entries) {
294 if (_closed) return; 297 if (_closed) return;
295 298
296 if (entry is Group) { 299 if (entry is Group) {
297 await _runGroup(suiteController, entry, parents); 300 await _runGroup(suiteController, entry, parents);
298 } else if (entry.metadata.skip) { 301 } else if (!_runSkipped && entry.metadata.skip) {
299 await _runSkippedTest(suiteController, entry, parents); 302 await _runSkippedTest(suiteController, entry, parents);
300 } else { 303 } else {
301 var test = entry as Test; 304 var test = entry as Test;
302 await _runLiveTest( 305 await _runLiveTest(
303 suiteController, 306 suiteController,
304 test.load(suiteController.liveSuite.suite, groups: parents)); 307 test.load(suiteController.liveSuite.suite, groups: parents));
305 } 308 }
306 } 309 }
307 } 310 }
308 311
309 // Even if we're closed or setUpAll failed, we want to run all the 312 // Even if we're closed or setUpAll failed, we want to run all the
310 // teardowns to ensure that any state is properly cleaned up. 313 // teardowns to ensure that any state is properly cleaned up.
311 if (group.tearDownAll != null) { 314 if (!skipGroup && group.tearDownAll != null) {
312 var liveTest = group.tearDownAll.load(suiteController.liveSuite.suite, 315 var liveTest = group.tearDownAll.load(suiteController.liveSuite.suite,
313 groups: parents); 316 groups: parents);
314 await _runLiveTest(suiteController, liveTest, countSuccess: false); 317 await _runLiveTest(suiteController, liveTest, countSuccess: false);
315 if (_closed) await liveTest.close(); 318 if (_closed) await liveTest.close();
316 } 319 }
317 } finally { 320 } finally {
318 parents.remove(group); 321 parents.remove(group);
319 } 322 }
320 } 323 }
321 324
(...skipping 29 matching lines...) Expand all
351 // Once the test finishes, use [new Future] to do a coarse-grained event 354 // Once the test finishes, use [new Future] to do a coarse-grained event
352 // loop pump to avoid starving non-microtask events. 355 // loop pump to avoid starving non-microtask events.
353 await new Future(() {}); 356 await new Future(() {});
354 357
355 if (!_restarted.contains(liveTest)) return; 358 if (!_restarted.contains(liveTest)) return;
356 await _runLiveTest(suiteController, liveTest.copy(), 359 await _runLiveTest(suiteController, liveTest.copy(),
357 countSuccess: countSuccess); 360 countSuccess: countSuccess);
358 _restarted.remove(liveTest); 361 _restarted.remove(liveTest);
359 } 362 }
360 363
361 /// Runs a dummy [LiveTest] for a test or group marked as "skip". 364 /// Runs a dummy [LiveTest] for a test marked as "skip".
362 /// 365 ///
363 /// [suiteController] is the controller for the suite that contains [entry]. 366 /// [suiteController] is the controller for the suite that contains [test].
364 /// [parents] is a list of groups that contain [entry]. 367 /// [parents] is a list of groups that contain [test].
365 Future _runSkippedTest(LiveSuiteController suiteController, GroupEntry entry, 368 Future _runSkippedTest(LiveSuiteController suiteController, Test test,
366 List<Group> parents) { 369 List<Group> parents) {
367 // The netry name will be `null` for the root group. 370 var skipped = new LocalTest(test.name, test.metadata, () {},
368 var test = new LocalTest(entry.name ?? "(suite)", entry.metadata, () {}, 371 trace: test.trace);
369 trace: entry.trace);
370 372
371 var controller; 373 var controller;
372 controller = new LiveTestController( 374 controller = new LiveTestController(
373 suiteController.liveSuite.suite, test, () { 375 suiteController.liveSuite.suite, skipped, () {
374 controller.setState(const State(Status.running, Result.success)); 376 controller.setState(const State(Status.running, Result.success));
375 controller.setState(const State(Status.running, Result.skipped)); 377 controller.setState(const State(Status.running, Result.skipped));
376 378
377 if (entry.metadata.skipReason != null) { 379 if (skipped.metadata.skipReason != null) {
378 controller.message( 380 controller.message(
379 new Message.skip("Skip: ${entry.metadata.skipReason}")); 381 new Message.skip("Skip: ${skipped.metadata.skipReason}"));
380 } 382 }
381 383
382 controller.setState(const State(Status.complete, Result.skipped)); 384 controller.setState(const State(Status.complete, Result.skipped));
383 controller.completer.complete(); 385 controller.completer.complete();
384 }, () {}, groups: parents); 386 }, () {}, groups: parents);
385 387
386 return _runLiveTest(suiteController, controller.liveTest); 388 return _runLiveTest(suiteController, controller.liveTest);
387 } 389 }
388 390
389 /// Closes [liveTest] and tells the engine to re-run it once it's done 391 /// Closes [liveTest] and tells the engine to re-run it once it's done
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 var futures = allLiveTests.map((liveTest) => liveTest.close()).toList(); 490 var futures = allLiveTests.map((liveTest) => liveTest.close()).toList();
489 491
490 // Closing the load pool will close the test suites as soon as their tests 492 // Closing the load pool will close the test suites as soon as their tests
491 // are done. For browser suites this is effectively immediate since their 493 // are done. For browser suites this is effectively immediate since their
492 // tests shut down as soon as they're closed, but for VM suites we may need 494 // tests shut down as soon as they're closed, but for VM suites we may need
493 // to wait for tearDowns or tearDownAlls to run. 495 // to wait for tearDowns or tearDownAlls to run.
494 futures.add(_loadPool.close()); 496 futures.add(_loadPool.close());
495 await Future.wait(futures, eagerError: true); 497 await Future.wait(futures, eagerError: true);
496 } 498 }
497 } 499 }
OLDNEW
« no previous file with comments | « lib/src/runner/configuration/load.dart ('k') | lib/src/runner/loader.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698