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

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

Issue 12475010: Revert "Update the test runner to use the new dart:io API" again (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 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
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | tools/testing/dart/test_suite.dart » ('j') | 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 658 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 * #EOF\n 669 * #EOF\n
670 * So we need to get the byte-range of the png data first, before 670 * So we need to get the byte-range of the png data first, before
671 * comparing it with the content of the expected output file. 671 * comparing it with the content of the expected output file.
672 * 672 *
673 * On a layout tests, the DRT output is directly compared with the 673 * On a layout tests, the DRT output is directly compared with the
674 * content of the expected output. 674 * content of the expected output.
675 */ 675 */
676 var stdout = testCase.commandOutputs[command].stdout; 676 var stdout = testCase.commandOutputs[command].stdout;
677 var file = new io.File.fromPath(command.expectedOutputFile); 677 var file = new io.File.fromPath(command.expectedOutputFile);
678 if (file.existsSync()) { 678 if (file.existsSync()) {
679 var bytesContentLength = "Content-Length:".codeUnits; 679 var bytesContentLength = "Content-Length:".charCodes;
680 var bytesNewLine = "\n".codeUnits; 680 var bytesNewLine = "\n".charCodes;
681 var bytesEOF = "#EOF\n".codeUnits; 681 var bytesEOF = "#EOF\n".charCodes;
682 682
683 var expectedContent = file.readAsBytesSync(); 683 var expectedContent = file.readAsBytesSync();
684 if (command.isPixelTest) { 684 if (command.isPixelTest) {
685 var startOfContentLength = findBytes(stdout, bytesContentLength); 685 var startOfContentLength = findBytes(stdout, bytesContentLength);
686 if (startOfContentLength >= 0) { 686 if (startOfContentLength >= 0) {
687 var newLineAfterContentLength = findBytes(stdout, 687 var newLineAfterContentLength = findBytes(stdout,
688 bytesNewLine, 688 bytesNewLine,
689 startOfContentLength); 689 startOfContentLength);
690 if (newLineAfterContentLength > 0) { 690 if (newLineAfterContentLength > 0) {
691 var startPosition = newLineAfterContentLength + 691 var startPosition = newLineAfterContentLength +
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 bool escaped = false; 902 bool escaped = false;
903 for (var i = 0 ; i < line.length; i++) { 903 for (var i = 0 ; i < line.length; i++) {
904 var c = line[i]; 904 var c = line[i];
905 if (!escaped && c == '\\') { 905 if (!escaped && c == '\\') {
906 escaped = true; 906 escaped = true;
907 continue; 907 continue;
908 } 908 }
909 escaped = false; 909 escaped = false;
910 if (c == '|') { 910 if (c == '|') {
911 result.add(field.toString()); 911 result.add(field.toString());
912 field = new StringBuffer(); 912 field.clear();
913 continue; 913 continue;
914 } 914 }
915 field.write(c); 915 field.add(c);
916 } 916 }
917 result.add(field.toString()); 917 result.add(field.toString());
918 return result; 918 return result;
919 } 919 }
920 } 920 }
921 921
922 /** 922 /**
923 * A RunningProcess actually runs a test, getting the command lines from 923 * A RunningProcess actually runs a test, getting the command lines from
924 * its [TestCase], starting the test process (and first, a compilation 924 * its [TestCase], starting the test process (and first, a compilation
925 * process if the TestCase is a [BrowserTestCase]), creating a timeout 925 * process if the TestCase is a [BrowserTestCase]), creating a timeout
926 * timer, and recording the results in a new [CommandOutput] object, which it 926 * timer, and recording the results in a new [CommandOutput] object, which it
927 * attaches to the TestCase. The lifetime of the RunningProcess is limited 927 * attaches to the TestCase. The lifetime of the RunningProcess is limited
928 * to the time it takes to start the process, run the process, and record 928 * to the time it takes to start the process, run the process, and record
929 * the result; there are no pointers to it, so it should be available to 929 * the result; there are no pointers to it, so it should be available to
930 * be garbage collected as soon as it is done. 930 * be garbage collected as soon as it is done.
931 */ 931 */
932 class RunningProcess { 932 class RunningProcess {
933 TestCase testCase; 933 TestCase testCase;
934 Command command; 934 Command command;
935 bool timedOut = false; 935 bool timedOut = false;
936 DateTime startTime; 936 Date startTime;
937 Timer timeoutTimer; 937 Timer timeoutTimer;
938 List<int> stdout = <int>[]; 938 List<int> stdout = <int>[];
939 List<int> stderr = <int>[]; 939 List<int> stderr = <int>[];
940 bool compilationSkipped = false; 940 bool compilationSkipped = false;
941 Completer<CommandOutput> completer; 941 Completer<CommandOutput> completer;
942 942
943 RunningProcess(TestCase this.testCase, Command this.command); 943 RunningProcess(TestCase this.testCase, Command this.command);
944 944
945 Future<CommandOutput> start() { 945 Future<CommandOutput> start() {
946 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); 946 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP));
947 947
948 completer = new Completer<CommandOutput>(); 948 completer = new Completer<CommandOutput>();
949 startTime = new DateTime.now(); 949 startTime = new Date.now();
950 _runCommand(); 950 _runCommand();
951 return completer.future; 951 return completer.future;
952 } 952 }
953 953
954 void _runCommand() { 954 void _runCommand() {
955 command.outputIsUpToDate.then((bool isUpToDate) { 955 command.outputIsUpToDate.then((bool isUpToDate) {
956 if (isUpToDate) { 956 if (isUpToDate) {
957 compilationSkipped = true; 957 compilationSkipped = true;
958 _commandComplete(0); 958 _commandComplete(0);
959 } else { 959 } else {
960 var processOptions = _createProcessOptions(); 960 var processOptions = _createProcessOptions();
961 Future processFuture = io.Process.start(command.executable, 961 Future processFuture = io.Process.start(command.executable,
962 command.arguments, 962 command.arguments,
963 processOptions); 963 processOptions);
964 processFuture.then((io.Process process) { 964 processFuture.then((io.Process process) {
965 void timeoutHandler() { 965 void timeoutHandler(_) {
966 timedOut = true; 966 timedOut = true;
967 if (process != null) { 967 if (process != null) {
968 process.kill(); 968 process.kill();
969 } 969 }
970 } 970 }
971 process.exitCode.then(_commandComplete); 971 process.onExit = _commandComplete;
972 _drainStream(process.stdout, stdout); 972 _drainStream(process.stdout, stdout);
973 _drainStream(process.stderr, stderr); 973 _drainStream(process.stderr, stderr);
974 timeoutTimer = new Timer(new Duration(seconds: testCase.timeout), 974 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler);
975 timeoutHandler);
976 }).catchError((e) { 975 }).catchError((e) {
977 print("Process error:"); 976 print("Process error:");
978 print(" Command: $command"); 977 print(" Command: $command");
979 print(" Error: $e"); 978 print(" Error: $e");
980 _commandComplete(-1); 979 _commandComplete(-1);
981 return true; 980 return true;
982 }); 981 });
983 } 982 }
984 }); 983 });
985 } 984 }
986 985
987 void _commandComplete(int exitCode) { 986 void _commandComplete(int exitCode) {
988 if (timeoutTimer != null) { 987 if (timeoutTimer != null) {
989 timeoutTimer.cancel(); 988 timeoutTimer.cancel();
990 } 989 }
991 var commandOutput = _createCommandOutput(command, exitCode); 990 var commandOutput = _createCommandOutput(command, exitCode);
992 completer.complete(commandOutput); 991 completer.complete(commandOutput);
993 } 992 }
994 993
995 CommandOutput _createCommandOutput(Command command, int exitCode) { 994 CommandOutput _createCommandOutput(Command command, int exitCode) {
996 var incomplete = command != testCase.commands.last; 995 var incomplete = command != testCase.commands.last;
997 var commandOutput = new CommandOutput.fromCase( 996 var commandOutput = new CommandOutput.fromCase(
998 testCase, 997 testCase,
999 command, 998 command,
1000 exitCode, 999 exitCode,
1001 incomplete, 1000 incomplete,
1002 timedOut, 1001 timedOut,
1003 stdout, 1002 stdout,
1004 stderr, 1003 stderr,
1005 new DateTime.now().difference(startTime), 1004 new Date.now().difference(startTime),
1006 compilationSkipped); 1005 compilationSkipped);
1007 return commandOutput; 1006 return commandOutput;
1008 } 1007 }
1009 1008
1010 void _drainStream(Stream<List<int>> source, List<int> destination) { 1009 void _drainStream(io.InputStream source, List<int> destination) {
1011 source.listen(destination.addAll); 1010 void onDataHandler () {
1011 if (source.closed) {
1012 return; // TODO(whesse): Remove when bug is fixed.
1013 }
1014 var data = source.read();
1015 while (data != null) {
1016 destination.addAll(data);
1017 data = source.read();
1018 }
1019 }
1020 source.onData = onDataHandler;
1021 source.onClosed = onDataHandler;
1012 } 1022 }
1013 1023
1014 io.ProcessOptions _createProcessOptions() { 1024 io.ProcessOptions _createProcessOptions() {
1015 var baseEnvironment = command.environment != null ? 1025 var baseEnvironment = command.environment != null ?
1016 command.environment : io.Platform.environment; 1026 command.environment : io.Platform.environment;
1017 io.ProcessOptions options = new io.ProcessOptions(); 1027 io.ProcessOptions options = new io.ProcessOptions();
1018 options.environment = new Map<String, String>.from(baseEnvironment); 1028 options.environment = new Map<String, String>.from(baseEnvironment);
1019 options.environment['DART_CONFIGURATION'] = 1029 options.environment['DART_CONFIGURATION'] =
1020 TestUtils.configurationDir(testCase.configuration); 1030 TestUtils.configurationDir(testCase.configuration);
1021 return options; 1031 return options;
1022 } 1032 }
1023 } 1033 }
1024 1034
1035 /**
1036 * This class holds a value, that can be changed. It is used when
1037 * closures need a shared value, that they can all change and read.
1038 */
1039 class MutableValue<T> {
1040 MutableValue(T this.value);
1041 T value;
1042 }
1043
1025 class BatchRunnerProcess { 1044 class BatchRunnerProcess {
1026 Command _command; 1045 Command _command;
1027 String _executable; 1046 String _executable;
1028 List<String> _batchArguments; 1047 List<String> _batchArguments;
1029 1048
1030 io.Process _process; 1049 io.Process _process;
1031 Completer _stdoutCompleter; 1050 io.StringInputStream _stdoutStream;
1032 Completer _stderrCompleter; 1051 io.StringInputStream _stderrStream;
1033 StreamSubscription<String> _stdoutSubscription;
1034 StreamSubscription<String> _stderrSubscription;
1035 Function _processExitHandler;
1036 1052
1037 TestCase _currentTest; 1053 TestCase _currentTest;
1038 List<int> _testStdout; 1054 List<int> _testStdout;
1039 List<int> _testStderr; 1055 List<int> _testStderr;
1040 String _status; 1056 String _status;
1041 DateTime _startTime; 1057 bool _stdoutDrained = false;
1058 bool _stderrDrained = false;
1059 MutableValue<bool> _ignoreStreams;
1060 Date _startTime;
1042 Timer _timer; 1061 Timer _timer;
1043 1062
1044 bool _isWebDriver; 1063 bool _isWebDriver;
1045 1064
1046 BatchRunnerProcess(TestCase testCase) { 1065 BatchRunnerProcess(TestCase testCase) {
1047 _command = testCase.commands.last; 1066 _command = testCase.commands.last;
1048 _executable = testCase.commands.last.executable; 1067 _executable = testCase.commands.last.executable;
1049 _batchArguments = testCase.batchRunnerArguments; 1068 _batchArguments = testCase.batchRunnerArguments;
1050 _isWebDriver = testCase.usesWebDriver; 1069 _isWebDriver = testCase.usesWebDriver;
1051 } 1070 }
1052 1071
1053 bool get active => _currentTest != null; 1072 bool get active => _currentTest != null;
1054 1073
1055 void startTest(TestCase testCase) { 1074 void startTest(TestCase testCase) {
1056 Expect.isNull(_currentTest); 1075 Expect.isNull(_currentTest);
1057 _currentTest = testCase; 1076 _currentTest = testCase;
1058 _command = testCase.commands.last; 1077 _command = testCase.commands.last;
1059 if (_process == null) { 1078 if (_process == null) {
1060 // Start process if not yet started. 1079 // Start process if not yet started.
1061 _executable = testCase.commands.last.executable; 1080 _executable = testCase.commands.last.executable;
1062 _startProcess(() { 1081 _startProcess(() {
1063 doStartTest(testCase); 1082 doStartTest(testCase);
1064 }); 1083 });
1065 } else if (testCase.commands.last.executable != _executable) { 1084 } else if (testCase.commands.last.executable != _executable) {
1066 // Restart this runner with the right executable for this test 1085 // Restart this runner with the right executable for this test
1067 // if needed. 1086 // if needed.
1068 _executable = testCase.commands.last.executable; 1087 _executable = testCase.commands.last.executable;
1069 _batchArguments = testCase.batchRunnerArguments; 1088 _batchArguments = testCase.batchRunnerArguments;
1070 _processExitHandler = (_) { 1089 _process.onExit = (exitCode) {
1071 _startProcess(() { 1090 _startProcess(() {
1072 doStartTest(testCase); 1091 doStartTest(testCase);
1073 }); 1092 });
1074 }; 1093 };
1075 _process.kill(); 1094 _process.kill();
1076 } else { 1095 } else {
1077 doStartTest(testCase); 1096 doStartTest(testCase);
1078 } 1097 }
1079 } 1098 }
1080 1099
1081 Future terminate() { 1100 Future terminate() {
1082 if (_process == null) return new Future.immediate(true); 1101 if (_process == null) return new Future.immediate(true);
1083 Completer completer = new Completer(); 1102 Completer completer = new Completer();
1084 Timer killTimer; 1103 Timer killTimer;
1085 _processExitHandler = (_) { 1104 _process.onExit = (exitCode) {
1086 if (killTimer != null) killTimer.cancel(); 1105 if (killTimer != null) killTimer.cancel();
1087 completer.complete(true); 1106 completer.complete(true);
1088 }; 1107 };
1089 if (_isWebDriver) { 1108 if (_isWebDriver) {
1090 // Use a graceful shutdown so our Selenium script can close 1109 // Use a graceful shutdown so our Selenium script can close
1091 // the open browser processes. On Windows, signals do not exist 1110 // the open browser processes. On Windows, signals do not exist
1092 // and a kill is a hard kill. 1111 // and a kill is a hard kill.
1093 _process.stdin.writeln('--terminate'); 1112 _process.stdin.write('--terminate\n'.charCodes);
1094 1113
1095 // In case the run_selenium process didn't close, kill it after 30s 1114 // In case the run_selenium process didn't close, kill it after 30s
1096 killTimer = new Timer(new Duration(seconds: 30), _process.kill); 1115 int shutdownMillisecs = 30000;
1116 killTimer = new Timer(shutdownMillisecs, (e) { _process.kill(); });
1097 } else { 1117 } else {
1098 _process.kill(); 1118 _process.kill();
1099 } 1119 }
1100 1120
1101 return completer.future; 1121 return completer.future;
1102 } 1122 }
1103 1123
1104 void doStartTest(TestCase testCase) { 1124 void doStartTest(TestCase testCase) {
1105 _startTime = new DateTime.now(); 1125 _startTime = new Date.now();
1106 _testStdout = []; 1126 _testStdout = [];
1107 _testStderr = []; 1127 _testStderr = [];
1108 _status = null; 1128 _status = null;
1109 _stdoutCompleter = new Completer(); 1129 _stdoutDrained = false;
1110 _stderrCompleter = new Completer(); 1130 _stderrDrained = false;
1111 _timer = new Timer(new Duration(seconds: testCase.timeout), 1131 _ignoreStreams = new MutableValue<bool>(false); // Captured by closures.
1112 _timeoutHandler); 1132 _readStdout(_stdoutStream, _testStdout);
1133 _readStderr(_stderrStream, _testStderr);
1134 _timer = new Timer(testCase.timeout * 1000, _timeoutHandler);
1113 1135
1114 if (testCase.commands.last.environment != null) { 1136 if (testCase.commands.last.environment != null) {
1115 print("Warning: command.environment != null, but we don't support custom " 1137 print("Warning: command.environment != null, but we don't support custom "
1116 "environments for batch runner tests!"); 1138 "environments for batch runner tests!");
1117 } 1139 }
1118 1140
1119 var line = _createArgumentsLine(testCase.batchTestArguments); 1141 var line = _createArgumentsLine(testCase.batchTestArguments);
1120 _process.stdin.write(line); 1142 _process.stdin.onError = (err) {
1121 _stdoutSubscription.resume(); 1143 print('Error on batch runner input stream stdin');
1122 _stderrSubscription.resume(); 1144 print(' Input line: $line');
1123 Future.wait([_stdoutCompleter.future, 1145 print(' Previous test\'s status: $_status');
1124 _stderrCompleter.future]).then((_) => _reportResult()); 1146 print(' Error: $err');
1147 throw err;
1148 };
1149 _process.stdin.write(line.charCodes);
1125 } 1150 }
1126 1151
1127 String _createArgumentsLine(List<String> arguments) { 1152 String _createArgumentsLine(List<String> arguments) {
1128 return arguments.join(' ').concat('\n'); 1153 return arguments.join(' ').concat('\n');
1129 } 1154 }
1130 1155
1131 void _reportResult() { 1156 void _reportResult() {
1132 if (!active) return; 1157 if (!active) return;
1133 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' 1158 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
1134 1159
1135 var outcome = _status.split(" ")[2]; 1160 var outcome = _status.split(" ")[2];
1136 var exitCode = 0; 1161 var exitCode = 0;
1137 if (outcome == "CRASH") exitCode = CRASHING_BROWSER_EXITCODE; 1162 if (outcome == "CRASH") exitCode = CRASHING_BROWSER_EXITCODE;
1138 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; 1163 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
1139 new CommandOutput.fromCase(_currentTest, 1164 new CommandOutput.fromCase(_currentTest,
1140 _command, 1165 _command,
1141 exitCode, 1166 exitCode,
1142 false, 1167 false,
1143 (outcome == "TIMEOUT"), 1168 (outcome == "TIMEOUT"),
1144 _testStdout, 1169 _testStdout,
1145 _testStderr, 1170 _testStderr,
1146 new DateTime.now().difference(_startTime), 1171 new Date.now().difference(_startTime),
1147 false); 1172 false);
1148 var test = _currentTest; 1173 var test = _currentTest;
1149 _currentTest = null; 1174 _currentTest = null;
1150 test.completed(); 1175 test.completed();
1151 } 1176 }
1152 1177
1178 void _stderrDone() {
1179 _stderrDrained = true;
1180 // Move on when both stdout and stderr has been drained.
1181 if (_stdoutDrained) _reportResult();
1182 }
1183
1184 void _stdoutDone() {
1185 _stdoutDrained = true;
1186 // Move on when both stdout and stderr has been drained.
1187 if (_stderrDrained) _reportResult();
1188 }
1189
1190 void _readStdout(io.StringInputStream stream, List<int> buffer) {
1191 var ignoreStreams = _ignoreStreams; // Capture this mutable object.
1192 void onLineHandler() {
1193 if (ignoreStreams.value) {
1194 while (stream.readLine() != null) {
1195 // Do nothing.
1196 }
1197 return;
1198 }
1199 // Otherwise, process output and call _reportResult() when done.
1200 var line = stream.readLine();
1201 while (line != null) {
1202 if (line.startsWith('>>> TEST')) {
1203 _status = line;
1204 } else if (line.startsWith('>>> BATCH')) {
1205 // ignore
1206 } else if (line.startsWith('>>> ')) {
1207 throw new Exception(
1208 'Unexpected command from ${testCase.configuration['compiler']} '
1209 'batch runner.');
1210 } else {
1211 buffer.addAll(encodeUtf8(line));
1212 buffer.addAll("\n".charCodes);
1213 }
1214 line = stream.readLine();
1215 }
1216 if (_status != null) {
1217 _timer.cancel();
1218 _stdoutDone();
1219 }
1220 }
1221 stream.onLine = onLineHandler;
1222 }
1223
1224 void _readStderr(io.StringInputStream stream, List<int> buffer) {
1225 var ignoreStreams = _ignoreStreams; // Capture this mutable object.
1226 void onLineHandler() {
1227 if (ignoreStreams.value) {
1228 while (stream.readLine() != null) {
1229 // Do nothing.
1230 }
1231 return;
1232 }
1233 // Otherwise, process output and call _reportResult() when done.
1234 var line = stream.readLine();
1235 while (line != null) {
1236 if (line.startsWith('>>> EOF STDERR')) {
1237 _stderrDone();
1238 } else {
1239 buffer.addAll(encodeUtf8(line));
1240 buffer.addAll("\n".charCodes);
1241 }
1242 line = stream.readLine();
1243 }
1244 }
1245 stream.onLine = onLineHandler;
1246 }
1247
1153 ExitCodeEvent makeExitHandler(String status) { 1248 ExitCodeEvent makeExitHandler(String status) {
1154 void handler(int exitCode) { 1249 void handler(int exitCode) {
1155 if (active) { 1250 if (active) {
1156 if (_timer != null) _timer.cancel(); 1251 if (_timer != null) _timer.cancel();
1157 _status = status; 1252 _status = status;
1158 _stdoutSubscription.cancel(); 1253 // Read current content of streams, ignore any later output.
1159 _stderrSubscription.cancel(); 1254 _ignoreStreams.value = true;
1255 var line = _stdoutStream.readLine();
1256 while (line != null) {
1257 _testStdout.add(line);
1258 line = _stdoutStream.readLine();
1259 }
1260 line = _stderrStream.readLine();
1261 while (line != null) {
1262 _testStderr.add(line);
1263 line = _stderrStream.readLine();
1264 }
1265 _stderrDrained = true;
1266 _stdoutDrained = true;
1160 _startProcess(_reportResult); 1267 _startProcess(_reportResult);
1161 } else { // No active test case running. 1268 } else { // No active test case running.
1162 _process = null; 1269 _process = null;
1163 } 1270 }
1164 } 1271 }
1165 return handler; 1272 return handler;
1166 } 1273 }
1167 1274
1168 void _timeoutHandler() { 1275 void _timeoutHandler(ignore) {
1169 _processExitHandler = makeExitHandler(">>> TEST TIMEOUT"); 1276 _process.onExit = makeExitHandler(">>> TEST TIMEOUT");
1170 _process.kill(); 1277 _process.kill();
1171 } 1278 }
1172 1279
1173 _startProcess(callback) { 1280 _startProcess(callback) {
1174 Future processFuture = io.Process.start(_executable, _batchArguments); 1281 Future processFuture = io.Process.start(_executable, _batchArguments);
1175 processFuture.then((io.Process p) { 1282 processFuture.then((io.Process p) {
1176 _process = p; 1283 _process = p;
1177 1284 _stdoutStream = new io.StringInputStream(_process.stdout);
1178 var _stdoutStream = 1285 _stderrStream = new io.StringInputStream(_process.stderr);
1179 _process.stdout 1286 _process.onExit = makeExitHandler(">>> TEST CRASH");
1180 .transform(new io.StringDecoder())
1181 .transform(new io.LineTransformer());
1182 _stdoutSubscription = _stdoutStream.listen((String line) {
1183 if (line.startsWith('>>> TEST')) {
1184 _status = line;
1185 } else if (line.startsWith('>>> BATCH')) {
1186 // ignore
1187 } else if (line.startsWith('>>> ')) {
1188 throw new Exception(
1189 'Unexpected command from ${testCase.configuration['compiler']} '
1190 'batch runner.');
1191 } else {
1192 _testStdout.addAll(encodeUtf8(line));
1193 _testStdout.addAll("\n".codeUnits);
1194 }
1195 if (_status != null) {
1196 _stdoutSubscription.pause();
1197 _timer.cancel();
1198 _stdoutCompleter.complete(null);
1199 }
1200 });
1201 _stdoutSubscription.pause();
1202
1203 var _stderrStream =
1204 _process.stderr
1205 .transform(new io.StringDecoder())
1206 .transform(new io.LineTransformer());
1207 _stderrSubscription = _stderrStream.listen((String line) {
1208 if (line.startsWith('>>> EOF STDERR')) {
1209 _stderrSubscription.pause();
1210 _stderrCompleter.complete(null);
1211 } else {
1212 _testStderr.addAll(encodeUtf8(line));
1213 _testStderr.addAll("\n".codeUnits);
1214 }
1215 });
1216 _stderrSubscription.pause();
1217
1218 _processExitHandler = makeExitHandler(">>> TEST CRASH");
1219 _process.exitCode.then((exitCode) {
1220 _processExitHandler(exitCode);
1221 });
1222
1223 _process.stdin.done.catchError((err) {
1224 print('Error on batch runner input stream stdin');
1225 print(' Previous test\'s status: $_status');
1226 print(' Error: $err');
1227 throw err;
1228 });
1229 callback(); 1287 callback();
1230 }).catchError((e) { 1288 }).catchError((e) {
1231 print("Process error:"); 1289 print("Process error:");
1232 print(" Command: $_executable ${_batchArguments.join(' ')}"); 1290 print(" Command: $_executable ${_batchArguments.join(' ')}");
1233 print(" Error: $e"); 1291 print(" Error: $e");
1234 // If there is an error starting a batch process, chances are that 1292 // If there is an error starting a batch process, chances are that
1235 // it will always fail. So rather than re-trying a 1000+ times, we 1293 // it will always fail. So rather than re-trying a 1000+ times, we
1236 // exit. 1294 // exit.
1237 io.exit(1); 1295 io.exit(1);
1238 return true; 1296 return true;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1291 io.Process _seleniumServer = null; 1349 io.Process _seleniumServer = null;
1292 1350
1293 /** True if we are in the process of starting the server. */ 1351 /** True if we are in the process of starting the server. */
1294 bool _startingServer = false; 1352 bool _startingServer = false;
1295 1353
1296 /** True if we find that there is already a selenium jar running. */ 1354 /** True if we find that there is already a selenium jar running. */
1297 bool _seleniumAlreadyRunning = false; 1355 bool _seleniumAlreadyRunning = false;
1298 1356
1299 ProcessQueue(this._maxProcesses, 1357 ProcessQueue(this._maxProcesses,
1300 this._maxBrowserProcesses, 1358 this._maxBrowserProcesses,
1301 DateTime startTime, 1359 Date startTime,
1302 testSuites, 1360 testSuites,
1303 this._eventListener, 1361 this._eventListener,
1304 this._allDone, 1362 this._allDone,
1305 [bool verbose = false, 1363 [bool verbose = false,
1306 bool listTests = false]) 1364 bool listTests = false])
1307 : _verbose = verbose, 1365 : _verbose = verbose,
1308 _listTests = listTests, 1366 _listTests = listTests,
1309 _tests = new Queue<TestCase>(), 1367 _tests = new Queue<TestCase>(),
1310 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), 1368 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(),
1311 _testCache = new Map<String, List<TestInformation>>() { 1369 _testCache = new Map<String, List<TestInformation>>() {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1377 String cmd = 'ps'; 1435 String cmd = 'ps';
1378 var arg = ['aux']; 1436 var arg = ['aux'];
1379 if (io.Platform.operatingSystem == 'windows') { 1437 if (io.Platform.operatingSystem == 'windows') {
1380 cmd = 'tasklist'; 1438 cmd = 'tasklist';
1381 arg.add('/v'); 1439 arg.add('/v');
1382 } 1440 }
1383 1441
1384 Future processFuture = io.Process.start(cmd, arg); 1442 Future processFuture = io.Process.start(cmd, arg);
1385 processFuture.then((io.Process p) { 1443 processFuture.then((io.Process p) {
1386 // Drain stderr to not leak resources. 1444 // Drain stderr to not leak resources.
1387 p.stderr.listen((_) {}); 1445 p.stderr.onData = p.stderr.read;
1388 final Stream<String> stdoutStringStream = 1446 final io.StringInputStream stdoutStringStream =
1389 p.stdout.transform(new io.StringDecoder()) 1447 new io.StringInputStream(p.stdout);
1390 .transform(new io.LineTransformer()); 1448 stdoutStringStream.onLine = () {
1391 stdoutStringStream.listen((String line) { 1449 var line = stdoutStringStream.readLine();
1392 var regexp = new RegExp(r".*selenium-server-standalone.*"); 1450 while (null != line) {
1393 if (regexp.hasMatch(line)) { 1451 var regexp = new RegExp(r".*selenium-server-standalone.*");
1394 _seleniumAlreadyRunning = true; 1452 if (regexp.hasMatch(line)) {
1395 resumeTesting(); 1453 _seleniumAlreadyRunning = true;
1454 resumeTesting();
1455 }
1456 line = stdoutStringStream.readLine();
1396 } 1457 }
1397 if (!_isSeleniumAvailable) { 1458 if (!_isSeleniumAvailable) {
1398 _startSeleniumServer(); 1459 _startSeleniumServer();
1399 } 1460 }
1400 }); 1461 };
1401 }).catchError((e) { 1462 }).catchError((e) {
1402 print("Error starting process:"); 1463 print("Error starting process:");
1403 print(" Command: $cmd ${arg.join(' ')}"); 1464 print(" Command: $cmd ${arg.join(' ')}");
1404 print(" Error: $e"); 1465 print(" Error: $e");
1405 // TODO(ahe): How to report this as a test failure? 1466 // TODO(ahe): How to report this as a test failure?
1406 io.exit(1); 1467 io.exit(1);
1407 return true; 1468 return true;
1408 }); 1469 });
1409 } 1470 }
1410 } 1471 }
1411 1472
1412 void _runTest(TestCase test) { 1473 void _runTest(TestCase test) {
1413 if (test.usesWebDriver) { 1474 if (test.usesWebDriver) {
1414 browserUsed = test.configuration['browser']; 1475 browserUsed = test.configuration['browser'];
1415 if (_needsSelenium) _ensureSeleniumServerRunning(); 1476 if (_needsSelenium) _ensureSeleniumServerRunning();
1416 } 1477 }
1417 eventTestAdded(test); 1478 eventTestAdded(test);
1418 _tests.add(test); 1479 _tests.add(test);
1419 _tryRunTest(); 1480 _tryRunTest();
1420 } 1481 }
1421 1482
1422 /** 1483 /**
1423 * Monitor the output of the Selenium server, to know when we are ready to 1484 * Monitor the output of the Selenium server, to know when we are ready to
1424 * begin running tests. 1485 * begin running tests.
1425 * source: Output(Stream) from the Java server. 1486 * source: Output(Stream) from the Java server.
1426 */ 1487 */
1427 void seleniumServerHandler(String line) { 1488 VoidFunction makeSeleniumServerHandler(io.StringInputStream source) {
1428 if (new RegExp(r".*Started.*Server.*").hasMatch(line) || 1489 void handler() {
1429 new RegExp(r"Exception.*Selenium is already running.*").hasMatch( 1490 if (source.closed) return; // TODO(whesse): Remove when bug is fixed.
1430 line)) { 1491 var line = source.readLine();
1431 resumeTesting(); 1492 while (null != line) {
1493 if (new RegExp(r".*Started.*Server.*").hasMatch(line) ||
1494 new RegExp(r"Exception.*Selenium is already running.*").hasMatch(
1495 line)) {
1496 resumeTesting();
1497 }
1498 line = source.readLine();
1499 }
1432 } 1500 }
1501 return handler;
1433 } 1502 }
1434 1503
1435 /** 1504 /**
1436 * For browser tests using Safari or Opera, we need to use the Selenium 1.0 1505 * For browser tests using Safari or Opera, we need to use the Selenium 1.0
1437 * Java server. 1506 * Java server.
1438 */ 1507 */
1439 void _startSeleniumServer() { 1508 void _startSeleniumServer() {
1440 // Get the absolute path to the Selenium jar. 1509 // Get the absolute path to the Selenium jar.
1441 String filePath = TestUtils.testScriptPath; 1510 String filePath = TestUtils.testScriptPath;
1442 String pathSep = io.Platform.pathSeparator; 1511 String pathSep = io.Platform.pathSeparator;
1443 int index = filePath.lastIndexOf(pathSep); 1512 int index = filePath.lastIndexOf(pathSep);
1444 filePath = '${filePath.substring(0, index)}${pathSep}testing${pathSep}'; 1513 filePath = '${filePath.substring(0, index)}${pathSep}testing${pathSep}';
1445 new io.Directory(filePath).list().listen((io.FileSystemEntity fse) { 1514 var lister = new io.Directory(filePath).list();
1446 if (fse is io.File) { 1515 lister.onFile = (String file) {
1447 String file = fse.path; 1516 if (new RegExp(r"selenium-server-standalone-.*\.jar").hasMatch(file)
1448 if (new RegExp(r"selenium-server-standalone-.*\.jar").hasMatch(file) 1517 && _seleniumServer == null) {
1449 && _seleniumServer == null) { 1518 Future processFuture = io.Process.start('java', ['-jar', file]);
1450 Future processFuture = io.Process.start('java', ['-jar', file]); 1519 processFuture.then((io.Process server) {
1451 processFuture.then((io.Process server) { 1520 _seleniumServer = server;
1452 _seleniumServer = server; 1521 // Heads up: there seems to an obscure data race of some form in
1453 // Heads up: there seems to an obscure data race of some form in 1522 // the VM between launching the server process and launching the test
1454 // the VM between launching the server process and launching the 1523 // tasks that disappears when you read IO (which is convenient, since
1455 // test tasks that disappears when you read IO (which is 1524 // that is our condition for knowing that the server is ready).
1456 // convenient, since that is our condition for knowing that the 1525 io.StringInputStream stdoutStringStream =
1457 // server is ready). 1526 new io.StringInputStream(_seleniumServer.stdout);
1458 Stream<String> stdoutStringStream = 1527 io.StringInputStream stderrStringStream =
1459 _seleniumServer.stdout.transform(new io.StringDecoder()) 1528 new io.StringInputStream(_seleniumServer.stderr);
1460 .transform(new io.LineTransformer()); 1529 stdoutStringStream.onLine =
1461 Stream<String> stderrStringStream = 1530 makeSeleniumServerHandler(stdoutStringStream);
1462 _seleniumServer.stderr.transform(new io.StringDecoder()) 1531 stderrStringStream.onLine =
1463 .transform(new io.LineTransformer()); 1532 makeSeleniumServerHandler(stderrStringStream);
1464 stdoutStringStream.listen(seleniumServerHandler); 1533 }).catchError((e) {
1465 stderrStringStream.listen(seleniumServerHandler); 1534 print("Process error:");
1466 }).catchError((e) { 1535 print(" Command: java -jar $file");
1467 print("Process error:"); 1536 print(" Error: $e");
1468 print(" Command: java -jar $file"); 1537 // TODO(ahe): How to report this as a test failure?
1469 print(" Error: $e"); 1538 io.exit(1);
1470 // TODO(ahe): How to report this as a test failure? 1539 return true;
1471 io.exit(1); 1540 });
1472 return true;
1473 });
1474 }
1475 } 1541 }
1476 }); 1542 };
1477 } 1543 }
1478 1544
1479 Future _terminateBatchRunners() { 1545 Future _terminateBatchRunners() {
1480 var futures = new List(); 1546 var futures = new List();
1481 for (var runners in _batchProcesses.values) { 1547 for (var runners in _batchProcesses.values) {
1482 for (var runner in runners) { 1548 for (var runner in runners) {
1483 futures.add(runner.terminate()); 1549 futures.add(runner.terminate());
1484 } 1550 }
1485 } 1551 }
1486 // Change to Future.wait when updating binaries. 1552 // Change to Future.wait when updating binaries.
(...skipping 28 matching lines...) Expand all
1515 test.isNegative.toString()]; 1581 test.isNegative.toString()];
1516 fields.addAll(test.commands.last.arguments); 1582 fields.addAll(test.commands.last.arguments);
1517 print(fields.join('\t')); 1583 print(fields.join('\t'));
1518 return; 1584 return;
1519 } 1585 }
1520 if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable || (test 1586 if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable || (test
1521 is BrowserTestCase && test.waitingForOtherTest)) { 1587 is BrowserTestCase && test.waitingForOtherTest)) {
1522 // The test is not yet ready to run. Put the test back in 1588 // The test is not yet ready to run. Put the test back in
1523 // the queue. Avoid spin-polling by using a timeout. 1589 // the queue. Avoid spin-polling by using a timeout.
1524 _tests.add(test); 1590 _tests.add(test);
1525 new Timer(new Duration(milliseconds: 100), 1591 new Timer(100, (_) => _tryRunTest()); // Don't lose a process.
1526 _tryRunTest); // Don't lose a process.
1527 return; 1592 return;
1528 } 1593 }
1529 // Before running any commands, we print out all commands if '--verbose' 1594 // Before running any commands, we print out all commands if '--verbose'
1530 // was specified. 1595 // was specified.
1531 if (_verbose && test.commandOutputs.length == 0) { 1596 if (_verbose && test.commandOutputs.length == 0) {
1532 int i = 1; 1597 int i = 1;
1533 if (test is BrowserTestCase) { 1598 if (test is BrowserTestCase) {
1534 // Additional command for rerunning the steps locally after the fact. 1599 // Additional command for rerunning the steps locally after the fact.
1535 var command = 1600 var command =
1536 test.configuration["_servers_"].httpServerCommandline(); 1601 test.configuration["_servers_"].httpServerCommandline();
1537 print('$i. $command'); 1602 print('$i. $command');
1538 i++; 1603 i++;
1539 } 1604 }
1540 for (Command command in test.commands) { 1605 for (Command command in test.commands) {
1541 print('$i. $command'); 1606 print('$i. $command');
1542 i++; 1607 i++;
1543 } 1608 }
1544 } 1609 }
1545 1610
1546 var isLastCommand = 1611 var isLastCommand =
1547 ((test.commands.length-1) == test.commandOutputs.length); 1612 ((test.commands.length-1) == test.commandOutputs.length);
1548 var isBrowserCommand = isLastCommand && (test is BrowserTestCase); 1613 var isBrowserCommand = isLastCommand && (test is BrowserTestCase);
1549 if (isBrowserCommand && _numBrowserProcesses == _maxBrowserProcesses) { 1614 if (isBrowserCommand && _numBrowserProcesses == _maxBrowserProcesses) {
1550 // If there is no free browser runner, put it back into the queue. 1615 // If there is no free browser runner, put it back into the queue.
1551 _tests.add(test); 1616 _tests.add(test);
1552 new Timer(new Duration(milliseconds: 100), 1617 new Timer(100, (_) => _tryRunTest()); // Don't lose a process.
1553 _tryRunTest); // Don't lose a process.
1554 return; 1618 return;
1555 } 1619 }
1556 1620
1557 eventStartTestCase(test); 1621 eventStartTestCase(test);
1558 1622
1559 // Analyzer and browser test commands can be run by a [BatchRunnerProcess] 1623 // Analyzer and browser test commands can be run by a [BatchRunnerProcess]
1560 var nextCommandIndex = test.commandOutputs.keys.length; 1624 var nextCommandIndex = test.commandOutputs.keys.length;
1561 var numberOfCommands = test.commands.length; 1625 var numberOfCommands = test.commands.length;
1562 1626
1563 var useBatchRunnerForAnalyzer = 1627 var useBatchRunnerForAnalyzer =
1564 test.configuration['analyzer'] && 1628 test.configuration['analyzer'] &&
1565 test.displayName != 'dartc/junit_tests'; 1629 test.displayName != 'dartc/junit_tests';
1566 var isWebdriverCommand = nextCommandIndex == (numberOfCommands - 1) && 1630 var isWebdriverCommand = nextCommandIndex == (numberOfCommands - 1) &&
1567 test.usesWebDriver && 1631 test.usesWebDriver &&
1568 !test.configuration['noBatch']; 1632 !test.configuration['noBatch'];
1569 if (useBatchRunnerForAnalyzer || isWebdriverCommand) { 1633 if (useBatchRunnerForAnalyzer || isWebdriverCommand) {
1570 TestCaseEvent oldCallback = test.completedHandler; 1634 TestCaseEvent oldCallback = test.completedHandler;
1571 void testCompleted(TestCase test_arg) { 1635 void testCompleted(TestCase test_arg) {
1572 _numProcesses--; 1636 _numProcesses--;
1573 if (isBrowserCommand) { 1637 if (isBrowserCommand) {
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1716 } 1780 }
1717 } 1781 }
1718 1782
1719 void eventAllTestsDone() { 1783 void eventAllTestsDone() {
1720 for (var listener in _eventListener) { 1784 for (var listener in _eventListener) {
1721 listener.allDone(); 1785 listener.allDone();
1722 } 1786 }
1723 } 1787 }
1724 } 1788 }
1725 1789
OLDNEW
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | tools/testing/dart/test_suite.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698