Skip to content

Commit

Permalink
Changed trigger message for wrapperWorker
Browse files Browse the repository at this point in the history
Added saving log output for tests
  • Loading branch information
infurio committed Jan 21, 2019
1 parent 87aa787 commit 47cc12a
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 153 deletions.
2 changes: 1 addition & 1 deletion bin/phpunit-wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ while (true) {
$_SERVER['argv'] = $arguments[1];

$lastExitCode = PHPUnit\TextUI\Command::main(false);
echo "FINISHED\n";
echo "FiNiShEd\n";
}
93 changes: 51 additions & 42 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,46 +1,55 @@
{
"name": "brianium/paratest",
"require": {
"php": ">=7.1",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-simplexml": "*",
"brianium/habitat": "1.0.0",
"composer/semver": "~1.2",
"phpunit/php-timer": "^2.0",
"phpunit/phpunit": "^7.0",
"symfony/console": "^3.4|^4.0",
"symfony/process": "^3.4|^4.0",
"phpunit/php-code-coverage": "^6.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.3.2"
},
"type": "library",
"description": "Parallel testing for PHP",
"keywords": ["testing","PHPUnit", "concurrent", "parallel"],
"homepage": "https://github.com/paratestphp/paratest",
"license": "MIT",
"authors": [
{
"name": "Brian Scaturro",
"email": "[email protected]",
"homepage": "http://brianscaturro.com",
"role": "Lead"
}
],
"bin": ["bin/paratest"],
"autoload": {
"psr-4": {
"ParaTest\\": ["src/"]
}
"name": "brianium/paratest",
"require": {
"php": ">=7.1",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-simplexml": "*",
"brianium/habitat": "1.0.0",
"composer/semver": "~1.2",
"phpunit/php-timer": "^1.0.4",
"phpunit/phpunit": "^6.3",
"symfony/console": "~2.3|~3.0",
"symfony/process": "~2.3|~3.0",
"phpunit/php-code-coverage": "5.3.2"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.3.2"
},
"type": "library",
"description": "Parallel testing for PHP",
"keywords": [
"testing",
"PHPUnit",
"concurrent",
"parallel"
],
"homepage": "https://github.com/paratestphp/paratest",
"license": "MIT",
"authors": [
{
"name": "Brian Scaturro",
"email": "[email protected]",
"homepage": "http://brianscaturro.com",
"role": "Lead"
}
],
"bin": [
"bin/paratest"
],
"autoload": {
"psr-4": {
"ParaTest\\": [
"src/"
]
}
},
"autoload-dev": {
"psr-0": {
"": "test/functional"
},
"autoload-dev": {
"psr-0": {
"": "test/functional"
},
"psr-4": {
"ParaTest\\": "test/unit/"
}
"psr-4": {
"ParaTest\\": "test/unit/"
}
}
}
251 changes: 142 additions & 109 deletions src/Runners/PHPUnit/Worker/BaseWorker.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,139 +8,172 @@

abstract class BaseWorker
{
protected static $descriptorspec = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
protected $proc;
protected $pipes;
protected $inExecution = 0;
private $exitCode = null;
private $chunks = '';
private $alreadyReadOutput = '';

public function start(string $wrapperBinary, $token = 1, $uniqueToken = null, array $parameters = [])
protected static $descriptorspec = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
protected $proc;
protected $pipes;
protected $inExecution = 0;
private $exitCode = null;
private $chunks = '';
private $alreadyReadOutput = '';
private $alreadyReadError = '';
protected $fileHandle;

public function start(string $wrapperBinary, $token = 1, $uniqueToken = null, array $parameters = [])
{
$this->fileHandle = fopen("paratestlog-{$token}.txt", "wr") or die("Unable to open file: paratestlog-{$token}.txt");
$bin = 'PARATEST=1 ';
if(is_numeric($token))
{
$bin = 'PARATEST=1 ';
if (is_numeric($token)) {
$bin .= "TEST_TOKEN=$token ";
}
if ($uniqueToken) {
$bin .= "UNIQUE_TEST_TOKEN=$uniqueToken ";
}
$finder = new PhpExecutableFinder();
$bin .= $finder->find() . " \"$wrapperBinary\"";
if ($parameters) {
$bin .= ' ' . implode(' ', array_map('escapeshellarg', $parameters));
}
$pipes = [];
$process = proc_open($bin, self::$descriptorspec, $pipes);
$this->proc = is_resource($process) ? $process : null;
$this->pipes = $pipes;
$bin .= "TEST_TOKEN=$token ";
}

public function isFree(): bool
if($uniqueToken)
{
$this->checkNotCrashed();
$this->updateStateFromAvailableOutput();

return $this->inExecution === 0;
$bin .= "UNIQUE_TEST_TOKEN=$uniqueToken ";
}

public function isRunning(): bool
$finder = new PhpExecutableFinder();
$bin .= $finder->find() . " \"$wrapperBinary\"";
if($parameters)
{
if ($this->proc === null) {
return false;
}

$status = proc_get_status($this->proc);

return $status ? $status['running'] : false;
$bin .= ' ' . implode(' ', array_map('escapeshellarg', $parameters));
}

public function isStarted(): bool
$pipes = [];
$process = proc_open($bin, self::$descriptorspec, $pipes);
$this->proc = is_resource($process) ? $process : null;
$this->pipes = $pipes;
}

public function isFree(): bool
{
$this->checkNotCrashed();
$this->updateStateFromAvailableOutput();

return $this->inExecution === 0;
}

public function isRunning(): bool
{
if($this->proc === null)
{
return $this->proc !== null && $this->pipes !== null;
return false;
}

public function isCrashed(): bool
{
if (!$this->isStarted()) {
return false;
}
$status = proc_get_status($this->proc);
$status = proc_get_status($this->proc);

$this->updateStateFromAvailableOutput();
return $status ? $status['running'] : false;
}

$this->setExitCode($status);
if ($this->exitCode === null) {
return false;
}
public function isStarted(): bool
{
return $this->proc !== null && $this->pipes !== null;
}

return $this->exitCode !== 0;
public function isCrashed(): bool
{
if(!$this->isStarted())
{
return false;
}
$status = proc_get_status($this->proc);

$this->updateStateFromAvailableOutput();

public function checkNotCrashed()
$this->setExitCode($status);
if($this->exitCode === null)
{
if ($this->isCrashed()) {
$lastCommand = isset($this->commands) ? ' Last executed command: ' . end($this->commands) : '';
throw new \RuntimeException(
'This worker has crashed.' . $lastCommand . PHP_EOL
. 'Output:' . PHP_EOL
. '----------------------' . PHP_EOL
. $this->alreadyReadOutput . PHP_EOL
. '----------------------' . PHP_EOL
. $this->readAllStderr()
);
}
return false;
}

public function stop()
return $this->exitCode !== 0;
}

public function checkNotCrashed()
{
if($this->isCrashed())
{
fclose($this->pipes[0]);
$lastCommand = isset($this->commands) ? ' Last executed command: ' . end($this->commands) : '';
throw new \RuntimeException(
'This worker has crashed.' . $lastCommand . PHP_EOL
. 'Output:' . PHP_EOL
. '----------------------' . PHP_EOL
. $this->alreadyReadOutput . PHP_EOL
. '----------------------' . PHP_EOL
. $this->readAllStderr()
);
}
}

public function stop()
{
fclose($this->pipes[0]);
}

protected function setExitCode(array $status)
protected function setExitCode(array $status)
{
if(!$status['running'])
{
if (!$status['running']) {
if ($this->exitCode === null) {
$this->exitCode = $status['exitcode'];
}
}
if($this->exitCode === null)
{
$this->exitCode = $status['exitcode'];
}
}

private function readAllStderr()
}

private function readAllStderr()
{
return $this->alreadyReadError;
}

/**
* Have to read even incomplete lines to play nice with stream_select()
* Otherwise it would continue to non-block because there are bytes to be read,
* but fgets() won't pick them up.
*/
private function updateStateFromAvailableOutput()
{
if(isset($this->pipes[1]))
{
return stream_get_contents($this->pipes[2]);
stream_set_blocking($this->pipes[1], false);
while($chunk = fread($this->pipes[1], 4096))
{
$this->chunks .= $chunk;
$this->alreadyReadOutput .= $chunk;
if($this->fileHandle)
{
fwrite($this->fileHandle, $chunk);
}
}
$lines = explode("\n", $this->chunks);
// last element is not a complete line,
// becomes part of a line completed later
$this->chunks = $lines[count($lines) - 1];
unset($lines[count($lines) - 1]);
// delivering complete lines to this Worker
foreach($lines as $line)
{
$line .= "\n";
if(strstr($line, "FiNiShEd\n"))
{
--$this->inExecution;
}
}
stream_set_blocking($this->pipes[1], true);
}

/**
* Have to read even incomplete lines to play nice with stream_select()
* Otherwise it would continue to non-block because there are bytes to be read,
* but fgets() won't pick them up.
*/
private function updateStateFromAvailableOutput()
if(isset($this->pipes[2]))
{
if (isset($this->pipes[1])) {
stream_set_blocking($this->pipes[1], false);
while ($chunk = fread($this->pipes[1], 4096)) {
$this->chunks .= $chunk;
$this->alreadyReadOutput .= $chunk;
}
$lines = explode("\n", $this->chunks);
// last element is not a complete line,
// becomes part of a line completed later
$this->chunks = $lines[count($lines) - 1];
unset($lines[count($lines) - 1]);
// delivering complete lines to this Worker
foreach ($lines as $line) {
$line .= "\n";
if (strstr($line, "FINISHED\n")) {
--$this->inExecution;
}
}
stream_set_blocking($this->pipes[1], true);
stream_set_blocking($this->pipes[2], false);
while($chunk = fread($this->pipes[2], 4096))
{
$this->alreadyReadError .= $chunk;
if($this->fileHandle)
{
fwrite($this->fileHandle, $chunk);
}
}
stream_set_blocking($this->pipes[2], true);
}
}
}
}
2 changes: 1 addition & 1 deletion src/Runners/PHPUnit/Worker/WrapperWorker.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function waitForFinishedJob()
$tellsUsItHasFinished = false;
stream_set_blocking($this->pipes[1], true);
while ($line = fgets($this->pipes[1])) {
if (strstr($line, "FINISHED\n")) {
if (strstr($line, "FiNiShEd\n")) {
$tellsUsItHasFinished = true;
--$this->inExecution;
break;
Expand Down

0 comments on commit 47cc12a

Please sign in to comment.