This source file includes following definitions.
- SetupExpectations
- OnSomeRead
- StartRegistryTest
- ProcessReceivedCharacter
- TestSucceeded
- SetupExpectations
- OnSomeRead
- StartRegistryTest
- SetupExpectations
- OnSomeRead
- StartRegistryTest
- InitRegistryTest
- EndRegistryTest
- RunTest
- TEST_F
- TEST_F
- TEST_F
#include <gtest/gtest.h>
#include <string>
#include <sys/wait.h>
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/process/kill.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "chromeos/process_proxy/process_proxy_registry.h"
namespace chromeos {
namespace {
const char kTestLineToSend[] = "abcdefgh\n";
const char kTestLineExpected[] = "abcdefgh\r\n";
const char kCatCommand[] = "cat";
const char kStdoutType[] = "stdout";
const int kTestLineNum = 100;
class TestRunner {
public:
virtual ~TestRunner() {}
virtual void SetupExpectations(pid_t pid) = 0;
virtual void OnSomeRead(pid_t pid, const std::string& type,
const std::string& output) = 0;
virtual void StartRegistryTest(ProcessProxyRegistry* registry) = 0;
protected:
pid_t pid_;
};
class RegistryTestRunner : public TestRunner {
public:
virtual ~RegistryTestRunner() {}
virtual void SetupExpectations(pid_t pid) OVERRIDE {
pid_ = pid;
left_to_check_index_[0] = 0;
left_to_check_index_[1] = 0;
lines_left_ = 2 * kTestLineNum - 2;
expected_line_ = kTestLineExpected;
}
virtual void OnSomeRead(pid_t pid, const std::string& type,
const std::string& output) OVERRIDE {
EXPECT_EQ(type, kStdoutType);
EXPECT_EQ(pid_, pid);
bool valid = true;
for (size_t i = 0; i < output.length(); i++) {
valid = (ProcessReceivedCharacter(output[i], 0) ||
ProcessReceivedCharacter(output[i], 1));
EXPECT_TRUE(valid) << "Received: " << output;
}
if (!valid || TestSucceeded()) {
base::MessageLoop::current()->PostTask(FROM_HERE,
base::MessageLoop::QuitClosure());
}
}
virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE {
for (int i = 0; i < kTestLineNum; i++) {
EXPECT_TRUE(registry->SendInput(pid_, kTestLineToSend));
}
}
private:
bool ProcessReceivedCharacter(char received, size_t stream) {
if (stream >= arraysize(left_to_check_index_))
return false;
bool success = left_to_check_index_[stream] < expected_line_.length() &&
expected_line_[left_to_check_index_[stream]] == received;
if (success)
left_to_check_index_[stream]++;
if (left_to_check_index_[stream] == expected_line_.length() &&
lines_left_ > 0) {
left_to_check_index_[stream] = 0;
lines_left_--;
}
return success;
}
bool TestSucceeded() {
return left_to_check_index_[0] == expected_line_.length() &&
left_to_check_index_[1] == expected_line_.length() &&
lines_left_ == 0;
}
size_t left_to_check_index_[2];
size_t lines_left_;
std::string expected_line_;
};
class RegistryNotifiedOnProcessExitTestRunner : public TestRunner {
public:
virtual ~RegistryNotifiedOnProcessExitTestRunner() {}
virtual void SetupExpectations(pid_t pid) OVERRIDE {
output_received_ = false;
pid_ = pid;
}
virtual void OnSomeRead(pid_t pid, const std::string& type,
const std::string& output) OVERRIDE {
EXPECT_EQ(pid_, pid);
if (!output_received_) {
output_received_ = true;
EXPECT_EQ(type, "stdout");
EXPECT_EQ(output, "p");
base::KillProcess(pid_, 0 , true);
return;
}
EXPECT_EQ("exit", type);
base::MessageLoop::current()->PostTask(FROM_HERE,
base::MessageLoop::QuitClosure());
}
virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE {
EXPECT_TRUE(registry->SendInput(pid_, "p"));
}
private:
bool output_received_;
};
class SigIntTestRunner : public TestRunner {
public:
virtual ~SigIntTestRunner() {}
virtual void SetupExpectations(pid_t pid) OVERRIDE {
pid_ = pid;
}
virtual void OnSomeRead(pid_t pid, const std::string& type,
const std::string& output) OVERRIDE {
EXPECT_EQ(pid_, pid);
if (type == "exit") {
base::MessageLoop::current()->PostTask(FROM_HERE,
base::MessageLoop::QuitClosure());
}
}
virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE {
EXPECT_TRUE(registry->SendInput(pid_, "\003"));
}
};
}
class ProcessProxyTest : public testing::Test {
public:
ProcessProxyTest() {}
virtual ~ProcessProxyTest() {}
protected:
void InitRegistryTest() {
registry_ = ProcessProxyRegistry::Get();
EXPECT_TRUE(registry_->OpenProcess(
kCatCommand, &pid_,
base::Bind(&TestRunner::OnSomeRead,
base::Unretained(test_runner_.get()))));
test_runner_->SetupExpectations(pid_);
test_runner_->StartRegistryTest(registry_);
}
void EndRegistryTest() {
registry_->CloseProcess(pid_);
base::TerminationStatus status = base::GetTerminationStatus(pid_, NULL);
EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status);
if (status == base::TERMINATION_STATUS_STILL_RUNNING)
base::KillProcess(pid_, 0, true);
base::MessageLoop::current()->PostTask(FROM_HERE,
base::MessageLoop::QuitClosure());
}
void RunTest() {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&ProcessProxyTest::InitRegistryTest,
base::Unretained(this)));
base::MessageLoop::current()->Run();
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&ProcessProxyTest::EndRegistryTest,
base::Unretained(this)));
base::MessageLoop::current()->Run();
}
scoped_ptr<TestRunner> test_runner_;
private:
ProcessProxyRegistry* registry_;
pid_t pid_;
base::MessageLoop message_loop_;
};
TEST_F(ProcessProxyTest, RegistryTest) {
test_runner_.reset(new RegistryTestRunner());
RunTest();
}
TEST_F(ProcessProxyTest, RegistryNotifiedOnProcessExit) {
test_runner_.reset(new RegistryNotifiedOnProcessExitTestRunner());
RunTest();
}
TEST_F(ProcessProxyTest, DISABLED_SigInt) {
test_runner_.reset(new SigIntTestRunner());
RunTest();
}
}