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

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

Issue 9426005: Don't retry browser tests if the bot is pretty red. Also, retry properly all (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 10 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') | 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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 // exceptions. 193 // exceptions.
194 return (!timedOut && ((exitCode < 0) || (exitCode == 253))); 194 return (!timedOut && ((exitCode < 0) || (exitCode == 253)));
195 } 195 }
196 196
197 bool get hasTimedOut() => timedOut; 197 bool get hasTimedOut() => timedOut;
198 198
199 bool get didFail() { 199 bool get didFail() {
200 if (testCase is !BrowserTestCase) return (exitCode != 0 && !hasCrashed); 200 if (testCase is !BrowserTestCase) return (exitCode != 0 && !hasCrashed);
201 201
202 // Browser case: 202 // Browser case:
203 // Browser tests fail unless stdout contains
204 // 'Content-Type: text/plain\nPASS'.
205 String previous_line = '';
206 for (String line in stdout) {
207 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') {
208 return (exitCode != 0 && !hasCrashed);
209 }
210 previous_line = line;
211 }
212
213 // If the browser test failed, it may have been because DumpRenderTree 203 // If the browser test failed, it may have been because DumpRenderTree
214 // and the virtual framebuffer X server didn't hook up, or DRT crashed with 204 // and the virtual framebuffer X server didn't hook up, or DRT crashed with
215 // a core dump. 205 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS,
206 // so we have to do this check first.
216 for (String line in stderr) { 207 for (String line in stderr) {
217 if (line.contains('Gtk-WARNING **: cannot open display: :99') || 208 if (line.contains('Gtk-WARNING **: cannot open display: :99') ||
218 line.contains('Failed to run command. return code=1')) { 209 line.contains('Failed to run command. return code=1')) {
219 // If we get the X server error, or DRT crashes with a core dump, retry 210 // If we get the X server error, or DRT crashes with a core dump, retry
220 // the test. 211 // the test.
221 requestRetry = true; 212 requestRetry = true;
222 return true; 213 return true;
223 } 214 }
224 } 215 }
216
217 // Browser tests fail unless stdout contains
218 // 'Content-Type: text/plain\nPASS'.
219 String previous_line = '';
220 for (String line in stdout) {
221 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') {
222 return (exitCode != 0 && !hasCrashed);
223 }
224 previous_line = line;
225 }
226
225 return true; 227 return true;
226 } 228 }
227 229
228 // Reverse result of a negative test. 230 // Reverse result of a negative test.
229 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); 231 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail);
230 } 232 }
231 233
232 /** 234 /**
233 * A RunningProcess actually runs a test, getting the command lines from 235 * A RunningProcess actually runs a test, getting the command lines from
234 * its [TestCase], starting the test process (and first, a compilation 236 * its [TestCase], starting the test process (and first, a compilation
235 * process if the TestCase is a [BrowserTestCase]), creating a timeout 237 * process if the TestCase is a [BrowserTestCase]), creating a timeout
236 * timer, and recording the results in a new [TestOutput] object, which it 238 * timer, and recording the results in a new [TestOutput] object, which it
237 * attaches to the TestCase. The lifetime of the RunningProcess is limited 239 * attaches to the TestCase. The lifetime of the RunningProcess is limited
238 * to the time it takes to start the process, run the process, and record 240 * to the time it takes to start the process, run the process, and record
239 * the result; there are no pointers to it, so it should be available to 241 * the result; there are no pointers to it, so it should be available to
240 * be garbage collected as soon as it is done. 242 * be garbage collected as soon as it is done.
241 */ 243 */
242 class RunningProcess { 244 class RunningProcess {
243 Process process; 245 Process process;
244 TestCase testCase; 246 TestCase testCase;
245 bool timedOut = false; 247 bool timedOut = false;
246 Date startTime; 248 Date startTime;
247 Timer timeoutTimer; 249 Timer timeoutTimer;
248 List<String> stdout; 250 List<String> stdout;
249 List<String> stderr; 251 List<String> stderr;
250 List<Function> handlers; 252 List<Function> handlers;
253 bool allowRetries;
251 254
252 RunningProcess(TestCase this.testCase); 255 RunningProcess(TestCase this.testCase, this.allowRetries);
253 256
254 void exitHandler(int exitCode) { 257 void exitHandler(int exitCode) {
255 new TestOutput(testCase, exitCode, timedOut, stdout, 258 new TestOutput(testCase, exitCode, timedOut, stdout,
256 stderr, new Date.now().difference(startTime)); 259 stderr, new Date.now().difference(startTime));
257 process.close(); 260 process.close();
258 timeoutTimer.cancel(); 261 timeoutTimer.cancel();
259 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { 262 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
260 print(testCase.displayName); 263 print(testCase.displayName);
261 for (var line in testCase.output.stderr) print(line); 264 for (var line in testCase.output.stderr) print(line);
262 for (var line in testCase.output.stdout) print(line); 265 for (var line in testCase.output.stdout) print(line);
263 } 266 }
264 if (testCase.configuration['component'] == 'webdriver' && 267 if (allowRetries && testCase.configuration['component'] == 'webdriver' &&
265 testCase.output.unexpectedOutput && testCase.numRetries > 0) { 268 testCase.output.unexpectedOutput && testCase.numRetries > 0) {
266 // Selenium tests can be flaky. Try rerunning. 269 // Selenium tests can be flaky. Try rerunning.
267 testCase.output.requestRetry = true; 270 testCase.output.requestRetry = true;
268 } 271 }
269 if (testCase.output.requestRetry) { 272 if (testCase.output.requestRetry) {
270 testCase.output.requestRetry = false; 273 testCase.output.requestRetry = false;
271 this.timedOut = false; 274 this.timedOut = false;
272 testCase.dynamic.numRetries--; 275 testCase.dynamic.numRetries--;
273 print("Potential flake. Re-running " + testCase.displayName); 276 print("Potential flake. Re-running " + testCase.displayName);
274 this.start(); 277 this.start();
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 * 496 *
494 * Because multiple configurations may be run on each test suite, the 497 * Because multiple configurations may be run on each test suite, the
495 * ProcessQueue contains a cache in which a test suite may record information 498 * ProcessQueue contains a cache in which a test suite may record information
496 * about its list of tests, and may retrieve that information when it is called 499 * about its list of tests, and may retrieve that information when it is called
497 * upon to enqueue its tests again. 500 * upon to enqueue its tests again.
498 */ 501 */
499 class ProcessQueue { 502 class ProcessQueue {
500 int _numProcesses = 0; 503 int _numProcesses = 0;
501 int _activeTestListers = 0; 504 int _activeTestListers = 0;
502 int _maxProcesses; 505 int _maxProcesses;
506 /** The number of tests we allow to actually fail before we stop retrying. */
507 int _MAX_FAILED_NO_RETRY = 4;
503 bool _verbose; 508 bool _verbose;
504 bool _listTests; 509 bool _listTests;
505 bool _keepGeneratedTests; 510 bool _keepGeneratedTests;
506 Function _enqueueMoreWork; 511 Function _enqueueMoreWork;
507 Queue<TestCase> _tests; 512 Queue<TestCase> _tests;
508 ProgressIndicator _progress; 513 ProgressIndicator _progress;
509 String _temporaryDirectory; 514 String _temporaryDirectory;
510 // For dartc batch processing we keep a list of batch processes. 515 // For dartc batch processing we keep a list of batch processes.
511 List<DartcBatchRunnerProcess> _batchProcesses; 516 List<DartcBatchRunnerProcess> _batchProcesses;
512 // Cache information about test cases per test suite. For multiple 517 // Cache information about test cases per test suite. For multiple
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
697 _progress.done(test_arg); 702 _progress.done(test_arg);
698 _tryRunTest(); 703 _tryRunTest();
699 oldCallback(test_arg); 704 oldCallback(test_arg);
700 }; 705 };
701 test.completedHandler = wrapper; 706 test.completedHandler = wrapper;
702 if (test.configuration['component'] == 'dartc' && 707 if (test.configuration['component'] == 'dartc' &&
703 test.displayName != 'dartc/junit_tests') { 708 test.displayName != 'dartc/junit_tests') {
704 _ensureDartcBatchRunnersStarted(test.executablePath); 709 _ensureDartcBatchRunnersStarted(test.executablePath);
705 _getDartcBatchRunnerProcess().startTest(test); 710 _getDartcBatchRunnerProcess().startTest(test);
706 } else { 711 } else {
707 new RunningProcess(test).start(); 712 // Once we've actually failed a test, technically, we wouldn't need to
713 // bother retrying any subsequent tests since the bot is already red.
714 // However, we continue to retry tests until we have actually failed
715 // four tests (arbitrarily chosen) for more debugable output, so that
716 // the developer doesn't waste his or her time trying to fix a bunch of
717 // tests that appear to be broken but were actually just flakes that
718 // didn't get retried because there had already been one failure.
719 new RunningProcess(test,
720 _MAX_FAILED_NO_RETRY > _progress.numFailedTests).start();
708 } 721 }
709 _numProcesses++; 722 _numProcesses++;
710 } 723 }
711 } 724 }
712 } 725 }
OLDNEW
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698