| 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; | 5 library test.runner; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:async/async.dart'; | 10 import 'package:async/async.dart'; |
| 11 | 11 |
| 12 import 'backend/group.dart'; | 12 import 'backend/group.dart'; |
| 13 import 'backend/group_entry.dart'; | 13 import 'backend/group_entry.dart'; |
| 14 import 'backend/suite.dart'; | 14 import 'backend/suite.dart'; |
| 15 import 'backend/test.dart'; | 15 import 'backend/test.dart'; |
| 16 import 'backend/test_platform.dart'; | 16 import 'backend/test_platform.dart'; |
| 17 import 'runner/application_exception.dart'; | 17 import 'runner/application_exception.dart'; |
| 18 import 'runner/configuration.dart'; | 18 import 'runner/configuration.dart'; |
| 19 import 'runner/debugger.dart'; |
| 19 import 'runner/engine.dart'; | 20 import 'runner/engine.dart'; |
| 20 import 'runner/load_exception.dart'; | 21 import 'runner/load_exception.dart'; |
| 21 import 'runner/load_suite.dart'; | 22 import 'runner/load_suite.dart'; |
| 22 import 'runner/loader.dart'; | 23 import 'runner/loader.dart'; |
| 23 import 'runner/reporter.dart'; | 24 import 'runner/reporter.dart'; |
| 24 import 'runner/reporter/compact.dart'; | 25 import 'runner/reporter/compact.dart'; |
| 25 import 'runner/reporter/expanded.dart'; | 26 import 'runner/reporter/expanded.dart'; |
| 26 import 'runner/reporter/json.dart'; | 27 import 'runner/reporter/json.dart'; |
| 27 import 'runner/runner_suite.dart'; | |
| 28 import 'util/io.dart'; | 28 import 'util/io.dart'; |
| 29 import 'utils.dart'; | 29 import 'utils.dart'; |
| 30 | 30 |
| 31 /// A class that loads and runs tests based on a [Configuration]. | 31 /// A class that loads and runs tests based on a [Configuration]. |
| 32 /// | 32 /// |
| 33 /// This maintains a [Loader] and an [Engine] and passes test suites from one to | 33 /// This maintains a [Loader] and an [Engine] and passes test suites from one to |
| 34 /// the other, as well as printing out tests with a [CompactReporter] or an | 34 /// the other, as well as printing out tests with a [CompactReporter] or an |
| 35 /// [ExpandedReporter]. | 35 /// [ExpandedReporter]. |
| 36 class Runner { | 36 class Runner { |
| 37 /// The configuration for the runner. | 37 /// The configuration for the runner. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 49 /// The subscription to the stream returned by [_loadSuites]. | 49 /// The subscription to the stream returned by [_loadSuites]. |
| 50 StreamSubscription _suiteSubscription; | 50 StreamSubscription _suiteSubscription; |
| 51 | 51 |
| 52 /// The set of suite paths for which [_warnForUnknownTags] has already been | 52 /// The set of suite paths for which [_warnForUnknownTags] has already been |
| 53 /// called. | 53 /// called. |
| 54 /// | 54 /// |
| 55 /// This is used to avoid printing duplicate warnings when a suite is loaded | 55 /// This is used to avoid printing duplicate warnings when a suite is loaded |
| 56 /// on multiple platforms. | 56 /// on multiple platforms. |
| 57 final _tagWarningSuites = new Set<String>(); | 57 final _tagWarningSuites = new Set<String>(); |
| 58 | 58 |
| 59 /// The current debug operation, if any. |
| 60 /// |
| 61 /// This is stored so that we can cancel it when the runner is closed. |
| 62 CancelableOperation _debugOperation; |
| 63 |
| 59 /// The memoizer for ensuring [close] only runs once. | 64 /// The memoizer for ensuring [close] only runs once. |
| 60 final _closeMemo = new AsyncMemoizer(); | 65 final _closeMemo = new AsyncMemoizer(); |
| 61 bool get _closed => _closeMemo.hasRun; | 66 bool get _closed => _closeMemo.hasRun; |
| 62 | 67 |
| 63 /// Creates a new runner based on [configuration]. | 68 /// Creates a new runner based on [configuration]. |
| 64 factory Runner(Configuration config) { | 69 factory Runner(Configuration config) { |
| 65 var loader = new Loader(config); | 70 var loader = new Loader(config); |
| 66 var engine = new Engine(concurrency: config.concurrency); | 71 var engine = new Engine(concurrency: config.concurrency); |
| 67 | 72 |
| 68 var reporter; | 73 var reporter; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 timer = new Timer(new Duration(seconds: 1), () { | 154 timer = new Timer(new Duration(seconds: 1), () { |
| 150 // Pause the reporter while we print to ensure that we don't interfere | 155 // Pause the reporter while we print to ensure that we don't interfere |
| 151 // with its output. | 156 // with its output. |
| 152 _reporter.pause(); | 157 _reporter.pause(); |
| 153 print("Waiting for current test(s) to finish."); | 158 print("Waiting for current test(s) to finish."); |
| 154 print("Press Control-C again to terminate immediately."); | 159 print("Press Control-C again to terminate immediately."); |
| 155 _reporter.resume(); | 160 _reporter.resume(); |
| 156 }); | 161 }); |
| 157 } | 162 } |
| 158 | 163 |
| 164 if (_debugOperation != null) await _debugOperation.cancel(); |
| 165 |
| 159 if (_suiteSubscription != null) _suiteSubscription.cancel(); | 166 if (_suiteSubscription != null) _suiteSubscription.cancel(); |
| 160 _suiteSubscription = null; | 167 _suiteSubscription = null; |
| 161 | 168 |
| 162 // Make sure we close the engine *before* the loader. Otherwise, | 169 // Make sure we close the engine *before* the loader. Otherwise, |
| 163 // LoadSuites provided by the loader may get into bad states. | 170 // LoadSuites provided by the loader may get into bad states. |
| 164 await _engine.close(); | 171 await _engine.close(); |
| 165 if (timer != null) timer.cancel(); | 172 if (timer != null) timer.cancel(); |
| 166 await _loader.close(); | 173 await _loader.close(); |
| 167 }); | 174 }); |
| 168 | 175 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 | 290 |
| 284 /// Loads each suite in [suites] in order, pausing after load for platforms | 291 /// Loads each suite in [suites] in order, pausing after load for platforms |
| 285 /// that support debugging. | 292 /// that support debugging. |
| 286 Future<bool> _loadThenPause(Stream<LoadSuite> suites) async { | 293 Future<bool> _loadThenPause(Stream<LoadSuite> suites) async { |
| 287 if (_config.platforms.contains(TestPlatform.vm)) { | 294 if (_config.platforms.contains(TestPlatform.vm)) { |
| 288 warn("Debugging is currently unsupported on the Dart VM.", | 295 warn("Debugging is currently unsupported on the Dart VM.", |
| 289 color: _config.color); | 296 color: _config.color); |
| 290 } | 297 } |
| 291 | 298 |
| 292 _suiteSubscription = suites.asyncMap((loadSuite) async { | 299 _suiteSubscription = suites.asyncMap((loadSuite) async { |
| 293 // Make the underlying suite null so that the engine doesn't start running | 300 _debugOperation = debug(_config, _engine, _reporter, loadSuite); |
| 294 // it immediately. | 301 await _debugOperation.valueOrCancellation(); |
| 295 _engine.suiteSink.add(loadSuite.changeSuite((_) => null)); | |
| 296 | |
| 297 var suite = await loadSuite.suite; | |
| 298 if (suite == null) return; | |
| 299 | |
| 300 await _pause(suite); | |
| 301 if (_closed) return; | |
| 302 | |
| 303 _engine.suiteSink.add(suite); | |
| 304 await _engine.onIdle.first; | |
| 305 }).listen(null); | 302 }).listen(null); |
| 306 | 303 |
| 307 var results = await Future.wait([ | 304 var results = await Future.wait([ |
| 308 _suiteSubscription.asFuture().then((_) => _engine.suiteSink.close()), | 305 _suiteSubscription.asFuture().then((_) => _engine.suiteSink.close()), |
| 309 _engine.run() | 306 _engine.run() |
| 310 ]); | 307 ]); |
| 311 return results.last; | 308 return results.last; |
| 312 } | 309 } |
| 313 | |
| 314 /// Pauses the engine and the reporter so that the user can set breakpoints as | |
| 315 /// necessary. | |
| 316 /// | |
| 317 /// This is a no-op for test suites that aren't on platforms where debugging | |
| 318 /// is supported. | |
| 319 Future _pause(RunnerSuite suite) async { | |
| 320 if (suite.platform == null) return; | |
| 321 if (suite.platform == TestPlatform.vm) return; | |
| 322 | |
| 323 try { | |
| 324 _reporter.pause(); | |
| 325 | |
| 326 var bold = _config.color ? '\u001b[1m' : ''; | |
| 327 var yellow = _config.color ? '\u001b[33m' : ''; | |
| 328 var noColor = _config.color ? '\u001b[0m' : ''; | |
| 329 print(''); | |
| 330 | |
| 331 if (suite.platform.isDartVM) { | |
| 332 var url = suite.environment.observatoryUrl; | |
| 333 if (url == null) { | |
| 334 print("${yellow}Observatory URL not found. Make sure you're using " | |
| 335 "${suite.platform.name} 1.11 or later.$noColor"); | |
| 336 } else { | |
| 337 print("Observatory URL: $bold$url$noColor"); | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 if (suite.platform.isHeadless) { | |
| 342 var url = suite.environment.remoteDebuggerUrl; | |
| 343 if (url == null) { | |
| 344 print("${yellow}Remote debugger URL not found.$noColor"); | |
| 345 } else { | |
| 346 print("Remote debugger URL: $bold$url$noColor"); | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 var buffer = new StringBuffer( | |
| 351 "${bold}The test runner is paused.${noColor} "); | |
| 352 if (!suite.platform.isHeadless) { | |
| 353 buffer.write("Open the dev console in ${suite.platform} "); | |
| 354 } else { | |
| 355 buffer.write("Open the remote debugger "); | |
| 356 } | |
| 357 if (suite.platform.isDartVM) buffer.write("or the Observatory "); | |
| 358 | |
| 359 buffer.write("and set breakpoints. Once you're finished, return to this " | |
| 360 "terminal and press Enter."); | |
| 361 | |
| 362 print(wordWrap(buffer.toString())); | |
| 363 | |
| 364 await inCompletionOrder([ | |
| 365 suite.environment.displayPause(), | |
| 366 cancelableNext(stdinLines) | |
| 367 ]).first; | |
| 368 } finally { | |
| 369 _reporter.resume(); | |
| 370 } | |
| 371 } | |
| 372 } | 310 } |
| OLD | NEW |