Arquivos
hhvm/hphp/test/test_ext_process.cpp
T
Wez Furlong d1e4f65ec9 proc_open should inherit g_context->m_envs
Some head scratching until I realized that my `putenv()` calls
in my PHP script weren't actually changing the environment for subsequent
`proc_open()` calls.

What I'd like this diff to do (and I fully expect that I'm violating some
referencing rules in hhvm) is to fall back to using our current view of
the environment as maintained in the execution context in the case that
proc_open is not explicitly passed an environment array.

I think I've even added a test to prove that this works, but I haven't
read the manual and fbmake runtests takes too long, so I'm just going
ahead to submit this diff.
2013-05-09 11:33:11 -07:00

409 linhas
11 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include <test/test_ext_process.h>
#include <runtime/ext/ext_process.h>
#include <runtime/ext/ext_file.h>
#include <runtime/base/file/file.h>
#include <runtime/base/util/string_buffer.h>
#include <runtime/base/runtime_option.h>
#include <util/light_process.h>
///////////////////////////////////////////////////////////////////////////////
bool TestExtProcess::RunTests(const std::string &which) {
bool ret = true;
RUN_TEST(test_pcntl_alarm);
//RUN_TEST(test_pcntl_exec); // this has to run manually
RUN_TEST(test_pcntl_fork);
RUN_TEST(test_pcntl_getpriority);
RUN_TEST(test_pcntl_setpriority);
RUN_TEST(test_pcntl_signal);
RUN_TEST(test_pcntl_wait);
RUN_TEST(test_pcntl_waitpid);
RUN_TEST(test_pcntl_wexitstatus);
RUN_TEST(test_pcntl_wifexited);
RUN_TEST(test_pcntl_wifsignaled);
RUN_TEST(test_pcntl_wifstopped);
RUN_TEST(test_pcntl_wstopsig);
RUN_TEST(test_pcntl_wtermsig);
RUN_TEST(test_pcntl_signal_dispatch);
RUN_TEST(test_shell_exec);
RUN_TEST(test_exec);
RUN_TEST(test_passthru);
RUN_TEST(test_system);
RUN_TEST(test_proc_open);
RUN_TEST(test_proc_terminate);
RUN_TEST(test_proc_close);
RUN_TEST(test_proc_open_env_inh);
RUN_TEST(test_proc_get_status);
RUN_TEST(test_proc_nice);
RUN_TEST(test_escapeshellarg);
RUN_TEST(test_escapeshellcmd);
LightProcess::Initialize(RuntimeOption::LightProcessFilePrefix,
RuntimeOption::LightProcessCount,
std::vector<int>());
RUN_TEST(test_pcntl_alarm);
//RUN_TEST(test_pcntl_exec); // this has to run manually
RUN_TEST(test_pcntl_fork);
RUN_TEST(test_pcntl_getpriority);
RUN_TEST(test_pcntl_setpriority);
RUN_TEST(test_pcntl_signal);
RUN_TEST(test_pcntl_wait);
RUN_TEST(test_pcntl_waitpid);
RUN_TEST(test_pcntl_wexitstatus);
RUN_TEST(test_pcntl_wifexited);
RUN_TEST(test_pcntl_wifsignaled);
RUN_TEST(test_pcntl_wifstopped);
RUN_TEST(test_pcntl_wstopsig);
RUN_TEST(test_pcntl_wtermsig);
RUN_TEST(test_pcntl_signal_dispatch);
RUN_TEST(test_shell_exec);
RUN_TEST(test_exec);
RUN_TEST(test_passthru);
RUN_TEST(test_system);
RUN_TEST(test_proc_open);
RUN_TEST(test_proc_terminate);
RUN_TEST(test_proc_close);
RUN_TEST(test_proc_open_env_inh);
RUN_TEST(test_proc_get_status);
RUN_TEST(test_proc_nice);
LightProcess::Close();
return ret;
}
///////////////////////////////////////////////////////////////////////////////
bool TestExtProcess::test_pcntl_alarm() {
//f_pcntl_alarm(1);
return Count(true);
}
bool TestExtProcess::test_pcntl_exec() {
f_pcntl_exec("/bin/sh",
CREATE_VECTOR1("test/test_pcntl_exec.sh"),
CREATE_MAP1("name", "value"));
return Count(true);
}
bool TestExtProcess::test_pcntl_fork() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(123);
}
Variant status;
f_pcntl_wait(ref(status));
return Count(true);
}
bool TestExtProcess::test_pcntl_getpriority() {
VS(f_pcntl_getpriority(), 0);
return Count(true);
}
bool TestExtProcess::test_pcntl_setpriority() {
VERIFY(f_pcntl_setpriority(0));
return Count(true);
}
bool TestExtProcess::test_pcntl_signal() {
f_pcntl_signal(k_SIGALRM, "test", true);
return Count(true);
}
bool TestExtProcess::test_pcntl_wait() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x12);
}
Variant status;
f_pcntl_wait(ref(status));
VS(status, 0x1200);
return Count(true);
}
bool TestExtProcess::test_pcntl_waitpid() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x12);
}
Variant status;
f_pcntl_waitpid(0, ref(status));
VS(status, 0x1200);
return Count(true);
}
bool TestExtProcess::test_pcntl_wexitstatus() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x80);
}
Variant status;
f_pcntl_waitpid(0, ref(status));
VS(f_pcntl_wexitstatus(status), 0x80);
return Count(true);
}
bool TestExtProcess::test_pcntl_wifexited() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x12);
}
Variant status;
f_pcntl_waitpid(0, ref(status));
VERIFY(f_pcntl_wifexited(status));
return Count(true);
}
bool TestExtProcess::test_pcntl_wifsignaled() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x12);
}
Variant status;
f_pcntl_waitpid(0, ref(status));
VERIFY(!f_pcntl_wifsignaled(status));
return Count(true);
}
bool TestExtProcess::test_pcntl_wifstopped() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x12);
}
Variant status;
f_pcntl_waitpid(0, ref(status));
VERIFY(!f_pcntl_wifstopped(status));
return Count(true);
}
bool TestExtProcess::test_pcntl_wstopsig() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x12);
}
Variant status;
f_pcntl_waitpid(0, ref(status));
VS(f_pcntl_wstopsig(status), 0x12);
return Count(true);
}
bool TestExtProcess::test_pcntl_wtermsig() {
int pid = f_pcntl_fork();
if (pid == 0) {
exit(0x12);
}
Variant status;
f_pcntl_waitpid(0, ref(status));
VS(f_pcntl_wtermsig(status), 0);
return Count(true);
}
bool TestExtProcess::test_shell_exec() {
Variant output = f_shell_exec("echo hello");
VS(output, "hello\n");
string cur_cwd = Process::GetCurrentDirectory();
f_chdir("/tmp/");
VS(f_shell_exec("/bin/pwd"), "/tmp\n");
f_chdir(String(cur_cwd));
return Count(true);
}
bool TestExtProcess::test_pcntl_signal_dispatch() {
f_pcntl_signal_dispatch();
return Count(true);
}
bool TestExtProcess::test_exec() {
Variant output, ret;
String last_line = f_exec("echo hello; echo world;", ref(output), ref(ret));
VS(output, CREATE_VECTOR2("hello", "world"));
VS(last_line, "world");
VS(ret, 0);
string cur_cwd = Process::GetCurrentDirectory();
f_chdir("/tmp/");
VS(f_exec("/bin/pwd"), "/tmp");
f_chdir(String(cur_cwd));
return Count(true);
}
bool TestExtProcess::test_passthru() {
g_context->obStart();
Variant ret;
f_passthru("echo hello; echo world;", ref(ret));
String output = g_context->obCopyContents();
g_context->obEnd();
VS(output, "hello\nworld\n");
VS(ret, 0);
string cur_cwd = Process::GetCurrentDirectory();
f_chdir("/tmp/");
g_context->obStart();
f_passthru("/bin/pwd");
output = g_context->obCopyContents();
g_context->obEnd();
VS(output, "/tmp\n");
f_chdir(String(cur_cwd));
return Count(true);
}
bool TestExtProcess::test_system() {
g_context->obStart();
Variant ret;
String last_line = f_system("echo hello; echo world;", ref(ret));
String output = g_context->obCopyContents();
g_context->obEnd();
VS(output, "hello\nworld\n");
VS(last_line, "world");
VS(ret, 0);
string cur_cwd = Process::GetCurrentDirectory();
f_chdir("/tmp/");
VS(f_system("/bin/pwd"), "/tmp");
f_chdir(String(cur_cwd));
return Count(true);
}
bool TestExtProcess::test_proc_open_env_inh() {
Array descriptorspec =
CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
1, CREATE_VECTOR2("pipe", "w"),
2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
Variant pipes;
g_context->setenv("inherit_me", "please");
Variant process = f_proc_open("echo $inherit_me", descriptorspec, ref(pipes));
VERIFY(!same(process, false));
{
File *f = pipes[1].toObject().getTyped<File>();
VERIFY(f->valid());
StringBuffer sbuf;
sbuf.read(f);
f->close();
VS(sbuf.detach(), "please\n");
}
VS(f_proc_close(process.toObject()), 0);
return Count(true);
}
bool TestExtProcess::test_proc_open() {
Array descriptorspec =
CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
1, CREATE_VECTOR2("pipe", "w"),
2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
String cwd = "/tmp";
Array env = CREATE_MAP1("some_option", "aeiou");
Variant pipes;
Variant process = f_proc_open(php_path, descriptorspec, ref(pipes), cwd, env);
VERIFY(!same(process, false));
{
File *f = pipes[0].toObject().getTyped<File>();
VERIFY(f->valid());
String s("<?php print(getenv('some_option')); ?>", AttachLiteral);
f->write(s);
f->close();
}
{
File *f = pipes[1].toObject().getTyped<File>();
VERIFY(f->valid());
StringBuffer sbuf;
sbuf.read(f);
f->close();
VS(sbuf.detach(), "aeiou");
}
VS(f_proc_close(process.toObject()), 0);
return Count(true);
}
bool TestExtProcess::test_proc_terminate() {
Array descriptorspec =
CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
1, CREATE_VECTOR2("pipe", "w"),
2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
Variant pipes;
Variant process = f_proc_open(php_path, descriptorspec, ref(pipes));
VERIFY(!same(process, false));
VERIFY(f_proc_terminate(process.toObject()));
// still need to close it, not to leave a zombie behind
f_proc_close(process.toObject());
return Count(true);
}
bool TestExtProcess::test_proc_close() {
return test_proc_open();
}
bool TestExtProcess::test_proc_get_status() {
Array descriptorspec =
CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
1, CREATE_VECTOR2("pipe", "w"),
2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
Variant pipes;
Variant process = f_proc_open(php_path, descriptorspec, ref(pipes));
VERIFY(!same(process, false));
Array ret = f_proc_get_status(process.toObject());
VS(ret["command"], php_path);
VERIFY(ret["pid"].toInt32() > 0);
VERIFY(ret["running"]);
VERIFY(!ret["signaled"]);
VS(ret["exitcode"], -1);
VS(ret["termsig"], 0);
VS(ret["stopsig"], 0);
{
File *f = pipes[0].toObject().getTyped<File>();
VERIFY(f->valid());
f->close();
}
{
File *f = pipes[1].toObject().getTyped<File>();
VERIFY(f->valid());
f->close();
}
VS(f_proc_close(process.toObject()), 0);
return Count(true);
}
bool TestExtProcess::test_proc_nice() {
VERIFY(f_proc_nice(0));
return Count(true);
}
bool TestExtProcess::test_escapeshellarg() {
VS(f_escapeshellarg("\""), "'\"'");
return Count(true);
}
bool TestExtProcess::test_escapeshellcmd() {
VS(f_escapeshellcmd("perl \""), "perl \\\"");
return Count(true);
}