| 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 | 
|---|