Home | History | Annotate | Download | only in host
      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/message_loop/message_loop.h"
      6 #include "remoting/base/auto_thread_task_runner.h"
      7 #include "remoting/base/constants.h"
      8 #include "remoting/host/audio_capturer.h"
      9 #include "remoting/host/client_session.h"
     10 #include "remoting/host/desktop_environment.h"
     11 #include "remoting/host/host_mock_objects.h"
     12 #include "remoting/host/screen_capturer_fake.h"
     13 #include "remoting/protocol/protocol_mock_objects.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
     16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
     17 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
     18 
     19 namespace remoting {
     20 
     21 using protocol::MockConnectionToClient;
     22 using protocol::MockClientStub;
     23 using protocol::MockHostStub;
     24 using protocol::MockInputStub;
     25 using protocol::MockSession;
     26 using protocol::MockVideoStub;
     27 using protocol::SessionConfig;
     28 
     29 using testing::_;
     30 using testing::AnyNumber;
     31 using testing::AtMost;
     32 using testing::DeleteArg;
     33 using testing::DoAll;
     34 using testing::Expectation;
     35 using testing::Return;
     36 using testing::ReturnRef;
     37 using testing::Sequence;
     38 
     39 namespace {
     40 
     41 ACTION_P2(InjectClipboardEvent, connection, event) {
     42   connection->clipboard_stub()->InjectClipboardEvent(event);
     43 }
     44 
     45 ACTION_P2(InjectKeyEvent, connection, event) {
     46   connection->input_stub()->InjectKeyEvent(event);
     47 }
     48 
     49 ACTION_P2(InjectMouseEvent, connection, event) {
     50   connection->input_stub()->InjectMouseEvent(event);
     51 }
     52 
     53 ACTION_P2(LocalMouseMoved, client_session, event) {
     54   client_session->OnLocalMouseMoved(
     55       webrtc::DesktopVector(event.x(), event.y()));
     56 }
     57 
     58 }  // namespace
     59 
     60 class ClientSessionTest : public testing::Test {
     61  public:
     62   ClientSessionTest() : client_jid_("user@domain/rest-of-jid") {}
     63 
     64   virtual void SetUp() OVERRIDE;
     65   virtual void TearDown() OVERRIDE;
     66 
     67   // Disconnects the client session.
     68   void DisconnectClientSession();
     69 
     70   // Stops and releases the ClientSession, allowing the MessageLoop to quit.
     71   void StopClientSession();
     72 
     73  protected:
     74   // Creates a DesktopEnvironment with a fake webrtc::ScreenCapturer, to mock
     75   // DesktopEnvironmentFactory::Create().
     76   DesktopEnvironment* CreateDesktopEnvironment();
     77 
     78   // Returns |input_injector_| created and initialized by SetUp(), to mock
     79   // DesktopEnvironment::CreateInputInjector().
     80   InputInjector* CreateInputInjector();
     81 
     82   // Creates a fake webrtc::ScreenCapturer, to mock
     83   // DesktopEnvironment::CreateVideoCapturer().
     84   webrtc::ScreenCapturer* CreateVideoCapturer();
     85 
     86   // Notifies the client session that the client connection has been
     87   // authenticated and channels have been connected. This effectively enables
     88   // the input pipe line and starts video capturing.
     89   void ConnectClientSession();
     90 
     91   // Invoked when the last reference to the AutoThreadTaskRunner has been
     92   // released and quits the message loop to finish the test.
     93   void QuitMainMessageLoop();
     94 
     95   // Message loop passed to |client_session_| to perform all functions on.
     96   base::MessageLoop message_loop_;
     97 
     98   // ClientSession instance under test.
     99   scoped_ptr<ClientSession> client_session_;
    100 
    101   // ClientSession::EventHandler mock for use in tests.
    102   MockClientSessionEventHandler session_event_handler_;
    103 
    104   // Storage for values to be returned by the protocol::Session mock.
    105   SessionConfig session_config_;
    106   const std::string client_jid_;
    107 
    108   // Stubs returned to |client_session_| components by |connection_|.
    109   MockClientStub client_stub_;
    110   MockVideoStub video_stub_;
    111 
    112   // DesktopEnvironment owns |input_injector_|, but input injection tests need
    113   // to express expectations on it.
    114   scoped_ptr<MockInputInjector> input_injector_;
    115 
    116   // ClientSession owns |connection_| but tests need it to inject fake events.
    117   MockConnectionToClient* connection_;
    118 
    119   scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory_;
    120 };
    121 
    122 void ClientSessionTest::SetUp() {
    123   // Arrange to run |message_loop_| until no components depend on it.
    124   scoped_refptr<AutoThreadTaskRunner> ui_task_runner = new AutoThreadTaskRunner(
    125       message_loop_.message_loop_proxy(),
    126       base::Bind(&ClientSessionTest::QuitMainMessageLoop,
    127                  base::Unretained(this)));
    128 
    129   desktop_environment_factory_.reset(new MockDesktopEnvironmentFactory());
    130   EXPECT_CALL(*desktop_environment_factory_, CreatePtr())
    131       .Times(AnyNumber())
    132       .WillRepeatedly(Invoke(this,
    133                              &ClientSessionTest::CreateDesktopEnvironment));
    134   EXPECT_CALL(*desktop_environment_factory_, SupportsAudioCapture())
    135       .Times(AnyNumber())
    136       .WillRepeatedly(Return(false));
    137 
    138   input_injector_.reset(new MockInputInjector());
    139 
    140   session_config_ = SessionConfig::ForTest();
    141 
    142   // Mock protocol::Session APIs called directly by ClientSession.
    143   protocol::MockSession* session = new MockSession();
    144   EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(session_config_));
    145   EXPECT_CALL(*session, jid()).WillRepeatedly(ReturnRef(client_jid_));
    146   EXPECT_CALL(*session, SetEventHandler(_));
    147 
    148   // Mock protocol::ConnectionToClient APIs called directly by ClientSession.
    149   // HostStub is not touched by ClientSession, so we can safely pass NULL.
    150   scoped_ptr<MockConnectionToClient> connection(
    151       new MockConnectionToClient(session, NULL));
    152   EXPECT_CALL(*connection, session()).WillRepeatedly(Return(session));
    153   EXPECT_CALL(*connection, client_stub())
    154       .WillRepeatedly(Return(&client_stub_));
    155   EXPECT_CALL(*connection, video_stub()).WillRepeatedly(Return(&video_stub_));
    156   EXPECT_CALL(*connection, Disconnect());
    157   connection_ = connection.get();
    158 
    159   client_session_.reset(new ClientSession(
    160       &session_event_handler_,
    161       ui_task_runner, // Audio thread.
    162       ui_task_runner, // Input thread.
    163       ui_task_runner, // Capture thread.
    164       ui_task_runner, // Encode thread.
    165       ui_task_runner, // Network thread.
    166       ui_task_runner, // UI thread.
    167       connection.PassAs<protocol::ConnectionToClient>(),
    168       desktop_environment_factory_.get(),
    169       base::TimeDelta(),
    170       NULL));
    171 }
    172 
    173 void ClientSessionTest::TearDown() {
    174   // Verify that the client session has been stopped.
    175   EXPECT_TRUE(!client_session_);
    176 }
    177 
    178 void ClientSessionTest::DisconnectClientSession() {
    179   client_session_->DisconnectSession();
    180   // MockSession won't trigger OnConnectionClosed, so fake it.
    181   client_session_->OnConnectionClosed(client_session_->connection(),
    182                                       protocol::OK);
    183 }
    184 
    185 void ClientSessionTest::StopClientSession() {
    186   client_session_.reset();
    187 
    188   desktop_environment_factory_.reset();
    189 }
    190 
    191 DesktopEnvironment* ClientSessionTest::CreateDesktopEnvironment() {
    192   MockDesktopEnvironment* desktop_environment = new MockDesktopEnvironment();
    193   EXPECT_CALL(*desktop_environment, CreateAudioCapturerPtr())
    194       .Times(0);
    195   EXPECT_CALL(*desktop_environment, CreateInputInjectorPtr())
    196       .WillOnce(Invoke(this, &ClientSessionTest::CreateInputInjector));
    197   EXPECT_CALL(*desktop_environment, CreateScreenControlsPtr())
    198       .Times(AtMost(1));
    199   EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr())
    200       .WillOnce(Invoke(this, &ClientSessionTest::CreateVideoCapturer));
    201   EXPECT_CALL(*desktop_environment, GetCapabilities())
    202       .Times(AtMost(1));
    203   EXPECT_CALL(*desktop_environment, SetCapabilities(_))
    204       .Times(AtMost(1));
    205 
    206   return desktop_environment;
    207 }
    208 
    209 InputInjector* ClientSessionTest::CreateInputInjector() {
    210   EXPECT_TRUE(input_injector_);
    211   return input_injector_.release();
    212 }
    213 
    214 webrtc::ScreenCapturer* ClientSessionTest::CreateVideoCapturer() {
    215   return new ScreenCapturerFake();
    216 }
    217 
    218 void ClientSessionTest::ConnectClientSession() {
    219   client_session_->OnConnectionAuthenticated(client_session_->connection());
    220   client_session_->OnConnectionChannelsConnected(client_session_->connection());
    221 }
    222 
    223 void ClientSessionTest::QuitMainMessageLoop() {
    224   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
    225 }
    226 
    227 MATCHER_P2(EqualsClipboardEvent, m, d, "") {
    228   return (strcmp(arg.mime_type().c_str(), m) == 0 &&
    229       memcmp(arg.data().data(), d, arg.data().size()) == 0);
    230 }
    231 
    232 TEST_F(ClientSessionTest, ClipboardStubFilter) {
    233   protocol::ClipboardEvent clipboard_event1;
    234   clipboard_event1.set_mime_type(kMimeTypeTextUtf8);
    235   clipboard_event1.set_data("a");
    236 
    237   protocol::ClipboardEvent clipboard_event2;
    238   clipboard_event2.set_mime_type(kMimeTypeTextUtf8);
    239   clipboard_event2.set_data("b");
    240 
    241   protocol::ClipboardEvent clipboard_event3;
    242   clipboard_event3.set_mime_type(kMimeTypeTextUtf8);
    243   clipboard_event3.set_data("c");
    244 
    245   Expectation authenticated =
    246       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    247           .WillOnce(Return(true));
    248   EXPECT_CALL(*input_injector_, StartPtr(_))
    249       .After(authenticated);
    250   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    251       .After(authenticated);
    252 
    253   // Wait for the first video packet to be captured to make sure that
    254   // the injected input will go though. Otherwise mouse events will be blocked
    255   // by the mouse clamping filter.
    256   Sequence s;
    257   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    258       .InSequence(s)
    259       .After(authenticated)
    260       .WillOnce(DoAll(
    261           // This event should get through to the clipboard stub.
    262           InjectClipboardEvent(connection_, clipboard_event2),
    263           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    264           // This event should not get through to the clipboard stub,
    265           // because the client has disconnected.
    266           InjectClipboardEvent(connection_, clipboard_event3),
    267           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    268   EXPECT_CALL(*input_injector_, InjectClipboardEvent(EqualsClipboardEvent(
    269       kMimeTypeTextUtf8, "b")))
    270       .InSequence(s);
    271   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    272       .InSequence(s);
    273 
    274   // This event should not get through to the clipboard stub,
    275   // because the client isn't authenticated yet.
    276   connection_->clipboard_stub()->InjectClipboardEvent(clipboard_event1);
    277 
    278   ConnectClientSession();
    279   message_loop_.Run();
    280 }
    281 
    282 namespace {
    283 
    284 MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") {
    285   return arg.usb_keycode() == (unsigned int)usb_keycode &&
    286          arg.pressed() == pressed;
    287 }
    288 
    289 MATCHER_P2(EqualsMouseEvent, x, y, "") {
    290   return arg.x() == x && arg.y() == y;
    291 }
    292 
    293 MATCHER_P2(EqualsMouseButtonEvent, button, down, "") {
    294   return arg.button() == button && arg.button_down() == down;
    295 }
    296 
    297 }
    298 
    299 TEST_F(ClientSessionTest, InputStubFilter) {
    300   protocol::KeyEvent key_event1;
    301   key_event1.set_pressed(true);
    302   key_event1.set_usb_keycode(1);
    303 
    304   protocol::KeyEvent key_event2_down;
    305   key_event2_down.set_pressed(true);
    306   key_event2_down.set_usb_keycode(2);
    307 
    308   protocol::KeyEvent key_event2_up;
    309   key_event2_up.set_pressed(false);
    310   key_event2_up.set_usb_keycode(2);
    311 
    312   protocol::KeyEvent key_event3;
    313   key_event3.set_pressed(true);
    314   key_event3.set_usb_keycode(3);
    315 
    316   protocol::MouseEvent mouse_event1;
    317   mouse_event1.set_x(100);
    318   mouse_event1.set_y(101);
    319 
    320   protocol::MouseEvent mouse_event2;
    321   mouse_event2.set_x(200);
    322   mouse_event2.set_y(201);
    323 
    324   protocol::MouseEvent mouse_event3;
    325   mouse_event3.set_x(300);
    326   mouse_event3.set_y(301);
    327 
    328   Expectation authenticated =
    329       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    330           .WillOnce(Return(true));
    331   EXPECT_CALL(*input_injector_, StartPtr(_))
    332       .After(authenticated);
    333   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    334       .After(authenticated);
    335 
    336   // Wait for the first video packet to be captured to make sure that
    337   // the injected input will go though. Otherwise mouse events will be blocked
    338   // by the mouse clamping filter.
    339   Sequence s;
    340   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    341       .InSequence(s)
    342       .After(authenticated)
    343       .WillOnce(DoAll(
    344           // These events should get through to the input stub.
    345           InjectKeyEvent(connection_, key_event2_down),
    346           InjectKeyEvent(connection_, key_event2_up),
    347           InjectMouseEvent(connection_, mouse_event2),
    348           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    349           // These events should not get through to the input stub,
    350           // because the client has disconnected.
    351           InjectKeyEvent(connection_, key_event3),
    352           InjectMouseEvent(connection_, mouse_event3),
    353           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    354   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true)))
    355       .InSequence(s);
    356   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false)))
    357       .InSequence(s);
    358   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201)))
    359       .InSequence(s);
    360   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    361       .InSequence(s);
    362 
    363   // These events should not get through to the input stub,
    364   // because the client isn't authenticated yet.
    365   connection_->input_stub()->InjectKeyEvent(key_event1);
    366   connection_->input_stub()->InjectMouseEvent(mouse_event1);
    367 
    368   ConnectClientSession();
    369   message_loop_.Run();
    370 }
    371 
    372 TEST_F(ClientSessionTest, LocalInputTest) {
    373   protocol::MouseEvent mouse_event1;
    374   mouse_event1.set_x(100);
    375   mouse_event1.set_y(101);
    376   protocol::MouseEvent mouse_event2;
    377   mouse_event2.set_x(200);
    378   mouse_event2.set_y(201);
    379   protocol::MouseEvent mouse_event3;
    380   mouse_event3.set_x(300);
    381   mouse_event3.set_y(301);
    382 
    383   Expectation authenticated =
    384       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    385           .WillOnce(Return(true));
    386   EXPECT_CALL(*input_injector_, StartPtr(_))
    387       .After(authenticated);
    388   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    389       .After(authenticated);
    390 
    391   // Wait for the first video packet to be captured to make sure that
    392   // the injected input will go though. Otherwise mouse events will be blocked
    393   // by the mouse clamping filter.
    394   Sequence s;
    395   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    396       .InSequence(s)
    397       .After(authenticated)
    398       .WillOnce(DoAll(
    399           // This event should get through to the input stub.
    400           InjectMouseEvent(connection_, mouse_event1),
    401 #if !defined(OS_WIN)
    402           // The OS echoes the injected event back.
    403           LocalMouseMoved(client_session_.get(), mouse_event1),
    404 #endif  // !defined(OS_WIN)
    405           // This one should get throught as well.
    406           InjectMouseEvent(connection_, mouse_event2),
    407           // Now this is a genuine local event.
    408           LocalMouseMoved(client_session_.get(), mouse_event1),
    409           // This one should be blocked because of the previous  local input
    410           // event.
    411           InjectMouseEvent(connection_, mouse_event3),
    412           // TODO(jamiewalch): Verify that remote inputs are re-enabled
    413           // eventually (via dependency injection, not sleep!)
    414           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    415           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    416   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(100, 101)))
    417       .InSequence(s);
    418   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201)))
    419       .InSequence(s);
    420   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    421       .InSequence(s);
    422 
    423   ConnectClientSession();
    424   message_loop_.Run();
    425 }
    426 
    427 TEST_F(ClientSessionTest, RestoreEventState) {
    428   protocol::KeyEvent key1;
    429   key1.set_pressed(true);
    430   key1.set_usb_keycode(1);
    431 
    432   protocol::KeyEvent key2;
    433   key2.set_pressed(true);
    434   key2.set_usb_keycode(2);
    435 
    436   protocol::MouseEvent mousedown;
    437   mousedown.set_button(protocol::MouseEvent::BUTTON_LEFT);
    438   mousedown.set_button_down(true);
    439 
    440   Expectation authenticated =
    441       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    442           .WillOnce(Return(true));
    443   EXPECT_CALL(*input_injector_, StartPtr(_))
    444       .After(authenticated);
    445   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    446       .After(authenticated);
    447 
    448   // Wait for the first video packet to be captured to make sure that
    449   // the injected input will go though. Otherwise mouse events will be blocked
    450   // by the mouse clamping filter.
    451   Sequence s;
    452   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    453       .InSequence(s)
    454       .After(authenticated)
    455       .WillOnce(DoAll(
    456           InjectKeyEvent(connection_, key1),
    457           InjectKeyEvent(connection_, key2),
    458           InjectMouseEvent(connection_, mousedown),
    459           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    460           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    461   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, true)))
    462       .InSequence(s);
    463   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true)))
    464       .InSequence(s);
    465   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent(
    466       protocol::MouseEvent::BUTTON_LEFT, true)))
    467       .InSequence(s);
    468   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, false)))
    469       .InSequence(s);
    470   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false)))
    471       .InSequence(s);
    472   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent(
    473       protocol::MouseEvent::BUTTON_LEFT, false)))
    474       .InSequence(s);
    475   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    476       .InSequence(s);
    477 
    478   ConnectClientSession();
    479   message_loop_.Run();
    480 }
    481 
    482 TEST_F(ClientSessionTest, ClampMouseEvents) {
    483   Expectation authenticated =
    484       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    485           .WillOnce(Return(true));
    486   EXPECT_CALL(*input_injector_, StartPtr(_))
    487       .After(authenticated);
    488   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    489       .After(authenticated);
    490   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    491       .After(authenticated);
    492 
    493   Expectation connected = authenticated;
    494 
    495   int input_x[3] = { -999, 100, 999 };
    496   int expected_x[3] = { 0, 100, ScreenCapturerFake::kWidth - 1 };
    497   int input_y[3] = { -999, 50, 999 };
    498   int expected_y[3] = { 0, 50, ScreenCapturerFake::kHeight - 1 };
    499 
    500   protocol::MouseEvent expected_event;
    501   for (int j = 0; j < 3; j++) {
    502     for (int i = 0; i < 3; i++) {
    503       protocol::MouseEvent injected_event;
    504       injected_event.set_x(input_x[i]);
    505       injected_event.set_y(input_y[j]);
    506 
    507       if (i == 0 && j == 0) {
    508         // Inject the 1st event once a video packet has been received.
    509         connected =
    510             EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    511                 .After(connected)
    512                 .WillOnce(InjectMouseEvent(connection_, injected_event));
    513       } else {
    514         // Every next event is injected once the previous event has been
    515         // received.
    516         connected =
    517             EXPECT_CALL(*input_injector_,
    518                         InjectMouseEvent(EqualsMouseEvent(expected_event.x(),
    519                                                           expected_event.y())))
    520                 .After(connected)
    521                 .WillOnce(InjectMouseEvent(connection_, injected_event));
    522       }
    523 
    524       expected_event.set_x(expected_x[i]);
    525       expected_event.set_y(expected_y[j]);
    526     }
    527   }
    528 
    529   // Shutdown the connection once the last event has been received.
    530   EXPECT_CALL(*input_injector_,
    531               InjectMouseEvent(EqualsMouseEvent(expected_event.x(),
    532                                                 expected_event.y())))
    533       .After(connected)
    534       .WillOnce(DoAll(
    535           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    536           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    537 
    538   ConnectClientSession();
    539   message_loop_.Run();
    540 }
    541 
    542 }  // namespace remoting
    543