-
-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
871 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Helpers; | ||
use Nette\Utils\Process; | ||
use Nette\Utils\ProcessFailedException; | ||
use Nette\Utils\ProcessTimeoutException; | ||
use Tester\Assert; | ||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
// Process execution - success | ||
|
||
test('run executable successfully', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo "hello";']); | ||
Assert::true($process->isSuccess()); | ||
Assert::same(0, $process->getExitCode()); | ||
Assert::same('hello', $process->getStdOutput()); | ||
Assert::same('', $process->getStdError()); | ||
}); | ||
|
||
test('run command successfully', function () { | ||
$process = Process::runCommand('echo hello'); | ||
Assert::true($process->isSuccess()); | ||
Assert::same(0, $process->getExitCode()); | ||
Assert::same('hello' . PHP_EOL, $process->getStdOutput()); | ||
Assert::same('', $process->getStdError()); | ||
}); | ||
|
||
|
||
// Process execution - errors | ||
|
||
test('run executable with error', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'exit(1);']); | ||
Assert::false($process->isSuccess()); | ||
Assert::same(1, $process->getExitCode()); | ||
}); | ||
|
||
test('run executable ensure success throws exception on error', function () { | ||
Assert::exception( | ||
fn() => Process::runExecutable(PHP_BINARY, ['-r', 'exit(1);'])->ensureSuccess(), | ||
ProcessFailedException::class, | ||
'Process failed with non-zero exit code: 1', | ||
); | ||
}); | ||
|
||
test('run command with error', function () { | ||
$process = Process::runCommand('"' . PHP_BINARY . '" -r "exit(1);"'); | ||
Assert::false($process->isSuccess()); | ||
Assert::same(1, $process->getExitCode()); | ||
}); | ||
|
||
test('run command ensure success throws exception on error', function () { | ||
Assert::exception( | ||
fn() => Process::runCommand('"' . PHP_BINARY . '" -r "exit(1);"')->ensureSuccess(), | ||
ProcessFailedException::class, | ||
'Process failed with non-zero exit code: 1', | ||
); | ||
}); | ||
|
||
|
||
// Process state monitoring | ||
|
||
test('is running', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'sleep(1);']); | ||
Assert::true($process->isRunning()); | ||
$process->wait(); | ||
Assert::false($process->isRunning()); | ||
}); | ||
|
||
test('get pid', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'sleep(1);']); | ||
Assert::type('int', $process->getPid()); | ||
$process->wait(); | ||
Assert::null($process->getPid()); | ||
}); | ||
|
||
|
||
// Waiting for process | ||
|
||
test('wait', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo "hello";']); | ||
$process->wait(); | ||
$process->wait(); | ||
Assert::false($process->isRunning()); | ||
Assert::same(0, $process->getExitCode()); | ||
Assert::same('hello', $process->getStdOutput()); | ||
}); | ||
|
||
test('wait with callback', function () { | ||
$output = ''; | ||
$error = ''; | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo "hello"; fwrite(STDERR, "error");']); | ||
$process->wait(function ($stdOut, $stdErr) use (&$output, &$error) { | ||
$output .= $stdOut; | ||
$error .= $stdErr; | ||
}); | ||
Assert::same('hello', $output); | ||
Assert::same('error', $error); | ||
}); | ||
|
||
|
||
// Automatically call wait() | ||
|
||
test('getStdOutput() automatically call wait()', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo "hello";']); | ||
Assert::same('hello', $process->getStdOutput()); | ||
Assert::false($process->isRunning()); | ||
}); | ||
|
||
test('getExitCode() automatically call wait()', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo exit(2);']); | ||
Assert::same(2, $process->getExitCode()); | ||
Assert::false($process->isRunning()); | ||
}); | ||
|
||
|
||
// Terminating process | ||
|
||
test('terminate', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'sleep(5);']); | ||
$process->terminate(); | ||
Assert::false($process->isRunning()); | ||
}); | ||
|
||
test('terminate() and then wait()', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-f', 'sleep(5);']); | ||
$process->terminate(); | ||
$process->wait(); | ||
Assert::false($process->isRunning()); | ||
}); | ||
|
||
|
||
// Timeout | ||
|
||
test('timeout', function () { | ||
Assert::exception( | ||
fn() => Process::runExecutable(PHP_BINARY, ['-r', 'sleep(5);'], timeout: 0.1)->wait(), | ||
ProcessTimeoutException::class, | ||
'Process exceeded the time limit of 0.1 seconds', | ||
); | ||
}); | ||
|
||
|
||
// bypass_shell | ||
|
||
if (Helpers::IsWindows) { | ||
test('bypass_shell = false', function () { | ||
$process = Process::runCommand('"' . PHP_BINARY . '" -r "echo 123;"', options: ['bypass_shell' => false]); | ||
Assert::same('123', $process->getStdOutput()); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Process; | ||
use Tester\Assert; | ||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
test('incremental output consumption', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-f', __DIR__ . '/fixtures.process/incremental.php', 'stdout']); | ||
usleep(50_000); | ||
Assert::same('hel', $process->consumeStdOutput()); | ||
usleep(50_000); | ||
Assert::same('lo', $process->consumeStdOutput()); | ||
usleep(50_000); | ||
Assert::same('wor', $process->consumeStdOutput()); | ||
usleep(50_000); | ||
Assert::same('ld', $process->consumeStdOutput()); | ||
$process->wait(); | ||
Assert::same('', $process->consumeStdOutput()); | ||
Assert::same('helloworld', $process->getStdOutput()); | ||
}); | ||
|
||
test('incremental error output consumption', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-f', __DIR__ . '/fixtures.process/incremental.php', 'stderr']); | ||
usleep(50_000); | ||
Assert::same('hello' . PHP_EOL, $process->consumeStdError()); | ||
usleep(50_000); | ||
Assert::same('world' . PHP_EOL, $process->consumeStdError()); | ||
usleep(50_000); | ||
Assert::same('', $process->consumeStdError()); | ||
Assert::same('hello' . PHP_EOL . 'world' . PHP_EOL, $process->getStdError()); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Process; | ||
use Tester\Assert; | ||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
// Environment variables | ||
|
||
test('environment variables', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo getenv("TEST_VAR");'], env: ['TEST_VAR' => '123']); | ||
Assert::same('123', $process->getStdOutput()); | ||
}); | ||
|
||
test('no environment variables', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo !getenv("PATH") ? "ok" : "no";'], env: []); | ||
Assert::same('ok', $process->getStdOutput()); | ||
}); | ||
|
||
test('parent environment variables', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo getenv("PATH") ? "ok" : "no";']); | ||
Assert::same('ok', $process->getStdOutput()); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Process; | ||
use Tester\Assert; | ||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
// Different input types | ||
|
||
test('string as input', function () { | ||
$input = 'Hello Input'; | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo fgets(STDIN);'], stdin: $input); | ||
Assert::same('Hello Input', $process->getStdOutput()); | ||
}); | ||
|
||
test('stream as input', function () { | ||
$input = fopen('php://memory', 'r+'); | ||
fwrite($input, 'Hello Input'); | ||
rewind($input); | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo fgets(STDIN);'], stdin: $input); | ||
Assert::same('Hello Input', $process->getStdOutput()); | ||
}); | ||
|
||
|
||
// Writing input | ||
|
||
test('write input', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo fgets(STDIN);'], stdin: null); | ||
$process->writeStdInput('hello' . PHP_EOL); | ||
$process->writeStdInput('world' . PHP_EOL); | ||
$process->closeStdInput(); | ||
Assert::same('hello' . PHP_EOL, $process->getStdOutput()); | ||
}); | ||
|
||
test('writeStdInput() after closeStdInput() throws exception', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo fgets(STDIN);'], stdin: null); | ||
$process->writeStdInput('hello' . PHP_EOL); | ||
$process->closeStdInput(); | ||
Assert::exception( | ||
fn() => $process->writeStdInput('world' . PHP_EOL), | ||
Nette\InvalidStateException::class, | ||
'Cannot write to process: STDIN pipe is closed', | ||
); | ||
}); | ||
|
||
test('writeStdInput() throws exception when stdin is not null', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo fgets(STDIN);']); | ||
Assert::exception( | ||
fn() => $process->writeStdInput('hello' . PHP_EOL), | ||
Nette\InvalidStateException::class, | ||
'Cannot write to process: STDIN pipe is closed', | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Process; | ||
use Tester\Assert; | ||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
// Different output types | ||
|
||
test('output to files', function () { | ||
$tempFile = tempnam(sys_get_temp_dir(), 'process_test_'); | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo "hello";'], stdout: $tempFile, stderr: false); | ||
$process->wait(); | ||
Assert::same('hello', file_get_contents($tempFile)); | ||
unlink($tempFile); | ||
}); | ||
|
||
test('setting stderr to false prevents reading from getStdError() or consumeStdError()', function () { | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo fwrite(STDERR, "hello");'], stderr: false); | ||
$process->wait(); | ||
Assert::exception( | ||
fn() => $process->getStdError(), | ||
LogicException::class, | ||
'Cannot read output: output capturing was not enabled', | ||
); | ||
Assert::exception( | ||
fn() => $process->consumeStdError(), | ||
LogicException::class, | ||
'Cannot read output: output capturing was not enabled', | ||
); | ||
}); | ||
|
||
test('stream as output', function () { | ||
$tempFile = tempnam(sys_get_temp_dir(), 'process_test_'); | ||
$output = fopen($tempFile, 'w'); | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo "hello";'], stdout: $output); | ||
$process->wait(); | ||
fclose($output); | ||
Assert::same('hello', file_get_contents($tempFile)); | ||
unlink($tempFile); | ||
}); | ||
|
||
test('stream as error output', function () { | ||
$tempFile = tempnam(sys_get_temp_dir(), 'process_test_'); | ||
$output = fopen($tempFile, 'w'); | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo fwrite(STDERR, "hello");'], stderr: $output); | ||
$process->wait(); | ||
fclose($output); | ||
Assert::same('hello', file_get_contents($tempFile)); | ||
unlink($tempFile); | ||
}); | ||
|
||
test('changing both stdout and stderr does not trigger callbacks in wait()', function () { | ||
$tempFile = tempnam(sys_get_temp_dir(), 'process_test_'); | ||
$output = fopen($tempFile, 'w'); | ||
$wasCalled = false; | ||
$process = Process::runExecutable(PHP_BINARY, ['-r', 'echo "hello";'], stdout: $output, stderr: $output); | ||
$process->wait(function () use (&$wasCalled) { | ||
$wasCalled = true; | ||
}); | ||
fclose($output); | ||
Assert::false($wasCalled); | ||
unlink($tempFile); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Helpers; | ||
use Nette\Utils\Process; | ||
use Tester\Assert; | ||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
if (Helpers::IsWindows) { | ||
Tester\Environment::skip('Process piping is not supported on Windows.'); | ||
} | ||
|
||
$process1 = Process::runExecutable( | ||
PHP_BINARY, | ||
['-f', __DIR__ . '/fixtures.process/tick.php'], | ||
); | ||
|
||
$process2 = Process::runExecutable( | ||
PHP_BINARY, | ||
['-f', __DIR__ . '/fixtures.process/rev.php'], | ||
stdin: $process1, | ||
); | ||
|
||
$output = ''; | ||
$process2->wait(function ($stdOut, $stdErr) use (&$output) { | ||
$output .= $stdOut; | ||
}); | ||
|
||
Assert::same('kcit' . PHP_EOL . 'kcit' . PHP_EOL . 'kcit' . PHP_EOL, $output); |
Oops, something went wrong.