Skip to content

Commit

Permalink
Make sure process starts with no output
Browse files Browse the repository at this point in the history
  • Loading branch information
ssigwart committed Dec 13, 2024
1 parent f2c09d0 commit bae8b9f
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 1 deletion.
14 changes: 14 additions & 0 deletions src/ProcessPool.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,20 @@ public function startProcess(): ProcessPoolRequest
$proc = array_pop($this->unassignedProcs);
$this->runningProcs[] = $proc;

// Make sure output is cleared
if ($proc->hasStderrData() || $proc->hasStdoutData())
{
$stderrLines = [];
$stdoutLines = [];
while ($proc->hasStderrData())
$stderrLines[] = $proc->getStderrResponse();
while ($proc->hasStdoutData())
$stdoutLines[] = $proc->getStdoutResponse();
$proc->markAsFailed();
$this->releaseProcess($proc);
throw new ProcessPoolProcessOutputBeforeStartingException($stderrLines, $stdoutLines);
}

return $proc;
}

Expand Down
45 changes: 45 additions & 0 deletions src/ProcessPoolProcessOutputBeforeStartingException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace ssigwart\ProcessPool;

/** Process pool exception that is thrown if a newly started process already has STDOUT or STDERR output */
class ProcessPoolProcessOutputBeforeStartingException extends ProcessPoolException
{
/** @var string[] STDERR lines */
private array $stderrLines = [];

/** @var string[] STDOUT lines */
private array $stdoutLines = [];

/**
* Constructor
*
* @param string[] $stderrLines STDERR lines
* @param string[] $stdoutLines STDOUT lines
*/
public function __construct(array $stderrLines, array $stdoutLines)
{
$this->stderrLines = $stderrLines;
$this->stdoutLines = $stdoutLines;
}

/**
* Get STDERR lines
*
* @return string[] STDERR lines
*/
public function getStderrLines(): array
{
return $this->stderrLines;
}

/**
* Get STDOUT lines
*
* @return string[] STDOUT lines
*/
public function getStdoutLines(): array
{
return $this->stdoutLines;
}
}
2 changes: 1 addition & 1 deletion tests/.phpunit.result.cache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":1,"defects":{"ProcessPoolTest::testProcessPool":3,"ProcessPoolTest::testProcessPoolErrors":3,"ProcessPoolTest::testProcessPoolWithLongMessage":4,"ProcessPoolTest::testInvalidResponse":3,"ProcessPoolTest::testProcessPoolNoRelease":3,"ProcessPoolTest::testProcessPoolWithLongResponse":4,"ProcessPoolTest::testProcessPoolEndOfFile":4,"ProcessPoolRequestTest::testProcessPoolEndOfFile":3,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":3,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":3,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":3,"ProcessPoolRequestTest::testProcessPoolHangOnExit":4,"ProcessPoolTest::testProcessPoolExit":3,"ProcessPoolTest::testProcessPoolSlientExit":4,"ProcessPoolTest::testProcessPoolSilentExit":3,"ProcessPoolTest::testProcessPoolExitHang":3,"ProcessPoolRequestTest::testPeek":3,"ProcessPoolRequestTest::testWaitForStdoutOrStderr":4,"ProcessPoolRequestTest::testWaitForStderr":3,"ProcessPoolRequestTest::testWaitForStdout":3,"ProcessPoolTest::testProcessPoolShutDown":3,"ProcessPoolTest::testProcessPoolNoReadBeforeRelease":3,"ProcessPoolTest::testProcessPoolMarkedAsFailed":3},"times":{"ProcessPoolTest::testInvalidResponse":0.007,"ProcessPoolTest::testInvalidMaxSpares":0.003,"ProcessPoolTest::testProcessPool":0.444,"ProcessPoolTest::testProcessPoolErrors":0.107,"ProcessPoolTest::testProcessPoolNoRelease":0.098,"ProcessPoolTest::testProcessPoolWithLongMessage":0.096,"ProcessPoolTest::testProcessPoolWithLongWriteMessage":0.122,"ProcessPoolTest::testProcessPoolWithLongResponse":0.097,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":0.15,"ProcessPoolTest::testProcessPoolEndOfFile":0.099,"ProcessPoolRequestTest::testProcessPoolEndOfFile":0.092,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":0.209,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":0.126,"ProcessPoolRequestTest::testProcessPoolHangOnExit":0.251,"ProcessPoolTest::testProcessPoolExit":0.097,"ProcessPoolTest::testProcessPoolSlientExit":0.101,"ProcessPoolTest::testProcessPoolSilentExit":0.099,"ProcessPoolTest::testProcessPoolExitHang":0.108,"ProcessPoolRequestTest::testPeek":0.113,"ProcessPoolRequestTest::testWaitForStdoutOrStderr":0.1,"ProcessPoolRequestTest::testWaitForStdout":0.113,"ProcessPoolRequestTest::testWaitForStderr":0.124,"ProcessPoolTest::testProcessPoolShutDown":0.131,"ProcessPoolTest::testProcessPoolNoReadBeforeRelease":0.101,"ProcessPoolTest::testProcessPoolNoReadBeforeRead":0.103,"ProcessPoolTest::testProcessPoolMarkedAsFailed":0.19}}
{"version":1,"defects":{"ProcessPoolRequestTest::testWaitForStdout":3,"ProcessPoolRequestTest::testWaitForStderr":3,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":3,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":3,"ProcessPoolTest::testProcessPool":3,"ProcessPoolTest::testProcessPoolErrors":3,"ProcessPoolTest::testProcessPoolMarkedAsFailed":3,"ProcessPoolTest::testProcessPoolErrorBeforeResponse":3,"ProcessPoolTest::testProcessPoolNoReadBeforeRead":3,"ProcessPoolTest::testProcessPoolWithLongMessage":3,"ProcessPoolTest::testProcessPoolWithLongResponse":3,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":3,"ProcessPoolTest::testProcessPoolExit":3,"ProcessPoolTest::testProcessPoolExitHang":3,"ProcessPoolTest::testProcessPoolShutDown":3},"times":{"ProcessPoolRequestTest::testWaitForStdout":0.109,"ProcessPoolRequestTest::testWaitForStderr":0.117,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":0.211,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":0.115,"ProcessPoolTest::testInvalidMaxSpares":0.002,"ProcessPoolTest::testProcessPool":0.454,"ProcessPoolTest::testProcessPoolErrors":0.111,"ProcessPoolTest::testProcessPoolMarkedAsFailed":0.197,"ProcessPoolTest::testProcessPoolErrorBeforeResponse":0.473,"ProcessPoolTest::testProcessPoolNoReadBeforeRead":0.101,"ProcessPoolTest::testProcessPoolWithLongMessage":0.093,"ProcessPoolTest::testProcessPoolWithLongResponse":0.092,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":0.092,"ProcessPoolTest::testProcessPoolExit":0.092,"ProcessPoolTest::testProcessPoolSilentExit":0.097,"ProcessPoolTest::testProcessPoolExitHang":0.094,"ProcessPoolTest::testProcessPoolShutDown":0.119}}
7 changes: 7 additions & 0 deletions tests/TestAuxFiles/PhpUnitTestProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ public function handleRequest(string $data)
// Check if we should output request count
else if ($data === 'req-count')
print $this->numRequests;
// Check if we should test error with late STDOUT
else if ($data === 'error-late-stdout')
{
fwrite(STDERR, 'Error, then sleep.');
usleep(20000);
print 'Done sleep';
}
else
{
// Output MD5 of data
Expand Down
45 changes: 45 additions & 0 deletions tests/TestCases/ProcessPoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use ssigwart\ProcessPool\ProcessPool;
use ssigwart\ProcessPool\ProcessPoolException;
use ssigwart\ProcessPool\ProcessPoolPoolExhaustedException;
use ssigwart\ProcessPool\ProcessPoolProcessOutputBeforeStartingException;

/**
* Process pool test
Expand Down Expand Up @@ -172,6 +173,50 @@ public function testProcessPoolMarkedAsFailed(): void
$pool->releaseProcess($req);
}

/**
* Test process pool error before response
*/
public function testProcessPoolErrorBeforeResponse(): void
{
$poolSize = 1;
$pool = new ProcessPool($poolSize, $poolSize, 'php processes/phpUnitProcesses.php', realpath(__DIR__ . DIRECTORY_SEPARATOR . '..'));

$req = $pool->startProcess();
$req->sendRequest('req-count');
self::assertEquals('1', $req->getStdoutResponse(), 'MD5 incorrect.');
$pool->releaseProcess($req);

$req = $pool->startProcess();
$req->sendRequest('req-count');
self::assertEquals('2', $req->getStdoutResponse(), 'MD5 incorrect.');
$pool->releaseProcess($req);

$req = $pool->startProcess();
$req->sendRequest('error-late-stdout');
usleep(5000);
self::assertEquals('Error, then sleep.', $req->getStderrResponse(), 'MD5 incorrect.');
self::assertEquals(false, $req->hasStdoutData(), 'No STDOUT expected.');
$pool->releaseProcess($req);
usleep(250000);

try {
$req = $pool->startProcess();
self::fail('Expected ProcessPoolProcessOutputBeforeStartingException.');
} catch (ProcessPoolProcessOutputBeforeStartingException $e) {
self::assertEquals([], $e->getStderrLines());
self::assertEquals(['Done sleep'], $e->getStdoutLines());
}
$req = $pool->startProcess();
$req->sendRequest('req-count');
self::assertEquals('1', $req->getStdoutResponse(), 'MD5 incorrect.');
$pool->releaseProcess($req);

$req = $pool->startProcess();
$req->sendRequest('req-count');
self::assertEquals('2', $req->getStdoutResponse(), 'MD5 incorrect.');
$pool->releaseProcess($req);
}

/**
* Test pool release before read
*/
Expand Down

0 comments on commit bae8b9f

Please sign in to comment.