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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |