| 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 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 | 353 |
| 354 void runCommand(Command command, | 354 void runCommand(Command command, |
| 355 void exitHandler(int exitCode)) { | 355 void exitHandler(int exitCode)) { |
| 356 if (new Platform().operatingSystem() == 'windows') { | 356 if (new Platform().operatingSystem() == 'windows') { |
| 357 // Windows can't handle the first command if it is a .bat file or the like | 357 // Windows can't handle the first command if it is a .bat file or the like |
| 358 // with the slashes going the other direction. | 358 // with the slashes going the other direction. |
| 359 // TODO(efortuna): Remove this when fixed (Issue 1306). | 359 // TODO(efortuna): Remove this when fixed (Issue 1306). |
| 360 command.executable = command.executable.replaceAll('/', '\\'); | 360 command.executable = command.executable.replaceAll('/', '\\'); |
| 361 } | 361 } |
| 362 process = new Process.start(command.executable, command.arguments); | 362 process = new Process.start(command.executable, command.arguments); |
| 363 process.exitHandler = exitHandler; | 363 process.onExit = exitHandler; |
| 364 startTime = new Date.now(); | 364 startTime = new Date.now(); |
| 365 InputStream stdoutStream = process.stdout; | 365 InputStream stdoutStream = process.stdout; |
| 366 InputStream stderrStream = process.stderr; | 366 InputStream stderrStream = process.stderr; |
| 367 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream); | 367 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream); |
| 368 StringInputStream stderrStringStream = new StringInputStream(stderrStream); | 368 StringInputStream stderrStringStream = new StringInputStream(stderrStream); |
| 369 stdoutStringStream.lineHandler = | 369 stdoutStringStream.onLine = |
| 370 makeReadHandler(stdoutStringStream, stdout); | 370 makeReadHandler(stdoutStringStream, stdout); |
| 371 stderrStringStream.lineHandler = | 371 stderrStringStream.onLine = |
| 372 makeReadHandler(stderrStringStream, stderr); | 372 makeReadHandler(stderrStringStream, stderr); |
| 373 timeoutTimer = new Timer(timeoutHandler, 1000 * testCase.timeout); | 373 timeoutTimer = new Timer(timeoutHandler, 1000 * testCase.timeout); |
| 374 } | 374 } |
| 375 | 375 |
| 376 void timeoutHandler(Timer unusedTimer) { | 376 void timeoutHandler(Timer unusedTimer) { |
| 377 timedOut = true; | 377 timedOut = true; |
| 378 process.kill(); | 378 process.kill(); |
| 379 } | 379 } |
| 380 } | 380 } |
| 381 | 381 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 409 // Start process if not yet started. | 409 // Start process if not yet started. |
| 410 _executable = testCase.commands.last().executable; | 410 _executable = testCase.commands.last().executable; |
| 411 _startProcess(() { | 411 _startProcess(() { |
| 412 doStartTest(testCase); | 412 doStartTest(testCase); |
| 413 }); | 413 }); |
| 414 } else if (testCase.commands.last().executable != _executable) { | 414 } else if (testCase.commands.last().executable != _executable) { |
| 415 // Restart this runner with the right executable for this test | 415 // Restart this runner with the right executable for this test |
| 416 // if needed. | 416 // if needed. |
| 417 _executable = testCase.commands.last().executable; | 417 _executable = testCase.commands.last().executable; |
| 418 _batchArguments = testCase.batchRunnerArguments; | 418 _batchArguments = testCase.batchRunnerArguments; |
| 419 _process.exitHandler = (exitCode) { | 419 _process.onExit = (exitCode) { |
| 420 _process.close(); | 420 _process.close(); |
| 421 _startProcess(() { | 421 _startProcess(() { |
| 422 doStartTest(testCase); | 422 doStartTest(testCase); |
| 423 }); | 423 }); |
| 424 }; | 424 }; |
| 425 _process.kill(); | 425 _process.kill(); |
| 426 } else { | 426 } else { |
| 427 doStartTest(testCase); | 427 doStartTest(testCase); |
| 428 } | 428 } |
| 429 } | 429 } |
| 430 | 430 |
| 431 void terminate() { | 431 void terminate() { |
| 432 if (_process !== null) { | 432 if (_process !== null) { |
| 433 bool closed = false; | 433 bool closed = false; |
| 434 _process.exitHandler = (exitCode) { | 434 _process.onExit = (exitCode) { |
| 435 closed = true; | 435 closed = true; |
| 436 _process.close(); | 436 _process.close(); |
| 437 }; | 437 }; |
| 438 if (_isWebDriver) { | 438 if (_isWebDriver) { |
| 439 // Use a graceful shutdown so our Selenium script can close | 439 // Use a graceful shutdown so our Selenium script can close |
| 440 // the open browser processes. TODO(jmesserly): Send a signal once | 440 // the open browser processes. TODO(jmesserly): Send a signal once |
| 441 // that's supported, see dartbug.com/1756. | 441 // that's supported, see dartbug.com/1756. |
| 442 _process.stdin.write('--terminate\n'.charCodes()); | 442 _process.stdin.write('--terminate\n'.charCodes()); |
| 443 | 443 |
| 444 // In case the run_selenium process didn't close, kill it after 30s | 444 // In case the run_selenium process didn't close, kill it after 30s |
| 445 bool shutdownMillisecs = 30000; | 445 bool shutdownMillisecs = 30000; |
| 446 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); | 446 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); |
| 447 } else { | 447 } else { |
| 448 _process.kill(); | 448 _process.kill(); |
| 449 } | 449 } |
| 450 } | 450 } |
| 451 } | 451 } |
| 452 | 452 |
| 453 void doStartTest(TestCase testCase) { | 453 void doStartTest(TestCase testCase) { |
| 454 _startTime = new Date.now(); | 454 _startTime = new Date.now(); |
| 455 _testStdout = new List<String>(); | 455 _testStdout = new List<String>(); |
| 456 _testStderr = new List<String>(); | 456 _testStderr = new List<String>(); |
| 457 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); | 457 _stdoutStream.onLine = _readOutput(_stdoutStream, _testStdout); |
| 458 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); | 458 _stderrStream.onLine = _readOutput(_stderrStream, _testStderr); |
| 459 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); | 459 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); |
| 460 var line = _createArgumentsLine(testCase.batchTestArguments); | 460 var line = _createArgumentsLine(testCase.batchTestArguments); |
| 461 _process.stdin.write(line.charCodes()); | 461 _process.stdin.write(line.charCodes()); |
| 462 } | 462 } |
| 463 | 463 |
| 464 String _createArgumentsLine(List<String> arguments) { | 464 String _createArgumentsLine(List<String> arguments) { |
| 465 return Strings.join(arguments, ' ') + '\n'; | 465 return Strings.join(arguments, ' ') + '\n'; |
| 466 } | 466 } |
| 467 | 467 |
| 468 int _reportResult(String output) { | 468 int _reportResult(String output) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 | 508 |
| 509 void _exitHandler(exitCode) { | 509 void _exitHandler(exitCode) { |
| 510 if (_timer != null) _timer.cancel(); | 510 if (_timer != null) _timer.cancel(); |
| 511 _process.close(); | 511 _process.close(); |
| 512 _startProcess(() { | 512 _startProcess(() { |
| 513 _reportResult(">>> TEST CRASH"); | 513 _reportResult(">>> TEST CRASH"); |
| 514 }); | 514 }); |
| 515 } | 515 } |
| 516 | 516 |
| 517 void _timeoutHandler(ignore) { | 517 void _timeoutHandler(ignore) { |
| 518 _process.exitHandler = (exitCode) { | 518 _process.onExit = (exitCode) { |
| 519 _process.close(); | 519 _process.close(); |
| 520 _startProcess(() { | 520 _startProcess(() { |
| 521 _reportResult(">>> TEST TIMEOUT"); | 521 _reportResult(">>> TEST TIMEOUT"); |
| 522 }); | 522 }); |
| 523 }; | 523 }; |
| 524 _process.kill(); | 524 _process.kill(); |
| 525 } | 525 } |
| 526 | 526 |
| 527 void _startProcess(then) { | 527 void _startProcess(then) { |
| 528 _process = new Process.start(_executable, _batchArguments); | 528 _process = new Process.start(_executable, _batchArguments); |
| 529 _stdoutStream = new StringInputStream(_process.stdout); | 529 _stdoutStream = new StringInputStream(_process.stdout); |
| 530 _stderrStream = new StringInputStream(_process.stderr); | 530 _stderrStream = new StringInputStream(_process.stderr); |
| 531 _testStdout = new List<String>(); | 531 _testStdout = new List<String>(); |
| 532 _testStderr = new List<String>(); | 532 _testStderr = new List<String>(); |
| 533 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); | 533 _stdoutStream.onLine = _readOutput(_stdoutStream, _testStdout); |
| 534 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); | 534 _stderrStream.onLine = _readOutput(_stderrStream, _testStderr); |
| 535 _process.exitHandler = _exitHandler; | 535 _process.onExit = _exitHandler; |
| 536 _process.startHandler = then; | 536 _process.onStart = then; |
| 537 } | 537 } |
| 538 } | 538 } |
| 539 | 539 |
| 540 /** | 540 /** |
| 541 * ProcessQueue is the master control class, responsible for running all | 541 * ProcessQueue is the master control class, responsible for running all |
| 542 * the tests in all the TestSuites that have been registered. It includes | 542 * 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, | 543 * a rate-limited queue to run a limited number of tests in parallel, |
| 544 * a ProgressIndicator which prints output when tests are started and | 544 * a ProgressIndicator which prints output when tests are started and |
| 545 * and completed, and a summary report when all tests are completed, | 545 * and completed, and a summary report when all tests are completed, |
| 546 * and counters to determine when all of the tests in all of the test suites | 546 * and counters to determine when all of the tests in all of the test suites |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 Process process = null; | 639 Process process = null; |
| 640 if (new Platform().operatingSystem() == 'windows') { | 640 if (new Platform().operatingSystem() == 'windows') { |
| 641 process = new Process.start( | 641 process = new Process.start( |
| 642 'C:\\Windows\\System32\\taskkill.exe', ['/F', '/IM', name + '.exe', | 642 'C:\\Windows\\System32\\taskkill.exe', ['/F', '/IM', name + '.exe', |
| 643 '/T']); | 643 '/T']); |
| 644 } else { | 644 } else { |
| 645 process = new Process.start('killall', ['-9', name]); | 645 process = new Process.start('killall', ['-9', name]); |
| 646 } | 646 } |
| 647 | 647 |
| 648 if (name == processNames[browserUsed].last()) { | 648 if (name == processNames[browserUsed].last()) { |
| 649 process.exitHandler = (exitCode) { | 649 process.onExit = (exitCode) { |
| 650 process.close(); | 650 process.close(); |
| 651 _progress.allDone(); | 651 _progress.allDone(); |
| 652 }; | 652 }; |
| 653 process.errorHandler = (error) { | 653 process.onError = (error) { |
| 654 _progress.allDone(); | 654 _progress.allDone(); |
| 655 }; | 655 }; |
| 656 } else { | 656 } else { |
| 657 process.exitHandler = (exitCode) { | 657 process.onExit = (exitCode) { |
| 658 process.close(); | 658 process.close(); |
| 659 }; | 659 }; |
| 660 } | 660 } |
| 661 } | 661 } |
| 662 } | 662 } |
| 663 | 663 |
| 664 /** | 664 /** |
| 665 * Perform any cleanup needed once all tests in a TestSuite have completed | 665 * Perform any cleanup needed once all tests in a TestSuite have completed |
| 666 * and notify our progress indicator that we are done. | 666 * and notify our progress indicator that we are done. |
| 667 */ | 667 */ |
| (...skipping 17 matching lines...) Expand all Loading... |
| 685 } else if (!_temporaryDirectory.startsWith('/tmp/') || | 685 } else if (!_temporaryDirectory.startsWith('/tmp/') || |
| 686 _temporaryDirectory.contains('/../')) { | 686 _temporaryDirectory.contains('/../')) { |
| 687 // Let's be extra careful, since rm -rf is so dangerous. | 687 // Let's be extra careful, since rm -rf is so dangerous. |
| 688 print('Temporary directory $_temporaryDirectory unsafe to delete!'); | 688 print('Temporary directory $_temporaryDirectory unsafe to delete!'); |
| 689 _cleanupAndMarkDone(); | 689 _cleanupAndMarkDone(); |
| 690 } else { | 690 } else { |
| 691 // TODO(dart:1211): Use delete(recursive=true) in Dart when it is | 691 // TODO(dart:1211): Use delete(recursive=true) in Dart when it is |
| 692 // implemented, and add Windows support. | 692 // implemented, and add Windows support. |
| 693 var deletion = | 693 var deletion = |
| 694 new Process.start('/bin/rm', ['-rf', _temporaryDirectory]); | 694 new Process.start('/bin/rm', ['-rf', _temporaryDirectory]); |
| 695 deletion.exitHandler = (int exitCode) { | 695 deletion.onExit = (int exitCode) { |
| 696 if (exitCode == 0) { | 696 if (exitCode == 0) { |
| 697 if (!_listTests) { // Output of --list option is used by scripts. | 697 if (!_listTests) { // Output of --list option is used by scripts. |
| 698 print('\nTemporary directory $_temporaryDirectory deleted.'); | 698 print('\nTemporary directory $_temporaryDirectory deleted.'); |
| 699 } | 699 } |
| 700 } else { | 700 } else { |
| 701 print('\nDeletion of temp dir $_temporaryDirectory failed.'); | 701 print('\nDeletion of temp dir $_temporaryDirectory failed.'); |
| 702 } | 702 } |
| 703 _cleanupAndMarkDone(); | 703 _cleanupAndMarkDone(); |
| 704 }; | 704 }; |
| 705 } | 705 } |
| (...skipping 69 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 | 775 // 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 | 776 // tests that appear to be broken but were actually just flakes that |
| 777 // didn't get retried because there had already been one failure. | 777 // didn't get retried because there had already been one failure. |
| 778 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 778 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; |
| 779 new RunningProcess(test, allowRetry, this).start(); | 779 new RunningProcess(test, allowRetry, this).start(); |
| 780 } | 780 } |
| 781 _numProcesses++; | 781 _numProcesses++; |
| 782 } | 782 } |
| 783 } | 783 } |
| 784 } | 784 } |
| OLD | NEW |