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

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

Issue 9559007: Update test.dart for detection output of machine formatted errors (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Added diagnostic for @static-clean conflicts Created 8 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
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 14 matching lines...) Expand all
25 25
26 /** Command line arguments to the executable. */ 26 /** Command line arguments to the executable. */
27 List<String> arguments; 27 List<String> arguments;
28 28
29 /** The actual command line that will be executed. */ 29 /** The actual command line that will be executed. */
30 String commandLine; 30 String commandLine;
31 31
32 Command(this.executable, this.arguments) { 32 Command(this.executable, this.arguments) {
33 commandLine = "$executable ${Strings.join(arguments, ' ')}"; 33 commandLine = "$executable ${Strings.join(arguments, ' ')}";
34 } 34 }
35
36 String toString() => commandLine;
35 } 37 }
36 38
37 /** 39 /**
38 * TestCase contains all the information needed to run a test and evaluate 40 * TestCase contains all the information needed to run a test and evaluate
39 * its output. Running a test involves starting a separate process, with 41 * its output. Running a test involves starting a separate process, with
40 * the executable and arguments given by the TestCase, and recording its 42 * the executable and arguments given by the TestCase, and recording its
41 * stdout and stderr output streams, and its exit code. TestCase only 43 * stdout and stderr output streams, and its exit code. TestCase only
42 * contains static information about the test; actually running the test is 44 * contains static information about the test; actually running the test is
43 * performed by [ProcessQueue] using a [RunningProcess] object. 45 * performed by [ProcessQueue] using a [RunningProcess] object.
44 * 46 *
(...skipping 13 matching lines...) Expand all
58 * multiple sources that are run in isolation. 60 * multiple sources that are run in isolation.
59 */ 61 */
60 final List<Command> commands; 62 final List<Command> commands;
61 63
62 Map configuration; 64 Map configuration;
63 String displayName; 65 String displayName;
64 TestOutput output; 66 TestOutput output;
65 bool isNegative; 67 bool isNegative;
66 Set<String> expectedOutcomes; 68 Set<String> expectedOutcomes;
67 Function completedHandler; 69 Function completedHandler;
70 TestInformation info;
68 71
69 TestCase(this.displayName, 72 TestCase(this.displayName,
70 this.commands, 73 this.commands,
71 this.configuration, 74 this.configuration,
72 this.completedHandler, 75 this.completedHandler,
73 this.expectedOutcomes, 76 this.expectedOutcomes,
74 [this.isNegative = false]) { 77 [this.isNegative = false,
78 this.info = null]) {
75 if (!isNegative) { 79 if (!isNegative) {
76 this.isNegative = displayName.contains("NegativeTest"); 80 this.isNegative = displayName.contains("NegativeTest");
77 } 81 }
78 82
79 // Special command handling. If a special command is specified 83 // Special command handling. If a special command is specified
80 // we have to completely rewrite the command that we are using. 84 // we have to completely rewrite the command that we are using.
81 // We generate a new command-line that is the special command 85 // We generate a new command-line that is the special command
82 // where we replace '@' with the original command. 86 // where we replace '@' with the original command.
83 var specialCommand = configuration['special-command']; 87 var specialCommand = configuration['special-command'];
84 if (!specialCommand.isEmpty()) { 88 if (!specialCommand.isEmpty()) {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 _lastArguments.getRange(1, _lastArguments.length - 1); 162 _lastArguments.getRange(1, _lastArguments.length - 1);
159 } 163 }
160 164
161 165
162 /** 166 /**
163 * TestOutput records the output of a completed test: the process's exit code, 167 * TestOutput records the output of a completed test: the process's exit code,
164 * the standard output and standard error, whether the process timed out, and 168 * the standard output and standard error, whether the process timed out, and
165 * the time the process took to run. It also contains a pointer to the 169 * the time the process took to run. It also contains a pointer to the
166 * [TestCase] this is the output of. 170 * [TestCase] this is the output of.
167 */ 171 */
168 class TestOutput { 172 interface TestOutput default TestOutputImpl {
173 TestOutput.fromCase(TestCase testCase, int exitCode, bool timedOut,
174 List<String> stdout, List<String> stderr, Duration time);
175
176 String get result();
177
178 bool get unexpectedOutput();
179
180 bool get hasCrashed();
181
182 bool get hasTimedOut();
183
184 bool get didFail();
185
186 List<String> get diagnostics();
187 }
188
189 class TestOutputImpl implements TestOutput {
169 TestCase testCase; 190 TestCase testCase;
170 int exitCode; 191 int exitCode;
171 bool timedOut; 192 bool timedOut;
172 bool failed = false; 193 bool failed = false;
173 List<String> stdout; 194 List<String> stdout;
174 List<String> stderr; 195 List<String> stderr;
175 Duration time; 196 Duration time;
197 List<String> diagnostics;
198
176 /** 199 /**
177 * Set to true if we encounter a condition in the output that indicates we 200 * Set to true if we encounter a condition in the output that indicates we
178 * need to rerun this test. 201 * need to rerun this test.
179 */ 202 */
180 bool requestRetry; 203 bool requestRetry = false;
181 204
182 TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout, 205 // Don't call this constructor, call TestOutput.fromCase() to
206 // get anew TestOutput instance.
207 TestOutputImpl(this.testCase, this.exitCode, this.timedOut, this.stdout,
183 this.stderr, this.time) { 208 this.stderr, this.time) {
184 testCase.output = this; 209 testCase.output = this;
185 requestRetry = false; 210 diagnostics = [];
186 } 211 }
187 212
213 factory TestOutputImpl.fromCase (testCase, exitCode, timedOut, stdout, stderr,
214 time) {
215 if (testCase is BrowserTestCase) {
216 return new BrowserTestOutputImpl(testCase, exitCode, timedOut,
217 stdout, stderr, time);
218 } else if (testCase.configuration['component'] == 'dartc') {
219 return new AnalysisTestOutputImpl(testCase, exitCode, timedOut,
220 stdout, stderr, time);
221 }
222 return new TestOutputImpl(testCase, exitCode, timedOut,
223 stdout, stderr, time);
224 }
225
188 String get result() => 226 String get result() =>
189 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); 227 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS));
190 228
191 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result); 229 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result);
192 230
193 bool get hasCrashed() { 231 bool get hasCrashed() {
194 if (new Platform().operatingSystem() == 'windows') { 232 if (new Platform().operatingSystem() == 'windows') {
195 // The VM uses std::abort to terminate on asserts. 233 // The VM uses std::abort to terminate on asserts.
196 // std::abort terminates with exit code 3 on Windows. 234 // std::abort terminates with exit code 3 on Windows.
197 if (exitCode == 3) { 235 if (exitCode == 3) {
198 return !timedOut; 236 return !timedOut;
199 } 237 }
200 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); 238 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0));
201 } 239 }
202 // The Java dartc runner exits with code 253 in case of unhandled 240 // The Java dartc runner exits with code 253 in case of unhandled
203 // exceptions. 241 // exceptions.
204 return (!timedOut && ((exitCode < 0) || (exitCode == 253))); 242 return (!timedOut && ((exitCode < 0) || (exitCode == 253)));
205 } 243 }
206 244
207 bool get hasTimedOut() => timedOut; 245 bool get hasTimedOut() => timedOut;
208 246
209 bool get didFail() { 247 bool get didFail() {
210 if (testCase is !BrowserTestCase) return (exitCode != 0 && !hasCrashed); 248 return (exitCode != 0 && !hasCrashed);
249 }
250
251 // Reverse result of a negative test.
252 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail);
211 253
254 }
255
256 class BrowserTestOutputImpl extends TestOutputImpl {
257 BrowserTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) :
258 super(testCase, exitCode, timedOut, stdout, stderr, time);
259
260 bool get didFail() {
212 // Browser case: 261 // Browser case:
213 // If the browser test failed, it may have been because DumpRenderTree 262 // 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 263 // and the virtual framebuffer X server didn't hook up, or DRT crashed with
215 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, 264 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS,
216 // so we have to do this check first. 265 // so we have to do this check first.
217 for (String line in stderr) { 266 for (String line in stderr) {
218 if (line.contains('Gtk-WARNING **: cannot open display: :99') || 267 if (line.contains('Gtk-WARNING **: cannot open display: :99') ||
219 line.contains('Failed to run command. return code=1')) { 268 line.contains('Failed to run command. return code=1')) {
220 // If we get the X server error, or DRT crashes with a core dump, retry 269 // If we get the X server error, or DRT crashes with a core dump, retry
221 // the test. 270 // the test.
222 if (testCase.dynamic.numRetries > 0) { 271 if (testCase.dynamic.numRetries > 0) {
223 requestRetry = true; 272 requestRetry = true;
224 } 273 }
225 return true; 274 return true;
226 } 275 }
227 } 276 }
228 277
229 // Browser tests fail unless stdout contains 278 // Browser tests fail unless stdout contains
230 // 'Content-Type: text/plain\nPASS'. 279 // 'Content-Type: text/plain\nPASS'.
231 String previous_line = ''; 280 String previous_line = '';
232 for (String line in stdout) { 281 for (String line in stdout) {
233 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') { 282 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') {
234 return (exitCode != 0 && !hasCrashed); 283 return (exitCode != 0 && !hasCrashed);
235 } 284 }
236 previous_line = line; 285 previous_line = line;
237 } 286 }
238
239 return true; 287 return true;
240 } 288 }
289 }
241 290
242 // Reverse result of a negative test. 291 // The static analyzer does not actaully execute code, so
243 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); 292 // the criteria for success now depend on the text sent
293 // to stderr.
294 class AnalysisTestOutputImpl extends TestOutputImpl {
295 boolean alreadyComputed = false;
296 boolean failResult;
297 AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) :
298 super(testCase, exitCode, timedOut, stdout, stderr, time) {
299 }
300
301 bool get didFail() {
302 if (!alreadyComputed) {
303 failResult = _didFail();
304 alreadyComputed = true;
305 }
306 return failResult;
307 }
308
309 bool _didFail() {
310 if (hasCrashed) return false;
311
312 List<String> errors = [];
313 List<String> staticWarnings = [];
314
315 // Read the returned list of errors and stuff them away.
316 for (String line in stderr) {
317 if (line.length == 0) continue;
318 List<String> fields = splitMachineError(line);
319 if (fields[0] == 'ERROR') {
320 errors.add(fields);
321 } else if (fields[0] == 'WARNING') {
322 // We only care about testing Static type warnings
323 // ignore all others
324 if (fields[1] == 'STATIC_TYPE') {
325 staticWarnings.add(fields);
326 }
327 }
328 // OK to Skip error output that doesn't match the machine format
329 }
330 if (testCase.info != null
331 && testCase.info.optionsFromFile['isMultitest']) {
332 return _didMultitestFail(errors, staticWarnings);
333 }
334 return _didStandardTestFail(errors, staticWarnings);
335 }
336
337 bool _didMultitestFail(List errors, List staticWarnings) {
338 String outcome = testCase.info.multitestOutcome;
339 if ((outcome == '' || outcome == 'compile-time error') && errors.length > 0) {
340 return true;
341 } else if (outcome == 'static type error' && staticWarnings.length > 0) {
342 return true;
343 }
344 return false;
345 }
346
347 bool _didStandardTestFail(List errors, List staticWarnings) {
348 bool hasFatalTypeErrors = false;
349 int numStaticTypeAnnotations = 0;
350 int numCompileTimeAnnotations = 0;
351 var isStaticClean = false;
352 if (testCase.info != null) {
353 var optionsFromFile = testCase.info.optionsFromFile;
354 hasFatalTypeErrors = optionsFromFile['hasFatalTypeErrors'];
355 for (Command c in testCase.commands) {
356 for (String arg in c.arguments) {
357 if (arg == '--fatal-type-errors') {
358 hasFatalTypeErrors = true;
359 break;
360 }
361 }
362 }
363 numStaticTypeAnnotations = optionsFromFile['numStaticTypeAnnotations'];
364 numCompileTimeAnnotations = optionsFromFile['numCompileTimeAnnotations'];
365 isStaticClean = optionsFromFile['isStaticClean'];
366 }
367
368 if (errors.length == 0) {
369 if (!hasFatalTypeErrors && exitCode != 0) {
370 diagnostics.add("EXIT CODE MISMATCH: Expected error message:");
371 diagnostics.add(" command[0]:${testCase.commands[0]}");
372 diagnostics.add(" exitCode:${exitCode}");
373 return true;
374 }
375 } else if (exitCode == 0) {
376 diagnostics.add("EXIT CODE MISMATCH: Unexpected error message:");
377 diagnostics.add(" errors[0]:${errors[0]}");
378 diagnostics.add(" command[0]:${testCase.commands[0]}");
379 diagnostics.add(" exitCode:${exitCode}");
380 return true;
381 }
382 if (numStaticTypeAnnotations > 0 && isStaticClean) {
383 diagnostics.add("Cannot have both @static-clean and /// static type warnin g annotations.");
384 return true;
385 }
386
387 if (isStaticClean && staticWarnings.length > 0) {
388 diagnostics.add("@static-clean annotation found but analyzer returned warn ings.");
389 return true;
390 }
391
392 if (numCompileTimeAnnotations > 0
393 && numCompileTimeAnnotations < errors.length) {
394
395 // Expected compile-time errors were not returned. The test did not 'fail ' in the way
396 // intended so don't return failed.
397 diagnostics.add("Fewer compile time errors than annotated: ${numCompileTim eAnnotations}");
398 return false;
399 }
400
401 if (numStaticTypeAnnotations > 0 || hasFatalTypeErrors) {
402 // TODO(zundel): match up the annotation line numbers
403 // with the reported error line numbers
404 if (staticWarnings.length < numStaticTypeAnnotations) {
405 diagnostics.add("Fewer static type warnings than annotated: ${numStaticT ypeAnnotations}");
406 return true;
407 }
408 return false;
409 } else if (errors.length != 0) {
410 return true;
411 }
412 return false;
413 }
414
415 // Parse a line delimited by the | character using \ as an escape charager
416 // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ
417 List<String> splitMachineError(String line) {
418 StringBuffer field = new StringBuffer();
419 List<String> result = [];
420 bool escaped = false;
421 for (var i = 0 ; i < line.length; i++) {
422 var c = line[i];
423 if (!escaped && c == '\\') {
424 escaped = true;
425 continue;
426 }
427 escaped = false;
428 if (c == '|') {
429 result.add(field.toString());
430 field.clear();
431 continue;
432 }
433 field.add(c);
434 }
435 result.add(field.toString());
436 return result;
437 }
244 } 438 }
245 439
246 /** 440 /**
247 * A RunningProcess actually runs a test, getting the command lines from 441 * A RunningProcess actually runs a test, getting the command lines from
248 * its [TestCase], starting the test process (and first, a compilation 442 * its [TestCase], starting the test process (and first, a compilation
249 * process if the TestCase is a [BrowserTestCase]), creating a timeout 443 * process if the TestCase is a [BrowserTestCase]), creating a timeout
250 * timer, and recording the results in a new [TestOutput] object, which it 444 * timer, and recording the results in a new [TestOutput] object, which it
251 * attaches to the TestCase. The lifetime of the RunningProcess is limited 445 * attaches to the TestCase. The lifetime of the RunningProcess is limited
252 * to the time it takes to start the process, run the process, and record 446 * to the time it takes to start the process, run the process, and record
253 * the result; there are no pointers to it, so it should be available to 447 * the result; there are no pointers to it, so it should be available to
(...skipping 16 matching lines...) Expand all
270 464
271 RunningProcess(TestCase this.testCase, 465 RunningProcess(TestCase this.testCase,
272 [this.allowRetries, this.processQueue]); 466 [this.allowRetries, this.processQueue]);
273 467
274 /** 468 /**
275 * Called when all commands are executed. [exitCode] is 0 if all command 469 * Called when all commands are executed. [exitCode] is 0 if all command
276 * succeded, otherwise it will have the exit code of the first failing 470 * succeded, otherwise it will have the exit code of the first failing
277 * command. 471 * command.
278 */ 472 */
279 void testComplete(int exitCode) { 473 void testComplete(int exitCode) {
280 new TestOutput(testCase, exitCode, timedOut, stdout, 474 new TestOutput.fromCase(testCase, exitCode, timedOut, stdout,
281 stderr, new Date.now().difference(startTime)); 475 stderr, new Date.now().difference(startTime));
282 timeoutTimer.cancel(); 476 timeoutTimer.cancel();
283 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { 477 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
284 print(testCase.displayName); 478 print(testCase.displayName);
285 for (var line in testCase.output.stderr) print(line); 479 for (var line in testCase.output.stderr) print(line);
286 for (var line in testCase.output.stdout) print(line); 480 for (var line in testCase.output.stdout) print(line);
287 } 481 }
288 if (allowRetries != null && allowRetries 482 if (allowRetries != null && allowRetries
289 && testCase.configuration['component'] == 'webdriver' && 483 && testCase.configuration['component'] == 'webdriver' &&
290 testCase.output.unexpectedOutput && testCase.numRetries > 0) { 484 testCase.output.unexpectedOutput && testCase.numRetries > 0) {
291 // Selenium tests can be flaky. Try rerunning. 485 // Selenium tests can be flaky. Try rerunning.
292 testCase.output.requestRetry = true; 486 testCase.output.requestRetry = true;
293 } 487 }
294 if (testCase.output.requestRetry) { 488 if (testCase.output.requestRetry) {
295 testCase.output.requestRetry = false; 489 testCase.output.requestRetry = false;
296 this.timedOut = false; 490 this.timedOut = false;
297 testCase.dynamic.numRetries--; 491 testCase.dynamic.numRetries--;
298 print("Potential flake. " + 492 print("Potential flake. Re-running ${testCase.displayName} " +
299 "Re-running ${testCase.displayName} " +
300 "(${testCase.dynamic.numRetries} attempt(s) remains)"); 493 "(${testCase.dynamic.numRetries} attempt(s) remains)");
301 this.start(); 494 this.start();
302 } else { 495 } else {
303 testCase.completed(); 496 testCase.completed();
304 } 497 }
305 } 498 }
306 499
307 /** 500 /**
308 * Process exit handler called at the end of every command. It internally 501 * Process exit handler called at the end of every command. It internally
309 * treats all but the last command as compilation steps. The last command is 502 * treats all but the last command as compilation steps. The last command is
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 bool shutdownMillisecs = 30000; 640 bool shutdownMillisecs = 30000;
448 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); 641 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs);
449 } else { 642 } else {
450 _process.kill(); 643 _process.kill();
451 } 644 }
452 } 645 }
453 } 646 }
454 647
455 void doStartTest(TestCase testCase) { 648 void doStartTest(TestCase testCase) {
456 _startTime = new Date.now(); 649 _startTime = new Date.now();
457 _testStdout = new List<String>(); 650 _testStdout = [];
458 _testStderr = new List<String>(); 651 _testStderr = [];
459 _stdoutDrained = false; 652 _stdoutDrained = false;
460 _stderrDrained = false; 653 _stderrDrained = false;
461 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout); 654 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout);
462 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr); 655 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr);
463 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); 656 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000);
464 var line = _createArgumentsLine(testCase.batchTestArguments); 657 var line = _createArgumentsLine(testCase.batchTestArguments);
465 _process.stdin.write(line.charCodes()); 658 _process.stdin.write(line.charCodes());
466 } 659 }
467 660
468 String _createArgumentsLine(List<String> arguments) { 661 String _createArgumentsLine(List<String> arguments) {
469 return Strings.join(arguments, ' ') + '\n'; 662 return Strings.join(arguments, ' ') + '\n';
470 } 663 }
471 664
472 void _testCompleted() { 665 void _testCompleted() {
473 var test = _currentTest; 666 var test = _currentTest;
474 _currentTest = null; 667 _currentTest = null;
475 test.completed(); 668 test.completed();
476 } 669 }
477 670
478 int _reportResult(String output) { 671 int _reportResult(String output) {
479 _stdoutDrained = true; 672 _stdoutDrained = true;
480 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' 673 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
481 var outcome = output.split(" ")[2]; 674 var outcome = output.split(" ")[2];
482 var exitCode = 0; 675 var exitCode = 0;
483 if (outcome == "CRASH") exitCode = -10; 676 if (outcome == "CRASH") exitCode = -10;
484 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; 677 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
485 new TestOutput(_currentTest, exitCode, outcome == "TIMEOUT", _testStdout, 678 new TestOutput.fromCase(_currentTest, exitCode, outcome == "TIMEOUT",
486 _testStderr, new Date.now().difference(_startTime)); 679 _testStdout, _testStderr, new Date.now().difference(_startTim e));
487 // Move on when both stdout and stderr has been drained. 680 // Move on when both stdout and stderr has been drained.
488 if (_stderrDrained) _testCompleted(); 681 if (_stderrDrained) _testCompleted();
489 } 682 }
490 683
491 void _stderrDone() { 684 void _stderrDone() {
492 _stderrDrained = true; 685 _stderrDrained = true;
493 // Move on when both stdout and stderr has been drained. 686 // Move on when both stdout and stderr has been drained.
494 if (_stdoutDrained) _testCompleted(); 687 if (_stdoutDrained) _testCompleted();
495 } 688 }
496 689
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 // the developer doesn't waste his or her time trying to fix a bunch of 998 // the developer doesn't waste his or her time trying to fix a bunch of
806 // tests that appear to be broken but were actually just flakes that 999 // tests that appear to be broken but were actually just flakes that
807 // didn't get retried because there had already been one failure. 1000 // didn't get retried because there had already been one failure.
808 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 1001 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
809 new RunningProcess(test, allowRetry, this).start(); 1002 new RunningProcess(test, allowRetry, this).start();
810 } 1003 }
811 _numProcesses++; 1004 _numProcesses++;
812 } 1005 }
813 } 1006 }
814 } 1007 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698