This source file includes following definitions.
- OnMessageReceived
- SetUp
- TearDown
- OnMessageReceived
- OnChannelConnected
- OnChannelError
- LaunchProcess
- LaunchProcessAndConnect
- FailLaunchAndStopWorker
- KillProcess
- TerminateWorker
- ConnectClient
- DisconnectClient
- DisconnectServer
- SendToProcess
- SendFakeMessageToLauncher
- CrashWorker
- StartWorker
- StopWorker
- QuitMainMessageLoop
- DoLaunchProcess
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/win/scoped_handle.h"
#include "base/win/scoped_process_information.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/host/chromoting_messages.h"
#include "remoting/host/host_exit_codes.h"
#include "remoting/host/ipc_util.h"
#include "remoting/host/win/launch_process_with_token.h"
#include "remoting/host/win/worker_process_launcher.h"
#include "remoting/host/worker_process_ipc_delegate.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::win::ScopedHandle;
using testing::_;
using testing::AnyNumber;
using testing::CreateFunctor;
using testing::DoAll;
using testing::Expectation;
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::Return;
namespace remoting {
namespace {
const char kIpcSecurityDescriptor[] = "D:(A;;GA;;;AU)";
class MockProcessLauncherDelegate : public WorkerProcessLauncher::Delegate {
public:
MockProcessLauncherDelegate() {}
virtual ~MockProcessLauncherDelegate() {}
MOCK_METHOD1(LaunchProcess, void(WorkerProcessLauncher*));
MOCK_METHOD1(Send, void(IPC::Message*));
MOCK_METHOD0(CloseChannel, void());
MOCK_METHOD0(KillProcess, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockProcessLauncherDelegate);
};
class MockIpcDelegate : public WorkerProcessIpcDelegate {
public:
MockIpcDelegate() {}
virtual ~MockIpcDelegate() {}
MOCK_METHOD1(OnChannelConnected, void(int32));
MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message&));
MOCK_METHOD1(OnPermanentError, void(int));
private:
DISALLOW_COPY_AND_ASSIGN(MockIpcDelegate);
};
class MockWorkerListener : public IPC::Listener {
public:
MockWorkerListener() {}
virtual ~MockWorkerListener() {}
MOCK_METHOD3(OnCrash, void(const std::string&, const std::string&, int));
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(MockWorkerListener);
};
bool MockWorkerListener::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(MockWorkerListener, message)
IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
EXPECT_TRUE(handled);
return handled;
}
}
class WorkerProcessLauncherTest
: public testing::Test,
public IPC::Listener {
public:
WorkerProcessLauncherTest();
virtual ~WorkerProcessLauncherTest();
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
virtual void OnChannelError() OVERRIDE;
void LaunchProcess(
WorkerProcessLauncher* event_handler);
void LaunchProcessAndConnect(
WorkerProcessLauncher* event_handler);
void FailLaunchAndStopWorker(
WorkerProcessLauncher* event_handler);
void KillProcess();
void TerminateWorker(DWORD exit_code);
void ConnectClient();
void DisconnectClient();
void DisconnectServer();
void SendToProcess(IPC::Message* message);
void SendFakeMessageToLauncher();
void CrashWorker();
void StartWorker();
void StopWorker();
void QuitMainMessageLoop();
protected:
void DoLaunchProcess();
base::MessageLoopForIO message_loop_;
scoped_refptr<AutoThreadTaskRunner> task_runner_;
MockWorkerListener client_listener_;
MockIpcDelegate server_listener_;
scoped_ptr<MockProcessLauncherDelegate> launcher_delegate_;
std::string channel_name_;
scoped_ptr<IPC::ChannelProxy> channel_client_;
scoped_ptr<IPC::ChannelProxy> channel_server_;
WorkerProcessLauncher* event_handler_;
scoped_ptr<WorkerProcessLauncher> launcher_;
ScopedHandle worker_process_;
};
WorkerProcessLauncherTest::WorkerProcessLauncherTest() : event_handler_(NULL) {
}
WorkerProcessLauncherTest::~WorkerProcessLauncherTest() {
}
void WorkerProcessLauncherTest::SetUp() {
task_runner_ = new AutoThreadTaskRunner(
message_loop_.message_loop_proxy(),
base::Bind(&WorkerProcessLauncherTest::QuitMainMessageLoop,
base::Unretained(this)));
launcher_delegate_.reset(new MockProcessLauncherDelegate());
EXPECT_CALL(*launcher_delegate_, Send(_))
.Times(AnyNumber())
.WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::SendToProcess));
EXPECT_CALL(*launcher_delegate_, CloseChannel())
.Times(AnyNumber())
.WillRepeatedly(Invoke(this,
&WorkerProcessLauncherTest::DisconnectServer));
EXPECT_CALL(*launcher_delegate_, KillProcess())
.Times(AnyNumber())
.WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::KillProcess));
EXPECT_CALL(server_listener_, OnMessageReceived(_))
.Times(0);
}
void WorkerProcessLauncherTest::TearDown() {
}
bool WorkerProcessLauncherTest::OnMessageReceived(const IPC::Message& message) {
return event_handler_->OnMessageReceived(message);
}
void WorkerProcessLauncherTest::OnChannelConnected(int32 peer_pid) {
event_handler_->OnChannelConnected(peer_pid);
}
void WorkerProcessLauncherTest::OnChannelError() {
event_handler_->OnChannelError();
}
void WorkerProcessLauncherTest::LaunchProcess(
WorkerProcessLauncher* event_handler) {
EXPECT_FALSE(event_handler_);
event_handler_ = event_handler;
DoLaunchProcess();
}
void WorkerProcessLauncherTest::LaunchProcessAndConnect(
WorkerProcessLauncher* event_handler) {
EXPECT_FALSE(event_handler_);
event_handler_ = event_handler;
DoLaunchProcess();
task_runner_->PostTask(
FROM_HERE,
base::Bind(&WorkerProcessLauncherTest::ConnectClient,
base::Unretained(this)));
}
void WorkerProcessLauncherTest::FailLaunchAndStopWorker(
WorkerProcessLauncher* event_handler) {
EXPECT_FALSE(event_handler_);
event_handler->OnFatalError();
task_runner_->PostTask(
FROM_HERE,
base::Bind(&WorkerProcessLauncherTest::StopWorker,
base::Unretained(this)));
}
void WorkerProcessLauncherTest::KillProcess() {
event_handler_ = NULL;
if (worker_process_.IsValid()) {
TerminateProcess(worker_process_, CONTROL_C_EXIT);
worker_process_.Close();
}
}
void WorkerProcessLauncherTest::TerminateWorker(DWORD exit_code) {
if (worker_process_.IsValid())
TerminateProcess(worker_process_, exit_code);
}
void WorkerProcessLauncherTest::ConnectClient() {
channel_client_.reset(new IPC::ChannelProxy(
IPC::ChannelHandle(channel_name_),
IPC::Channel::MODE_CLIENT,
&client_listener_,
task_runner_));
launcher_->RecordSuccessfulLaunchForTest();
}
void WorkerProcessLauncherTest::DisconnectClient() {
channel_client_.reset();
}
void WorkerProcessLauncherTest::DisconnectServer() {
channel_server_.reset();
}
void WorkerProcessLauncherTest::SendToProcess(IPC::Message* message) {
if (channel_server_) {
channel_server_->Send(message);
return;
}
delete message;
}
void WorkerProcessLauncherTest::SendFakeMessageToLauncher() {
if (channel_client_)
channel_client_->Send(new ChromotingDesktopNetworkMsg_DisconnectSession());
}
void WorkerProcessLauncherTest::CrashWorker() {
launcher_->Crash(FROM_HERE);
}
void WorkerProcessLauncherTest::StartWorker() {
launcher_.reset(new WorkerProcessLauncher(launcher_delegate_.Pass(),
&server_listener_));
launcher_->SetKillProcessTimeoutForTest(base::TimeDelta::FromMilliseconds(0));
}
void WorkerProcessLauncherTest::StopWorker() {
launcher_.reset();
DisconnectClient();
channel_name_.clear();
channel_server_.reset();
task_runner_ = NULL;
}
void WorkerProcessLauncherTest::QuitMainMessageLoop() {
message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
}
void WorkerProcessLauncherTest::DoLaunchProcess() {
EXPECT_TRUE(event_handler_);
EXPECT_FALSE(worker_process_.IsValid());
WCHAR notepad[MAX_PATH + 1];
ASSERT_GT(ExpandEnvironmentStrings(
L"\045SystemRoot\045\\system32\\notepad.exe", notepad, MAX_PATH), 0u);
STARTUPINFOW startup_info = { 0 };
startup_info.cb = sizeof(startup_info);
PROCESS_INFORMATION temp_process_info = {};
ASSERT_TRUE(CreateProcess(NULL,
notepad,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&startup_info,
&temp_process_info));
base::win::ScopedProcessInformation process_information(temp_process_info);
worker_process_.Set(process_information.TakeProcessHandle());
ASSERT_TRUE(worker_process_.IsValid());
channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID();
ScopedHandle pipe;
ASSERT_TRUE(CreateIpcChannel(channel_name_, kIpcSecurityDescriptor, &pipe));
channel_server_.reset(new IPC::ChannelProxy(
IPC::ChannelHandle(pipe),
IPC::Channel::MODE_SERVER,
this,
task_runner_));
HANDLE temp_handle;
ASSERT_TRUE(DuplicateHandle(GetCurrentProcess(),
worker_process_,
GetCurrentProcess(),
&temp_handle,
0,
FALSE,
DUPLICATE_SAME_ACCESS));
ScopedHandle copy(temp_handle);
event_handler_->OnProcessLaunched(copy.Pass());
}
TEST_F(WorkerProcessLauncherTest, Start) {
EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
.Times(1)
.WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::LaunchProcess));
EXPECT_CALL(server_listener_, OnChannelConnected(_))
.Times(0);
EXPECT_CALL(server_listener_, OnPermanentError(_))
.Times(0);
StartWorker();
StopWorker();
message_loop_.Run();
}
TEST_F(WorkerProcessLauncherTest, StartAndConnect) {
EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
.Times(1)
.WillRepeatedly(Invoke(
this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
EXPECT_CALL(server_listener_, OnChannelConnected(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(this,
&WorkerProcessLauncherTest::StopWorker));
EXPECT_CALL(server_listener_, OnPermanentError(_))
.Times(0);
StartWorker();
message_loop_.Run();
}
TEST_F(WorkerProcessLauncherTest, Restart) {
EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
.Times(2)
.WillRepeatedly(Invoke(
this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
Expectation first_connect =
EXPECT_CALL(server_listener_, OnChannelConnected(_))
.Times(2)
.WillOnce(InvokeWithoutArgs(CreateFunctor(
this, &WorkerProcessLauncherTest::TerminateWorker,
CONTROL_C_EXIT)))
.WillOnce(InvokeWithoutArgs(this,
&WorkerProcessLauncherTest::StopWorker));
EXPECT_CALL(server_listener_, OnPermanentError(_))
.Times(0);
StartWorker();
message_loop_.Run();
}
TEST_F(WorkerProcessLauncherTest, DropIpcChannel) {
EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
.Times(2)
.WillRepeatedly(Invoke(
this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
Expectation first_connect =
EXPECT_CALL(server_listener_, OnChannelConnected(_))
.Times(2)
.WillOnce(InvokeWithoutArgs(
this, &WorkerProcessLauncherTest::DisconnectClient))
.WillOnce(InvokeWithoutArgs(
this, &WorkerProcessLauncherTest::StopWorker));
EXPECT_CALL(server_listener_, OnPermanentError(_))
.Times(0);
StartWorker();
message_loop_.Run();
}
TEST_F(WorkerProcessLauncherTest, PermanentError) {
EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
.Times(1)
.WillRepeatedly(Invoke(
this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
EXPECT_CALL(server_listener_, OnChannelConnected(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(CreateFunctor(
this, &WorkerProcessLauncherTest::TerminateWorker,
kMinPermanentErrorExitCode)));
EXPECT_CALL(server_listener_, OnPermanentError(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(this,
&WorkerProcessLauncherTest::StopWorker));
StartWorker();
message_loop_.Run();
}
TEST_F(WorkerProcessLauncherTest, Crash) {
EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
.Times(2)
.WillRepeatedly(Invoke(
this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
EXPECT_CALL(server_listener_, OnChannelConnected(_))
.Times(2)
.WillOnce(InvokeWithoutArgs(this,
&WorkerProcessLauncherTest::CrashWorker))
.WillOnce(InvokeWithoutArgs(this,
&WorkerProcessLauncherTest::StopWorker));
EXPECT_CALL(client_listener_, OnCrash(_, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(CreateFunctor(
this, &WorkerProcessLauncherTest::TerminateWorker,
EXCEPTION_BREAKPOINT)));
StartWorker();
message_loop_.Run();
}
TEST_F(WorkerProcessLauncherTest, CrashAnyway) {
EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
.Times(2)
.WillRepeatedly(Invoke(
this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
EXPECT_CALL(server_listener_, OnChannelConnected(_))
.Times(2)
.WillOnce(InvokeWithoutArgs(this,
&WorkerProcessLauncherTest::CrashWorker))
.WillOnce(InvokeWithoutArgs(this,
&WorkerProcessLauncherTest::StopWorker));
EXPECT_CALL(client_listener_, OnCrash(_, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(
this, &WorkerProcessLauncherTest::SendFakeMessageToLauncher));
StartWorker();
message_loop_.Run();
}
}