| 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 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |