Your IP : 3.149.239.70
#include <TestSupport.h>
#include <Core/ApplicationPool/Process.h>
#include <LoggingKit/Context.h>
#include <FileTools/FileManip.h>
using namespace Passenger;
using namespace Passenger::ApplicationPool2;
using namespace std;
namespace tut {
struct Core_ApplicationPool_ProcessTest: public TestBase {
WrapperRegistry::Registry wrapperRegistry;
SpawningKit::Context::Schema skContextSchema;
SpawningKit::Context skContext;
Context context;
BasicGroupInfo groupInfo;
vector<SpawningKit::Result::Socket> sockets;
Pipe stdinFd, stdoutAndErrFd;
FileDescriptor server1, server2, server3;
Core_ApplicationPool_ProcessTest()
: skContext(skContextSchema)
{
wrapperRegistry.finalize();
skContext.resourceLocator = resourceLocator;
skContext.wrapperRegistry = &wrapperRegistry;
skContext.integrationMode = "standalone";
skContext.finalize();
context.spawningKitFactory = boost::make_shared<SpawningKit::Factory>(&skContext);
context.finalize();
groupInfo.context = &context;
groupInfo.group = NULL;
groupInfo.name = "test";
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SpawningKit::Result::Socket socket;
server1.assign(createTcpServer("127.0.0.1", 0, 0, __FILE__, __LINE__), NULL, 0);
getsockname(server1, (struct sockaddr *) &addr, &len);
socket.address = "tcp://127.0.0.1:" + toString(addr.sin_port);
socket.protocol = "session";
socket.concurrency = 3;
socket.acceptHttpRequests = true;
sockets.push_back(socket);
server2.assign(createTcpServer("127.0.0.1", 0, 0, __FILE__, __LINE__), NULL, 0);
getsockname(server2, (struct sockaddr *) &addr, &len);
socket = SpawningKit::Result::Socket();
socket.address = "tcp://127.0.0.1:" + toString(addr.sin_port);
socket.protocol = "session";
socket.concurrency = 3;
socket.acceptHttpRequests = true;
sockets.push_back(socket);
server3.assign(createTcpServer("127.0.0.1", 0, 0, __FILE__, __LINE__), NULL, 0);
getsockname(server3, (struct sockaddr *) &addr, &len);
socket = SpawningKit::Result::Socket();
socket.address = "tcp://127.0.0.1:" + toString(addr.sin_port);
socket.protocol = "session";
socket.concurrency = 3;
socket.acceptHttpRequests = true;
sockets.push_back(socket);
stdinFd = createPipe(__FILE__, __LINE__);
stdoutAndErrFd = createPipe(__FILE__, __LINE__);
Json::Value config;
vector<ConfigKit::Error> errors;
LoggingKit::ConfigChangeRequest req;
config["app_output_log_level"] = "debug";
if (LoggingKit::context->prepareConfigChange(config, errors, req)) {
LoggingKit::context->commitConfigChange(req);
} else {
P_BUG("Error configuring LoggingKit: " << ConfigKit::toString(errors));
}
}
~Core_ApplicationPool_ProcessTest() {
Json::Value config;
vector<ConfigKit::Error> errors;
LoggingKit::ConfigChangeRequest req;
config["level"] = DEFAULT_LOG_LEVEL_NAME;
config["app_output_log_level"] = DEFAULT_APP_OUTPUT_LOG_LEVEL_NAME;
if (LoggingKit::context->prepareConfigChange(config, errors, req)) {
LoggingKit::context->commitConfigChange(req);
} else {
P_BUG("Error configuring LoggingKit: " << ConfigKit::toString(errors));
}
}
ProcessPtr createProcess(const Json::Value &extraArgs = Json::Value()) {
SpawningKit::Result result;
Json::Value args = extraArgs;
vector<StaticString> internalFieldErrors;
vector<StaticString> appSuppliedFieldErrors;
result.pid = 123;
result.gupid = "123";
result.type = SpawningKit::Result::DUMMY;
result.spawnStartTime = 1;
result.spawnEndTime = 1;
result.spawnStartTimeMonotonic = 1;
result.spawnEndTimeMonotonic = 1;
result.sockets = sockets;
result.stdinFd = stdinFd[1];
result.stdoutAndErrFd = stdoutAndErrFd[0];
if (!result.validate(internalFieldErrors, appSuppliedFieldErrors)) {
P_BUG("Cannot create dummy process:\n"
<< toString(internalFieldErrors)
<< "\n" << toString(appSuppliedFieldErrors));
}
args["spawner_creation_time"] = 0;
ProcessPtr process(context.processObjectPool.construct(
&groupInfo, result, args), false);
process->shutdownNotRequired();
return process;
}
};
DEFINE_TEST_GROUP(Core_ApplicationPool_ProcessTest);
TEST_METHOD(1) {
set_test_name("Test initial state");
ProcessPtr process = createProcess();
ensure_equals(process->busyness(), 0);
ensure(!process->isTotallyBusy());
}
TEST_METHOD(2) {
set_test_name("Test opening and closing sessions");
ProcessPtr process = createProcess();
SessionPtr session = process->newSession();
SessionPtr session2 = process->newSession();
ensure_equals(process->sessions, 2);
process->sessionClosed(session.get());
ensure_equals(process->sessions, 1);
process->sessionClosed(session2.get());
ensure_equals(process->sessions, 0);
}
TEST_METHOD(3) {
set_test_name("newSession() checks out the socket with the smallest busyness number "
"and sessionClosed() restores the session busyness statistics");
ProcessPtr process = createProcess();
// The first 3 newSession() commands check out an idle socket.
SessionPtr session1 = process->newSession();
SessionPtr session2 = process->newSession();
SessionPtr session3 = process->newSession();
ensure(session1->getSocket()->address != session2->getSocket()->address);
ensure(session1->getSocket()->address != session3->getSocket()->address);
ensure(session2->getSocket()->address != session3->getSocket()->address);
// The next 2 newSession() commands check out sockets with sessions == 1.
SessionPtr session4 = process->newSession();
SessionPtr session5 = process->newSession();
ensure(session4->getSocket()->address != session5->getSocket()->address);
// There should now be 1 process with 1 session
// and 2 processes with 2 sessions.
map<int, int> sessionCount;
SocketList::const_iterator it;
for (it = process->getSockets().begin(); it != process->getSockets().end(); it++) {
sessionCount[it->sessions]++;
}
ensure_equals(sessionCount.size(), 2u);
ensure_equals(sessionCount[1], 1);
ensure_equals(sessionCount[2], 2);
// Closing the first 3 sessions will result in no processes having 1 session
// and 1 process having 2 sessions.
process->sessionClosed(session1.get());
process->sessionClosed(session2.get());
process->sessionClosed(session3.get());
sessionCount.clear();
for (it = process->getSockets().begin(); it != process->getSockets().end(); it++) {
sessionCount[it->sessions]++;
}
ensure_equals(sessionCount[0], 1);
ensure_equals(sessionCount[1], 2);
}
TEST_METHOD(4) {
set_test_name("If all sockets are at their full capacity then newSession() will fail");
ProcessPtr process = createProcess();
vector<SessionPtr> sessions;
for (int i = 0; i < 9; i++) {
ensure(!process->isTotallyBusy());
SessionPtr session = process->newSession();
ensure(session != NULL);
sessions.push_back(session);
}
ensure(process->isTotallyBusy());
ensure(process->newSession() == NULL);
}
TEST_METHOD(5) {
set_test_name("It forwards all stdout and stderr output, even after the "
"Process object has been destroyed");
TempDir temp("tmp.log");
Json::Value extraArgs;
extraArgs["log_file"] = "tmp.log/file";
fclose(fopen("tmp.log/file", "w"));
ProcessPtr process = createProcess(extraArgs);
if (defaultLogLevel == (LoggingKit::Level) DEFAULT_LOG_LEVEL) {
// If the user did not customize the test's log level,
// then we'll want to tone down the noise.
LoggingKit::setLevel(LoggingKit::WARN);
}
writeExact(stdoutAndErrFd[1], "stdout and err 1\n");
writeExact(stdoutAndErrFd[1], "stdout and err 2\n");
EVENTUALLY(2,
string contents = unsafeReadFile("tmp.log/file");
result = contents.find("stdout and err 1\n") != string::npos
&& contents.find("stdout and err 2\n") != string::npos;
);
fclose(fopen("tmp.log/file", "w"));
process.reset();
writeExact(stdoutAndErrFd[1], "stdout and err 3\n");
writeExact(stdoutAndErrFd[1], "stdout and err 4\n");
EVENTUALLY(2,
string contents = unsafeReadFile("tmp.log/file");
result = contents.find("stdout and err 3\n") != string::npos
&& contents.find("stdout and err 4\n") != string::npos;
);
}
}