Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Process.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function __construct($cmd, $cwd = null, array $env = null, array $options
}
}

$this->options = $options;
$this->options = array_merge(['bypass_shell' => true], $options);
$this->enhanceSigchildCompatibility = $this->isSigchildEnabled();
}

Expand Down
92 changes: 84 additions & 8 deletions tests/AbstractProcessTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,29 @@ public function testGetTermSignalWhenRunning($process)

public function testProcessWithDefaultCwdAndEnv()
{
$cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL, count($_SERVER), PHP_EOL;');
$cmd = $this->getPhpCommandLine('echo getcwd(), PHP_EOL, count($_SERVER), PHP_EOL;');

$loop = $this->createLoop();
$process = new Process($cmd);

$output = '';
$error = '';

$loop->addTimer(0.001, function(Timer $timer) use ($process, &$output) {
$loop->addTimer(0.001, function(Timer $timer) use ($process, &$output, &$error) {
$process->start($timer->getLoop());
$process->stdout->on('data', function () use (&$output) {
$output .= func_get_arg(0);
$process->stdout->on('data', function ($data) use (&$output) {
$output .= $data;
});
$process->stderr->on('data', function ($data) use (&$error) {
$error .= $data;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@moufmouf: Why was the stderr check only added to this test case? Was there a case where it failed on Windows and you caught some output here?

});
});

$loop->run();

$this->assertEmpty($error);
$this->assertNotEmpty($output);

list($cwd, $envCount) = explode(PHP_EOL, $output);

/* Child process should inherit the same current working directory and
Expand All @@ -96,10 +103,11 @@ public function testProcessWithDefaultCwdAndEnv()

public function testProcessWithCwd()
{
$cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL;');
$cmd = $this->getPhpCommandLine('echo getcwd(), PHP_EOL;');
$cwd = defined('PHP_WINDOWS_VERSION_BUILD') ? 'C:\\' : '/';

$loop = $this->createLoop();
$process = new Process($cmd, '/');
$process = new Process($cmd, $cwd);

$output = '';

Expand All @@ -112,7 +120,7 @@ public function testProcessWithCwd()

$loop->run();

$this->assertSame('/' . PHP_EOL, $output);
$this->assertSame($cwd . PHP_EOL, $output);
}

public function testProcessWithEnv()
Expand All @@ -121,7 +129,13 @@ public function testProcessWithEnv()
$this->markTestSkipped('Cannot execute PHP processes with custom environments on Travis CI.');
}

$cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getenv("foo"), PHP_EOL;');
$cmd = $this->getPhpCommandLine('echo getenv("foo"), PHP_EOL;');

if (defined('PHP_WINDOWS_VERSION_BUILD')) {
// Windows madness! escapeshellarg seems to completely remove double quotes in Windows!
// We need to use simple quotes in our PHP code!
$cmd = $this->getPhpCommandLine('echo getenv(\'foo\'), PHP_EOL;');
}

$loop = $this->createLoop();
$process = new Process($cmd, null, array('foo' => 'bar'));
Expand Down Expand Up @@ -173,6 +187,10 @@ public function testStartAndAllowProcessToExitSuccessfullyUsingEventLoop()

public function testStartInvalidProcess()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('Windows does not have an executable flag.');
}

$cmd = tempnam(sys_get_temp_dir(), 'react');

$loop = $this->createLoop();
Expand Down Expand Up @@ -298,6 +316,49 @@ public function testTerminateWithStopAndContinueSignalsUsingEventLoop()
$this->assertFalse($process->isTerminated());
}

/**
* @dataProvider provideOutputSizeAndExpectedMaxDuration
*/
public function testProcessWithFixedOutputSize($size, $expectedMaxDuration = 5)
{
// Note: very strange behaviour of Windows (PHP 5.5.6):
// on a 1000 long string, Windows succeeds.
// on a 10000 long string, Windows fails to output anything.
// On a 100000 long string, it takes a lot of time but succeeds.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@moufmouf: Per your explanation in #10 and the above comments, this test fails on Windows. Does the workaround you're proposing in #11 fix this?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmikola: Yes, this test fails on Windows... In PHP > 5.6.3, it fails. In PHP < 5.6.3, it locks and the test never halts, which is even worst. #11 fixes this test case.

$cmd = $this->getPhpCommandLine(sprintf('echo str_repeat("o", %d), PHP_EOL;', $size));

$loop = $this->createLoop();
$process = new Process($cmd);

$output = '';

$loop->addTimer(0.001, function(Timer $timer) use ($process, &$output) {
$process->start($timer->getLoop());
$process->stdout->on('data', function () use (&$output) {
$output .= func_get_arg(0);
});
});

$startTime = microtime(true);
$loop->run();
$endTime = microtime(true);

$expectedOutput = str_repeat('o', $size) . PHP_EOL;

$this->assertEquals(strlen($expectedOutput), strlen($output));
$this->assertSame($expectedOutput, $output);
$this->assertLessThanOrEqual($expectedMaxDuration, $endTime - $startTime, "Process took longer than expected.");
}

public function provideOutputSizeAndExpectedMaxDuration()
{
return [
[1000, 5],
[10000, 5],
[100000, 5],
];
}

/**
* Execute a callback at regular intervals until it returns successfully or
* a timeout is reached.
Expand Down Expand Up @@ -333,4 +394,19 @@ private function getPhpBinary()

return $runtime->getBinary();
}

private function getPhpCommandLine($phpCode)
{
/* The following is a suitable workaround for Windows given some
* escapeshellarg() incompatibilies in older PHP versions and knowledge
* that we're only escaping echo statements destined for "php -r".
*
* See: http://php.net/manual/en/function.escapeshellarg.php#114873
*/
$phpCode = defined('PHP_WINDOWS_VERSION_BUILD')
? '"' . addcslashes($phpCode, '\\"') . '"'
: escapeshellarg($phpCode);

return $this->getPhpBinary() . ' -r ' . $phpCode;
}
}