| 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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 * process, before the regular test is run as in the base class [TestCase]. | 175 * process, before the regular test is run as in the base class [TestCase]. |
| 176 * If the compilation command fails, then the rest of the test is not run. | 176 * If the compilation command fails, then the rest of the test is not run. |
| 177 */ | 177 */ |
| 178 class BrowserTestCase extends TestCase { | 178 class BrowserTestCase extends TestCase { |
| 179 /** | 179 /** |
| 180 * Indicates the number of potential retries remaining, to compensate for | 180 * Indicates the number of potential retries remaining, to compensate for |
| 181 * flaky browser tests. | 181 * flaky browser tests. |
| 182 */ | 182 */ |
| 183 int numRetries; | 183 int numRetries; |
| 184 | 184 |
| 185 /** |
| 186 * True if this test is dependent on another test completing before it can |
| 187 * star (for example, we might need to depend on some other test completing |
| 188 * first). |
| 189 */ |
| 190 bool waitingForOtherTest; |
| 191 |
| 192 /** |
| 193 * The set of test cases that wish to be notified when this test has |
| 194 * completed. |
| 195 */ |
| 196 List<BrowserTestCase> observers; |
| 197 |
| 185 BrowserTestCase(displayName, commands, configuration, completedHandler, | 198 BrowserTestCase(displayName, commands, configuration, completedHandler, |
| 186 expectedOutcomes, info, isNegative) | 199 expectedOutcomes, info, isNegative, [this.waitingForOtherTest = false]) |
| 187 : super(displayName, commands, configuration, completedHandler, | 200 : super(displayName, commands, configuration, completedHandler, |
| 188 expectedOutcomes, isNegative: isNegative, info: info) { | 201 expectedOutcomes, isNegative: isNegative, info: info) { |
| 189 numRetries = 2; // Allow two retries to compensate for flaky browser tests. | 202 numRetries = 2; // Allow two retries to compensate for flaky browser tests. |
| 203 observers = []; |
| 190 } | 204 } |
| 191 | 205 |
| 192 List<String> get _lastArguments => commands.last.arguments; | 206 List<String> get _lastArguments => commands.last.arguments; |
| 193 | 207 |
| 194 List<String> get batchRunnerArguments => [_lastArguments[0], '--batch']; | 208 List<String> get batchRunnerArguments => [_lastArguments[0], '--batch']; |
| 195 | 209 |
| 196 List<String> get batchTestArguments => | 210 List<String> get batchTestArguments => |
| 197 _lastArguments.getRange(1, _lastArguments.length - 1); | 211 _lastArguments.getRange(1, _lastArguments.length - 1); |
| 212 |
| 213 /** Add a test case to listen for when this current test has completed. */ |
| 214 void addObserver(BrowserTestCase testCase) { |
| 215 observers.add(testCase); |
| 216 } |
| 217 |
| 218 /** |
| 219 * Notify all of the test cases that are dependent on this one that they can |
| 220 * proceed. |
| 221 */ |
| 222 void notifyObservers() { |
| 223 for (BrowserTestCase testCase in observers) { |
| 224 testCase.waitingForOtherTest = false; |
| 225 } |
| 226 } |
| 198 } | 227 } |
| 199 | 228 |
| 200 | 229 |
| 201 /** | 230 /** |
| 202 * TestOutput records the output of a completed test: the process's exit code, | 231 * TestOutput records the output of a completed test: the process's exit code, |
| 203 * the standard output and standard error, whether the process timed out, and | 232 * the standard output and standard error, whether the process timed out, and |
| 204 * the time the process took to run. It also contains a pointer to the | 233 * the time the process took to run. It also contains a pointer to the |
| 205 * [TestCase] this is the output of. | 234 * [TestCase] this is the output of. |
| 206 */ | 235 */ |
| 207 abstract class TestOutput { | 236 abstract class TestOutput { |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 } | 684 } |
| 656 return handler; | 685 return handler; |
| 657 } | 686 } |
| 658 | 687 |
| 659 void start() { | 688 void start() { |
| 660 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); | 689 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); |
| 661 stdout = new List<String>(); | 690 stdout = new List<String>(); |
| 662 stderr = new List<String>(); | 691 stderr = new List<String>(); |
| 663 currentStep = 0; | 692 currentStep = 0; |
| 664 startTime = new Date.now(); | 693 startTime = new Date.now(); |
| 665 runCommand(testCase.commands[currentStep++], stepExitHandler); | 694 if (testCase.commands.length == 1 && testCase.usesWebDriver && |
| 695 !testCase.configuration['noBatch']) { |
| 696 // Browser test cases that do not require a precompilation step, start |
| 697 // with the batch runner right away. |
| 698 processQueue._getBatchRunner(testCase).startTest(testCase); |
| 699 } else { |
| 700 runCommand(testCase.commands[currentStep++], stepExitHandler); |
| 701 } |
| 666 } | 702 } |
| 667 | 703 |
| 668 void runCommand(Command command, void exitHandler(int exitCode)) { | 704 void runCommand(Command command, void exitHandler(int exitCode)) { |
| 669 Future processFuture = Process.start(command.executable, command.arguments); | 705 Future processFuture = Process.start(command.executable, command.arguments); |
| 670 processFuture.then((Process p) { | 706 processFuture.then((Process p) { |
| 671 process = p; | 707 process = p; |
| 672 process.onExit = exitHandler; | 708 process.onExit = exitHandler; |
| 673 var stdoutStringStream = new StringInputStream(process.stdout); | 709 var stdoutStringStream = new StringInputStream(process.stdout); |
| 674 var stderrStringStream = new StringInputStream(process.stderr); | 710 var stderrStringStream = new StringInputStream(process.stderr); |
| 675 stdoutStringStream.onLine = | 711 stdoutStringStream.onLine = |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1069 if (_tests.isEmpty && _numProcesses == 0) { | 1105 if (_tests.isEmpty && _numProcesses == 0) { |
| 1070 _terminateBatchRunners().then((_) => _cleanupAndMarkDone()); | 1106 _terminateBatchRunners().then((_) => _cleanupAndMarkDone()); |
| 1071 } | 1107 } |
| 1072 } | 1108 } |
| 1073 } | 1109 } |
| 1074 | 1110 |
| 1075 /** | 1111 /** |
| 1076 * True if we are using a browser + platform combination that needs the | 1112 * True if we are using a browser + platform combination that needs the |
| 1077 * Selenium server jar. | 1113 * Selenium server jar. |
| 1078 */ | 1114 */ |
| 1079 bool get _needsSelenium => Platform.operatingSystem == 'macos' && | 1115 bool get _needsSelenium => (Platform.operatingSystem == 'macos' && |
| 1080 browserUsed == 'safari'; | 1116 browserUsed == 'safari') || browserUsed == 'opera'; |
| 1081 | 1117 |
| 1082 /** True if the Selenium Server is ready to be used. */ | 1118 /** True if the Selenium Server is ready to be used. */ |
| 1083 bool get _isSeleniumAvailable => _seleniumServer != null || | 1119 bool get _isSeleniumAvailable => _seleniumServer != null || |
| 1084 _seleniumAlreadyRunning; | 1120 _seleniumAlreadyRunning; |
| 1085 | 1121 |
| 1086 /** | 1122 /** |
| 1087 * Restart all the processes that have been waiting/stopped for the server to | 1123 * Restart all the processes that have been waiting/stopped for the server to |
| 1088 * start up. If we just call this once we end up with a single-"threaded" run. | 1124 * start up. If we just call this once we end up with a single-"threaded" run. |
| 1089 */ | 1125 */ |
| 1090 void resumeTesting() { | 1126 void resumeTesting() { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1242 if (_numProcesses < _maxProcesses && !_tests.isEmpty) { | 1278 if (_numProcesses < _maxProcesses && !_tests.isEmpty) { |
| 1243 TestCase test = _tests.removeFirst(); | 1279 TestCase test = _tests.removeFirst(); |
| 1244 if (_listTests) { | 1280 if (_listTests) { |
| 1245 var fields = [test.displayName, | 1281 var fields = [test.displayName, |
| 1246 Strings.join(new List.from(test.expectedOutcomes), ','), | 1282 Strings.join(new List.from(test.expectedOutcomes), ','), |
| 1247 test.isNegative.toString()]; | 1283 test.isNegative.toString()]; |
| 1248 fields.addAll(test.commands.last.arguments); | 1284 fields.addAll(test.commands.last.arguments); |
| 1249 print(Strings.join(fields, '\t')); | 1285 print(Strings.join(fields, '\t')); |
| 1250 return; | 1286 return; |
| 1251 } | 1287 } |
| 1252 if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable) { | 1288 if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable || (test |
| 1253 // The server is not ready to run Selenium tests. Put the test back in | 1289 is BrowserTestCase && test.waitingForOtherTest)) { |
| 1290 // The test is not yet ready to run. Put the test back in |
| 1254 // the queue. Avoid spin-polling by using a timeout. | 1291 // the queue. Avoid spin-polling by using a timeout. |
| 1255 _tests.add(test); | 1292 _tests.add(test); |
| 1256 new Timer(1000, (timer) {_tryRunTest();}); // Don't lose a process. | 1293 new Timer(100, (timer) {_tryRunTest();}); // Don't lose a process. |
| 1257 return; | 1294 return; |
| 1258 } | 1295 } |
| 1259 if (_verbose) { | 1296 if (_verbose) { |
| 1260 int i = 1; | 1297 int i = 1; |
| 1261 for (Command command in test.commands) { | 1298 for (Command command in test.commands) { |
| 1262 print('$i. ${command.commandLine}'); | 1299 print('$i. ${command.commandLine}'); |
| 1263 i++; | 1300 i++; |
| 1264 } | 1301 } |
| 1265 } | 1302 } |
| 1266 _progress.start(test); | 1303 _progress.start(test); |
| 1267 TestCaseEvent oldCallback = test.completedHandler; | 1304 TestCaseEvent oldCallback = test.completedHandler; |
| 1268 void wrapper(TestCase test_arg) { | 1305 void wrapper(TestCase test_arg) { |
| 1306 if (test_arg is BrowserTestCase) test_arg.notifyObservers(); |
| 1269 _numProcesses--; | 1307 _numProcesses--; |
| 1270 _progress.done(test_arg); | 1308 _progress.done(test_arg); |
| 1271 _tryRunTest(); | 1309 _tryRunTest(); |
| 1272 oldCallback(test_arg); | 1310 oldCallback(test_arg); |
| 1273 }; | 1311 }; |
| 1274 test.completedHandler = wrapper; | 1312 test.completedHandler = wrapper; |
| 1275 if (test.configuration['compiler'] == 'dartc' && | 1313 if (test.configuration['compiler'] == 'dartc' && |
| 1276 test.displayName != 'dartc/junit_tests') { | 1314 test.displayName != 'dartc/junit_tests') { |
| 1277 _getBatchRunner(test).startTest(test); | 1315 _getBatchRunner(test).startTest(test); |
| 1278 } else { | 1316 } else { |
| 1279 // Once we've actually failed a test, technically, we wouldn't need to | 1317 // Once we've actually failed a test, technically, we wouldn't need to |
| 1280 // bother retrying any subsequent tests since the bot is already red. | 1318 // bother retrying any subsequent tests since the bot is already red. |
| 1281 // However, we continue to retry tests until we have actually failed | 1319 // However, we continue to retry tests until we have actually failed |
| 1282 // four tests (arbitrarily chosen) for more debugable output, so that | 1320 // four tests (arbitrarily chosen) for more debugable output, so that |
| 1283 // the developer doesn't waste his or her time trying to fix a bunch of | 1321 // the developer doesn't waste his or her time trying to fix a bunch of |
| 1284 // tests that appear to be broken but were actually just flakes that | 1322 // tests that appear to be broken but were actually just flakes that |
| 1285 // didn't get retried because there had already been one failure. | 1323 // didn't get retried because there had already been one failure. |
| 1286 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 1324 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; |
| 1287 new RunningProcess(test, allowRetry, this).start(); | 1325 new RunningProcess(test, allowRetry, this).start(); |
| 1288 } | 1326 } |
| 1289 _numProcesses++; | 1327 _numProcesses++; |
| 1290 } | 1328 } |
| 1291 } | 1329 } |
| 1292 } | 1330 } |
| OLD | NEW |