1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/basictypes.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/win/scoped_handle.h"
10 #include "base/win/scoped_process_information.h"
11 #include "ipc/ipc_channel.h"
12 #include "ipc/ipc_channel_proxy.h"
13 #include "ipc/ipc_listener.h"
14 #include "ipc/ipc_message.h"
15 #include "remoting/base/auto_thread_task_runner.h"
16 #include "remoting/host/chromoting_messages.h"
17 #include "remoting/host/host_exit_codes.h"
18 #include "remoting/host/ipc_util.h"
19 #include "remoting/host/win/launch_process_with_token.h"
20 #include "remoting/host/win/worker_process_launcher.h"
21 #include "remoting/host/worker_process_ipc_delegate.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gmock_mutant.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using base::win::ScopedHandle
;
28 using testing::AnyNumber
;
29 using testing::CreateFunctor
;
31 using testing::Expectation
;
32 using testing::Invoke
;
33 using testing::InvokeWithoutArgs
;
34 using testing::Return
;
40 const char kIpcSecurityDescriptor
[] = "D:(A;;GA;;;AU)";
42 class MockProcessLauncherDelegate
: public WorkerProcessLauncher::Delegate
{
44 MockProcessLauncherDelegate() {}
45 virtual ~MockProcessLauncherDelegate() {}
47 // WorkerProcessLauncher::Delegate interface.
48 MOCK_METHOD1(LaunchProcess
, void(WorkerProcessLauncher
*));
49 MOCK_METHOD1(Send
, void(IPC::Message
*));
50 MOCK_METHOD0(CloseChannel
, void());
51 MOCK_METHOD0(KillProcess
, void());
54 DISALLOW_COPY_AND_ASSIGN(MockProcessLauncherDelegate
);
57 class MockIpcDelegate
: public WorkerProcessIpcDelegate
{
60 virtual ~MockIpcDelegate() {}
62 // WorkerProcessIpcDelegate interface.
63 MOCK_METHOD1(OnChannelConnected
, void(int32
));
64 MOCK_METHOD1(OnMessageReceived
, bool(const IPC::Message
&));
65 MOCK_METHOD1(OnPermanentError
, void(int));
68 DISALLOW_COPY_AND_ASSIGN(MockIpcDelegate
);
71 class MockWorkerListener
: public IPC::Listener
{
73 MockWorkerListener() {}
74 virtual ~MockWorkerListener() {}
76 MOCK_METHOD3(OnCrash
, void(const std::string
&, const std::string
&, int));
78 // IPC::Listener implementation
79 virtual bool OnMessageReceived(const IPC::Message
& message
) override
;
82 DISALLOW_COPY_AND_ASSIGN(MockWorkerListener
);
85 bool MockWorkerListener::OnMessageReceived(const IPC::Message
& message
) {
87 IPC_BEGIN_MESSAGE_MAP(MockWorkerListener
, message
)
88 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash
, OnCrash
)
89 IPC_MESSAGE_UNHANDLED(handled
= false)
99 class WorkerProcessLauncherTest
100 : public testing::Test
,
101 public IPC::Listener
{
103 WorkerProcessLauncherTest();
104 virtual ~WorkerProcessLauncherTest();
106 virtual void SetUp() override
;
107 virtual void TearDown() override
;
109 // IPC::Listener implementation.
110 virtual bool OnMessageReceived(const IPC::Message
& message
) override
;
111 virtual void OnChannelConnected(int32 peer_pid
) override
;
112 virtual void OnChannelError() override
;
114 // WorkerProcessLauncher::Delegate mocks
116 WorkerProcessLauncher
* event_handler
);
117 void LaunchProcessAndConnect(
118 WorkerProcessLauncher
* event_handler
);
119 void FailLaunchAndStopWorker(
120 WorkerProcessLauncher
* event_handler
);
123 void TerminateWorker(DWORD exit_code
);
125 // Connects the client end of the channel (the worker process's end).
126 void ConnectClient();
128 // Disconnects the client end of the channel.
129 void DisconnectClient();
131 // Disconnects the server end of the channel (the launcher's end).
132 void DisconnectServer();
134 // Sends a message to the worker process.
135 void SendToProcess(IPC::Message
* message
);
137 // Sends a fake message to the launcher.
138 void SendFakeMessageToLauncher();
140 // Requests the worker to crash.
143 // Starts the worker.
149 // Quits |message_loop_|.
150 void QuitMainMessageLoop();
153 void DoLaunchProcess();
155 base::MessageLoopForIO message_loop_
;
156 scoped_refptr
<AutoThreadTaskRunner
> task_runner_
;
158 // Receives messages sent to the worker process.
159 MockWorkerListener client_listener_
;
161 // Receives messages sent from the worker process.
162 MockIpcDelegate server_listener_
;
164 // Implements WorkerProcessLauncher::Delegate.
165 scoped_ptr
<MockProcessLauncherDelegate
> launcher_delegate_
;
167 // The name of the IPC channel.
168 std::string channel_name_
;
170 // Client and server ends of the IPC channel.
171 scoped_ptr
<IPC::ChannelProxy
> channel_client_
;
172 scoped_ptr
<IPC::ChannelProxy
> channel_server_
;
174 WorkerProcessLauncher
* event_handler_
;
176 // The worker process launcher.
177 scoped_ptr
<WorkerProcessLauncher
> launcher_
;
179 // An event that is used to emulate the worker process's handle.
180 ScopedHandle worker_process_
;
183 WorkerProcessLauncherTest::WorkerProcessLauncherTest()
184 : event_handler_(nullptr) {
187 WorkerProcessLauncherTest::~WorkerProcessLauncherTest() {
190 void WorkerProcessLauncherTest::SetUp() {
191 task_runner_
= new AutoThreadTaskRunner(
192 message_loop_
.message_loop_proxy(),
193 base::Bind(&WorkerProcessLauncherTest::QuitMainMessageLoop
,
194 base::Unretained(this)));
196 // Set up process launcher delegate
197 launcher_delegate_
.reset(new MockProcessLauncherDelegate());
198 EXPECT_CALL(*launcher_delegate_
, Send(_
))
200 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::SendToProcess
));
201 EXPECT_CALL(*launcher_delegate_
, CloseChannel())
203 .WillRepeatedly(Invoke(this,
204 &WorkerProcessLauncherTest::DisconnectServer
));
205 EXPECT_CALL(*launcher_delegate_
, KillProcess())
207 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::KillProcess
));
209 // Set up IPC delegate.
210 EXPECT_CALL(server_listener_
, OnMessageReceived(_
))
214 void WorkerProcessLauncherTest::TearDown() {
217 bool WorkerProcessLauncherTest::OnMessageReceived(const IPC::Message
& message
) {
218 return event_handler_
->OnMessageReceived(message
);
221 void WorkerProcessLauncherTest::OnChannelConnected(int32 peer_pid
) {
222 event_handler_
->OnChannelConnected(peer_pid
);
225 void WorkerProcessLauncherTest::OnChannelError() {
226 event_handler_
->OnChannelError();
229 void WorkerProcessLauncherTest::LaunchProcess(
230 WorkerProcessLauncher
* event_handler
) {
231 EXPECT_FALSE(event_handler_
);
232 event_handler_
= event_handler
;
237 void WorkerProcessLauncherTest::LaunchProcessAndConnect(
238 WorkerProcessLauncher
* event_handler
) {
239 EXPECT_FALSE(event_handler_
);
240 event_handler_
= event_handler
;
244 task_runner_
->PostTask(
246 base::Bind(&WorkerProcessLauncherTest::ConnectClient
,
247 base::Unretained(this)));
250 void WorkerProcessLauncherTest::FailLaunchAndStopWorker(
251 WorkerProcessLauncher
* event_handler
) {
252 EXPECT_FALSE(event_handler_
);
254 event_handler
->OnFatalError();
256 task_runner_
->PostTask(
258 base::Bind(&WorkerProcessLauncherTest::StopWorker
,
259 base::Unretained(this)));
262 void WorkerProcessLauncherTest::KillProcess() {
263 event_handler_
= nullptr;
265 if (worker_process_
.IsValid()) {
266 TerminateProcess(worker_process_
.Get(), CONTROL_C_EXIT
);
267 worker_process_
.Close();
271 void WorkerProcessLauncherTest::TerminateWorker(DWORD exit_code
) {
272 if (worker_process_
.IsValid())
273 TerminateProcess(worker_process_
.Get(), exit_code
);
276 void WorkerProcessLauncherTest::ConnectClient() {
277 channel_client_
= IPC::ChannelProxy::Create(IPC::ChannelHandle(channel_name_
),
278 IPC::Channel::MODE_CLIENT
,
282 // Pretend that |kLaunchSuccessTimeoutSeconds| passed since launching
283 // the worker process. This will make the backoff algorithm think that this
284 // launch attempt was successful and it will not delay the next launch.
285 launcher_
->RecordSuccessfulLaunchForTest();
288 void WorkerProcessLauncherTest::DisconnectClient() {
289 channel_client_
.reset();
292 void WorkerProcessLauncherTest::DisconnectServer() {
293 channel_server_
.reset();
296 void WorkerProcessLauncherTest::SendToProcess(IPC::Message
* message
) {
297 if (channel_server_
) {
298 channel_server_
->Send(message
);
305 void WorkerProcessLauncherTest::SendFakeMessageToLauncher() {
307 channel_client_
->Send(new ChromotingDesktopNetworkMsg_DisconnectSession());
310 void WorkerProcessLauncherTest::CrashWorker() {
311 launcher_
->Crash(FROM_HERE
);
314 void WorkerProcessLauncherTest::StartWorker() {
315 launcher_
.reset(new WorkerProcessLauncher(
316 launcher_delegate_
.Pass(),
319 launcher_
->SetKillProcessTimeoutForTest(base::TimeDelta::FromMilliseconds(0));
322 void WorkerProcessLauncherTest::StopWorker() {
325 channel_name_
.clear();
326 channel_server_
.reset();
327 task_runner_
= nullptr;
330 void WorkerProcessLauncherTest::QuitMainMessageLoop() {
331 message_loop_
.PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
334 void WorkerProcessLauncherTest::DoLaunchProcess() {
335 EXPECT_TRUE(event_handler_
);
336 EXPECT_FALSE(worker_process_
.IsValid());
338 WCHAR notepad
[MAX_PATH
+ 1];
339 ASSERT_GT(ExpandEnvironmentStrings(
340 L
"\045SystemRoot\045\\system32\\notepad.exe", notepad
, MAX_PATH
), 0u);
342 STARTUPINFOW startup_info
= { 0 };
343 startup_info
.cb
= sizeof(startup_info
);
345 PROCESS_INFORMATION temp_process_info
= {};
346 ASSERT_TRUE(CreateProcess(nullptr,
348 nullptr, // default process attibutes
349 nullptr, // default thread attibutes
350 FALSE
, // do not inherit handles
352 nullptr, // no environment
353 nullptr, // default current directory
355 &temp_process_info
));
356 base::win::ScopedProcessInformation
process_information(temp_process_info
);
357 worker_process_
.Set(process_information
.TakeProcessHandle());
358 ASSERT_TRUE(worker_process_
.IsValid());
360 channel_name_
= IPC::Channel::GenerateUniqueRandomChannelID();
362 ASSERT_TRUE(CreateIpcChannel(channel_name_
, kIpcSecurityDescriptor
, &pipe
));
364 // Wrap the pipe into an IPC channel.
365 channel_server_
= IPC::ChannelProxy::Create(
366 IPC::ChannelHandle(pipe
.Get()), IPC::Channel::MODE_SERVER
, this,
370 ASSERT_TRUE(DuplicateHandle(GetCurrentProcess(),
371 worker_process_
.Get(),
376 DUPLICATE_SAME_ACCESS
));
377 ScopedHandle
copy(temp_handle
);
379 event_handler_
->OnProcessLaunched(copy
.Pass());
382 TEST_F(WorkerProcessLauncherTest
, Start
) {
383 EXPECT_CALL(*launcher_delegate_
, LaunchProcess(_
))
385 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::LaunchProcess
));
387 EXPECT_CALL(server_listener_
, OnChannelConnected(_
))
389 EXPECT_CALL(server_listener_
, OnPermanentError(_
))
397 // Starts and connects to the worker process. Expect OnChannelConnected to be
399 TEST_F(WorkerProcessLauncherTest
, StartAndConnect
) {
400 EXPECT_CALL(*launcher_delegate_
, LaunchProcess(_
))
402 .WillRepeatedly(Invoke(
403 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect
));
405 EXPECT_CALL(server_listener_
, OnChannelConnected(_
))
407 .WillOnce(InvokeWithoutArgs(this,
408 &WorkerProcessLauncherTest::StopWorker
));
409 EXPECT_CALL(server_listener_
, OnPermanentError(_
))
416 // Kills the worker process after the 1st connect and expects it to be
418 TEST_F(WorkerProcessLauncherTest
, Restart
) {
419 EXPECT_CALL(*launcher_delegate_
, LaunchProcess(_
))
421 .WillRepeatedly(Invoke(
422 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect
));
423 Expectation first_connect
=
424 EXPECT_CALL(server_listener_
, OnChannelConnected(_
))
426 .WillOnce(InvokeWithoutArgs(CreateFunctor(
427 this, &WorkerProcessLauncherTest::TerminateWorker
,
429 .WillOnce(InvokeWithoutArgs(this,
430 &WorkerProcessLauncherTest::StopWorker
));
432 EXPECT_CALL(server_listener_
, OnPermanentError(_
))
439 // Drops the IPC channel to the worker process after the 1st connect and expects
440 // the worker process to be restarted.
441 TEST_F(WorkerProcessLauncherTest
, DropIpcChannel
) {
442 EXPECT_CALL(*launcher_delegate_
, LaunchProcess(_
))
444 .WillRepeatedly(Invoke(
445 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect
));
447 Expectation first_connect
=
448 EXPECT_CALL(server_listener_
, OnChannelConnected(_
))
450 .WillOnce(InvokeWithoutArgs(
451 this, &WorkerProcessLauncherTest::DisconnectClient
))
452 .WillOnce(InvokeWithoutArgs(
453 this, &WorkerProcessLauncherTest::StopWorker
));
455 EXPECT_CALL(server_listener_
, OnPermanentError(_
))
462 // Returns a permanent error exit code and expects OnPermanentError() to be
464 TEST_F(WorkerProcessLauncherTest
, PermanentError
) {
465 EXPECT_CALL(*launcher_delegate_
, LaunchProcess(_
))
467 .WillRepeatedly(Invoke(
468 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect
));
470 EXPECT_CALL(server_listener_
, OnChannelConnected(_
))
472 .WillOnce(InvokeWithoutArgs(CreateFunctor(
473 this, &WorkerProcessLauncherTest::TerminateWorker
,
474 kMinPermanentErrorExitCode
)));
475 EXPECT_CALL(server_listener_
, OnPermanentError(_
))
477 .WillOnce(InvokeWithoutArgs(this,
478 &WorkerProcessLauncherTest::StopWorker
));
484 // Requests the worker to crash and expects it to honor the request.
485 TEST_F(WorkerProcessLauncherTest
, Crash
) {
486 EXPECT_CALL(*launcher_delegate_
, LaunchProcess(_
))
488 .WillRepeatedly(Invoke(
489 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect
));
491 EXPECT_CALL(server_listener_
, OnChannelConnected(_
))
493 .WillOnce(InvokeWithoutArgs(this,
494 &WorkerProcessLauncherTest::CrashWorker
))
495 .WillOnce(InvokeWithoutArgs(this,
496 &WorkerProcessLauncherTest::StopWorker
));
498 EXPECT_CALL(client_listener_
, OnCrash(_
, _
, _
))
500 .WillOnce(InvokeWithoutArgs(CreateFunctor(
501 this, &WorkerProcessLauncherTest::TerminateWorker
,
502 EXCEPTION_BREAKPOINT
)));
508 // Requests the worker to crash and terminates the worker even if it does not
510 TEST_F(WorkerProcessLauncherTest
, CrashAnyway
) {
511 EXPECT_CALL(*launcher_delegate_
, LaunchProcess(_
))
513 .WillRepeatedly(Invoke(
514 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect
));
516 EXPECT_CALL(server_listener_
, OnChannelConnected(_
))
518 .WillOnce(InvokeWithoutArgs(this,
519 &WorkerProcessLauncherTest::CrashWorker
))
520 .WillOnce(InvokeWithoutArgs(this,
521 &WorkerProcessLauncherTest::StopWorker
));
523 // Ignore the crash request and try send another message to the launcher.
524 EXPECT_CALL(client_listener_
, OnCrash(_
, _
, _
))
526 .WillOnce(InvokeWithoutArgs(
527 this, &WorkerProcessLauncherTest::SendFakeMessageToLauncher
));
533 } // namespace remoting