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

Side by Side Diff: tools/testing/dart/test_runner.dart

Issue 9581025: Webdriver install script, take 2. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 /** 5 /**
6 * Classes and methods for executing tests. 6 * Classes and methods for executing tests.
7 * 7 *
8 * This module includes: 8 * This module includes:
9 * - Managing parallel execution of tests, including timeout checks. 9 * - Managing parallel execution of tests, including timeout checks.
10 * - Evaluating the output of each test as pass/fail/crash/timeout. 10 * - Evaluating the output of each test as pass/fail/crash/timeout.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 final component = configuration['component']; 121 final component = configuration['component'];
122 final mode = configuration['mode']; 122 final mode = configuration['mode'];
123 final arch = configuration['arch']; 123 final arch = configuration['arch'];
124 return "$component ${mode}_$arch"; 124 return "$component ${mode}_$arch";
125 } 125 }
126 126
127 List<String> get batchRunnerArguments() => ['-batch']; 127 List<String> get batchRunnerArguments() => ['-batch'];
128 List<String> get batchTestArguments() => commands.last().arguments; 128 List<String> get batchTestArguments() => commands.last().arguments;
129 129
130 void completed() { completedHandler(this); } 130 void completed() { completedHandler(this); }
131
132 bool get usesWebDriver() => configuration['component'] == 'webdriver';
131 } 133 }
132 134
133 135
134 /** 136 /**
135 * BrowserTestCase has an extra compilation command that is run in a separate 137 * BrowserTestCase has an extra compilation command that is run in a separate
136 * process, before the regular test is run as in the base class [TestCase]. 138 * process, before the regular test is run as in the base class [TestCase].
137 * If the compilation command fails, then the rest of the test is not run. 139 * If the compilation command fails, then the rest of the test is not run.
138 */ 140 */
139 class BrowserTestCase extends TestCase { 141 class BrowserTestCase extends TestCase {
140 /** 142 /**
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 void testComplete(int exitCode) { 281 void testComplete(int exitCode) {
280 new TestOutput(testCase, exitCode, timedOut, stdout, 282 new TestOutput(testCase, exitCode, timedOut, stdout,
281 stderr, new Date.now().difference(startTime)); 283 stderr, new Date.now().difference(startTime));
282 timeoutTimer.cancel(); 284 timeoutTimer.cancel();
283 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { 285 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
284 print(testCase.displayName); 286 print(testCase.displayName);
285 for (var line in testCase.output.stderr) print(line); 287 for (var line in testCase.output.stderr) print(line);
286 for (var line in testCase.output.stdout) print(line); 288 for (var line in testCase.output.stdout) print(line);
287 } 289 }
288 if (allowRetries != null && allowRetries 290 if (allowRetries != null && allowRetries
289 && testCase.configuration['component'] == 'webdriver' && 291 && testCase.usesWebDriver && testCase.output.unexpectedOutput
290 testCase.output.unexpectedOutput && testCase.numRetries > 0) { 292 && testCase.numRetries > 0) {
291 // Selenium tests can be flaky. Try rerunning. 293 // Selenium tests can be flaky. Try rerunning.
292 testCase.output.requestRetry = true; 294 testCase.output.requestRetry = true;
293 } 295 }
294 if (testCase.output.requestRetry) { 296 if (testCase.output.requestRetry) {
295 testCase.output.requestRetry = false; 297 testCase.output.requestRetry = false;
296 this.timedOut = false; 298 this.timedOut = false;
297 testCase.dynamic.numRetries--; 299 testCase.dynamic.numRetries--;
298 print("Potential flake. " + 300 print("Potential flake. " +
299 "Re-running ${testCase.displayName} " + 301 "Re-running ${testCase.displayName} " +
300 "(${testCase.dynamic.numRetries} attempt(s) remains)"); 302 "(${testCase.dynamic.numRetries} attempt(s) remains)");
(...skipping 13 matching lines...) Expand all
314 int totalSteps = testCase.commands.length; 316 int totalSteps = testCase.commands.length;
315 String suffix =' (step $currentStep of $totalSteps)'; 317 String suffix =' (step $currentStep of $totalSteps)';
316 if (currentStep == totalSteps) { // done with test command 318 if (currentStep == totalSteps) { // done with test command
317 testComplete(exitCode); 319 testComplete(exitCode);
318 } else if (exitCode != 0) { 320 } else if (exitCode != 0) {
319 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n'); 321 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n');
320 testComplete(exitCode); 322 testComplete(exitCode);
321 } else { 323 } else {
322 stderr.add('test.dart: Compilion finished $suffix\n'); 324 stderr.add('test.dart: Compilion finished $suffix\n');
323 stdout.add('test.dart: Compilion finished $suffix\n'); 325 stdout.add('test.dart: Compilion finished $suffix\n');
324 if (currentStep == totalSteps - 1 326 if (currentStep == totalSteps - 1 && testCase.usesWebDriver &&
325 && testCase.configuration['component'] == 'webdriver') { 327 !testCase.configuration['noBatch']) {
326 // Note: processQueue will always be non-null for component == webdriver 328 // Note: processQueue will always be non-null for component == webdriver
327 // (It is only null for component == vm) 329 // (It is only null for component == vm)
328 processQueue._getBatchRunner(testCase).startTest(testCase); 330 processQueue._getBatchRunner(testCase).startTest(testCase);
329 } else { 331 } else {
330 runCommand(testCase.commands[currentStep++], stepExitHandler); 332 runCommand(testCase.commands[currentStep++], stepExitHandler);
331 } 333 }
332 } 334 }
333 } 335 }
334 336
335 Function makeReadHandler(StringInputStream source, List<String> destination) { 337 Function makeReadHandler(StringInputStream source, List<String> destination) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 bool _stdoutDrained = false; 395 bool _stdoutDrained = false;
394 bool _stderrDrained = false; 396 bool _stderrDrained = false;
395 Date _startTime; 397 Date _startTime;
396 Timer _timer; 398 Timer _timer;
397 399
398 bool _isWebDriver; 400 bool _isWebDriver;
399 401
400 BatchRunnerProcess(TestCase testCase) { 402 BatchRunnerProcess(TestCase testCase) {
401 _executable = testCase.commands.last().executable; 403 _executable = testCase.commands.last().executable;
402 _batchArguments = testCase.batchRunnerArguments; 404 _batchArguments = testCase.batchRunnerArguments;
403 _isWebDriver = testCase.configuration['component'] == 'webdriver'; 405 _isWebDriver = testCase.usesWebDriver;
404 } 406 }
405 407
406 bool get active() => _currentTest != null; 408 bool get active() => _currentTest != null;
407 409
408 void startTest(TestCase testCase) { 410 void startTest(TestCase testCase) {
409 _currentTest = testCase; 411 _currentTest = testCase;
410 if (_process === null) { 412 if (_process === null) {
411 // Start process if not yet started. 413 // Start process if not yet started.
412 _executable = testCase.commands.last().executable; 414 _executable = testCase.commands.last().executable;
413 _startProcess(() { 415 _startProcess(() {
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 Map<String, List<BatchRunnerProcess>> _batchProcesses; 600 Map<String, List<BatchRunnerProcess>> _batchProcesses;
599 601
600 // Cache information about test cases per test suite. For multiple 602 // Cache information about test cases per test suite. For multiple
601 // configurations there is no need to repeatedly search the file 603 // configurations there is no need to repeatedly search the file
602 // system, generate tests, and search test files for options. 604 // system, generate tests, and search test files for options.
603 Map<String, List<TestInformation>> _testCache; 605 Map<String, List<TestInformation>> _testCache;
604 /** 606 /**
605 * String indicating the browser used to run the tests. Empty if no browser 607 * String indicating the browser used to run the tests. Empty if no browser
606 * used. 608 * used.
607 */ 609 */
608 String browserUsed; 610 String browserUsed = '';
611 /**
612 * Process running the selenium server .jar (only used for Safari and Opera
613 * tests.)
614 */
615 Process _seleniumServer = null;
616 /** True if we are in the process of starting the server. */
617 bool _startingServer = false;
618 /** True if we find that there is already a selenium jar running. */
619 bool _seleniumAlreadyRunning = false;
609 620
610 ProcessQueue(int this._maxProcesses, 621 ProcessQueue(int this._maxProcesses,
611 String progress, 622 String progress,
612 Date startTime, 623 Date startTime,
613 bool printTiming, 624 bool printTiming,
614 Function this._enqueueMoreWork, 625 Function this._enqueueMoreWork,
615 [bool this._verbose = false, 626 [bool this._verbose = false,
616 bool this._listTests = false, 627 bool this._listTests = false,
617 bool this._keepGeneratedTests = false]) 628 bool this._keepGeneratedTests = false])
618 : _tests = new Queue<TestCase>(), 629 : _tests = new Queue<TestCase>(),
619 _progress = new ProgressIndicator.fromName(progress, 630 _progress = new ProgressIndicator.fromName(progress,
620 startTime, 631 startTime,
621 printTiming), 632 printTiming),
622 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), 633 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(),
623 _testCache = new Map<String, List<TestInformation>>() { 634 _testCache = new Map<String, List<TestInformation>>() {
624 if (!_enqueueMoreWork(this)) _progress.allDone(); 635 if (!_enqueueMoreWork(this)) _progress.allDone();
625 browserUsed = '';
626 } 636 }
627 637
628 /** 638 /**
629 * Registers a TestSuite so that all of its tests will be run. 639 * Registers a TestSuite so that all of its tests will be run.
630 */ 640 */
631 void addTestSuite(TestSuite testSuite) { 641 void addTestSuite(TestSuite testSuite) {
632 _activeTestListers++; 642 _activeTestListers++;
633 testSuite.forEachTest(_runTest, _testCache, globalTemporaryDirectory, 643 testSuite.forEachTest(_runTest, _testCache, globalTemporaryDirectory,
634 _testListerDone); 644 _testListerDone);
635 } 645 }
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 } 701 }
692 } 702 }
693 703
694 /** 704 /**
695 * Perform any cleanup needed once all tests in a TestSuite have completed 705 * Perform any cleanup needed once all tests in a TestSuite have completed
696 * and notify our progress indicator that we are done. 706 * and notify our progress indicator that we are done.
697 */ 707 */
698 void _cleanupAndMarkDone() { 708 void _cleanupAndMarkDone() {
699 if (browserUsed != '') { 709 if (browserUsed != '') {
700 killZombieBrowsers(); 710 killZombieBrowsers();
711 if (_seleniumServer != null) {
712 _seleniumServer.kill();
713 }
701 } else { 714 } else {
702 _progress.allDone(); 715 _progress.allDone();
703 } 716 }
704 } 717 }
705 718
706 void _checkDone() { 719 void _checkDone() {
707 // When there are no more active test listers ask for more work 720 // When there are no more active test listers ask for more work
708 // from process queue users. 721 // from process queue users.
709 if (_activeTestListers == 0 && !_enqueueMoreWork(this)) { 722 if (_activeTestListers == 0 && !_enqueueMoreWork(this)) {
710 _progress.allTestsKnown(); 723 _progress.allTestsKnown();
(...skipping 18 matching lines...) Expand all
729 } 742 }
730 } else { 743 } else {
731 print('\nDeletion of temp dir $_temporaryDirectory failed.'); 744 print('\nDeletion of temp dir $_temporaryDirectory failed.');
732 } 745 }
733 _cleanupAndMarkDone(); 746 _cleanupAndMarkDone();
734 }; 747 };
735 } 748 }
736 } 749 }
737 } 750 }
738 } 751 }
752
753 /**
754 * True if we are using a browser + platform combination that needs the
755 * Selenium server jar.
756 */
757 bool get _needsSelenium() => new Platform().operatingSystem() == 'macos' &&
758 browserUsed == 'safari';
759
760 /** True if the Selenium Server is ready to be used. */
761 bool get _isSeleniumAvailable() => _seleniumServer != null ||
762 _seleniumAlreadyRunning;
763 /**
764 * Restart all the processes that have been waiting/stopped for the server to
765 * start up. If we just call this once we end up with a single-"threaded" run.
766 */
767 void resumeTesting() {
768 for (int i = 0; i < _maxProcesses; i++) _tryRunTest();
769 }
770
771 /** Start the Selenium Server jar, if appropriate for this platform. */
772 void _ensureSeleniumServerRunning() {
773 if (!_isSeleniumAvailable && !_startingServer) {
774 _startingServer = true;
775
776 // Check to see if the jar was already running before the program started.
Emily Fortuna 2012/03/02 22:45:35 New stuff here: check if selenium is already runni
777 String cmd = 'ps';
778 var arg = [];
Siggi Cherem (dart-lang) 2012/03/02 23:38:39 arg = ['axu']
779 if (new Platform().operatingSystem() == 'windows') {
780 cmd = 'tasklist';
781 arg.add('/v');
782 }
783 Process p = new Process.start(cmd, arg);
784 final StringInputStream stdoutStringStream =
785 new StringInputStream(p.stdout);
786 stdoutStringStream.onLine = () {
787 var line = stdoutStringStream.readLine();
788 while (null != line) {
789 if (const RegExp(@".*selenium-server-standalone.*").hasMatch(line)) {
790 _seleniumAlreadyRunning = true;
791 resumeTesting();
792 }
793 line = stdoutStringStream.readLine();
794 }
795 if (!_isSeleniumAvailable) {
796 _startSeleniumServer();
797 }
798 };
799 }
800 }
739 801
740 void _runTest(TestCase test) { 802 void _runTest(TestCase test) {
741 if (test.configuration['component'] == 'webdriver') { 803 if (test.usesWebDriver) {
742 browserUsed = test.configuration['browser']; 804 browserUsed = test.configuration['browser'];
805 if (_needsSelenium) _ensureSeleniumServerRunning();
743 } 806 }
744 _progress.testAdded(); 807 _progress.testAdded();
745 _tests.add(test); 808 _tests.add(test);
746 _tryRunTest(); 809 _tryRunTest();
747 } 810 }
748 811
812 /**
813 * Monitor the output of the Selenium server, to know when we are ready to
814 * begin running tests.
815 * source: Output(Stream) from the Java server.
816 */
817 Function makeSeleniumServerHandler(StringInputStream source) {
818 return () {
819 if (source.closed) return; // TODO(whesse): Remove when bug is fixed.
820 var line = source.readLine();
821 while (null != line) {
822 if (const RegExp(@".*Started.*Server.*").hasMatch(line) ||
823 const RegExp(@"Exception.*Selenium is already running.*").hasMatch(
824 line)) {
825 resumeTesting();
826 }
827 line = source.readLine();
828 }
829 };
830 }
831
832 /**
833 * For browser tests using Safari or Opera, we need to use the Selenium 1.0
834 * Java server.
835 */
836 void _startSeleniumServer() {
837 // Get the absolute path to the Selenium jar.
838 String filePath = new Options().script;
839 String pathSep = new Platform().pathSeparator();
840 int index = filePath.lastIndexOf(pathSep);
841 filePath = filePath.substring(0, index) + '${pathSep}testing${pathSep}';
842 var dir = new Directory(filePath);
843 dir.onFile = (String file) {
844 if (const RegExp(@"selenium-server-standalone-.*\.jar").hasMatch(file)
845 && _seleniumServer == null) {
846 _seleniumServer = new Process.start('java', ['-jar', file]);
847 // Heads up: there seems to an obscure data race of some form in
848 // the VM between launching the server process and launching the test
849 // tasks that disappears when you read IO (which is convenient, since
850 // that is our condition for knowing that the server is ready).
851 StringInputStream stdoutStringStream =
852 new StringInputStream(_seleniumServer.stdout);
853 StringInputStream stderrStringStream =
854 new StringInputStream(_seleniumServer.stderr);
855 stdoutStringStream.onLine =
856 makeSeleniumServerHandler(stdoutStringStream);
857 stderrStringStream.onLine =
858 makeSeleniumServerHandler(stderrStringStream);
859 }
860 };
861 dir.list();
862 }
863
749 void _terminateBatchRunners() { 864 void _terminateBatchRunners() {
750 for (var runners in _batchProcesses.getValues()) { 865 for (var runners in _batchProcesses.getValues()) {
751 for (var runner in runners) { 866 for (var runner in runners) {
752 runner.terminate(); 867 runner.terminate();
753 } 868 }
754 } 869 }
755 } 870 }
756 871
757 BatchRunnerProcess _getBatchRunner(TestCase test) { 872 BatchRunnerProcess _getBatchRunner(TestCase test) {
758 // Start batch processes if needed 873 // Start batch processes if needed
(...skipping 10 matching lines...) Expand all
769 for (var runner in runners) { 884 for (var runner in runners) {
770 if (!runner.active) return runner; 885 if (!runner.active) return runner;
771 } 886 }
772 throw new Exception('Unable to find inactive batch runner.'); 887 throw new Exception('Unable to find inactive batch runner.');
773 } 888 }
774 889
775 void _tryRunTest() { 890 void _tryRunTest() {
776 _checkDone(); 891 _checkDone();
777 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) { 892 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) {
778 TestCase test = _tests.removeFirst(); 893 TestCase test = _tests.removeFirst();
779 if (_verbose) print(test.commands.last().commandLine);
780 if (_listTests) { 894 if (_listTests) {
781 final String tab = '\t'; 895 final String tab = '\t';
782 String outcomes = 896 String outcomes =
783 Strings.join(new List.from(test.expectedOutcomes), ','); 897 Strings.join(new List.from(test.expectedOutcomes), ',');
784 print(test.displayName + tab + outcomes + tab + test.isNegative + 898 print(test.displayName + tab + outcomes + tab + test.isNegative +
785 tab + Strings.join(test.commands.last().arguments, tab)); 899 tab + Strings.join(test.commands.last().arguments, tab));
786 return; 900 return;
787 } 901 }
902 if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable) {
903 // The server is not ready to run Selenium tests. Put the test back in
904 // the queue.
905 _tests.addFirst(test);
906 return;
907 }
908 if (_verbose) print(test.commands.last().commandLine);
788 _progress.start(test); 909 _progress.start(test);
789 Function oldCallback = test.completedHandler; 910 Function oldCallback = test.completedHandler;
790 Function wrapper = (TestCase test_arg) { 911 Function wrapper = (TestCase test_arg) {
791 _numProcesses--; 912 _numProcesses--;
792 _progress.done(test_arg); 913 _progress.done(test_arg);
793 _tryRunTest(); 914 _tryRunTest();
794 oldCallback(test_arg); 915 oldCallback(test_arg);
795 }; 916 };
796 test.completedHandler = wrapper; 917 test.completedHandler = wrapper;
797 if (test.configuration['component'] == 'dartc' && 918 if (test.configuration['component'] == 'dartc' &&
798 test.displayName != 'dartc/junit_tests') { 919 test.displayName != 'dartc/junit_tests') {
799 _getBatchRunner(test).startTest(test); 920 _getBatchRunner(test).startTest(test);
800 } else { 921 } else {
801 // Once we've actually failed a test, technically, we wouldn't need to 922 // Once we've actually failed a test, technically, we wouldn't need to
802 // bother retrying any subsequent tests since the bot is already red. 923 // bother retrying any subsequent tests since the bot is already red.
803 // However, we continue to retry tests until we have actually failed 924 // However, we continue to retry tests until we have actually failed
804 // four tests (arbitrarily chosen) for more debugable output, so that 925 // four tests (arbitrarily chosen) for more debugable output, so that
805 // the developer doesn't waste his or her time trying to fix a bunch of 926 // the developer doesn't waste his or her time trying to fix a bunch of
806 // tests that appear to be broken but were actually just flakes that 927 // tests that appear to be broken but were actually just flakes that
807 // didn't get retried because there had already been one failure. 928 // didn't get retried because there had already been one failure.
808 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 929 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
809 new RunningProcess(test, allowRetry, this).start(); 930 new RunningProcess(test, allowRetry, this).start();
810 } 931 }
811 _numProcesses++; 932 _numProcesses++;
812 } 933 }
813 } 934 }
814 } 935 }
OLDNEW
« no previous file with comments | « tools/testing/dart/test_options.dart ('k') | tools/testing/perf_testing/buildbot_browser_test_setup.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698