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

Unified Diff: mojo/public/dart/third_party/test/lib/src/runner.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: mojo/public/dart/third_party/test/lib/src/runner.dart
diff --git a/mojo/public/dart/third_party/test/lib/src/runner.dart b/mojo/public/dart/third_party/test/lib/src/runner.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9a5756bc6de3f9cd4727205c90e47c6cb89e1422
--- /dev/null
+++ b/mojo/public/dart/third_party/test/lib/src/runner.dart
@@ -0,0 +1,256 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.runner;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:async/async.dart';
+
+import 'backend/test_platform.dart';
+import 'runner/application_exception.dart';
+import 'runner/configuration.dart';
+import 'runner/engine.dart';
+import 'runner/load_exception.dart';
+import 'runner/load_suite.dart';
+import 'runner/loader.dart';
+import 'runner/reporter.dart';
+import 'runner/reporter/compact.dart';
+import 'runner/reporter/expanded.dart';
+import 'runner/runner_suite.dart';
+import 'util/io.dart';
+import 'utils.dart';
+
+/// A class that loads and runs tests based on a [Configuration].
+///
+/// This maintains a [Loader] and an [Engine] and passes test suites from one to
+/// the other, as well as printing out tests with a [CompactReporter] or an
+/// [ExpandedReporter].
+class Runner {
+ /// The configuration for the runner.
+ final Configuration _config;
+
+ /// The loader that loads the test suites from the filesystem.
+ final Loader _loader;
+
+ /// The engine that runs the test suites.
+ final Engine _engine;
+
+ /// The reporter that's emitting the test runner's results.
+ final Reporter _reporter;
+
+ /// The subscription to the stream returned by [_loadSuites].
+ StreamSubscription _suiteSubscription;
+
+ /// The memoizer for ensuring [close] only runs once.
+ final _closeMemo = new AsyncMemoizer();
+ bool get _closed => _closeMemo.hasRun;
+
+ /// Creates a new runner based on [configuration].
+ factory Runner(Configuration config) {
+ var loader = new Loader(config);
+ var engine = new Engine(concurrency: config.concurrency);
+
+ var watch = config.reporter == "compact"
+ ? CompactReporter.watch
+ : ExpandedReporter.watch;
+
+ var reporter = watch(
+ engine,
+ color: config.color,
+ verboseTrace: config.verboseTrace,
+ printPath: config.paths.length > 1 ||
+ new Directory(config.paths.single).existsSync(),
+ printPlatform: config.platforms.length > 1);
+
+ return new Runner._(config, loader, engine, reporter);
+ }
+
+ Runner._(this._config, this._loader, this._engine, this._reporter);
+
+ /// Starts the runner.
+ ///
+ /// This starts running tests and printing their progress. It returns whether
+ /// or not they ran successfully.
+ Future<bool> run() async {
+ if (_closed) {
+ throw new StateError("run() may not be called on a closed Runner.");
+ }
+
+ var suites = _loadSuites();
+
+ var success;
+ if (_config.pauseAfterLoad) {
+ success = await _loadThenPause(suites);
+ } else {
+ _suiteSubscription = suites.listen(_engine.suiteSink.add);
+ var results = await Future.wait([
+ _suiteSubscription.asFuture().then((_) => _engine.suiteSink.close()),
+ _engine.run()
+ ], eagerError: true);
+ success = results.last;
+ }
+
+ if (_closed) return false;
+
+ if (_engine.passed.length == 0 && _engine.failed.length == 0 &&
+ _engine.skipped.length == 0 && _config.pattern != null) {
+ var message = 'No tests match ';
+
+ if (_config.pattern is RegExp) {
+ var pattern = (_config.pattern as RegExp).pattern;
+ message += 'regular expression "$pattern".';
+ } else {
+ message += '"${_config.pattern}".';
+ }
+ throw new ApplicationException(message);
+ }
+
+ // Explicitly check "== true" here because [Engine.run] can return `null`
+ // if the engine was closed prematurely.
+ return success == true;
+ }
+
+ /// Closes the runner.
+ ///
+ /// This stops any future test suites from running. It will wait for any
+ /// currently-running VM tests, in case they have stuff to clean up on the
+ /// filesystem.
+ Future close() => _closeMemo.runOnce(() async {
+ var timer;
+ if (!_engine.isIdle) {
+ // Wait a bit to print this message, since printing it eagerly looks weird
+ // if the tests then finish immediately.
+ timer = new Timer(new Duration(seconds: 1), () {
+ // Pause the reporter while we print to ensure that we don't interfere
+ // with its output.
+ _reporter.pause();
+ print("Waiting for current test(s) to finish.");
+ print("Press Control-C again to terminate immediately.");
+ _reporter.resume();
+ });
+ }
+
+ if (_suiteSubscription != null) _suiteSubscription.cancel();
+ _suiteSubscription = null;
+
+ // Make sure we close the engine *before* the loader. Otherwise,
+ // LoadSuites provided by the loader may get into bad states.
+ await _engine.close();
+ if (timer != null) timer.cancel();
+ await _loader.close();
+ });
+
+ /// Return a stream of [LoadSuite]s in [_config.paths].
+ ///
+ /// Only tests that match [_config.pattern] will be included in the
+ /// suites once they're loaded.
+ Stream<LoadSuite> _loadSuites() {
+ return mergeStreams(_config.paths.map((path) {
+ if (new Directory(path).existsSync()) return _loader.loadDir(path);
+ if (new File(path).existsSync()) return _loader.loadFile(path);
+
+ return new Stream.fromIterable([
+ new LoadSuite("loading $path", () =>
+ throw new LoadException(path, 'Does not exist.'))
+ ]);
+ })).map((loadSuite) {
+ return loadSuite.changeSuite((suite) {
+ if (_config.pattern == null) return suite;
+ return suite.change(tests: suite.tests.where((test) =>
+ test.name.contains(_config.pattern)));
+ });
+ });
+ }
+
+ /// Loads each suite in [suites] in order, pausing after load for platforms
+ /// that support debugging.
+ Future<bool> _loadThenPause(Stream<LoadSuite> suites) async {
+ if (_config.platforms.contains(TestPlatform.vm)) {
+ warn("Debugging is currently unsupported on the Dart VM.",
+ color: _config.color);
+ }
+
+ _suiteSubscription = suites.asyncMap((loadSuite) async {
+ // Make the underlying suite null so that the engine doesn't start running
+ // it immediately.
+ _engine.suiteSink.add(loadSuite.changeSuite((_) => null));
+
+ var suite = await loadSuite.suite;
+ if (suite == null) return;
+
+ await _pause(suite);
+ if (_closed) return;
+
+ _engine.suiteSink.add(suite);
+ await _engine.onIdle.first;
+ }).listen(null);
+
+ var results = await Future.wait([
+ _suiteSubscription.asFuture().then((_) => _engine.suiteSink.close()),
+ _engine.run()
+ ]);
+ return results.last;
+ }
+
+ /// Pauses the engine and the reporter so that the user can set breakpoints as
+ /// necessary.
+ ///
+ /// This is a no-op for test suites that aren't on platforms where debugging
+ /// is supported.
+ Future _pause(RunnerSuite suite) async {
+ if (suite.platform == null) return;
+ if (suite.platform == TestPlatform.vm) return;
+
+ try {
+ _reporter.pause();
+
+ var bold = _config.color ? '\u001b[1m' : '';
+ var yellow = _config.color ? '\u001b[33m' : '';
+ var noColor = _config.color ? '\u001b[0m' : '';
+ print('');
+
+ if (suite.platform.isDartVM) {
+ var url = suite.environment.observatoryUrl;
+ if (url == null) {
+ print("${yellow}Observatory URL not found. Make sure you're using "
+ "${suite.platform.name} 1.11 or later.$noColor");
+ } else {
+ print("Observatory URL: $bold$url$noColor");
+ }
+ }
+
+ if (suite.platform.isHeadless) {
+ var url = suite.environment.remoteDebuggerUrl;
+ if (url == null) {
+ print("${yellow}Remote debugger URL not found.$noColor");
+ } else {
+ print("Remote debugger URL: $bold$url$noColor");
+ }
+ }
+
+ var buffer = new StringBuffer(
+ "${bold}The test runner is paused.${noColor} ");
+ if (!suite.platform.isHeadless) {
+ buffer.write("Open the dev console in ${suite.platform} ");
+ } else {
+ buffer.write("Open the remote debugger ");
+ }
+ if (suite.platform.isDartVM) buffer.write("or the Observatory ");
+
+ buffer.write("and set breakpoints. Once you're finished, return to this "
+ "terminal and press Enter.");
+
+ print(wordWrap(buffer.toString()));
+
+ await inCompletionOrder([
+ suite.environment.displayPause(),
+ cancelableNext(stdinLines)
+ ]).first;
+ } finally {
+ _reporter.resume();
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698