| 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 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 void runCommand(String executable, | 335 void runCommand(String executable, |
| 336 List<String> arguments, | 336 List<String> arguments, |
| 337 void exitHandler(int exitCode)) { | 337 void exitHandler(int exitCode)) { |
| 338 if (new Platform().operatingSystem() == 'windows') { | 338 if (new Platform().operatingSystem() == 'windows') { |
| 339 // Windows can't handle the first command if it is a .bat file or the like | 339 // Windows can't handle the first command if it is a .bat file or the like |
| 340 // with the slashes going the other direction. | 340 // with the slashes going the other direction. |
| 341 // TODO(efortuna): Remove this when fixed (Issue 1306). | 341 // TODO(efortuna): Remove this when fixed (Issue 1306). |
| 342 executable = executable.replaceAll('/', '\\'); | 342 executable = executable.replaceAll('/', '\\'); |
| 343 } | 343 } |
| 344 process = new Process.start(executable, arguments); | 344 process = new Process.start(executable, arguments); |
| 345 process.exitHandler = exitHandler; | 345 process.onExit = exitHandler; |
| 346 startTime = new Date.now(); | 346 startTime = new Date.now(); |
| 347 InputStream stdoutStream = process.stdout; | 347 InputStream stdoutStream = process.stdout; |
| 348 InputStream stderrStream = process.stderr; | 348 InputStream stderrStream = process.stderr; |
| 349 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream); | 349 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream); |
| 350 StringInputStream stderrStringStream = new StringInputStream(stderrStream); | 350 StringInputStream stderrStringStream = new StringInputStream(stderrStream); |
| 351 stdoutStringStream.lineHandler = | 351 stdoutStringStream.onLine = |
| 352 makeReadHandler(stdoutStringStream, stdout); | 352 makeReadHandler(stdoutStringStream, stdout); |
| 353 stderrStringStream.lineHandler = | 353 stderrStringStream.onLine = |
| 354 makeReadHandler(stderrStringStream, stderr); | 354 makeReadHandler(stderrStringStream, stderr); |
| 355 timeoutTimer = new Timer(timeoutHandler, 1000 * testCase.timeout); | 355 timeoutTimer = new Timer(timeoutHandler, 1000 * testCase.timeout); |
| 356 } | 356 } |
| 357 | 357 |
| 358 void timeoutHandler(Timer unusedTimer) { | 358 void timeoutHandler(Timer unusedTimer) { |
| 359 timedOut = true; | 359 timedOut = true; |
| 360 process.kill(); | 360 process.kill(); |
| 361 } | 361 } |
| 362 } | 362 } |
| 363 | 363 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 391 // Start process if not yet started. | 391 // Start process if not yet started. |
| 392 _executable = testCase.executablePath; | 392 _executable = testCase.executablePath; |
| 393 _startProcess(() { | 393 _startProcess(() { |
| 394 doStartTest(testCase); | 394 doStartTest(testCase); |
| 395 }); | 395 }); |
| 396 } else if (testCase.executablePath != _executable) { | 396 } else if (testCase.executablePath != _executable) { |
| 397 // Restart this runner with the right executable for this test | 397 // Restart this runner with the right executable for this test |
| 398 // if needed. | 398 // if needed. |
| 399 _executable = testCase.executablePath; | 399 _executable = testCase.executablePath; |
| 400 _batchArguments = testCase.batchRunnerArguments; | 400 _batchArguments = testCase.batchRunnerArguments; |
| 401 _process.exitHandler = (exitCode) { | 401 _process.onExit = (exitCode) { |
| 402 _process.close(); | 402 _process.close(); |
| 403 _startProcess(() { | 403 _startProcess(() { |
| 404 doStartTest(testCase); | 404 doStartTest(testCase); |
| 405 }); | 405 }); |
| 406 }; | 406 }; |
| 407 _process.kill(); | 407 _process.kill(); |
| 408 } else { | 408 } else { |
| 409 doStartTest(testCase); | 409 doStartTest(testCase); |
| 410 } | 410 } |
| 411 } | 411 } |
| 412 | 412 |
| 413 void terminate() { | 413 void terminate() { |
| 414 if (_process !== null) { | 414 if (_process !== null) { |
| 415 bool closed = false; | 415 bool closed = false; |
| 416 _process.exitHandler = (exitCode) { | 416 _process.onExit = (exitCode) { |
| 417 closed = true; | 417 closed = true; |
| 418 _process.close(); | 418 _process.close(); |
| 419 }; | 419 }; |
| 420 if (_isWebDriver) { | 420 if (_isWebDriver) { |
| 421 // Use a graceful shutdown so our Selenium script can close | 421 // Use a graceful shutdown so our Selenium script can close |
| 422 // the open browser processes. TODO(jmesserly): Send a signal once | 422 // the open browser processes. TODO(jmesserly): Send a signal once |
| 423 // that's supported, see dartbug.com/1756. | 423 // that's supported, see dartbug.com/1756. |
| 424 _process.stdin.write('--terminate\n'.charCodes()); | 424 _process.stdin.write('--terminate\n'.charCodes()); |
| 425 | 425 |
| 426 // In case the run_selenium process didn't close, kill it after 30s | 426 // In case the run_selenium process didn't close, kill it after 30s |
| 427 bool shutdownMillisecs = 30000; | 427 bool shutdownMillisecs = 30000; |
| 428 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); | 428 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); |
| 429 } else { | 429 } else { |
| 430 _process.kill(); | 430 _process.kill(); |
| 431 } | 431 } |
| 432 } | 432 } |
| 433 } | 433 } |
| 434 | 434 |
| 435 void doStartTest(TestCase testCase) { | 435 void doStartTest(TestCase testCase) { |
| 436 _startTime = new Date.now(); | 436 _startTime = new Date.now(); |
| 437 _testStdout = new List<String>(); | 437 _testStdout = new List<String>(); |
| 438 _testStderr = new List<String>(); | 438 _testStderr = new List<String>(); |
| 439 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); | 439 _stdoutStream.onLine = _readOutput(_stdoutStream, _testStdout); |
| 440 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); | 440 _stderrStream.onLine = _readOutput(_stderrStream, _testStderr); |
| 441 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); | 441 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); |
| 442 var line = _createArgumentsLine(testCase.batchTestArguments); | 442 var line = _createArgumentsLine(testCase.batchTestArguments); |
| 443 _process.stdin.write(line.charCodes()); | 443 _process.stdin.write(line.charCodes()); |
| 444 } | 444 } |
| 445 | 445 |
| 446 String _createArgumentsLine(List<String> arguments) { | 446 String _createArgumentsLine(List<String> arguments) { |
| 447 return Strings.join(arguments, ' ') + '\n'; | 447 return Strings.join(arguments, ' ') + '\n'; |
| 448 } | 448 } |
| 449 | 449 |
| 450 int _reportResult(String output) { | 450 int _reportResult(String output) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 | 490 |
| 491 void _exitHandler(exitCode) { | 491 void _exitHandler(exitCode) { |
| 492 if (_timer != null) _timer.cancel(); | 492 if (_timer != null) _timer.cancel(); |
| 493 _process.close(); | 493 _process.close(); |
| 494 _startProcess(() { | 494 _startProcess(() { |
| 495 _reportResult(">>> TEST CRASH"); | 495 _reportResult(">>> TEST CRASH"); |
| 496 }); | 496 }); |
| 497 } | 497 } |
| 498 | 498 |
| 499 void _timeoutHandler(ignore) { | 499 void _timeoutHandler(ignore) { |
| 500 _process.exitHandler = (exitCode) { | 500 _process.onExit = (exitCode) { |
| 501 _process.close(); | 501 _process.close(); |
| 502 _startProcess(() { | 502 _startProcess(() { |
| 503 _reportResult(">>> TEST TIMEOUT"); | 503 _reportResult(">>> TEST TIMEOUT"); |
| 504 }); | 504 }); |
| 505 }; | 505 }; |
| 506 _process.kill(); | 506 _process.kill(); |
| 507 } | 507 } |
| 508 | 508 |
| 509 void _startProcess(then) { | 509 void _startProcess(then) { |
| 510 _process = new Process.start(_executable, _batchArguments); | 510 _process = new Process.start(_executable, _batchArguments); |
| 511 _stdoutStream = new StringInputStream(_process.stdout); | 511 _stdoutStream = new StringInputStream(_process.stdout); |
| 512 _stderrStream = new StringInputStream(_process.stderr); | 512 _stderrStream = new StringInputStream(_process.stderr); |
| 513 _testStdout = new List<String>(); | 513 _testStdout = new List<String>(); |
| 514 _testStderr = new List<String>(); | 514 _testStderr = new List<String>(); |
| 515 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); | 515 _stdoutStream.onLine = _readOutput(_stdoutStream, _testStdout); |
| 516 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); | 516 _stderrStream.onLine = _readOutput(_stderrStream, _testStderr); |
| 517 _process.exitHandler = _exitHandler; | 517 _process.onExit = _exitHandler; |
| 518 _process.startHandler = then; | 518 _process.onStart = then; |
| 519 } | 519 } |
| 520 } | 520 } |
| 521 | 521 |
| 522 /** | 522 /** |
| 523 * ProcessQueue is the master control class, responsible for running all | 523 * ProcessQueue is the master control class, responsible for running all |
| 524 * the tests in all the TestSuites that have been registered. It includes | 524 * the tests in all the TestSuites that have been registered. It includes |
| 525 * a rate-limited queue to run a limited number of tests in parallel, | 525 * a rate-limited queue to run a limited number of tests in parallel, |
| 526 * a ProgressIndicator which prints output when tests are started and | 526 * a ProgressIndicator which prints output when tests are started and |
| 527 * and completed, and a summary report when all tests are completed, | 527 * and completed, and a summary report when all tests are completed, |
| 528 * and counters to determine when all of the tests in all of the test suites | 528 * 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... |
| 621 Process process = null; | 621 Process process = null; |
| 622 if (new Platform().operatingSystem() == 'windows') { | 622 if (new Platform().operatingSystem() == 'windows') { |
| 623 process = new Process.start( | 623 process = new Process.start( |
| 624 'C:\\Windows\\System32\\taskkill.exe', ['/F', '/IM', name + '.exe', | 624 'C:\\Windows\\System32\\taskkill.exe', ['/F', '/IM', name + '.exe', |
| 625 '/T']); | 625 '/T']); |
| 626 } else { | 626 } else { |
| 627 process = new Process.start('killall', ['-9', name]); | 627 process = new Process.start('killall', ['-9', name]); |
| 628 } | 628 } |
| 629 | 629 |
| 630 if (name == processNames[browserUsed].last()) { | 630 if (name == processNames[browserUsed].last()) { |
| 631 process.exitHandler = (exitCode) { | 631 process.onExit = (exitCode) { |
| 632 process.close(); | 632 process.close(); |
| 633 _progress.allDone(); | 633 _progress.allDone(); |
| 634 }; | 634 }; |
| 635 process.errorHandler = (error) { | 635 process.onError = (error) { |
| 636 _progress.allDone(); | 636 _progress.allDone(); |
| 637 }; | 637 }; |
| 638 } else { | 638 } else { |
| 639 process.exitHandler = (exitCode) { | 639 process.onExit = (exitCode) { |
| 640 process.close(); | 640 process.close(); |
| 641 }; | 641 }; |
| 642 } | 642 } |
| 643 } | 643 } |
| 644 } | 644 } |
| 645 | 645 |
| 646 /** | 646 /** |
| 647 * Perform any cleanup needed once all tests in a TestSuite have completed | 647 * Perform any cleanup needed once all tests in a TestSuite have completed |
| 648 * and notify our progress indicator that we are done. | 648 * and notify our progress indicator that we are done. |
| 649 */ | 649 */ |
| (...skipping 17 matching lines...) Expand all Loading... |
| 667 } else if (!_temporaryDirectory.startsWith('/tmp/') || | 667 } else if (!_temporaryDirectory.startsWith('/tmp/') || |
| 668 _temporaryDirectory.contains('/../')) { | 668 _temporaryDirectory.contains('/../')) { |
| 669 // Let's be extra careful, since rm -rf is so dangerous. | 669 // Let's be extra careful, since rm -rf is so dangerous. |
| 670 print('Temporary directory $_temporaryDirectory unsafe to delete!'); | 670 print('Temporary directory $_temporaryDirectory unsafe to delete!'); |
| 671 _cleanupAndMarkDone(); | 671 _cleanupAndMarkDone(); |
| 672 } else { | 672 } else { |
| 673 // TODO(dart:1211): Use delete(recursive=true) in Dart when it is | 673 // TODO(dart:1211): Use delete(recursive=true) in Dart when it is |
| 674 // implemented, and add Windows support. | 674 // implemented, and add Windows support. |
| 675 var deletion = | 675 var deletion = |
| 676 new Process.start('/bin/rm', ['-rf', _temporaryDirectory]); | 676 new Process.start('/bin/rm', ['-rf', _temporaryDirectory]); |
| 677 deletion.exitHandler = (int exitCode) { | 677 deletion.onExit = (int exitCode) { |
| 678 if (exitCode == 0) { | 678 if (exitCode == 0) { |
| 679 if (!_listTests) { // Output of --list option is used by scripts. | 679 if (!_listTests) { // Output of --list option is used by scripts. |
| 680 print('\nTemporary directory $_temporaryDirectory deleted.'); | 680 print('\nTemporary directory $_temporaryDirectory deleted.'); |
| 681 } | 681 } |
| 682 } else { | 682 } else { |
| 683 print('\nDeletion of temp dir $_temporaryDirectory failed.'); | 683 print('\nDeletion of temp dir $_temporaryDirectory failed.'); |
| 684 } | 684 } |
| 685 _cleanupAndMarkDone(); | 685 _cleanupAndMarkDone(); |
| 686 }; | 686 }; |
| 687 } | 687 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 // the developer doesn't waste his or her time trying to fix a bunch of | 757 // the developer doesn't waste his or her time trying to fix a bunch of |
| 758 // tests that appear to be broken but were actually just flakes that | 758 // tests that appear to be broken but were actually just flakes that |
| 759 // didn't get retried because there had already been one failure. | 759 // didn't get retried because there had already been one failure. |
| 760 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 760 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; |
| 761 new RunningProcess(test, allowRetry, this).start(); | 761 new RunningProcess(test, allowRetry, this).start(); |
| 762 } | 762 } |
| 763 _numProcesses++; | 763 _numProcesses++; |
| 764 } | 764 } |
| 765 } | 765 } |
| 766 } | 766 } |
| OLD | NEW |