OLD | NEW |
---|---|
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 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
325 && testCase.configuration['component'] == 'webdriver') { | 325 && testCase.configuration['component'] == 'webdriver') { |
326 // Note: processQueue will always be non-null for component == webdriver | 326 // Note: processQueue will always be non-null for component == webdriver |
327 // (It is only null for component == vm) | 327 // (It is only null for component == vm) |
328 processQueue._getBatchRunner(testCase).startTest(testCase); | 328 processQueue._getBatchRunner(testCase).startTest(testCase); |
329 } else { | 329 } else { |
330 runCommand(testCase.commands[currentStep++], stepExitHandler); | 330 runCommand(testCase.commands[currentStep++], stepExitHandler); |
331 } | 331 } |
332 } | 332 } |
333 } | 333 } |
334 | 334 |
335 Function makeReadHandler(StringInputStream source, List<String> destination) { | 335 Function makeReadHandler(StringInputStream source, |
336 List<String> destination) { | |
336 return () { | 337 return () { |
337 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. | 338 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. |
338 var line = source.readLine(); | 339 var line = source.readLine(); |
339 while (null != line) { | 340 while (null != line) { |
340 destination.add(line); | 341 destination.add(line); |
341 line = source.readLine(); | 342 line = source.readLine(); |
342 } | 343 } |
343 }; | 344 }; |
344 } | 345 } |
345 | 346 |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
569 | 570 |
570 // Cache information about test cases per test suite. For multiple | 571 // Cache information about test cases per test suite. For multiple |
571 // configurations there is no need to repeatedly search the file | 572 // configurations there is no need to repeatedly search the file |
572 // system, generate tests, and search test files for options. | 573 // system, generate tests, and search test files for options. |
573 Map<String, List<TestInformation>> _testCache; | 574 Map<String, List<TestInformation>> _testCache; |
574 /** | 575 /** |
575 * String indicating the browser used to run the tests. Empty if no browser | 576 * String indicating the browser used to run the tests. Empty if no browser |
576 * used. | 577 * used. |
577 */ | 578 */ |
578 String browserUsed; | 579 String browserUsed; |
580 /** | |
581 * Process running the selenium server .jar (only used for Safari and Opera | |
582 * tests.) | |
583 */ | |
584 Process seleniumServer; | |
585 /** True if we are in the process of starting the server. */ | |
586 bool startingServer; | |
579 | 587 |
580 ProcessQueue(int this._maxProcesses, | 588 ProcessQueue(int this._maxProcesses, |
581 String progress, | 589 String progress, |
582 Date startTime, | 590 Date startTime, |
583 bool printTiming, | 591 bool printTiming, |
584 Function this._enqueueMoreWork, | 592 Function this._enqueueMoreWork, |
585 [bool this._verbose = false, | 593 [bool this._verbose = false, |
586 bool this._listTests = false, | 594 bool this._listTests = false, |
587 bool this._keepGeneratedTests = false]) | 595 bool this._keepGeneratedTests = false]) |
588 : _tests = new Queue<TestCase>(), | 596 : _tests = new Queue<TestCase>(), |
589 _progress = new ProgressIndicator.fromName(progress, | 597 _progress = new ProgressIndicator.fromName(progress, |
590 startTime, | 598 startTime, |
591 printTiming), | 599 printTiming), |
592 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), | 600 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), |
593 _testCache = new Map<String, List<TestInformation>>() { | 601 _testCache = new Map<String, List<TestInformation>>() { |
594 if (!_enqueueMoreWork(this)) _progress.allDone(); | 602 if (!_enqueueMoreWork(this)) _progress.allDone(); |
595 browserUsed = ''; | 603 browserUsed = ''; |
604 seleniumServer = null; | |
605 startingServer = false; | |
Siggi Cherem (dart-lang)
2012/02/29 02:12:08
you should be able to initialize both inline in th
Emily Fortuna
2012/03/01 23:55:13
Done.
| |
596 } | 606 } |
597 | 607 |
598 /** | 608 /** |
599 * Registers a TestSuite so that all of its tests will be run. | 609 * Registers a TestSuite so that all of its tests will be run. |
600 */ | 610 */ |
601 void addTestSuite(TestSuite testSuite) { | 611 void addTestSuite(TestSuite testSuite) { |
602 _activeTestListers++; | 612 _activeTestListers++; |
603 testSuite.forEachTest(_runTest, _testCache, globalTemporaryDirectory, | 613 testSuite.forEachTest(_runTest, _testCache, globalTemporaryDirectory, |
604 _testListerDone); | 614 _testListerDone); |
605 } | 615 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
661 } | 671 } |
662 } | 672 } |
663 | 673 |
664 /** | 674 /** |
665 * Perform any cleanup needed once all tests in a TestSuite have completed | 675 * Perform any cleanup needed once all tests in a TestSuite have completed |
666 * and notify our progress indicator that we are done. | 676 * and notify our progress indicator that we are done. |
667 */ | 677 */ |
668 void _cleanupAndMarkDone() { | 678 void _cleanupAndMarkDone() { |
669 if (browserUsed != '') { | 679 if (browserUsed != '') { |
670 killZombieBrowsers(); | 680 killZombieBrowsers(); |
681 if (seleniumServer != null) { | |
682 seleniumServer.kill(); | |
683 } | |
671 } else { | 684 } else { |
672 _progress.allDone(); | 685 _progress.allDone(); |
673 } | 686 } |
674 } | 687 } |
675 | 688 |
676 void _checkDone() { | 689 void _checkDone() { |
677 // When there are no more active test listers ask for more work | 690 // When there are no more active test listers ask for more work |
678 // from process queue users. | 691 // from process queue users. |
679 if (_activeTestListers == 0 && !_enqueueMoreWork(this)) { | 692 if (_activeTestListers == 0 && !_enqueueMoreWork(this)) { |
680 _progress.allTestsKnown(); | 693 _progress.allTestsKnown(); |
(...skipping 22 matching lines...) Expand all Loading... | |
703 _cleanupAndMarkDone(); | 716 _cleanupAndMarkDone(); |
704 }; | 717 }; |
705 } | 718 } |
706 } | 719 } |
707 } | 720 } |
708 } | 721 } |
709 | 722 |
710 void _runTest(TestCase test) { | 723 void _runTest(TestCase test) { |
711 if (test.configuration['component'] == 'webdriver') { | 724 if (test.configuration['component'] == 'webdriver') { |
712 browserUsed = test.configuration['browser']; | 725 browserUsed = test.configuration['browser']; |
726 if (new Platform().operatingSystem() == 'macos' && browserUsed == 'safari' | |
727 && seleniumServer == null && startingServer == false) { | |
Siggi Cherem (dart-lang)
2012/02/29 02:12:08
style nit: I'd move these last two conditions into
Jennifer Messerly
2012/02/29 08:51:21
+1
Emily Fortuna
2012/03/01 23:55:13
Done.
| |
728 startingServer = true; | |
729 _startSeleniumServer(); | |
730 } | |
713 } | 731 } |
714 _progress.testAdded(); | 732 _progress.testAdded(); |
715 _tests.add(test); | 733 _tests.add(test); |
716 _tryRunTest(); | 734 _tryRunTest(); |
717 } | 735 } |
718 | 736 |
737 /** | |
738 * For browser tests using Safari or Opera, we need to use the Selenium 1.0 | |
739 * Java server. | |
740 */ | |
741 void _startSeleniumServer() { | |
742 // Get the absolute path to the Selenium jar. | |
743 String filePath = new Options().script; | |
744 String pathSep = new Platform().pathSeparator(); | |
745 int index = filePath.lastIndexOf(pathSep); | |
746 filePath = filePath.substring(0, index) + '${pathSep}testing${pathSep}'; | |
747 String command = 'ls'; | |
748 List<String> args = [filePath]; | |
749 // Right now the Selenium server is only used on the mac, but it will be | |
750 // used on Windows when we are testing Opera. | |
751 if (new Platform().operatingSystem() == 'windows') { | |
752 command = 'dir'; | |
753 args.add('/B'); | |
754 } | |
755 Process process = new Process.start(command, args); | |
756 StringInputStream stdoutStringStream = | |
757 new StringInputStream(process.stdout); | |
758 stdoutStringStream.lineHandler = () { | |
759 String seleniumJar = stdoutStringStream.readLine(); | |
760 // Loop through the files in the directory to find the jar. We can't do | |
761 // this a more elegant way right now because | |
762 // 'ls selenium-standalone-server*' doesn't work without a shell. | |
763 // TODO(efortuna): Clean this up when the IO API provides more. | |
Siggi Cherem (dart-lang)
2012/02/29 02:12:08
instead of reading the output of dir/ls to find th
| |
764 while (seleniumJar != null) { | |
765 if (seleniumJar.startsWith('selenium-server-standalone-') && | |
766 seleniumJar.endsWith('.jar')) { | |
767 var seleniumProcess = new Process.start('java', ['-jar', | |
Siggi Cherem (dart-lang)
2012/02/29 02:12:08
does this process print anything when it's ready?
| |
768 '${filePath}${seleniumJar}']); | |
769 // The Selenium server takes a little while to start and be ready to | |
770 // receive connections, so we wait before running our tests (~8 sec). | |
771 new Timer((Timer t) { | |
772 seleniumServer = seleniumProcess; | |
773 for (int i = 0; i < _maxProcesses; i++) { | |
774 // Attempt to run all the processes that have been waiting for | |
775 // the server to start up. If we just call this once we end up | |
776 // with a single-threaded run. | |
777 _tryRunTest(); | |
778 } | |
779 }, 8000); | |
780 return; | |
781 } | |
782 seleniumJar = stderrStringStream.readLine(); | |
Siggi Cherem (dart-lang)
2012/02/29 02:12:08
should this be stdoutStringStream? (of course this
| |
783 } | |
784 }; | |
785 } | |
786 | |
719 void _terminateBatchRunners() { | 787 void _terminateBatchRunners() { |
720 for (var runners in _batchProcesses.getValues()) { | 788 for (var runners in _batchProcesses.getValues()) { |
721 for (var runner in runners) { | 789 for (var runner in runners) { |
722 runner.terminate(); | 790 runner.terminate(); |
723 } | 791 } |
724 } | 792 } |
725 } | 793 } |
726 | 794 |
727 BatchRunnerProcess _getBatchRunner(TestCase test) { | 795 BatchRunnerProcess _getBatchRunner(TestCase test) { |
728 // Start batch processes if needed | 796 // Start batch processes if needed |
(...skipping 10 matching lines...) Expand all Loading... | |
739 for (var runner in runners) { | 807 for (var runner in runners) { |
740 if (!runner.active) return runner; | 808 if (!runner.active) return runner; |
741 } | 809 } |
742 throw new Exception('Unable to find inactive batch runner.'); | 810 throw new Exception('Unable to find inactive batch runner.'); |
743 } | 811 } |
744 | 812 |
745 void _tryRunTest() { | 813 void _tryRunTest() { |
746 _checkDone(); | 814 _checkDone(); |
747 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) { | 815 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) { |
748 TestCase test = _tests.removeFirst(); | 816 TestCase test = _tests.removeFirst(); |
817 if (test.configuration['component'] == 'webdriver' | |
818 && seleniumServer == null) { | |
Siggi Cherem (dart-lang)
2012/02/29 02:12:08
should this also check for safari & mac? maybe int
Jennifer Messerly
2012/02/29 08:51:21
also: we have a decent number of "test.configurati
Emily Fortuna
2012/03/01 23:55:13
Done.
Emily Fortuna
2012/03/01 23:55:13
Done.
| |
819 _tests.addFirst(test); | |
820 return; | |
821 } | |
749 if (_verbose) print(test.commands.last().commandLine); | 822 if (_verbose) print(test.commands.last().commandLine); |
750 if (_listTests) { | 823 if (_listTests) { |
751 final String tab = '\t'; | 824 final String tab = '\t'; |
752 String outcomes = | 825 String outcomes = |
753 Strings.join(new List.from(test.expectedOutcomes), ','); | 826 Strings.join(new List.from(test.expectedOutcomes), ','); |
754 print(test.displayName + tab + outcomes + tab + test.isNegative + | 827 print(test.displayName + tab + outcomes + tab + test.isNegative + |
755 tab + Strings.join(test.commands.last().arguments, tab)); | 828 tab + Strings.join(test.commands.last().arguments, tab)); |
756 return; | 829 return; |
757 } | 830 } |
758 _progress.start(test); | 831 _progress.start(test); |
(...skipping 16 matching lines...) Expand all Loading... | |
775 // the developer doesn't waste his or her time trying to fix a bunch of | 848 // the developer doesn't waste his or her time trying to fix a bunch of |
776 // tests that appear to be broken but were actually just flakes that | 849 // tests that appear to be broken but were actually just flakes that |
777 // didn't get retried because there had already been one failure. | 850 // didn't get retried because there had already been one failure. |
778 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 851 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; |
779 new RunningProcess(test, allowRetry, this).start(); | 852 new RunningProcess(test, allowRetry, this).start(); |
780 } | 853 } |
781 _numProcesses++; | 854 _numProcesses++; |
782 } | 855 } |
783 } | 856 } |
784 } | 857 } |
OLD | NEW |