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

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

Issue 1062813006: Add the ability to run test suites in parallel. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Code review changes Created 5 years, 8 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/browser/compiler_pool.dart ('k') | lib/src/runner/reporter/compact.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 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:pool/pool.dart';
11
10 import '../backend/live_test.dart'; 12 import '../backend/live_test.dart';
11 import '../backend/state.dart'; 13 import '../backend/state.dart';
12 import '../backend/suite.dart'; 14 import '../backend/suite.dart';
13 import '../utils.dart'; 15 import '../utils.dart';
14 16
15 /// An [Engine] manages a run that encompasses multiple test suites. 17 /// An [Engine] manages a run that encompasses multiple test suites.
16 /// 18 ///
17 /// The current status of every test is visible via [liveTests]. [onTestStarted] 19 /// The current status of every test is visible via [liveTests]. [onTestStarted]
18 /// can also be used to be notified when a test is about to be run. 20 /// can also be used to be notified when a test is about to be run.
19 /// 21 ///
20 /// Suites will be run in the order they're provided to [new Engine]. Tests 22 /// Suites will be run in the order they're provided to [new Engine]. Tests
21 /// within those suites will likewise be run in the order of [Suite.tests]. 23 /// within those suites will likewise be run in the order of [Suite.tests].
22 class Engine { 24 class Engine {
23 /// Whether [run] has been called yet. 25 /// Whether [run] has been called yet.
24 var _runCalled = false; 26 var _runCalled = false;
25 27
26 /// Whether [close] has been called. 28 /// Whether [close] has been called.
27 var _closed = false; 29 var _closed = false;
28 30
31 /// A pool that limits the number of test suites running concurrently.
32 final Pool _pool;
33
29 /// An unmodifiable list of tests to run. 34 /// An unmodifiable list of tests to run.
30 /// 35 ///
31 /// These are [LiveTest]s, representing the in-progress state of each test. 36 /// These are [LiveTest]s, representing the in-progress state of each test.
32 /// Tests that have not yet begun running are marked [Status.pending]; tests 37 /// Tests that have not yet begun running are marked [Status.pending]; tests
33 /// that have finished are marked [Status.complete]. 38 /// that have finished are marked [Status.complete].
34 /// 39 ///
35 /// [LiveTest.run] must not be called on these tests. 40 /// [LiveTest.run] must not be called on these tests.
36 final List<LiveTest> liveTests; 41 List<LiveTest> get liveTests =>
42 new UnmodifiableListView(flatten(_liveTestsBySuite));
43
44 final List<List<LiveTest>> _liveTestsBySuite;
37 45
38 /// A stream that emits each [LiveTest] as it's about to start running. 46 /// A stream that emits each [LiveTest] as it's about to start running.
39 /// 47 ///
40 /// This is guaranteed to fire before [LiveTest.onStateChange] first fires. 48 /// This is guaranteed to fire before [LiveTest.onStateChange] first fires.
41 Stream<LiveTest> get onTestStarted => _onTestStartedController.stream; 49 Stream<LiveTest> get onTestStarted => _onTestStartedController.stream;
42 final _onTestStartedController = new StreamController<LiveTest>.broadcast(); 50 final _onTestStartedController = new StreamController<LiveTest>.broadcast();
43 51
44 /// Creates an [Engine] that will run all tests in [suites]. 52 /// Creates an [Engine] that will run all tests in [suites].
45 Engine(Iterable<Suite> suites) 53 Engine(Iterable<Suite> suites, {int concurrency})
46 : liveTests = new UnmodifiableListView(flatten(suites.map((suite) => 54 : _liveTestsBySuite = suites.map((suite) =>
47 suite.tests.map((test) => test.load(suite))))); 55 suite.tests.map((test) => test.load(suite)).toList()).toList(),
56 _pool = new Pool(concurrency == null ? 1 : concurrency);
48 57
49 /// Runs all tests in all suites defined by this engine. 58 /// Runs all tests in all suites defined by this engine.
50 /// 59 ///
51 /// This returns `true` if all tests succeed, and `false` otherwise. It will 60 /// This returns `true` if all tests succeed, and `false` otherwise. It will
52 /// only return once all tests have finished running. 61 /// only return once all tests have finished running.
53 Future<bool> run() { 62 Future<bool> run() {
54 if (_runCalled) { 63 if (_runCalled) {
55 throw new StateError("Engine.run() may not be called more than once."); 64 throw new StateError("Engine.run() may not be called more than once.");
56 } 65 }
57 _runCalled = true; 66 _runCalled = true;
58 67
59 return Future.forEach(liveTests, (liveTest) { 68 return Future.wait(_liveTestsBySuite.map((suite) {
60 if (_closed) return new Future.value(); 69 return _pool.withResource(() {
61 _onTestStartedController.add(liveTest); 70 if (_closed) return null;
62 71
63 // First, schedule a microtask to ensure that [onTestStarted] fires before 72 return Future.forEach(suite, (liveTest) {
64 // the first [LiveTest.onStateChange] event. Once the test finishes, use 73 if (_closed) return new Future.value();
65 // [new Future] to do a coarse-grained event loop pump to avoid starving 74 _onTestStartedController.add(liveTest);
66 // the DOM or other non-microtask events. 75
67 return new Future.microtask(liveTest.run).then((_) => new Future(() {})); 76 // First, schedule a microtask to ensure that [onTestStarted] fires
68 }).then((_) => 77 // before the first [LiveTest.onStateChange] event. Once the test
78 // finishes, use [new Future] to do a coarse-grained event loop pump
79 // to avoid starving the DOM or other non-microtask events.
80 return new Future.microtask(liveTest.run)
81 .then((_) => new Future(() {}));
82 });
83 });
84 })).then((_) =>
69 liveTests.every((liveTest) => liveTest.state.result == Result.success)); 85 liveTests.every((liveTest) => liveTest.state.result == Result.success));
70 } 86 }
71 87
72 /// Signals that the caller is done paying attention to test results and the 88 /// Signals that the caller is done paying attention to test results and the
73 /// engine should release any resources it has allocated. 89 /// engine should release any resources it has allocated.
74 /// 90 ///
75 /// Any actively-running tests are also closed. VM tests are allowed to finish 91 /// Any actively-running tests are also closed. VM tests are allowed to finish
76 /// running so that any modifications they've made to the filesystem can be 92 /// running so that any modifications they've made to the filesystem can be
77 /// cleaned up. 93 /// cleaned up.
78 Future close() { 94 Future close() {
79 _closed = true; 95 _closed = true;
80 return Future.wait(liveTests.map((liveTest) => liveTest.close())); 96 return Future.wait(liveTests.map((liveTest) => liveTest.close()));
81 } 97 }
82 } 98 }
OLDNEW
« no previous file with comments | « lib/src/runner/browser/compiler_pool.dart ('k') | lib/src/runner/reporter/compact.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698