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