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

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

Issue 10440071: Fix erroneous asynchronous code in test scripts (batch runner). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove stray line of code. Created 8 years, 6 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 621 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler); 632 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler);
633 } 633 }
634 } 634 }
635 635
636 void timeoutHandler(Timer unusedTimer) { 636 void timeoutHandler(Timer unusedTimer) {
637 timedOut = true; 637 timedOut = true;
638 process.kill(); 638 process.kill();
639 } 639 }
640 } 640 }
641 641
642 /**
643 * This class holds a value, that can be changed. It is used when
644 * closures need a shared value, that they can all change and read.
645 */
646 class MutableValue<T> {
647 MutableValue(T this.value);
648 T value;
649 }
650
642 class BatchRunnerProcess { 651 class BatchRunnerProcess {
643 String _executable; 652 String _executable;
644 List<String> _batchArguments; 653 List<String> _batchArguments;
645 654
646 Process _process; 655 Process _process;
647 StringInputStream _stdoutStream; 656 StringInputStream _stdoutStream;
648 StringInputStream _stderrStream; 657 StringInputStream _stderrStream;
649 658
650 TestCase _currentTest; 659 TestCase _currentTest;
651 List<String> _testStdout; 660 List<String> _testStdout;
652 List<String> _testStderr; 661 List<String> _testStderr;
662 String _status;
653 bool _stdoutDrained = false; 663 bool _stdoutDrained = false;
654 bool _stderrDrained = false; 664 bool _stderrDrained = false;
665 MutableValue<bool> _ignoreStreams;
655 Date _startTime; 666 Date _startTime;
656 Timer _timer; 667 Timer _timer;
657 668
658 bool _isWebDriver; 669 bool _isWebDriver;
659 670
660 BatchRunnerProcess(TestCase testCase) { 671 BatchRunnerProcess(TestCase testCase) {
661 _executable = testCase.commands.last().executable; 672 _executable = testCase.commands.last().executable;
662 _batchArguments = testCase.batchRunnerArguments; 673 _batchArguments = testCase.batchRunnerArguments;
663 _isWebDriver = testCase.usesWebDriver; 674 _isWebDriver = testCase.usesWebDriver;
664 } 675 }
665 676
666 bool get active() => _currentTest != null; 677 bool get active() => _currentTest != null;
667 678
668 void startTest(TestCase testCase) { 679 void startTest(TestCase testCase) {
680 Expect.isNull(_currentTest);
669 _currentTest = testCase; 681 _currentTest = testCase;
670 if (_process === null) { 682 if (_process === null) {
671 // Start process if not yet started. 683 // Start process if not yet started.
672 _executable = testCase.commands.last().executable; 684 _executable = testCase.commands.last().executable;
673 _startProcess(() { 685 _startProcess(() {
674 doStartTest(testCase); 686 doStartTest(testCase);
675 }); 687 });
676 } else if (testCase.commands.last().executable != _executable) { 688 } else if (testCase.commands.last().executable != _executable) {
677 // Restart this runner with the right executable for this test 689 // Restart this runner with the right executable for this test
678 // if needed. 690 // if needed.
(...skipping 30 matching lines...) Expand all
709 } else { 721 } else {
710 _process.kill(); 722 _process.kill();
711 } 723 }
712 } 724 }
713 } 725 }
714 726
715 void doStartTest(TestCase testCase) { 727 void doStartTest(TestCase testCase) {
716 _startTime = new Date.now(); 728 _startTime = new Date.now();
717 _testStdout = []; 729 _testStdout = [];
718 _testStderr = []; 730 _testStderr = [];
731 _status = null;
719 _stdoutDrained = false; 732 _stdoutDrained = false;
720 _stderrDrained = false; 733 _stderrDrained = false;
734 _ignoreStreams = new MutableValue<bool>(false); // Captured by closures.
721 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout); 735 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout);
722 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr); 736 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr);
723 _timer = new Timer(testCase.timeout * 1000, _timeoutHandler); 737 _timer = new Timer(testCase.timeout * 1000, _timeoutHandler);
724 var line = _createArgumentsLine(testCase.batchTestArguments); 738 var line = _createArgumentsLine(testCase.batchTestArguments);
725 _process.stdin.write(line.charCodes()); 739 _process.stdin.write(line.charCodes());
726 } 740 }
727 741
728 String _createArgumentsLine(List<String> arguments) { 742 String _createArgumentsLine(List<String> arguments) {
729 return Strings.join(arguments, ' ').concat('\n'); 743 return Strings.join(arguments, ' ').concat('\n');
730 } 744 }
731 745
732 void _testCompleted() { 746 void _reportResult() {
733 var test = _currentTest; 747 if (!active) return;
734 _currentTest = null; 748 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
735 test.completed();
736 }
737 749
738 int _reportResult(String output) { 750 var outcome = _status.split(" ")[2];
739 _stdoutDrained = true;
740 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
741 var outcome = output.split(" ")[2];
742 var exitCode = 0; 751 var exitCode = 0;
743 if (outcome == "CRASH") exitCode = -10; 752 if (outcome == "CRASH") exitCode = -10;
744 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; 753 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
745 new TestOutput.fromCase(_currentTest, exitCode, (outcome == "TIMEOUT"), 754 new TestOutput.fromCase(_currentTest, exitCode, (outcome == "TIMEOUT"),
746 _testStdout, _testStderr, 755 _testStdout, _testStderr,
747 new Date.now().difference(_startTime)); 756 new Date.now().difference(_startTime));
748 // Move on when both stdout and stderr has been drained. If the test 757 var test = _currentTest;
749 // crashed, we restarted the process and therefore do not attempt to 758 _currentTest = null;
750 // drain stderr. 759 test.completed();
751 if (_stderrDrained || (_currentTest.output.hasCrashed)) _testCompleted();
752 } 760 }
753 761
754 void _stderrDone() { 762 void _stderrDone() {
755 _stderrDrained = true; 763 _stderrDrained = true;
756 // Move on when both stdout and stderr has been drained. 764 // Move on when both stdout and stderr has been drained.
757 if (_stdoutDrained) _testCompleted(); 765 if (_stdoutDrained) _reportResult();
766 }
767
768 void _stdoutDone() {
769 _stdoutDrained = true;
770 // Move on when both stdout and stderr has been drained.
771 if (_stderrDrained) _reportResult();
758 } 772 }
759 773
760 Function _readStdout(StringInputStream stream, List<String> buffer) { 774 Function _readStdout(StringInputStream stream, List<String> buffer) {
775 var ignoreStreams = _ignoreStreams; // Capture this mutable object.
761 return () { 776 return () {
762 var status; 777 if (ignoreStreams.value) {
778 while (stream.readLine() != null) {
779 // Do nothing.
780 }
781 return;
782 }
783 // Otherwise, process output and call _reportResult() when done.
763 var line = stream.readLine(); 784 var line = stream.readLine();
764 while (line != null) { 785 while (line != null) {
765 if (line.startsWith('>>> TEST')) { 786 if (line.startsWith('>>> TEST')) {
766 status = line; 787 _status = line;
767 } else if (line.startsWith('>>> BATCH START')) { 788 } else if (line.startsWith('>>> BATCH START')) {
768 // ignore 789 // ignore
769 } else if (line.startsWith('>>> ')) { 790 } else if (line.startsWith('>>> ')) {
770 throw new Exception('Unexpected command from dartc batch runner.'); 791 throw new Exception('Unexpected command from dartc batch runner.');
771 } else { 792 } else {
772 buffer.add(line); 793 buffer.add(line);
773 } 794 }
774 line = stream.readLine(); 795 line = stream.readLine();
775 } 796 }
776 if (status != null) { 797 if (_status != null) {
777 _timer.cancel(); 798 _timer.cancel();
778 // For crashing processes, let the exit handler deal with it. 799 _stdoutDone();
779 if (!status.contains("CRASH")) {
780 _reportResult(status);
781 }
782 } 800 }
783 }; 801 };
784 } 802 }
785 803
786 Function _readStderr(StringInputStream stream, List<String> buffer) { 804 Function _readStderr(StringInputStream stream, List<String> buffer) {
805 var ignoreStreams = _ignoreStreams; // Capture this mutable object.
787 return () { 806 return () {
807 if (ignoreStreams.value) {
808 while (stream.readLine() != null) {
809 // Do nothing.
810 }
811 return;
812 }
813 // Otherwise, process output and call _reportResult() when done.
788 var line = stream.readLine(); 814 var line = stream.readLine();
789 while (line != null) { 815 while (line != null) {
790 if (line.startsWith('>>> EOF STDERR')) { 816 if (line.startsWith('>>> EOF STDERR')) {
791 _stderrDone(); 817 _stderrDone();
792 } else { 818 } else {
793 buffer.add(line); 819 buffer.add(line);
794 } 820 }
795 line = stream.readLine(); 821 line = stream.readLine();
796 } 822 }
797 }; 823 };
798 } 824 }
799 825
800 void _exitHandler(exitCode) { 826 Function makeExitHandler(String status) {
801 if (_timer != null) _timer.cancel(); 827 return (exitCode) {
802 _process.close(); 828 if (active) {
803 _startProcess(() { 829 if (_timer != null) _timer.cancel();
804 _reportResult(">>> TEST CRASH"); 830 _status = status;
805 }); 831 // Read current content of streams, ignore any later output.
806 } 832 _ignoreStreams.value = true;
833 var line = _stdoutStream.readLine();
834 while (line != null) {
835 _testStdout.add(line);
836 line = _stdoutStream.readLine();
837 }
838 line = _stderrStream.readLine();
839 while (line != null) {
840 _testStderr.add(line);
841 line = _stderrStream.readLine();
842 }
843 _stderrDrained = true;
844 _stdoutDrained = true;
845 _process.close();
846 _startProcess(() { _reportResult(); });
847 } else { // No active test case running.
848 _process.close();
849 _startProcess(() { });
850 }
851 };
852 }
807 853
808 void _timeoutHandler(ignore) { 854 void _timeoutHandler(ignore) {
809 _process.onExit = (exitCode) { 855 _process.onExit = makeExitHandler(">>> TEST TIMEOUT");
810 _process.close();
811 _startProcess(() {
812 _reportResult(">>> TEST TIMEOUT");
813 });
814 };
815 _process.kill(); 856 _process.kill();
816 } 857 }
817 858
818 void _startProcess(then) { 859 void _startProcess(then) {
819 _process = Process.start(_executable, _batchArguments); 860 _process = Process.start(_executable, _batchArguments);
820 _stdoutStream = new StringInputStream(_process.stdout); 861 _stdoutStream = new StringInputStream(_process.stdout);
821 _stderrStream = new StringInputStream(_process.stderr); 862 _stderrStream = new StringInputStream(_process.stderr);
822 _testStdout = new List<String>(); 863 _process.onExit = makeExitHandler(">>> TEST CRASH");
823 _testStderr = new List<String>();
824 _stdoutDrained = false;
825 _stderrDrained = false;
826 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout);
827 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr);
828 _process.onExit = _exitHandler;
829 _process.onError = (e) { 864 _process.onError = (e) {
830 print("Error starting process:"); 865 print("Error starting process:");
831 print(" Command: $_executable ${Strings.join(_batchArguments, ' ')}"); 866 print(" Command: $_executable ${Strings.join(_batchArguments, ' ')}");
832 print(" Error: $e"); 867 print(" Error: $e");
833 }; 868 };
834 _process.onStart = then; 869 _process.onStart = then;
835 } 870 }
836 } 871 }
837 872
838 /** 873 /**
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
1136 // the developer doesn't waste his or her time trying to fix a bunch of 1171 // the developer doesn't waste his or her time trying to fix a bunch of
1137 // tests that appear to be broken but were actually just flakes that 1172 // tests that appear to be broken but were actually just flakes that
1138 // didn't get retried because there had already been one failure. 1173 // didn't get retried because there had already been one failure.
1139 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 1174 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
1140 new RunningProcess(test, allowRetry, this).start(); 1175 new RunningProcess(test, allowRetry, this).start();
1141 } 1176 }
1142 _numProcesses++; 1177 _numProcesses++;
1143 } 1178 }
1144 } 1179 }
1145 } 1180 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698