From 45319086b9b2a6968915cc5fadfb39eaca6715d5 Mon Sep 17 00:00:00 2001 From: David Negrier Date: Sat, 28 Feb 2015 10:33:50 +0100 Subject: [PATCH 1/5] Working on tests compatibility with Windows OS --- composer.json | 3 +- tests/AbstractProcessTest.php | 95 ++++++++++++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 881a178..e614736 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,8 @@ "php": ">=5.4.0", "evenement/evenement": "~2.0", "react/event-loop": "0.4.*", - "react/stream": "0.4.*" + "react/stream": "0.4.*", + "phpunit/phpunit": "~4.0" }, "require-dev": { "sebastian/environment": "~1.0" diff --git a/tests/AbstractProcessTest.php b/tests/AbstractProcessTest.php index c11c63a..35f2b57 100644 --- a/tests/AbstractProcessTest.php +++ b/tests/AbstractProcessTest.php @@ -69,21 +69,34 @@ public function testGetTermSignalWhenRunning($process) public function testProcessWithDefaultCwdAndEnv() { $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL, count($_SERVER), PHP_EOL;'); - + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + // Windows madness! for some obscure reason, the whole command lines needs to be + // wrapped in quotes (?!?) + $cmd = '"'.$cmd.'"'; + } + $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; }); }); $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 @@ -98,8 +111,18 @@ public function testProcessWithCwd() { $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL;'); + $testCwd = '/'; + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + // Windows madness! for some obscure reason, the whole command lines needs to be + // wrapped in quotes (?!?) + $cmd = '"'.$cmd.'"'; + + $testCwd = 'C:\\'; + } + $loop = $this->createLoop(); - $process = new Process($cmd, '/'); + $process = new Process($cmd, $testCwd); $output = ''; @@ -112,7 +135,7 @@ public function testProcessWithCwd() $loop->run(); - $this->assertSame('/' . PHP_EOL, $output); + $this->assertSame($testCwd . PHP_EOL, $output); } public function testProcessWithEnv() @@ -123,6 +146,15 @@ public function testProcessWithEnv() $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('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->getPhpBinary() . ' -r ' . escapeshellarg('echo getenv(\'foo\'), PHP_EOL;'); + // Windows madness! for some obscure reason, the whole command lines needs to be + // wrapped in quotes (?!?) + $cmd = '"'.$cmd.'"'; + } + $loop = $this->createLoop(); $process = new Process($cmd, null, array('foo' => 'bar')); @@ -173,6 +205,10 @@ public function testStartAndAllowProcessToExitSuccessfullyUsingEventLoop() public function testStartInvalidProcess() { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not have an executable flag. This test does not make sense on Windows.'); + } + $cmd = tempnam(sys_get_temp_dir(), 'react'); $loop = $this->createLoop(); @@ -297,6 +333,51 @@ public function testTerminateWithStopAndContinueSignalsUsingEventLoop() $this->assertNull($process->getTermSignal()); $this->assertFalse($process->isTerminated()); } + + public function testProcessSmallOutput() { + $this->processOutputOfSize(1000); + } + + public function testProcessMediumOutput() { + $this->processOutputOfSize(10000); + } + + public function testProcessBigOutput() { + $this->processOutputOfSize(100000); + } + + public function processOutputOfSize($size) + { + // 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. + $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo str_repeat(\'o\', '.$size.'), PHP_EOL;'); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + // Windows madness! for some obscure reason, the whole command lines needs to be + // wrapped in quotes (?!?) + $cmd = '"'.$cmd.'"'; + } + + $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); + }); + }); + + $loop->run(); + + $this->assertEquals($size + strlen(PHP_EOL), strlen($output)); + $this->assertSame(str_repeat('o', $size) . PHP_EOL, $output); + } + /** * Execute a callback at regular intervals until it returns successfully or From f1604678ebf3fdeb4c17151050887fcf7228c913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Sat, 28 Feb 2015 10:41:48 +0100 Subject: [PATCH 2/5] Adding timer on process to track locks --- tests/AbstractProcessTest.php | 49 +++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/tests/AbstractProcessTest.php b/tests/AbstractProcessTest.php index 35f2b57..a85cda3 100644 --- a/tests/AbstractProcessTest.php +++ b/tests/AbstractProcessTest.php @@ -69,13 +69,13 @@ public function testGetTermSignalWhenRunning($process) public function testProcessWithDefaultCwdAndEnv() { $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL, count($_SERVER), PHP_EOL;'); - + if (defined('PHP_WINDOWS_VERSION_BUILD')) { // Windows madness! for some obscure reason, the whole command lines needs to be // wrapped in quotes (?!?) $cmd = '"'.$cmd.'"'; } - + $loop = $this->createLoop(); $process = new Process($cmd); @@ -93,10 +93,10 @@ public function testProcessWithDefaultCwdAndEnv() }); $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 @@ -112,15 +112,15 @@ public function testProcessWithCwd() $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL;'); $testCwd = '/'; - + if (defined('PHP_WINDOWS_VERSION_BUILD')) { // Windows madness! for some obscure reason, the whole command lines needs to be // wrapped in quotes (?!?) $cmd = '"'.$cmd.'"'; - + $testCwd = 'C:\\'; } - + $loop = $this->createLoop(); $process = new Process($cmd, $testCwd); @@ -154,7 +154,7 @@ public function testProcessWithEnv() // wrapped in quotes (?!?) $cmd = '"'.$cmd.'"'; } - + $loop = $this->createLoop(); $process = new Process($cmd, null, array('foo' => 'bar')); @@ -206,9 +206,9 @@ public function testStartAndAllowProcessToExitSuccessfullyUsingEventLoop() public function testStartInvalidProcess() { if (defined('PHP_WINDOWS_VERSION_BUILD')) { - $this->markTestSkipped('Windows does not have an executable flag. This test does not make sense on Windows.'); + $this->markTestSkipped('Windows does not have an executable flag. This test does not make sense on Windows.'); } - + $cmd = tempnam(sys_get_temp_dir(), 'react'); $loop = $this->createLoop(); @@ -333,51 +333,56 @@ public function testTerminateWithStopAndContinueSignalsUsingEventLoop() $this->assertNull($process->getTermSignal()); $this->assertFalse($process->isTerminated()); } - + public function testProcessSmallOutput() { $this->processOutputOfSize(1000); } - + public function testProcessMediumOutput() { $this->processOutputOfSize(10000); } - + public function testProcessBigOutput() { $this->processOutputOfSize(100000); } - - public function processOutputOfSize($size) + + public function processOutputOfSize($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. $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo str_repeat(\'o\', '.$size.'), PHP_EOL;'); - + if (defined('PHP_WINDOWS_VERSION_BUILD')) { // Windows madness! for some obscure reason, the whole command lines needs to be // wrapped in quotes (?!?) $cmd = '"'.$cmd.'"'; } - + $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 = time(); + $loop->run(); - + + $endTime = time(); + + $this->assertLessThanOrEqual($expectedMaxDuration, $endTime - $startTime, "Process took longer than expected."); $this->assertEquals($size + strlen(PHP_EOL), strlen($output)); $this->assertSame(str_repeat('o', $size) . PHP_EOL, $output); } - + /** * Execute a callback at regular intervals until it returns successfully or From 6b841d4e8f6024e4d5486d4fb905aad2d61e7aa3 Mon Sep 17 00:00:00 2001 From: David Negrier Date: Sat, 28 Feb 2015 10:57:30 +0100 Subject: [PATCH 3/5] Cleaning unit tests code --- tests/AbstractProcessTest.php | 39 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/tests/AbstractProcessTest.php b/tests/AbstractProcessTest.php index a85cda3..685d513 100644 --- a/tests/AbstractProcessTest.php +++ b/tests/AbstractProcessTest.php @@ -68,13 +68,7 @@ public function testGetTermSignalWhenRunning($process) public function testProcessWithDefaultCwdAndEnv() { - $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL, count($_SERVER), PHP_EOL;'); - - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - // Windows madness! for some obscure reason, the whole command lines needs to be - // wrapped in quotes (?!?) - $cmd = '"'.$cmd.'"'; - } + $cmd = $this->getPhpCommandLine('echo getcwd(), PHP_EOL, count($_SERVER), PHP_EOL;'); $loop = $this->createLoop(); $process = new Process($cmd); @@ -109,16 +103,12 @@ public function testProcessWithDefaultCwdAndEnv() public function testProcessWithCwd() { - $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg('echo getcwd(), PHP_EOL;'); - - $testCwd = '/'; + $cmd = $this->getPhpCommandLine('echo getcwd(), PHP_EOL;'); if (defined('PHP_WINDOWS_VERSION_BUILD')) { - // Windows madness! for some obscure reason, the whole command lines needs to be - // wrapped in quotes (?!?) - $cmd = '"'.$cmd.'"'; - $testCwd = 'C:\\'; + } else { + $testCwd = '/'; } $loop = $this->createLoop(); @@ -144,15 +134,12 @@ 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->getPhpBinary() . ' -r ' . escapeshellarg('echo getenv(\'foo\'), PHP_EOL;'); - // Windows madness! for some obscure reason, the whole command lines needs to be - // wrapped in quotes (?!?) - $cmd = '"'.$cmd.'"'; + $cmd = $this->getPhpCommandLine('echo getenv(\'foo\'), PHP_EOL;'); } $loop = $this->createLoop(); @@ -378,9 +365,9 @@ public function processOutputOfSize($size, $expectedMaxDuration = 5) $endTime = time(); - $this->assertLessThanOrEqual($expectedMaxDuration, $endTime - $startTime, "Process took longer than expected."); $this->assertEquals($size + strlen(PHP_EOL), strlen($output)); $this->assertSame(str_repeat('o', $size) . PHP_EOL, $output); + $this->assertLessThanOrEqual($expectedMaxDuration, $endTime - $startTime, "Process took longer than expected."); } @@ -419,4 +406,16 @@ private function getPhpBinary() return $runtime->getBinary(); } + + private function getPhpCommandLine($phpCode) + { + $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg($phpCode); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + // Windows madness! for some obscure reason, the whole command lines needs to be + // wrapped in quotes (?!?) + $cmd = '"'.$cmd.'"'; + } + return $cmd; + } } From fd658f22a4fd0f5e582e805eaa5c8e4c78375307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Wed, 4 Mar 2015 22:24:55 +0100 Subject: [PATCH 4/5] Taking into account @jmikola comments --- composer.json | 3 +-- tests/AbstractProcessTest.php | 35 +++++++++++++++-------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index e614736..881a178 100644 --- a/composer.json +++ b/composer.json @@ -7,8 +7,7 @@ "php": ">=5.4.0", "evenement/evenement": "~2.0", "react/event-loop": "0.4.*", - "react/stream": "0.4.*", - "phpunit/phpunit": "~4.0" + "react/stream": "0.4.*" }, "require-dev": { "sebastian/environment": "~1.0" diff --git a/tests/AbstractProcessTest.php b/tests/AbstractProcessTest.php index 685d513..3c5b07e 100644 --- a/tests/AbstractProcessTest.php +++ b/tests/AbstractProcessTest.php @@ -321,19 +321,14 @@ public function testTerminateWithStopAndContinueSignalsUsingEventLoop() $this->assertFalse($process->isTerminated()); } - public function testProcessSmallOutput() { - $this->processOutputOfSize(1000); + public function outputSizeProvider() { + return [ [1000, 5], [10000, 5], [100000, 5] ]; } - public function testProcessMediumOutput() { - $this->processOutputOfSize(10000); - } - - public function testProcessBigOutput() { - $this->processOutputOfSize(100000); - } - - public function processOutputOfSize($size, $expectedMaxDuration = 5) + /** + * @dataProvider outputSizeProvider + */ + public function testProcessOutputOfSize($size, $expectedMaxDuration = 5) { // Note: very strange behaviour of Windows (PHP 5.5.6): // on a 1000 long string, Windows succeeds. @@ -406,16 +401,16 @@ private function getPhpBinary() return $runtime->getBinary(); } - + private function getPhpCommandLine($phpCode) { - $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg($phpCode); - - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - // Windows madness! for some obscure reason, the whole command lines needs to be - // wrapped in quotes (?!?) - $cmd = '"'.$cmd.'"'; - } - return $cmd; + $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg($phpCode); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + // Windows madness! for some obscure reason, the whole command lines needs to be + // wrapped in quotes (?!?) + $cmd = '"'.$cmd.'"'; + } + return $cmd; } } From a708cb89174c5eb3a85c619d8a3b7c96979e83dd Mon Sep 17 00:00:00 2001 From: David Negrier Date: Wed, 4 Mar 2015 22:55:07 +0100 Subject: [PATCH 5/5] Applying cleaner fix to windows problem following @jmikola and @auroraeosrose advices --- tests/AbstractProcessTest.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/AbstractProcessTest.php b/tests/AbstractProcessTest.php index 3c5b07e..702eef1 100644 --- a/tests/AbstractProcessTest.php +++ b/tests/AbstractProcessTest.php @@ -71,7 +71,7 @@ public function testProcessWithDefaultCwdAndEnv() $cmd = $this->getPhpCommandLine('echo getcwd(), PHP_EOL, count($_SERVER), PHP_EOL;'); $loop = $this->createLoop(); - $process = new Process($cmd); + $process = new Process($cmd, null, null, array("bypass_shell"=>true)); $output = ''; $error = ''; @@ -112,7 +112,7 @@ public function testProcessWithCwd() } $loop = $this->createLoop(); - $process = new Process($cmd, $testCwd); + $process = new Process($cmd, $testCwd, null, array("bypass_shell"=>true)); $output = ''; @@ -143,7 +143,7 @@ public function testProcessWithEnv() } $loop = $this->createLoop(); - $process = new Process($cmd, null, array('foo' => 'bar')); + $process = new Process($cmd, null, array('foo' => 'bar'), array("bypass_shell"=>true)); $output = ''; @@ -404,13 +404,6 @@ private function getPhpBinary() private function getPhpCommandLine($phpCode) { - $cmd = $this->getPhpBinary() . ' -r ' . escapeshellarg($phpCode); - - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - // Windows madness! for some obscure reason, the whole command lines needs to be - // wrapped in quotes (?!?) - $cmd = '"'.$cmd.'"'; - } - return $cmd; + return $this->getPhpBinary() . ' -r ' . escapeshellarg($phpCode); } }