diff --git a/CHANGELOG.md b/CHANGELOG.md index 286a560a..43c573f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Changed - The `logs/results.xml` could now be also accessed locally (the XSLT is now embedded right into the file, so we don't encounter same-origin policy problems). - Use tagged version 0.6.0 of [php-webdriver](https://github.com/facebook/php-webdriver). +- If any test fails, the `run-tests` command now exits with code `1`. This behavior could be altered using new `--no-exit` option, which forces the command to exit `0` even if some test fails. ### Fixed - Properly trigger PHPUnit colored (ANSI) mode when Steward itself is in ANSI mode. diff --git a/src/Console/Command/RunTestsCommand.php b/src/Console/Command/RunTestsCommand.php index 4c871a79..001ff952 100644 --- a/src/Console/Command/RunTestsCommand.php +++ b/src/Console/Command/RunTestsCommand.php @@ -47,6 +47,7 @@ class RunTestsCommand extends Command const OPTION_GROUP = 'group'; const OPTION_EXCLUDE_GROUP = 'exclude-group'; const OPTION_PUBLISH_RESULTS = 'publish-results'; + const OPTION_NO_EXIT = 'no-exit'; /** * @param SeleniumServerAdapter $seleniumAdapter @@ -132,6 +133,12 @@ protected function configure() null, InputOption::VALUE_NONE, 'Publish test results to test storage' + ) + ->addOption( + self::OPTION_NO_EXIT, + null, + InputOption::VALUE_NONE, + 'Always exit with code 0 (by default any failed test causes the command to return 1)' ); $this->getDispatcher()->dispatch(CommandEvents::CONFIGURE, new BasicConsoleEvent($this)); @@ -259,7 +266,13 @@ protected function execute(InputInterface $input, OutputInterface $output) $processSet->dequeueProcessesWithoutDelay($output->isDebug() ? $output : null); // Start execution loop - $this->executionLoop($output, $processSet); + $allTestsPassed = $this->executionLoop($output, $processSet); + + if ($input->getOption(self::OPTION_NO_EXIT)) { + return 0; + } else { + return $allTestsPassed ? 0 : 1; + } } /** @@ -299,11 +312,13 @@ protected function getProcessSetCreator(InputInterface $input, OutputInterface $ * * @param OutputInterface $output * @param ProcessSet $processSet + * @return bool Return true if all test returned exit code 0 (or if none test was run) */ protected function executionLoop(OutputInterface $output, ProcessSet $processSet) { $counterWaitingOutput = 1; $counterProcessesLast = 0; + $allTestsPassed = true; // Iterate over prepared and queued until everything is done while (true) { $prepared = $processSet->get(ProcessSet::PROCESS_STATUS_PREPARED); @@ -344,6 +359,9 @@ protected function executionLoop(OutputInterface $output, ProcessSet $processSet // Mark no longer running processes as finished if (!$processObject->process->isRunning()) { + if ($processObject->process->getExitCode()) { // non-zero exit code (= failed/exception) + $allTestsPassed = false; + } $output->writeln(sprintf('Process for class "%s" finished', $testClass)); $processSet->setStatus($testClass, ProcessSet::PROCESS_STATUS_DONE); $processObject->finishedTime = time(); @@ -389,6 +407,8 @@ protected function executionLoop(OutputInterface $output, ProcessSet $processSet $counterProcessesLast = $counterProcesses; sleep(1); } + + return $allTestsPassed; } /**