Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / remoting / host / win / worker_process_launcher_unittest.cc
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.
4
5 #include "base/basictypes.h"
6 #include "base/bind.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"
25
26 using base::win::ScopedHandle;
27 using testing::_;
28 using testing::AnyNumber;
29 using testing::CreateFunctor;
30 using testing::DoAll;
31 using testing::Expectation;
32 using testing::Invoke;
33 using testing::InvokeWithoutArgs;
34 using testing::Return;
35
36 namespace remoting {
37
38 namespace {
39
40 const char kIpcSecurityDescriptor[] = "D:(A;;GA;;;AU)";
41
42 class MockProcessLauncherDelegate : public WorkerProcessLauncher::Delegate {
43  public:
44   MockProcessLauncherDelegate() {}
45   virtual ~MockProcessLauncherDelegate() {}
46
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());
52
53  private:
54   DISALLOW_COPY_AND_ASSIGN(MockProcessLauncherDelegate);
55 };
56
57 class MockIpcDelegate : public WorkerProcessIpcDelegate {
58  public:
59   MockIpcDelegate() {}
60   virtual ~MockIpcDelegate() {}
61
62   // WorkerProcessIpcDelegate interface.
63   MOCK_METHOD1(OnChannelConnected, void(int32));
64   MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message&));
65   MOCK_METHOD1(OnPermanentError, void(int));
66
67  private:
68   DISALLOW_COPY_AND_ASSIGN(MockIpcDelegate);
69 };
70
71 class MockWorkerListener : public IPC::Listener {
72  public:
73   MockWorkerListener() {}
74   virtual ~MockWorkerListener() {}
75
76   MOCK_METHOD3(OnCrash, void(const std::string&, const std::string&, int));
77
78   // IPC::Listener implementation
79   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
80
81  private:
82   DISALLOW_COPY_AND_ASSIGN(MockWorkerListener);
83 };
84
85 bool MockWorkerListener::OnMessageReceived(const IPC::Message& message) {
86   bool handled = true;
87   IPC_BEGIN_MESSAGE_MAP(MockWorkerListener, message)
88     IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash)
89     IPC_MESSAGE_UNHANDLED(handled = false)
90   IPC_END_MESSAGE_MAP()
91
92   EXPECT_TRUE(handled);
93
94   return handled;
95 }
96
97 }  // namespace
98
99 class WorkerProcessLauncherTest
100     : public testing::Test,
101       public IPC::Listener {
102  public:
103   WorkerProcessLauncherTest();
104   virtual ~WorkerProcessLauncherTest();
105
106   virtual void SetUp() OVERRIDE;
107   virtual void TearDown() OVERRIDE;
108
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;
113
114   // WorkerProcessLauncher::Delegate mocks
115   void LaunchProcess(
116       WorkerProcessLauncher* event_handler);
117   void LaunchProcessAndConnect(
118       WorkerProcessLauncher* event_handler);
119   void FailLaunchAndStopWorker(
120       WorkerProcessLauncher* event_handler);
121   void KillProcess();
122
123   void TerminateWorker(DWORD exit_code);
124
125   // Connects the client end of the channel (the worker process's end).
126   void ConnectClient();
127
128   // Disconnects the client end of the channel.
129   void DisconnectClient();
130
131   // Disconnects the server end of the channel (the launcher's end).
132   void DisconnectServer();
133
134   // Sends a message to the worker process.
135   void SendToProcess(IPC::Message* message);
136
137   // Sends a fake message to the launcher.
138   void SendFakeMessageToLauncher();
139
140   // Requests the worker to crash.
141   void CrashWorker();
142
143   // Starts the worker.
144   void StartWorker();
145
146   // Stops the worker.
147   void StopWorker();
148
149   // Quits |message_loop_|.
150   void QuitMainMessageLoop();
151
152  protected:
153   void DoLaunchProcess();
154
155   base::MessageLoopForIO message_loop_;
156   scoped_refptr<AutoThreadTaskRunner> task_runner_;
157
158   // Receives messages sent to the worker process.
159   MockWorkerListener client_listener_;
160
161   // Receives messages sent from the worker process.
162   MockIpcDelegate server_listener_;
163
164   // Implements WorkerProcessLauncher::Delegate.
165   scoped_ptr<MockProcessLauncherDelegate> launcher_delegate_;
166
167   // The name of the IPC channel.
168   std::string channel_name_;
169
170   // Client and server ends of the IPC channel.
171   scoped_ptr<IPC::ChannelProxy> channel_client_;
172   scoped_ptr<IPC::ChannelProxy> channel_server_;
173
174   WorkerProcessLauncher* event_handler_;
175
176   // The worker process launcher.
177   scoped_ptr<WorkerProcessLauncher> launcher_;
178
179   // An event that is used to emulate the worker process's handle.
180   ScopedHandle worker_process_;
181 };
182
183 WorkerProcessLauncherTest::WorkerProcessLauncherTest() : event_handler_(NULL) {
184 }
185
186 WorkerProcessLauncherTest::~WorkerProcessLauncherTest() {
187 }
188
189 void WorkerProcessLauncherTest::SetUp() {
190   task_runner_ = new AutoThreadTaskRunner(
191       message_loop_.message_loop_proxy(),
192       base::Bind(&WorkerProcessLauncherTest::QuitMainMessageLoop,
193                  base::Unretained(this)));
194
195   // Set up process launcher delegate
196   launcher_delegate_.reset(new MockProcessLauncherDelegate());
197   EXPECT_CALL(*launcher_delegate_, Send(_))
198       .Times(AnyNumber())
199       .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::SendToProcess));
200   EXPECT_CALL(*launcher_delegate_, CloseChannel())
201       .Times(AnyNumber())
202       .WillRepeatedly(Invoke(this,
203                              &WorkerProcessLauncherTest::DisconnectServer));
204   EXPECT_CALL(*launcher_delegate_, KillProcess())
205       .Times(AnyNumber())
206       .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::KillProcess));
207
208   // Set up IPC delegate.
209   EXPECT_CALL(server_listener_, OnMessageReceived(_))
210       .Times(0);
211 }
212
213 void WorkerProcessLauncherTest::TearDown() {
214 }
215
216 bool WorkerProcessLauncherTest::OnMessageReceived(const IPC::Message& message) {
217   return event_handler_->OnMessageReceived(message);
218 }
219
220 void WorkerProcessLauncherTest::OnChannelConnected(int32 peer_pid) {
221   event_handler_->OnChannelConnected(peer_pid);
222 }
223
224 void WorkerProcessLauncherTest::OnChannelError() {
225   event_handler_->OnChannelError();
226 }
227
228 void WorkerProcessLauncherTest::LaunchProcess(
229     WorkerProcessLauncher* event_handler) {
230   EXPECT_FALSE(event_handler_);
231   event_handler_ = event_handler;
232
233   DoLaunchProcess();
234 }
235
236 void WorkerProcessLauncherTest::LaunchProcessAndConnect(
237     WorkerProcessLauncher* event_handler) {
238   EXPECT_FALSE(event_handler_);
239   event_handler_ = event_handler;
240
241   DoLaunchProcess();
242
243   task_runner_->PostTask(
244       FROM_HERE,
245       base::Bind(&WorkerProcessLauncherTest::ConnectClient,
246                  base::Unretained(this)));
247 }
248
249 void WorkerProcessLauncherTest::FailLaunchAndStopWorker(
250     WorkerProcessLauncher* event_handler) {
251   EXPECT_FALSE(event_handler_);
252
253   event_handler->OnFatalError();
254
255   task_runner_->PostTask(
256       FROM_HERE,
257       base::Bind(&WorkerProcessLauncherTest::StopWorker,
258                  base::Unretained(this)));
259 }
260
261 void WorkerProcessLauncherTest::KillProcess() {
262   event_handler_ = NULL;
263
264   if (worker_process_.IsValid()) {
265     TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT);
266     worker_process_.Close();
267   }
268 }
269
270 void WorkerProcessLauncherTest::TerminateWorker(DWORD exit_code) {
271   if (worker_process_.IsValid())
272     TerminateProcess(worker_process_.Get(), exit_code);
273 }
274
275 void WorkerProcessLauncherTest::ConnectClient() {
276   channel_client_ = IPC::ChannelProxy::Create(IPC::ChannelHandle(channel_name_),
277                                               IPC::Channel::MODE_CLIENT,
278                                               &client_listener_,
279                                               task_runner_);
280
281   // Pretend that |kLaunchSuccessTimeoutSeconds| passed since launching
282   // the worker process. This will make the backoff algorithm think that this
283   // launch attempt was successful and it will not delay the next launch.
284   launcher_->RecordSuccessfulLaunchForTest();
285 }
286
287 void WorkerProcessLauncherTest::DisconnectClient() {
288   channel_client_.reset();
289 }
290
291 void WorkerProcessLauncherTest::DisconnectServer() {
292   channel_server_.reset();
293 }
294
295 void WorkerProcessLauncherTest::SendToProcess(IPC::Message* message) {
296   if (channel_server_) {
297     channel_server_->Send(message);
298     return;
299   }
300
301   delete message;
302 }
303
304 void WorkerProcessLauncherTest::SendFakeMessageToLauncher() {
305   if (channel_client_)
306     channel_client_->Send(new ChromotingDesktopNetworkMsg_DisconnectSession());
307 }
308
309 void WorkerProcessLauncherTest::CrashWorker() {
310   launcher_->Crash(FROM_HERE);
311 }
312
313 void WorkerProcessLauncherTest::StartWorker() {
314   launcher_.reset(new WorkerProcessLauncher(
315       launcher_delegate_.PassAs<WorkerProcessLauncher::Delegate>(),
316       &server_listener_));
317
318   launcher_->SetKillProcessTimeoutForTest(base::TimeDelta::FromMilliseconds(0));
319 }
320
321 void WorkerProcessLauncherTest::StopWorker() {
322   launcher_.reset();
323   DisconnectClient();
324   channel_name_.clear();
325   channel_server_.reset();
326   task_runner_ = NULL;
327 }
328
329 void WorkerProcessLauncherTest::QuitMainMessageLoop() {
330   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
331 }
332
333 void WorkerProcessLauncherTest::DoLaunchProcess() {
334   EXPECT_TRUE(event_handler_);
335   EXPECT_FALSE(worker_process_.IsValid());
336
337   WCHAR notepad[MAX_PATH + 1];
338   ASSERT_GT(ExpandEnvironmentStrings(
339       L"\045SystemRoot\045\\system32\\notepad.exe", notepad, MAX_PATH), 0u);
340
341   STARTUPINFOW startup_info = { 0 };
342   startup_info.cb = sizeof(startup_info);
343
344   PROCESS_INFORMATION temp_process_info = {};
345   ASSERT_TRUE(CreateProcess(NULL,
346                             notepad,
347                             NULL,   // default process attibutes
348                             NULL,   // default thread attibutes
349                             FALSE,  // do not inherit handles
350                             CREATE_SUSPENDED,
351                             NULL,   // no environment
352                             NULL,   // default current directory
353                             &startup_info,
354                             &temp_process_info));
355   base::win::ScopedProcessInformation process_information(temp_process_info);
356   worker_process_.Set(process_information.TakeProcessHandle());
357   ASSERT_TRUE(worker_process_.IsValid());
358
359   channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID();
360   ScopedHandle pipe;
361   ASSERT_TRUE(CreateIpcChannel(channel_name_, kIpcSecurityDescriptor, &pipe));
362
363   // Wrap the pipe into an IPC channel.
364   channel_server_ = IPC::ChannelProxy::Create(
365       IPC::ChannelHandle(pipe.Get()), IPC::Channel::MODE_SERVER, this,
366       task_runner_);
367
368   HANDLE temp_handle;
369   ASSERT_TRUE(DuplicateHandle(GetCurrentProcess(),
370                               worker_process_.Get(),
371                               GetCurrentProcess(),
372                               &temp_handle,
373                               0,
374                               FALSE,
375                               DUPLICATE_SAME_ACCESS));
376   ScopedHandle copy(temp_handle);
377
378   event_handler_->OnProcessLaunched(copy.Pass());
379 }
380
381 TEST_F(WorkerProcessLauncherTest, Start) {
382   EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
383       .Times(1)
384       .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::LaunchProcess));
385
386   EXPECT_CALL(server_listener_, OnChannelConnected(_))
387       .Times(0);
388   EXPECT_CALL(server_listener_, OnPermanentError(_))
389       .Times(0);
390
391   StartWorker();
392   StopWorker();
393   message_loop_.Run();
394 }
395
396 // Starts and connects to the worker process. Expect OnChannelConnected to be
397 // called.
398 TEST_F(WorkerProcessLauncherTest, StartAndConnect) {
399   EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
400       .Times(1)
401       .WillRepeatedly(Invoke(
402           this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
403
404   EXPECT_CALL(server_listener_, OnChannelConnected(_))
405       .Times(1)
406       .WillOnce(InvokeWithoutArgs(this,
407                                   &WorkerProcessLauncherTest::StopWorker));
408   EXPECT_CALL(server_listener_, OnPermanentError(_))
409       .Times(0);
410
411   StartWorker();
412   message_loop_.Run();
413 }
414
415 // Kills the worker process after the 1st connect and expects it to be
416 // restarted.
417 TEST_F(WorkerProcessLauncherTest, Restart) {
418   EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
419       .Times(2)
420       .WillRepeatedly(Invoke(
421           this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
422   Expectation first_connect =
423       EXPECT_CALL(server_listener_, OnChannelConnected(_))
424           .Times(2)
425           .WillOnce(InvokeWithoutArgs(CreateFunctor(
426               this, &WorkerProcessLauncherTest::TerminateWorker,
427               CONTROL_C_EXIT)))
428           .WillOnce(InvokeWithoutArgs(this,
429                                       &WorkerProcessLauncherTest::StopWorker));
430
431   EXPECT_CALL(server_listener_, OnPermanentError(_))
432       .Times(0);
433
434   StartWorker();
435   message_loop_.Run();
436 }
437
438 // Drops the IPC channel to the worker process after the 1st connect and expects
439 // the worker process to be restarted.
440 TEST_F(WorkerProcessLauncherTest, DropIpcChannel) {
441   EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
442       .Times(2)
443       .WillRepeatedly(Invoke(
444           this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
445
446   Expectation first_connect =
447       EXPECT_CALL(server_listener_, OnChannelConnected(_))
448           .Times(2)
449           .WillOnce(InvokeWithoutArgs(
450               this, &WorkerProcessLauncherTest::DisconnectClient))
451           .WillOnce(InvokeWithoutArgs(
452               this, &WorkerProcessLauncherTest::StopWorker));
453
454   EXPECT_CALL(server_listener_, OnPermanentError(_))
455       .Times(0);
456
457   StartWorker();
458   message_loop_.Run();
459 }
460
461 // Returns a permanent error exit code and expects OnPermanentError() to be
462 // invoked.
463 TEST_F(WorkerProcessLauncherTest, PermanentError) {
464   EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
465       .Times(1)
466       .WillRepeatedly(Invoke(
467           this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
468
469   EXPECT_CALL(server_listener_, OnChannelConnected(_))
470       .Times(1)
471       .WillOnce(InvokeWithoutArgs(CreateFunctor(
472           this, &WorkerProcessLauncherTest::TerminateWorker,
473           kMinPermanentErrorExitCode)));
474   EXPECT_CALL(server_listener_, OnPermanentError(_))
475       .Times(1)
476       .WillOnce(InvokeWithoutArgs(this,
477                                   &WorkerProcessLauncherTest::StopWorker));
478
479   StartWorker();
480   message_loop_.Run();
481 }
482
483 // Requests the worker to crash and expects it to honor the request.
484 TEST_F(WorkerProcessLauncherTest, Crash) {
485   EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
486       .Times(2)
487       .WillRepeatedly(Invoke(
488           this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
489
490   EXPECT_CALL(server_listener_, OnChannelConnected(_))
491       .Times(2)
492       .WillOnce(InvokeWithoutArgs(this,
493                                   &WorkerProcessLauncherTest::CrashWorker))
494       .WillOnce(InvokeWithoutArgs(this,
495                                   &WorkerProcessLauncherTest::StopWorker));
496
497   EXPECT_CALL(client_listener_, OnCrash(_, _, _))
498       .Times(1)
499       .WillOnce(InvokeWithoutArgs(CreateFunctor(
500           this, &WorkerProcessLauncherTest::TerminateWorker,
501           EXCEPTION_BREAKPOINT)));
502
503   StartWorker();
504   message_loop_.Run();
505 }
506
507 // Requests the worker to crash and terminates the worker even if it does not
508 // comply.
509 TEST_F(WorkerProcessLauncherTest, CrashAnyway) {
510   EXPECT_CALL(*launcher_delegate_, LaunchProcess(_))
511       .Times(2)
512       .WillRepeatedly(Invoke(
513           this, &WorkerProcessLauncherTest::LaunchProcessAndConnect));
514
515   EXPECT_CALL(server_listener_, OnChannelConnected(_))
516       .Times(2)
517       .WillOnce(InvokeWithoutArgs(this,
518                                   &WorkerProcessLauncherTest::CrashWorker))
519       .WillOnce(InvokeWithoutArgs(this,
520                                   &WorkerProcessLauncherTest::StopWorker));
521
522   // Ignore the crash request and try send another message to the launcher.
523   EXPECT_CALL(client_listener_, OnCrash(_, _, _))
524       .Times(1)
525       .WillOnce(InvokeWithoutArgs(
526           this, &WorkerProcessLauncherTest::SendFakeMessageToLauncher));
527
528   StartWorker();
529   message_loop_.Run();
530 }
531
532 }  // namespace remoting