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