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

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

Issue 9538009: test.dart sometimes associates the wrong stderr with a task. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: : Adds a method to drain stderr 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
« no previous file with comments | « no previous file | 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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 } 159 }
160 160
161 161
162 /** 162 /**
163 * TestOutput records the output of a completed test: the process's exit code, 163 * 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 164 * 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 165 * the time the process took to run. It also contains a pointer to the
166 * [TestCase] this is the output of. 166 * [TestCase] this is the output of.
167 */ 167 */
168 class TestOutput { 168 class TestOutput {
169 TestCase testCase; 169 final TestCase testCase;
170 int exitCode; 170 final int exitCode;
171 bool timedOut; 171 final bool timedOut;
172 final List<String> stdout;
173 final List<String> stderr;
174 final Duration time;
172 bool failed = false; 175 bool failed = false;
173 List<String> stdout;
174 List<String> stderr;
175 Duration time;
176 /** 176 /**
177 * Set to true if we encounter a condition in the output that indicates we 177 * Set to true if we encounter a condition in the output that indicates we
178 * need to rerun this test. 178 * need to rerun this test.
179 */ 179 */
180 bool requestRetry; 180 bool requestRetry = false;
181 181
182 TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout, 182 TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout,
183 this.stderr, this.time) { 183 this.stderr, this.time) {
184 testCase.output = this; 184 testCase.output = this;
185 requestRetry = false;
186 } 185 }
187 186
188 String get result() => 187 String get result() =>
189 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); 188 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS));
190 189
191 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result); 190 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result);
192 191
193 bool get hasCrashed() { 192 bool get hasCrashed() {
194 if (new Platform().operatingSystem() == 'windows') { 193 if (new Platform().operatingSystem() == 'windows') {
195 // The VM uses std::abort to terminate on asserts. 194 // The VM uses std::abort to terminate on asserts.
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 List<Function> handlers; 264 List<Function> handlers;
266 bool allowRetries = false; 265 bool allowRetries = false;
267 266
268 /** Which command of [testCase.commands] is currently being executed. */ 267 /** Which command of [testCase.commands] is currently being executed. */
269 int currentStep; 268 int currentStep;
270 269
271 RunningProcess(TestCase this.testCase, 270 RunningProcess(TestCase this.testCase,
272 [this.allowRetries, this.processQueue]); 271 [this.allowRetries, this.processQueue]);
273 272
274 /** 273 /**
275 * Called when all commands are executed. [exitCode] is 0 if all command 274 * Called when all commands are executed. [exitCode] is 0 if all commands
276 * succeded, otherwise it will have the exit code of the first failing 275 * succeded, otherwise it will have the exit code of the first failing
277 * command. 276 * command.
278 */ 277 */
279 void testComplete(int exitCode) { 278 void testComplete(int exitCode) {
280 new TestOutput(testCase, exitCode, timedOut, stdout, 279 new TestOutput(testCase, exitCode, timedOut, stdout,
281 stderr, new Date.now().difference(startTime)); 280 stderr, new Date.now().difference(startTime));
282 timeoutTimer.cancel(); 281 timeoutTimer.cancel();
283 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { 282 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
284 print(testCase.displayName); 283 print(testCase.displayName);
285 for (var line in testCase.output.stderr) print(line); 284 for (var line in testCase.output.stderr) print(line);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 var line = source.readLine(); 337 var line = source.readLine();
339 while (null != line) { 338 while (null != line) {
340 destination.add(line); 339 destination.add(line);
341 line = source.readLine(); 340 line = source.readLine();
342 } 341 }
343 }; 342 };
344 } 343 }
345 344
346 void start() { 345 void start() {
347 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); 346 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP));
348 stdout = new List<String>(); 347 stdout = [];
349 stderr = new List<String>(); 348 stderr = [];
350 currentStep = 0; 349 currentStep = 0;
351 runCommand(testCase.commands[currentStep++], stepExitHandler); 350 runCommand(testCase.commands[currentStep++], stepExitHandler);
352 } 351 }
353 352
354 void runCommand(Command command, 353 void runCommand(Command command,
355 void exitHandler(int exitCode)) { 354 void exitHandler(int exitCode)) {
356 if (new Platform().operatingSystem() == 'windows') { 355 if (new Platform().operatingSystem() == 'windows') {
357 // Windows can't handle the first command if it is a .bat file or the like 356 // Windows can't handle the first command if it is a .bat file or the like
358 // with the slashes going the other direction. 357 // with the slashes going the other direction.
359 // TODO(efortuna): Remove this when fixed (Issue 1306). 358 // TODO(efortuna): Remove this when fixed (Issue 1306).
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 bool shutdownMillisecs = 30000; 444 bool shutdownMillisecs = 30000;
446 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); 445 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs);
447 } else { 446 } else {
448 _process.kill(); 447 _process.kill();
449 } 448 }
450 } 449 }
451 } 450 }
452 451
453 void doStartTest(TestCase testCase) { 452 void doStartTest(TestCase testCase) {
454 _startTime = new Date.now(); 453 _startTime = new Date.now();
455 _testStdout = new List<String>(); 454 _testStdout = [];
456 _testStderr = new List<String>(); 455 _testStderr = [];
457 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); 456 _stdoutStream.lineHandler = _readStdout(_stdoutStream, _testStdout);
458 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); 457 _stderrStream.lineHandler = _readStderr(_stderrStream, _testStderr);
459 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); 458 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000);
460 var line = _createArgumentsLine(testCase.batchTestArguments); 459 var line = _createArgumentsLine(testCase.batchTestArguments);
461 _process.stdin.write(line.charCodes()); 460 _process.stdin.write(line.charCodes());
462 } 461 }
463 462
464 String _createArgumentsLine(List<String> arguments) { 463 String _createArgumentsLine(List<String> arguments) {
465 return Strings.join(arguments, ' ') + '\n'; 464 return Strings.join(arguments, ' ') + '\n';
466 } 465 }
467 466
467 // This removes the line handler from stderr and reads all
468 // remaining bytes from it.
469 // TODO(zundel): This is pretty bad - streams need flush()
Emily Fortuna 2012/02/29 19:59:03 Add issue id # (1407) in comment (also possibly le
zundel 2012/02/29 20:19:08 Done.
470 _drainStderr() {
471 _stderrStream.lineHandler = null;
472 while(true) {
473 var available = 0;
474 try {
475 available = _process.stderr.available();
476 } catch (SocketIOException ex) {
477 break;
478 }
479 if (available <= 0) break;
480 String result = _stderrStream.readLine();
481 if (result == null) {
482 // This is intended to catch the last line, but might foul up
483 // if more bytes immediately come available after read() and before
484 // the test for available()
485 result = _stderrStream.read();
Emily Fortuna 2012/02/29 19:59:03 Perhaps I'm misunderstanding the API, but would th
zundel 2012/02/29 20:19:08 (see next comment).
486 if (result == null) {
487 var buf = new List<int>(available);
488 _process.stderr.readInto(buf, 0, available);;
Siggi Cherem (dart-lang) 2012/02/29 19:13:32 extra ;
Emily Fortuna 2012/02/29 19:59:03 _stderrStream was instantiated from new StringInpu
zundel 2012/02/29 20:19:08 I didn't know about 1407 and filed this bug to try
489 result = new String.fromCharCodes(buf);
490 _testStderr.add(result);
491 break;
492 }
493 }
494 _testStderr.add(result);
495 }
496 }
497
468 int _reportResult(String output) { 498 int _reportResult(String output) {
499 _drainStderr();
469 var test = _currentTest; 500 var test = _currentTest;
470 _currentTest = null; 501 _currentTest = null;
471 502
472 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' 503 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
473 var outcome = output.split(" ")[2]; 504 var outcome = output.split(" ")[2];
474 var exitCode = 0; 505 var exitCode = 0;
475 if (outcome == "CRASH") exitCode = -10; 506 if (outcome == "CRASH") exitCode = -10;
476 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; 507 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
477 new TestOutput(test, exitCode, outcome == "TIMEOUT", _testStdout, 508 new TestOutput(test, exitCode, outcome == "TIMEOUT", _testStdout,
478 _testStderr, new Date.now().difference(_startTime)); 509 _testStderr, new Date.now().difference(_startTime));
479 test.completed(); 510 test.completed();
480 } 511 }
481 512
482 Function _readOutput(StringInputStream stream, List<String> buffer) { 513 Function _readStdout(StringInputStream stream, List<String> buffer) {
483 return () { 514 return () {
484 var status; 515 var status;
485 var line = stream.readLine(); 516 var line = stream.readLine();
486 // Drain the input stream to get the error output. 517 // Drain the input stream to get the error output.
487 while (line != null) { 518 while (line != null) {
488 if (line.startsWith('>>> TEST')) { 519 if (line.startsWith('>>> TEST')) {
489 status = line; 520 status = line;
490 } else if (line.startsWith('>>> BATCH START')) { 521 } else if (line.startsWith('>>> BATCH START')) {
491 // ignore 522 // ignore
492 } else if (line.startsWith('>>> ')) { 523 } else if (line.startsWith('>>> ')) {
493 throw new Exception('Unexpected command from dartc batch runner.'); 524 throw new Exception('Unexpected command from dartc batch runner.');
494 } else { 525 } else {
495 buffer.add(line); 526 buffer.add(line);
496 } 527 }
497 line = stream.readLine(); 528 line = stream.readLine();
498 } 529 }
499 if (status != null) { 530 if (status != null) {
500 _timer.cancel(); 531 _timer.cancel();
501 // For crashing processes, let the exit handler deal with it. 532 // For crashing processes, let the exit handler deal with it.
502 if (!status.contains("CRASH")) { 533 if (!status.contains("CRASH")) {
503 _reportResult(status); 534 _reportResult(status);
504 } 535 }
505 } 536 }
506 }; 537 };
507 } 538 }
539
540 Function _readStderr(StringInputStream stream, List<String> buffer) {
541 return () {
Emily Fortuna 2012/02/29 19:59:03 Check out makeReadHandler on line 334. whesse als
zundel 2012/02/29 20:19:08 I just got rid of _readStdout() and replaced it wi
542 var line;
543 while ((line = stream.readLine()) != null) {
544 buffer.add(line);
545 }
546 };
547 }
508 548
509 void _exitHandler(exitCode) { 549 void _exitHandler(exitCode) {
510 if (_timer != null) _timer.cancel(); 550 if (_timer != null) _timer.cancel();
551 _reportResult(">>> TEST CRASH");
511 _process.close(); 552 _process.close();
512 _startProcess(() { 553 _startProcess();
513 _reportResult(">>> TEST CRASH");
514 });
515 } 554 }
516 555
517 void _timeoutHandler(ignore) { 556 void _timeoutHandler(ignore) {
518 _process.exitHandler = (exitCode) { 557 _process.exitHandler = (exitCode) {_
558 reportResult(">>> TEST TIMEOUT");
519 _process.close(); 559 _process.close();
520 _startProcess(() { 560 _startProcess();
521 _reportResult(">>> TEST TIMEOUT");
522 });
523 }; 561 };
524 _process.kill(); 562 _process.kill();
525 } 563 }
526 564
527 void _startProcess(then) { 565 void _startProcess([Function then = null]) {
528 _process = new Process.start(_executable, _batchArguments); 566 _process = new Process.start(_executable, _batchArguments);
529 _stdoutStream = new StringInputStream(_process.stdout); 567 _stdoutStream = new StringInputStream(_process.stdout);
530 _stderrStream = new StringInputStream(_process.stderr); 568 _stderrStream = new StringInputStream(_process.stderr);
531 _testStdout = new List<String>(); 569 _testStdout = [];
532 _testStderr = new List<String>(); 570 _testStderr = [];
533 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); 571 _stdoutStream.lineHandler = _readStdout(_stdoutStream, _testStdout);
534 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); 572 _stderrStream.lineHandler = _readStderr(_stderrStream, _testStderr);
535 _process.exitHandler = _exitHandler; 573 _process.exitHandler = _exitHandler;
536 _process.startHandler = then; 574 _process.startHandler = then;
537 } 575 }
538 } 576 }
539 577
540 /** 578 /**
541 * ProcessQueue is the master control class, responsible for running all 579 * ProcessQueue is the master control class, responsible for running all
542 * the tests in all the TestSuites that have been registered. It includes 580 * the tests in all the TestSuites that have been registered. It includes
543 * a rate-limited queue to run a limited number of tests in parallel, 581 * a rate-limited queue to run a limited number of tests in parallel,
544 * a ProgressIndicator which prints output when tests are started and 582 * a ProgressIndicator which prints output when tests are started and
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
775 // the developer doesn't waste his or her time trying to fix a bunch of 813 // the developer doesn't waste his or her time trying to fix a bunch of
776 // tests that appear to be broken but were actually just flakes that 814 // tests that appear to be broken but were actually just flakes that
777 // didn't get retried because there had already been one failure. 815 // didn't get retried because there had already been one failure.
778 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 816 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
779 new RunningProcess(test, allowRetry, this).start(); 817 new RunningProcess(test, allowRetry, this).start();
780 } 818 }
781 _numProcesses++; 819 _numProcesses++;
782 } 820 }
783 } 821 }
784 } 822 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698