1// Copyright (c) 2013 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/bind.h"
6#include "base/bind_helpers.h"
7#include "base/callback.h"
8#include "base/memory/ref_counted.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "base/process/process.h"
12#include "base/process/process_handle.h"
13#include "base/run_loop.h"
14#include "ipc/ipc_channel.h"
15#include "ipc/ipc_channel_proxy.h"
16#include "ipc/ipc_listener.h"
17#include "ipc/ipc_message.h"
18#include "ipc/ipc_platform_file.h"
19#include "remoting/base/auto_thread.h"
20#include "remoting/base/auto_thread_task_runner.h"
21#include "remoting/base/constants.h"
22#include "remoting/host/chromoting_messages.h"
23#include "remoting/host/desktop_process.h"
24#include "remoting/host/desktop_session.h"
25#include "remoting/host/desktop_session_connector.h"
26#include "remoting/host/desktop_session_proxy.h"
27#include "remoting/host/fake_desktop_capturer.h"
28#include "remoting/host/fake_mouse_cursor_monitor.h"
29#include "remoting/host/host_mock_objects.h"
30#include "remoting/host/ipc_desktop_environment.h"
31#include "remoting/protocol/protocol_mock_objects.h"
32#include "testing/gmock/include/gmock/gmock.h"
33#include "testing/gtest/include/gtest/gtest.h"
34#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
35#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
36#include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
37
38using testing::_;
39using testing::AnyNumber;
40using testing::AtLeast;
41using testing::AtMost;
42using testing::DeleteArg;
43using testing::DoAll;
44using testing::Return;
45using testing::ReturnRef;
46
47namespace remoting {
48
49namespace {
50
51// Receives messages sent from the network process to the daemon.
52class FakeDaemonSender : public IPC::Sender {
53 public:
54  FakeDaemonSender() {}
55  virtual ~FakeDaemonSender() {}
56
57  // IPC::Sender implementation.
58  virtual bool Send(IPC::Message* message) OVERRIDE;
59
60  MOCK_METHOD3(ConnectTerminal, void(int, const ScreenResolution&, bool));
61  MOCK_METHOD1(DisconnectTerminal, void(int));
62  MOCK_METHOD2(SetScreenResolution, void(int, const ScreenResolution&));
63
64 private:
65  void OnMessageReceived(const IPC::Message& message);
66
67  DISALLOW_COPY_AND_ASSIGN(FakeDaemonSender);
68};
69
70// Receives messages sent from the desktop process to the daemon.
71class MockDaemonListener : public IPC::Listener {
72 public:
73  MockDaemonListener() {}
74  virtual ~MockDaemonListener() {}
75
76  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
77
78  MOCK_METHOD1(OnDesktopAttached, void(IPC::PlatformFileForTransit));
79  MOCK_METHOD1(OnChannelConnected, void(int32));
80  MOCK_METHOD0(OnChannelError, void());
81
82 private:
83  DISALLOW_COPY_AND_ASSIGN(MockDaemonListener);
84};
85
86bool FakeDaemonSender::Send(IPC::Message* message) {
87  OnMessageReceived(*message);
88  delete message;
89  return true;
90}
91
92void FakeDaemonSender::OnMessageReceived(const IPC::Message& message) {
93  bool handled = true;
94  IPC_BEGIN_MESSAGE_MAP(FakeDaemonSender, message)
95    IPC_MESSAGE_HANDLER(ChromotingNetworkHostMsg_ConnectTerminal,
96                        ConnectTerminal)
97    IPC_MESSAGE_HANDLER(ChromotingNetworkHostMsg_DisconnectTerminal,
98                        DisconnectTerminal)
99    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_SetScreenResolution,
100                        SetScreenResolution)
101    IPC_MESSAGE_UNHANDLED(handled = false)
102  IPC_END_MESSAGE_MAP()
103
104  EXPECT_TRUE(handled);
105}
106
107bool MockDaemonListener::OnMessageReceived(const IPC::Message& message) {
108  bool handled = true;
109  IPC_BEGIN_MESSAGE_MAP(MockDaemonListener, message)
110    IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached,
111                        OnDesktopAttached)
112    IPC_MESSAGE_UNHANDLED(handled = false)
113  IPC_END_MESSAGE_MAP()
114
115  EXPECT_TRUE(handled);
116  return handled;
117}
118
119}  // namespace
120
121class IpcDesktopEnvironmentTest : public testing::Test {
122 public:
123  IpcDesktopEnvironmentTest();
124  virtual ~IpcDesktopEnvironmentTest();
125
126  virtual void SetUp() OVERRIDE;
127
128  void ConnectTerminal(int terminal_id,
129                       const ScreenResolution& resolution,
130                       bool virtual_terminal);
131  void DisconnectTerminal(int terminal_id);
132
133  // Creates a DesktopEnvironment with a fake webrtc::DesktopCapturer, to mock
134  // DesktopEnvironmentFactory::Create().
135  DesktopEnvironment* CreateDesktopEnvironment();
136
137  // Creates a dummy InputInjector, to mock
138  // DesktopEnvironment::CreateInputInjector().
139  InputInjector* CreateInputInjector();
140
141  // Creates a fake webrtc::DesktopCapturer, to mock
142  // DesktopEnvironment::CreateVideoCapturer().
143  webrtc::DesktopCapturer* CreateVideoCapturer();
144
145  // Creates a MockMouseCursorMonitor, to mock
146  // DesktopEnvironment::CreateMouseCursorMonitor
147  webrtc::MouseCursorMonitor* CreateMouseCursorMonitor();
148
149  void DeleteDesktopEnvironment();
150
151  // Forwards |event| to |clipboard_stub_|.
152  void ReflectClipboardEvent(const protocol::ClipboardEvent& event);
153
154 protected:
155  // Creates and starts an instance of desktop process object.
156  void CreateDesktopProcess();
157
158  // Destroys the desktop process object created by CreateDesktopProcess().
159  void DestoyDesktopProcess();
160
161  void OnDisconnectCallback();
162
163  // Invoked when ChromotingDesktopDaemonMsg_DesktopAttached message is
164  // received.
165  void OnDesktopAttached(IPC::PlatformFileForTransit desktop_pipe);
166
167  // The main message loop.
168  base::MessageLoopForUI message_loop_;
169
170  // Runs until |desktop_session_proxy_| is connected to the desktop.
171  scoped_ptr<base::RunLoop> setup_run_loop_;
172
173  // Runs until there are references to |task_runner_|.
174  base::RunLoop main_run_loop_;
175
176  scoped_refptr<AutoThreadTaskRunner> task_runner_;
177  scoped_refptr<AutoThreadTaskRunner> io_task_runner_;
178
179  std::string client_jid_;
180
181  // Clipboard stub that receives clipboard events from the desktop process.
182  protocol::ClipboardStub* clipboard_stub_;
183
184  // The daemons's end of the daemon-to-desktop channel.
185  scoped_ptr<IPC::ChannelProxy> desktop_channel_;
186
187  // Name of the daemon-to-desktop channel.
188  std::string desktop_channel_name_;
189
190  // Delegate that is passed to |desktop_channel_|.
191  MockDaemonListener desktop_listener_;
192
193  FakeDaemonSender daemon_channel_;
194
195  scoped_ptr<IpcDesktopEnvironmentFactory> desktop_environment_factory_;
196  scoped_ptr<DesktopEnvironment> desktop_environment_;
197
198  // The IPC input injector.
199  scoped_ptr<InputInjector> input_injector_;
200
201  // The IPC screen controls.
202  scoped_ptr<ScreenControls> screen_controls_;
203
204  // The IPC screen capturer.
205  scoped_ptr<webrtc::DesktopCapturer> video_capturer_;
206
207  // Represents the desktop process running in a user session.
208  scoped_ptr<DesktopProcess> desktop_process_;
209
210  // Input injector owned by |desktop_process_|.
211  MockInputInjector* remote_input_injector_;
212
213  // The last |terminal_id| passed to ConnectTermina();
214  int terminal_id_;
215
216  webrtc::MockScreenCapturerCallback desktop_capturer_callback_;
217
218  MockClientSessionControl client_session_control_;
219  base::WeakPtrFactory<ClientSessionControl> client_session_control_factory_;
220};
221
222IpcDesktopEnvironmentTest::IpcDesktopEnvironmentTest()
223    : client_jid_("user@domain/rest-of-jid"),
224      clipboard_stub_(NULL),
225      remote_input_injector_(NULL),
226      terminal_id_(-1),
227      client_session_control_factory_(&client_session_control_) {
228}
229
230IpcDesktopEnvironmentTest::~IpcDesktopEnvironmentTest() {
231}
232
233void IpcDesktopEnvironmentTest::SetUp() {
234  // Arrange to run |message_loop_| until no components depend on it.
235  task_runner_ = new AutoThreadTaskRunner(
236      message_loop_.message_loop_proxy(), main_run_loop_.QuitClosure());
237
238  io_task_runner_ = AutoThread::CreateWithType(
239      "IPC thread", task_runner_, base::MessageLoop::TYPE_IO);
240
241  setup_run_loop_.reset(new base::RunLoop());
242
243  // Set expectation that the DaemonProcess will send DesktopAttached message
244  // once it is ready.
245  EXPECT_CALL(desktop_listener_, OnChannelConnected(_))
246      .Times(AnyNumber());
247  EXPECT_CALL(desktop_listener_, OnDesktopAttached(_))
248      .Times(AnyNumber())
249      .WillRepeatedly(Invoke(this,
250                             &IpcDesktopEnvironmentTest::OnDesktopAttached));
251  EXPECT_CALL(desktop_listener_, OnChannelError())
252      .Times(AnyNumber())
253      .WillOnce(Invoke(this,
254                       &IpcDesktopEnvironmentTest::DestoyDesktopProcess));
255
256  // Intercept requests to connect and disconnect a terminal.
257  EXPECT_CALL(daemon_channel_, ConnectTerminal(_, _, _))
258      .Times(AnyNumber())
259      .WillRepeatedly(Invoke(this,
260                             &IpcDesktopEnvironmentTest::ConnectTerminal));
261  EXPECT_CALL(daemon_channel_, DisconnectTerminal(_))
262      .Times(AnyNumber())
263      .WillRepeatedly(Invoke(this,
264                             &IpcDesktopEnvironmentTest::DisconnectTerminal));
265
266  EXPECT_CALL(client_session_control_, client_jid())
267      .Times(AnyNumber())
268      .WillRepeatedly(ReturnRef(client_jid_));
269  EXPECT_CALL(client_session_control_, DisconnectSession())
270      .Times(AnyNumber())
271      .WillRepeatedly(Invoke(
272          this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
273  EXPECT_CALL(client_session_control_, OnLocalMouseMoved(_))
274      .Times(0);
275  EXPECT_CALL(client_session_control_, SetDisableInputs(_))
276      .Times(0);
277
278  // Create a desktop environment instance.
279  desktop_environment_factory_.reset(new IpcDesktopEnvironmentFactory(
280      task_runner_,
281      task_runner_,
282      task_runner_,
283      io_task_runner_,
284      &daemon_channel_));
285  desktop_environment_ = desktop_environment_factory_->Create(
286      client_session_control_factory_.GetWeakPtr());
287
288  screen_controls_ = desktop_environment_->CreateScreenControls();
289
290  // Create the input injector.
291  input_injector_ = desktop_environment_->CreateInputInjector();
292
293  // Create the screen capturer.
294  video_capturer_ =
295      desktop_environment_->CreateVideoCapturer();
296
297  desktop_environment_->SetCapabilities(std::string());
298}
299
300void IpcDesktopEnvironmentTest::ConnectTerminal(
301    int terminal_id,
302    const ScreenResolution& resolution,
303    bool virtual_terminal) {
304  EXPECT_NE(terminal_id_, terminal_id);
305
306  terminal_id_ = terminal_id;
307  CreateDesktopProcess();
308}
309
310void IpcDesktopEnvironmentTest::DisconnectTerminal(int terminal_id) {
311  EXPECT_EQ(terminal_id_, terminal_id);
312
313  // The IPC desktop environment is fully destroyed now. Release the remaining
314  // task runners.
315  desktop_environment_factory_.reset();
316}
317
318DesktopEnvironment* IpcDesktopEnvironmentTest::CreateDesktopEnvironment() {
319  MockDesktopEnvironment* desktop_environment = new MockDesktopEnvironment();
320  EXPECT_CALL(*desktop_environment, CreateAudioCapturerPtr())
321      .Times(0);
322  EXPECT_CALL(*desktop_environment, CreateInputInjectorPtr())
323      .Times(AtMost(1))
324      .WillOnce(Invoke(
325          this, &IpcDesktopEnvironmentTest::CreateInputInjector));
326  EXPECT_CALL(*desktop_environment, CreateScreenControlsPtr())
327      .Times(AtMost(1));
328  EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr())
329      .Times(AtMost(1))
330      .WillOnce(Invoke(
331          this, &IpcDesktopEnvironmentTest::CreateVideoCapturer));
332  EXPECT_CALL(*desktop_environment, CreateMouseCursorMonitorPtr())
333      .Times(AtMost(1))
334      .WillOnce(Invoke(
335          this, &IpcDesktopEnvironmentTest::CreateMouseCursorMonitor));
336  EXPECT_CALL(*desktop_environment, GetCapabilities())
337      .Times(AtMost(1));
338  EXPECT_CALL(*desktop_environment, SetCapabilities(_))
339      .Times(AtMost(1));
340
341  // Let tests know that the remote desktop environment is created.
342  message_loop_.PostTask(FROM_HERE, setup_run_loop_->QuitClosure());
343
344  return desktop_environment;
345}
346
347InputInjector* IpcDesktopEnvironmentTest::CreateInputInjector() {
348  EXPECT_TRUE(remote_input_injector_ == NULL);
349  remote_input_injector_ = new testing::StrictMock<MockInputInjector>();
350
351  EXPECT_CALL(*remote_input_injector_, StartPtr(_));
352  return remote_input_injector_;
353}
354
355webrtc::DesktopCapturer* IpcDesktopEnvironmentTest::CreateVideoCapturer() {
356  return new FakeDesktopCapturer();
357}
358
359webrtc::MouseCursorMonitor*
360IpcDesktopEnvironmentTest::CreateMouseCursorMonitor() {
361  return new FakeMouseCursorMonitor();
362}
363
364void IpcDesktopEnvironmentTest::DeleteDesktopEnvironment() {
365  input_injector_.reset();
366  screen_controls_.reset();
367  video_capturer_.reset();
368
369  // Trigger DisconnectTerminal().
370  desktop_environment_.reset();
371}
372
373void IpcDesktopEnvironmentTest::ReflectClipboardEvent(
374    const protocol::ClipboardEvent& event) {
375  clipboard_stub_->InjectClipboardEvent(event);
376}
377
378void IpcDesktopEnvironmentTest::CreateDesktopProcess() {
379  EXPECT_TRUE(task_runner_.get());
380  EXPECT_TRUE(io_task_runner_.get());
381
382  // Create the daemon end of the daemon-to-desktop channel.
383  desktop_channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID();
384  desktop_channel_ =
385      IPC::ChannelProxy::Create(IPC::ChannelHandle(desktop_channel_name_),
386                                IPC::Channel::MODE_SERVER,
387                                &desktop_listener_,
388                                io_task_runner_.get());
389
390  // Create and start the desktop process.
391  desktop_process_.reset(new DesktopProcess(task_runner_,
392                                            io_task_runner_,
393                                            desktop_channel_name_));
394
395  scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory(
396      new MockDesktopEnvironmentFactory());
397  EXPECT_CALL(*desktop_environment_factory, CreatePtr())
398      .Times(AnyNumber())
399      .WillRepeatedly(Invoke(
400          this, &IpcDesktopEnvironmentTest::CreateDesktopEnvironment));
401  EXPECT_CALL(*desktop_environment_factory, SupportsAudioCapture())
402      .Times(AnyNumber())
403      .WillRepeatedly(Return(false));
404
405  EXPECT_TRUE(desktop_process_->Start(
406      desktop_environment_factory.PassAs<DesktopEnvironmentFactory>()));
407}
408
409void IpcDesktopEnvironmentTest::DestoyDesktopProcess() {
410  desktop_channel_.reset();
411  if (desktop_process_) {
412    desktop_process_->OnChannelError();
413    desktop_process_.reset();
414  }
415  remote_input_injector_ = NULL;
416}
417
418void IpcDesktopEnvironmentTest::OnDisconnectCallback() {
419  DeleteDesktopEnvironment();
420}
421
422void IpcDesktopEnvironmentTest::OnDesktopAttached(
423    IPC::PlatformFileForTransit desktop_pipe) {
424
425  // Instruct DesktopSessionProxy to connect to the network-to-desktop pipe.
426  desktop_environment_factory_->OnDesktopSessionAgentAttached(
427      terminal_id_, base::GetCurrentProcessHandle(), desktop_pipe);
428}
429
430// Runs until the desktop is attached and exits immediately after that.
431TEST_F(IpcDesktopEnvironmentTest, Basic) {
432  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
433      new protocol::MockClipboardStub());
434  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
435      .Times(0);
436
437  // Start the input injector and screen capturer.
438  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
439
440  // Run the message loop until the desktop is attached.
441  setup_run_loop_->Run();
442
443  // Stop the test.
444  DeleteDesktopEnvironment();
445
446  task_runner_ = NULL;
447  io_task_runner_ = NULL;
448  main_run_loop_.Run();
449}
450
451// Tests that the video capturer receives a frame over IPC.
452TEST_F(IpcDesktopEnvironmentTest, CaptureFrame) {
453  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
454      new protocol::MockClipboardStub());
455  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
456      .Times(0);
457
458  // Start the input injector and screen capturer.
459  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
460  video_capturer_->Start(&desktop_capturer_callback_);
461
462  // Run the message loop until the desktop is attached.
463  setup_run_loop_->Run();
464
465  // Stop the test when the first frame is captured.
466  EXPECT_CALL(desktop_capturer_callback_, OnCaptureCompleted(_))
467      .WillOnce(DoAll(
468          DeleteArg<0>(),
469          InvokeWithoutArgs(
470              this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment)));
471
472  // Capture a single frame.
473  video_capturer_->Capture(webrtc::DesktopRegion());
474
475  task_runner_ = NULL;
476  io_task_runner_ = NULL;
477  main_run_loop_.Run();
478}
479
480// Tests that attaching to a new desktop works.
481TEST_F(IpcDesktopEnvironmentTest, Reattach) {
482  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
483      new protocol::MockClipboardStub());
484  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
485      .Times(0);
486
487  // Start the input injector and screen capturer.
488  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
489  video_capturer_->Start(&desktop_capturer_callback_);
490
491  // Run the message loop until the desktop is attached.
492  setup_run_loop_->Run();
493
494  // Create and start a new desktop process object.
495  setup_run_loop_.reset(new base::RunLoop());
496  DestoyDesktopProcess();
497  CreateDesktopProcess();
498  setup_run_loop_->Run();
499
500  // Stop the test.
501  DeleteDesktopEnvironment();
502
503  task_runner_ = NULL;
504  io_task_runner_ = NULL;
505  main_run_loop_.Run();
506}
507
508// Tests injection of clipboard events.
509TEST_F(IpcDesktopEnvironmentTest, InjectClipboardEvent) {
510  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
511      new protocol::MockClipboardStub());
512  clipboard_stub_ = clipboard_stub.get();
513
514  // Stop the test when a clipboard event is received from the desktop process.
515  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
516      .Times(1)
517      .WillOnce(InvokeWithoutArgs(
518          this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
519
520  // Start the input injector and screen capturer.
521  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
522  video_capturer_->Start(&desktop_capturer_callback_);
523
524  // Run the message loop until the desktop is attached.
525  setup_run_loop_->Run();
526
527  // Expect a single clipboard event.
528  EXPECT_CALL(*remote_input_injector_, InjectClipboardEvent(_))
529      .Times(1)
530      .WillOnce(Invoke(this,
531                       &IpcDesktopEnvironmentTest::ReflectClipboardEvent));
532
533  // Send a clipboard event.
534  protocol::ClipboardEvent event;
535  event.set_mime_type(kMimeTypeTextUtf8);
536  event.set_data("a");
537  input_injector_->InjectClipboardEvent(event);
538
539  task_runner_ = NULL;
540  io_task_runner_ = NULL;
541  main_run_loop_.Run();
542}
543
544// Tests injection of key events.
545TEST_F(IpcDesktopEnvironmentTest, InjectKeyEvent) {
546  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
547      new protocol::MockClipboardStub());
548  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
549      .Times(0);
550
551  // Start the input injector and screen capturer.
552  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
553  video_capturer_->Start(&desktop_capturer_callback_);
554
555  // Run the message loop until the desktop is attached.
556  setup_run_loop_->Run();
557
558  // Expect a single key event.
559  EXPECT_CALL(*remote_input_injector_, InjectKeyEvent(_))
560      .Times(AtLeast(1))
561      .WillRepeatedly(InvokeWithoutArgs(
562          this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
563
564  // Send a key event.
565  protocol::KeyEvent event;
566  event.set_usb_keycode(0x070004);
567  event.set_pressed(true);
568  input_injector_->InjectKeyEvent(event);
569
570  task_runner_ = NULL;
571  io_task_runner_ = NULL;
572  main_run_loop_.Run();
573}
574
575// Tests injection of text events.
576TEST_F(IpcDesktopEnvironmentTest, InjectTextEvent) {
577  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
578      new protocol::MockClipboardStub());
579  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
580      .Times(0);
581
582  // Start the input injector and screen capturer.
583  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
584  video_capturer_->Start(&desktop_capturer_callback_);
585
586  // Run the message loop until the desktop is attached.
587  setup_run_loop_->Run();
588
589  // Expect a single text event.
590  EXPECT_CALL(*remote_input_injector_, InjectTextEvent(_))
591      .Times(AtLeast(1))
592      .WillRepeatedly(InvokeWithoutArgs(
593          this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
594
595  // Send a text event.
596  protocol::TextEvent event;
597  event.set_text("hello");
598  input_injector_->InjectTextEvent(event);
599
600  task_runner_ = NULL;
601  io_task_runner_ = NULL;
602  main_run_loop_.Run();
603}
604
605// Tests injection of mouse events.
606TEST_F(IpcDesktopEnvironmentTest, InjectMouseEvent) {
607  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
608      new protocol::MockClipboardStub());
609  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
610      .Times(0);
611
612  // Start the input injector and screen capturer.
613  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
614  video_capturer_->Start(&desktop_capturer_callback_);
615
616  // Run the message loop until the desktop is attached.
617  setup_run_loop_->Run();
618
619  // Expect a single mouse event.
620  EXPECT_CALL(*remote_input_injector_, InjectMouseEvent(_))
621      .Times(1)
622      .WillOnce(InvokeWithoutArgs(
623          this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
624
625  // Send a mouse event.
626  protocol::MouseEvent event;
627  event.set_x(0);
628  event.set_y(0);
629  input_injector_->InjectMouseEvent(event);
630
631  task_runner_ = NULL;
632  io_task_runner_ = NULL;
633  main_run_loop_.Run();
634}
635
636// Tests that setting the desktop resolution works.
637TEST_F(IpcDesktopEnvironmentTest, SetScreenResolution) {
638  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
639      new protocol::MockClipboardStub());
640  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
641      .Times(0);
642
643  // Start the input injector and screen capturer.
644  input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
645  video_capturer_->Start(&desktop_capturer_callback_);
646
647  // Run the message loop until the desktop is attached.
648  setup_run_loop_->Run();
649
650  EXPECT_CALL(daemon_channel_, SetScreenResolution(_, _))
651      .Times(1)
652      .WillOnce(InvokeWithoutArgs(
653          this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
654
655  // Change the desktop resolution.
656  screen_controls_->SetScreenResolution(ScreenResolution(
657      webrtc::DesktopSize(100, 100),
658      webrtc::DesktopVector(96, 96)));
659
660  task_runner_ = NULL;
661  io_task_runner_ = NULL;
662  main_run_loop_.Run();
663}
664
665}  // namespace remoting
666