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

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

Issue 1379203002: Refactor groups to pipe them through to the runner. (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/runner/browser/iframe_test.dart ('k') | lib/src/runner/load_suite.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:async/async.dart' hide Result; 10 import 'package:async/async.dart' hide Result;
11 import 'package:collection/collection.dart'; 11 import 'package:collection/collection.dart';
12 import 'package:pool/pool.dart'; 12 import 'package:pool/pool.dart';
13 13
14 import '../backend/group.dart';
15 import '../backend/invoker.dart';
14 import '../backend/live_test.dart'; 16 import '../backend/live_test.dart';
15 import '../backend/live_test_controller.dart'; 17 import '../backend/live_test_controller.dart';
16 import '../backend/state.dart'; 18 import '../backend/state.dart';
19 import '../backend/suite_entry.dart';
17 import '../backend/test.dart'; 20 import '../backend/test.dart';
18 import 'load_suite.dart'; 21 import 'load_suite.dart';
19 import 'runner_suite.dart'; 22 import 'runner_suite.dart';
20 23
21 /// An [Engine] manages a run that encompasses multiple test suites. 24 /// An [Engine] manages a run that encompasses multiple test suites.
22 /// 25 ///
23 /// Test suites are provided by passing them into [suiteSink]. Once all suites 26 /// Test suites are provided by passing them into [suiteSink]. Once all suites
24 /// have been provided, the user should close [suiteSink] to indicate this. 27 /// have been provided, the user should close [suiteSink] to indicate this.
25 /// [run] won't terminate until [suiteSink] is closed. Suites will be run in the 28 /// [run] won't terminate until [suiteSink] is closed. Suites will be run in the
26 /// order they're provided to [suiteSink]. Tests within those suites will 29 /// order they're provided to [suiteSink]. Tests within those suites will
27 /// likewise be run in the order of [Suite.tests]. 30 /// likewise be run in the order they're declared.
28 /// 31 ///
29 /// The current status of every test is visible via [liveTests]. [onTestStarted] 32 /// The current status of every test is visible via [liveTests]. [onTestStarted]
30 /// can also be used to be notified when a test is about to be run. 33 /// can also be used to be notified when a test is about to be run.
31 /// 34 ///
32 /// The engine has some special logic for [LoadSuite]s and the tests they 35 /// The engine has some special logic for [LoadSuite]s and the tests they
33 /// contain, referred to as "load tests". Load tests exist to provide visibility 36 /// contain, referred to as "load tests". Load tests exist to provide visibility
34 /// into the process of loading test files, but as long as that process is 37 /// into the process of loading test files, but as long as that process is
35 /// proceeding normally users usually don't care about it, so the engine only 38 /// proceeding normally users usually don't care about it, so the engine only
36 /// surfaces running load tests (that is, includes them in [liveTests] and other 39 /// surfaces running load tests (that is, includes them in [liveTests] and other
37 /// collections) under specific circumstances. 40 /// collections) under specific circumstances.
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 191
189 if (suite is LoadSuite) { 192 if (suite is LoadSuite) {
190 suite = await _addLoadSuite(suite); 193 suite = await _addLoadSuite(suite);
191 if (suite == null) { 194 if (suite == null) {
192 loadResource.release(); 195 loadResource.release();
193 return; 196 return;
194 } 197 }
195 } 198 }
196 199
197 await _runPool.withResource(() async { 200 await _runPool.withResource(() async {
198 if (_closed) return null; 201 if (_closed) return;
199 202 await _runEntries(suite, suite.entries);
200 // TODO(nweiz): Use a real for loop when issue 23394 is fixed.
201 await Future.forEach(suite.tests, (test) async {
202 if (_closed) return;
203
204 var liveTest = test.metadata.skip
205 ? _skippedTest(suite, test)
206 : test.load(suite);
207 _liveTests.add(liveTest);
208 _active.add(liveTest);
209
210 // If there were no active non-load tests, the current active test
211 // would have been a load test. In that case, remove it, since now w e
212 // have a non-load test to add.
213 if (_active.isNotEmpty && _active.first.suite is LoadSuite) {
214 _liveTests.remove(_active.removeFirst());
215 }
216
217 liveTest.onStateChange.listen((state) {
218 if (state.status != Status.complete) return;
219 _active.remove(liveTest);
220
221 // If we're out of non-load tests, surface a load test.
222 if (_active.isEmpty && _activeLoadTests.isNotEmpty) {
223 _active.add(_activeLoadTests.first);
224 _liveTests.add(_activeLoadTests.first);
225 }
226
227 if (state.result != Result.success) {
228 _passed.remove(liveTest);
229 _failed.add(liveTest);
230 } else if (liveTest.test.metadata.skip) {
231 _skipped.add(liveTest);
232 } else {
233 _passed.add(liveTest);
234 }
235 });
236
237 _onTestStartedController.add(liveTest);
238
239 // First, schedule a microtask to ensure that [onTestStarted] fires
240 // before the first [LiveTest.onStateChange] event. Once the test
241 // finishes, use [new Future] to do a coarse-grained event loop pump
242 // to avoid starving non-microtask events.
243 await new Future.microtask(liveTest.run);
244 await new Future(() {});
245 });
246
247 loadResource.allowRelease(() => suite.close()); 203 loadResource.allowRelease(() => suite.close());
248 }); 204 });
249 })); 205 }));
250 }, onDone: _group.close); 206 }, onDone: _group.close);
251 207
252 return success; 208 return success;
253 } 209 }
254 210
255 /// Returns a dummy [LiveTest] for a test marked as "skip". 211 /// Runs all the entries in [entries] in sequence.
256 LiveTest _skippedTest(RunnerSuite suite, Test test) { 212 Future _runEntries(RunnerSuite suite, List<SuiteEntry> entries) async {
213 for (var entry in entries) {
214 if (_closed) return;
215
216 if (entry.metadata.skip) {
217 await _runLiveTest(_skippedTest(suite, entry));
218 } else if (entry is Test) {
219 await _runLiveTest(entry.load(suite));
220 } else {
221 var group = entry as Group;
222 await _runEntries(suite, group.entries);
223 }
224 }
225 }
226
227 /// Returns a dummy [LiveTest] for a test or group marked as "skip".
228 LiveTest _skippedTest(RunnerSuite suite, SuiteEntry entry) {
229 var test = new LocalTest(entry.name, entry.metadata, () {});
257 var controller; 230 var controller;
258 controller = new LiveTestController(suite, test, () { 231 controller = new LiveTestController(suite, test, () {
259 controller.setState(const State(Status.running, Result.success)); 232 controller.setState(const State(Status.running, Result.success));
260 controller.setState(const State(Status.complete, Result.success)); 233 controller.setState(const State(Status.complete, Result.success));
261 controller.completer.complete(); 234 controller.completer.complete();
262 }, () {}); 235 }, () {});
263 return controller.liveTest; 236 return controller.liveTest;
264 } 237 }
265 238
239 /// Runs [liveTest].
240 Future _runLiveTest(LiveTest liveTest) async {
241 _liveTests.add(liveTest);
242 _active.add(liveTest);
243
244 // If there were no active non-load tests, the current active test would
245 // have been a load test. In that case, remove it, since now we have a
246 // non-load test to add.
247 if (_active.isNotEmpty && _active.first.suite is LoadSuite) {
248 _liveTests.remove(_active.removeFirst());
249 }
250
251 liveTest.onStateChange.listen((state) {
252 if (state.status != Status.complete) return;
253 _active.remove(liveTest);
254
255 // If we're out of non-load tests, surface a load test.
256 if (_active.isEmpty && _activeLoadTests.isNotEmpty) {
257 _active.add(_activeLoadTests.first);
258 _liveTests.add(_activeLoadTests.first);
259 }
260
261 if (state.result != Result.success) {
262 _passed.remove(liveTest);
263 _failed.add(liveTest);
264 } else if (liveTest.test.metadata.skip) {
265 _skipped.add(liveTest);
266 } else {
267 _passed.add(liveTest);
268 }
269 });
270
271 _onTestStartedController.add(liveTest);
272
273 // First, schedule a microtask to ensure that [onTestStarted] fires before
274 // the first [LiveTest.onStateChange] event. Once the test finishes, use
275 // [new Future] to do a coarse-grained event loop pump to avoid starving
276 // non-microtask events.
277 await new Future.microtask(liveTest.run);
278 await new Future(() {});
279 }
280
266 /// Adds listeners for [suite]. 281 /// Adds listeners for [suite].
267 /// 282 ///
268 /// Load suites have specific logic apart from normal test suites. 283 /// Load suites have specific logic apart from normal test suites.
269 Future<RunnerSuite> _addLoadSuite(LoadSuite suite) async { 284 Future<RunnerSuite> _addLoadSuite(LoadSuite suite) async {
270 var liveTest = await suite.tests.single.load(suite); 285 var liveTest = await suite.test.load(suite);
271 286
272 _activeLoadTests.add(liveTest); 287 _activeLoadTests.add(liveTest);
273 288
274 // Only surface the load test if there are no other tests currently running. 289 // Only surface the load test if there are no other tests currently running.
275 if (_active.isEmpty) { 290 if (_active.isEmpty) {
276 _liveTests.add(liveTest); 291 _liveTests.add(liveTest);
277 _active.add(liveTest); 292 _active.add(liveTest);
278 } 293 }
279 294
280 liveTest.onStateChange.listen((state) { 295 liveTest.onStateChange.listen((state) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 340
326 // Close the running tests first so that we're sure to wait for them to 341 // Close the running tests first so that we're sure to wait for them to
327 // finish before we close their suites and cause them to become unloaded. 342 // finish before we close their suites and cause them to become unloaded.
328 var allLiveTests = liveTests.toSet()..addAll(_activeLoadTests); 343 var allLiveTests = liveTests.toSet()..addAll(_activeLoadTests);
329 await Future.wait(allLiveTests.map((liveTest) => liveTest.close())); 344 await Future.wait(allLiveTests.map((liveTest) => liveTest.close()));
330 345
331 var allSuites = allLiveTests.map((liveTest) => liveTest.suite).toSet(); 346 var allSuites = allLiveTests.map((liveTest) => liveTest.suite).toSet();
332 await Future.wait(allSuites.map((suite) => suite.close())); 347 await Future.wait(allSuites.map((suite) => suite.close()));
333 } 348 }
334 } 349 }
OLDNEW
« no previous file with comments | « lib/src/runner/browser/iframe_test.dart ('k') | lib/src/runner/load_suite.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698