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
26using base::win::ScopedHandle;
27using testing::_;
28using testing::AnyNumber;
29using testing::CreateFunctor;
30using testing::DoAll;
31using testing::Expectation;
32using testing::Invoke;
33using testing::InvokeWithoutArgs;
34using testing::Return;
35
36namespace remoting {
37
38namespace {
39
40const char kIpcSecurityDescriptor[] = "D:(A;;GA;;;AU)";
41
42class 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
57class 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
71class 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
85bool 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
99class 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
183WorkerProcessLauncherTest::WorkerProcessLauncherTest() : event_handler_(NULL) {
184}
185
186WorkerProcessLauncherTest::~WorkerProcessLauncherTest() {
187}
188
189void 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
213void WorkerProcessLauncherTest::TearDown() {
214}
215
216bool WorkerProcessLauncherTest::OnMessageReceived(const IPC::Message& message) {
217  return event_handler_->OnMessageReceived(message);
218}
219
220void WorkerProcessLauncherTest::OnChannelConnected(int32 peer_pid) {
221  event_handler_->OnChannelConnected(peer_pid);
222}
223
224void WorkerProcessLauncherTest::OnChannelError() {
225  event_handler_->OnChannelError();
226}
227
228void WorkerProcessLauncherTest::LaunchProcess(
229    WorkerProcessLauncher* event_handler) {
230  EXPECT_FALSE(event_handler_);
231  event_handler_ = event_handler;
232
233  DoLaunchProcess();
234}
235
236void 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
249void 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
261void 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
270void WorkerProcessLauncherTest::TerminateWorker(DWORD exit_code) {
271  if (worker_process_.IsValid())
272    TerminateProcess(worker_process_.Get(), exit_code);
273}
274
275void 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
287void WorkerProcessLauncherTest::DisconnectClient() {
288  channel_client_.reset();
289}
290
291void WorkerProcessLauncherTest::DisconnectServer() {
292  channel_server_.reset();
293}
294
295void WorkerProcessLauncherTest::SendToProcess(IPC::Message* message) {
296  if (channel_server_) {
297    channel_server_->Send(message);
298    return;
299  }
300
301  delete message;
302}
303
304void WorkerProcessLauncherTest::SendFakeMessageToLauncher() {
305  if (channel_client_)
306    channel_client_->Send(new ChromotingDesktopNetworkMsg_DisconnectSession());
307}
308
309void WorkerProcessLauncherTest::CrashWorker() {
310  launcher_->Crash(FROM_HERE);
311}
312
313void 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
321void WorkerProcessLauncherTest::StopWorker() {
322  launcher_.reset();
323  DisconnectClient();
324  channel_name_.clear();
325  channel_server_.reset();
326  task_runner_ = NULL;
327}
328
329void WorkerProcessLauncherTest::QuitMainMessageLoop() {
330  message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
331}
332
333void 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
381TEST_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.
398TEST_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.
417TEST_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.
440TEST_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.
463TEST_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.
484TEST_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.
509TEST_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
533