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 <algorithm>
      6 #include <string>
      7 #include <vector>
      8 
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/strings/string_util.h"
     11 #include "base/test/test_simple_task_runner.h"
     12 #include "remoting/base/auto_thread_task_runner.h"
     13 #include "remoting/base/constants.h"
     14 #include "remoting/host/audio_capturer.h"
     15 #include "remoting/host/client_session.h"
     16 #include "remoting/host/desktop_environment.h"
     17 #include "remoting/host/host_extension.h"
     18 #include "remoting/host/host_mock_objects.h"
     19 #include "remoting/host/screen_capturer_fake.h"
     20 #include "remoting/protocol/protocol_mock_objects.h"
     21 #include "testing/gmock/include/gmock/gmock-matchers.h"
     22 #include "testing/gmock_mutant.h"
     23 #include "testing/gtest/include/gtest/gtest.h"
     24 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
     25 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
     26 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
     27 
     28 namespace remoting {
     29 
     30 using protocol::MockConnectionToClient;
     31 using protocol::MockClientStub;
     32 using protocol::MockHostStub;
     33 using protocol::MockInputStub;
     34 using protocol::MockSession;
     35 using protocol::MockVideoStub;
     36 using protocol::SessionConfig;
     37 
     38 using testing::_;
     39 using testing::AnyNumber;
     40 using testing::AtMost;
     41 using testing::CreateFunctor;
     42 using testing::DeleteArg;
     43 using testing::DoAll;
     44 using testing::Expectation;
     45 using testing::Invoke;
     46 using testing::Return;
     47 using testing::ReturnRef;
     48 using testing::Sequence;
     49 using testing::StrEq;
     50 using testing::StrictMock;
     51 
     52 namespace {
     53 
     54 const char kDefaultTestCapability[] = "default";
     55 
     56 ACTION_P2(InjectClipboardEvent, connection, event) {
     57   connection->clipboard_stub()->InjectClipboardEvent(event);
     58 }
     59 
     60 ACTION_P2(InjectKeyEvent, connection, event) {
     61   connection->input_stub()->InjectKeyEvent(event);
     62 }
     63 
     64 ACTION_P2(InjectMouseEvent, connection, event) {
     65   connection->input_stub()->InjectMouseEvent(event);
     66 }
     67 
     68 ACTION_P2(LocalMouseMoved, client_session, event) {
     69   client_session->OnLocalMouseMoved(
     70       webrtc::DesktopVector(event.x(), event.y()));
     71 }
     72 
     73 ACTION_P2(SetGnubbyAuthHandlerForTesting, client_session, gnubby_auth_handler) {
     74   client_session->SetGnubbyAuthHandlerForTesting(gnubby_auth_handler);
     75 }
     76 
     77 ACTION_P2(DeliverClientMessage, client_session, message) {
     78   client_session->DeliverClientMessage(message);
     79 }
     80 
     81 ACTION_P2(AddHostCapabilities, client_session, capability) {
     82   client_session->AddHostCapabilities(capability);
     83 }
     84 
     85 // Matches a |protocol::Capabilities| argument against a list of capabilities
     86 // formatted as a space-separated string.
     87 MATCHER_P(EqCapabilities, expected_capabilities, "") {
     88   if (!arg.has_capabilities())
     89     return false;
     90 
     91   std::vector<std::string> words_args;
     92   std::vector<std::string> words_expected;
     93   Tokenize(arg.capabilities(), " ", &words_args);
     94   Tokenize(expected_capabilities, " ", &words_expected);
     95   std::sort(words_args.begin(), words_args.end());
     96   std::sort(words_expected.begin(), words_expected.end());
     97   return words_args == words_expected;
     98 }
     99 
    100 // |HostExtension| implementation that can handle an extension message type and
    101 // provide capabilities.
    102 class FakeExtension : public HostExtension {
    103  public:
    104   FakeExtension(const std::string& message_type,
    105                 const std::string& capabilities);
    106   virtual ~FakeExtension();
    107 
    108   virtual std::string GetCapabilities() OVERRIDE;
    109   virtual scoped_ptr<HostExtensionSession> CreateExtensionSession(
    110       ClientSession* client_session) OVERRIDE;
    111 
    112   bool message_handled() {
    113     return message_handled_;
    114   }
    115 
    116  private:
    117   class FakeExtensionSession : public HostExtensionSession {
    118    public:
    119     FakeExtensionSession(FakeExtension* extension);
    120     virtual ~FakeExtensionSession();
    121 
    122     virtual bool OnExtensionMessage(
    123         ClientSession* client_session,
    124         const protocol::ExtensionMessage& message) OVERRIDE;
    125 
    126    private:
    127     FakeExtension* extension_;
    128   };
    129 
    130   std::string message_type_;
    131   std::string capabilities_;
    132   bool message_handled_;
    133 };
    134 
    135 typedef std::vector<HostExtension*> HostExtensionList;
    136 
    137 void CreateExtensionSessions(const HostExtensionList& extensions,
    138                              ClientSession* client_session) {
    139   for (HostExtensionList::const_iterator extension = extensions.begin();
    140        extension != extensions.end(); ++extension) {
    141     scoped_ptr<HostExtensionSession> extension_session =
    142         (*extension)->CreateExtensionSession(client_session);
    143     if (extension_session)
    144       client_session->AddExtensionSession(extension_session.Pass());
    145   }
    146 }
    147 
    148 }  // namespace
    149 
    150 class ClientSessionTest : public testing::Test {
    151  public:
    152   ClientSessionTest() : client_jid_("user@domain/rest-of-jid") {}
    153 
    154   virtual void SetUp() OVERRIDE;
    155   virtual void TearDown() OVERRIDE;
    156 
    157   // Disconnects the client session.
    158   void DisconnectClientSession();
    159 
    160   // Stops and releases the ClientSession, allowing the MessageLoop to quit.
    161   void StopClientSession();
    162 
    163  protected:
    164   // Creates a DesktopEnvironment with a fake webrtc::ScreenCapturer, to mock
    165   // DesktopEnvironmentFactory::Create().
    166   DesktopEnvironment* CreateDesktopEnvironment();
    167 
    168   // Returns |input_injector_| created and initialized by SetUp(), to mock
    169   // DesktopEnvironment::CreateInputInjector().
    170   InputInjector* CreateInputInjector();
    171 
    172   // Creates a fake webrtc::ScreenCapturer, to mock
    173   // DesktopEnvironment::CreateVideoCapturer().
    174   webrtc::ScreenCapturer* CreateVideoCapturer();
    175 
    176   // Notifies the client session that the client connection has been
    177   // authenticated and channels have been connected. This effectively enables
    178   // the input pipe line and starts video capturing.
    179   void ConnectClientSession();
    180 
    181   // Creates expectations to send an extension message and to disconnect
    182   // afterwards.
    183   void SetSendMessageAndDisconnectExpectation(const std::string& message_type);
    184 
    185   // Invoked when the last reference to the AutoThreadTaskRunner has been
    186   // released and quits the message loop to finish the test.
    187   void QuitMainMessageLoop();
    188 
    189   // Message loop passed to |client_session_| to perform all functions on.
    190   base::MessageLoop message_loop_;
    191 
    192   // ClientSession instance under test.
    193   scoped_ptr<ClientSession> client_session_;
    194 
    195   // ClientSession::EventHandler mock for use in tests.
    196   MockClientSessionEventHandler session_event_handler_;
    197 
    198   // Storage for values to be returned by the protocol::Session mock.
    199   SessionConfig session_config_;
    200   const std::string client_jid_;
    201 
    202   // Stubs returned to |client_session_| components by |connection_|.
    203   MockClientStub client_stub_;
    204   MockVideoStub video_stub_;
    205 
    206   // DesktopEnvironment owns |input_injector_|, but input injection tests need
    207   // to express expectations on it.
    208   scoped_ptr<MockInputInjector> input_injector_;
    209 
    210   // ClientSession owns |connection_| but tests need it to inject fake events.
    211   MockConnectionToClient* connection_;
    212 
    213   scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory_;
    214 };
    215 
    216 FakeExtension::FakeExtension(const std::string& message_type,
    217                              const std::string& capabilities)
    218     : message_type_(message_type),
    219       capabilities_(capabilities),
    220       message_handled_(false) {
    221 }
    222 
    223 FakeExtension::~FakeExtension() {}
    224 
    225 std::string FakeExtension::GetCapabilities() {
    226   return capabilities_;
    227 }
    228 
    229 scoped_ptr<HostExtensionSession> FakeExtension::CreateExtensionSession(
    230     ClientSession* client_session) {
    231   return scoped_ptr<HostExtensionSession>(new FakeExtensionSession(this));
    232 }
    233 
    234 FakeExtension::FakeExtensionSession::FakeExtensionSession(
    235     FakeExtension* extension)
    236     : extension_(extension) {
    237 }
    238 
    239 FakeExtension::FakeExtensionSession::~FakeExtensionSession() {}
    240 
    241 bool FakeExtension::FakeExtensionSession::OnExtensionMessage(
    242     ClientSession* client_session,
    243     const protocol::ExtensionMessage& message) {
    244   if (message.type() == extension_->message_type_) {
    245     extension_->message_handled_ = true;
    246     return true;
    247   }
    248   return false;
    249 }
    250 
    251 void ClientSessionTest::SetUp() {
    252   // Arrange to run |message_loop_| until no components depend on it.
    253   scoped_refptr<AutoThreadTaskRunner> ui_task_runner = new AutoThreadTaskRunner(
    254       message_loop_.message_loop_proxy(),
    255       base::Bind(&ClientSessionTest::QuitMainMessageLoop,
    256                  base::Unretained(this)));
    257 
    258   desktop_environment_factory_.reset(new MockDesktopEnvironmentFactory());
    259   EXPECT_CALL(*desktop_environment_factory_, CreatePtr())
    260       .Times(AnyNumber())
    261       .WillRepeatedly(Invoke(this,
    262                              &ClientSessionTest::CreateDesktopEnvironment));
    263   EXPECT_CALL(*desktop_environment_factory_, SupportsAudioCapture())
    264       .Times(AnyNumber())
    265       .WillRepeatedly(Return(false));
    266 
    267   input_injector_.reset(new MockInputInjector());
    268 
    269   session_config_ = SessionConfig::ForTest();
    270 
    271   // Mock protocol::Session APIs called directly by ClientSession.
    272   protocol::MockSession* session = new MockSession();
    273   EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(session_config_));
    274   EXPECT_CALL(*session, jid()).WillRepeatedly(ReturnRef(client_jid_));
    275   EXPECT_CALL(*session, SetEventHandler(_));
    276 
    277   // Mock protocol::ConnectionToClient APIs called directly by ClientSession.
    278   // HostStub is not touched by ClientSession, so we can safely pass NULL.
    279   scoped_ptr<MockConnectionToClient> connection(
    280       new MockConnectionToClient(session, NULL));
    281   EXPECT_CALL(*connection, session()).WillRepeatedly(Return(session));
    282   EXPECT_CALL(*connection, client_stub())
    283       .WillRepeatedly(Return(&client_stub_));
    284   EXPECT_CALL(*connection, video_stub()).WillRepeatedly(Return(&video_stub_));
    285   EXPECT_CALL(*connection, Disconnect());
    286   connection_ = connection.get();
    287 
    288   client_session_.reset(new ClientSession(
    289       &session_event_handler_,
    290       ui_task_runner, // Audio thread.
    291       ui_task_runner, // Input thread.
    292       ui_task_runner, // Capture thread.
    293       ui_task_runner, // Encode thread.
    294       ui_task_runner, // Network thread.
    295       ui_task_runner, // UI thread.
    296       connection.PassAs<protocol::ConnectionToClient>(),
    297       desktop_environment_factory_.get(),
    298       base::TimeDelta(),
    299       NULL));
    300 
    301   // By default, client will report the same capabilities as the host.
    302   EXPECT_CALL(client_stub_, SetCapabilities(_))
    303       .Times(AtMost(1))
    304       .WillOnce(Invoke(client_session_.get(), &ClientSession::SetCapabilities));
    305 }
    306 
    307 void ClientSessionTest::TearDown() {
    308   // Verify that the client session has been stopped.
    309   EXPECT_TRUE(!client_session_);
    310 }
    311 
    312 void ClientSessionTest::DisconnectClientSession() {
    313   client_session_->DisconnectSession();
    314   // MockSession won't trigger OnConnectionClosed, so fake it.
    315   client_session_->OnConnectionClosed(client_session_->connection(),
    316                                       protocol::OK);
    317 }
    318 
    319 void ClientSessionTest::StopClientSession() {
    320   client_session_.reset();
    321 
    322   desktop_environment_factory_.reset();
    323 }
    324 
    325 DesktopEnvironment* ClientSessionTest::CreateDesktopEnvironment() {
    326   MockDesktopEnvironment* desktop_environment = new MockDesktopEnvironment();
    327   EXPECT_CALL(*desktop_environment, CreateAudioCapturerPtr())
    328       .Times(0);
    329   EXPECT_CALL(*desktop_environment, CreateInputInjectorPtr())
    330       .WillOnce(Invoke(this, &ClientSessionTest::CreateInputInjector));
    331   EXPECT_CALL(*desktop_environment, CreateScreenControlsPtr())
    332       .Times(AtMost(1));
    333   EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr())
    334       .WillOnce(Invoke(this, &ClientSessionTest::CreateVideoCapturer));
    335   EXPECT_CALL(*desktop_environment, GetCapabilities())
    336       .Times(AtMost(1))
    337        .WillOnce(Return(kDefaultTestCapability));
    338   EXPECT_CALL(*desktop_environment, SetCapabilities(_))
    339       .Times(AtMost(1));
    340 
    341   return desktop_environment;
    342 }
    343 
    344 InputInjector* ClientSessionTest::CreateInputInjector() {
    345   EXPECT_TRUE(input_injector_);
    346   return input_injector_.release();
    347 }
    348 
    349 webrtc::ScreenCapturer* ClientSessionTest::CreateVideoCapturer() {
    350   return new ScreenCapturerFake();
    351 }
    352 
    353 void ClientSessionTest::ConnectClientSession() {
    354   client_session_->OnConnectionAuthenticated(client_session_->connection());
    355   client_session_->OnConnectionChannelsConnected(client_session_->connection());
    356 }
    357 
    358 void ClientSessionTest::SetSendMessageAndDisconnectExpectation(
    359     const std::string& message_type) {
    360   protocol::ExtensionMessage message;
    361   message.set_type(message_type);
    362   message.set_data("data");
    363 
    364   Expectation authenticated =
    365       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    366       .WillOnce(Return(true));
    367   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    368       .After(authenticated)
    369       .WillOnce(DoAll(
    370           DeliverClientMessage(client_session_.get(), message),
    371           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    372           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    373 }
    374 
    375 void ClientSessionTest::QuitMainMessageLoop() {
    376   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
    377 }
    378 
    379 MATCHER_P2(EqualsClipboardEvent, m, d, "") {
    380   return (strcmp(arg.mime_type().c_str(), m) == 0 &&
    381       memcmp(arg.data().data(), d, arg.data().size()) == 0);
    382 }
    383 
    384 TEST_F(ClientSessionTest, ClipboardStubFilter) {
    385   protocol::ClipboardEvent clipboard_event1;
    386   clipboard_event1.set_mime_type(kMimeTypeTextUtf8);
    387   clipboard_event1.set_data("a");
    388 
    389   protocol::ClipboardEvent clipboard_event2;
    390   clipboard_event2.set_mime_type(kMimeTypeTextUtf8);
    391   clipboard_event2.set_data("b");
    392 
    393   protocol::ClipboardEvent clipboard_event3;
    394   clipboard_event3.set_mime_type(kMimeTypeTextUtf8);
    395   clipboard_event3.set_data("c");
    396 
    397   Expectation authenticated =
    398       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    399           .WillOnce(Return(true));
    400   EXPECT_CALL(*input_injector_, StartPtr(_))
    401       .After(authenticated);
    402   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    403       .After(authenticated);
    404 
    405   // Wait for the first video packet to be captured to make sure that
    406   // the injected input will go though. Otherwise mouse events will be blocked
    407   // by the mouse clamping filter.
    408   Sequence s;
    409   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    410       .InSequence(s)
    411       .After(authenticated)
    412       .WillOnce(DoAll(
    413           // This event should get through to the clipboard stub.
    414           InjectClipboardEvent(connection_, clipboard_event2),
    415           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    416           // This event should not get through to the clipboard stub,
    417           // because the client has disconnected.
    418           InjectClipboardEvent(connection_, clipboard_event3),
    419           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    420   EXPECT_CALL(*input_injector_, InjectClipboardEvent(EqualsClipboardEvent(
    421       kMimeTypeTextUtf8, "b")))
    422       .InSequence(s);
    423   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    424       .InSequence(s);
    425 
    426   // This event should not get through to the clipboard stub,
    427   // because the client isn't authenticated yet.
    428   connection_->clipboard_stub()->InjectClipboardEvent(clipboard_event1);
    429 
    430   ConnectClientSession();
    431   message_loop_.Run();
    432 }
    433 
    434 namespace {
    435 
    436 MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") {
    437   return arg.usb_keycode() == (unsigned int)usb_keycode &&
    438          arg.pressed() == pressed;
    439 }
    440 
    441 MATCHER_P2(EqualsMouseEvent, x, y, "") {
    442   return arg.x() == x && arg.y() == y;
    443 }
    444 
    445 MATCHER_P2(EqualsMouseButtonEvent, button, down, "") {
    446   return arg.button() == button && arg.button_down() == down;
    447 }
    448 
    449 }  // namespace
    450 
    451 TEST_F(ClientSessionTest, InputStubFilter) {
    452   protocol::KeyEvent key_event1;
    453   key_event1.set_pressed(true);
    454   key_event1.set_usb_keycode(1);
    455 
    456   protocol::KeyEvent key_event2_down;
    457   key_event2_down.set_pressed(true);
    458   key_event2_down.set_usb_keycode(2);
    459 
    460   protocol::KeyEvent key_event2_up;
    461   key_event2_up.set_pressed(false);
    462   key_event2_up.set_usb_keycode(2);
    463 
    464   protocol::KeyEvent key_event3;
    465   key_event3.set_pressed(true);
    466   key_event3.set_usb_keycode(3);
    467 
    468   protocol::MouseEvent mouse_event1;
    469   mouse_event1.set_x(100);
    470   mouse_event1.set_y(101);
    471 
    472   protocol::MouseEvent mouse_event2;
    473   mouse_event2.set_x(200);
    474   mouse_event2.set_y(201);
    475 
    476   protocol::MouseEvent mouse_event3;
    477   mouse_event3.set_x(300);
    478   mouse_event3.set_y(301);
    479 
    480   Expectation authenticated =
    481       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    482           .WillOnce(Return(true));
    483   EXPECT_CALL(*input_injector_, StartPtr(_))
    484       .After(authenticated);
    485   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    486       .After(authenticated);
    487 
    488   // Wait for the first video packet to be captured to make sure that
    489   // the injected input will go though. Otherwise mouse events will be blocked
    490   // by the mouse clamping filter.
    491   Sequence s;
    492   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    493       .InSequence(s)
    494       .After(authenticated)
    495       .WillOnce(DoAll(
    496           // These events should get through to the input stub.
    497           InjectKeyEvent(connection_, key_event2_down),
    498           InjectKeyEvent(connection_, key_event2_up),
    499           InjectMouseEvent(connection_, mouse_event2),
    500           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    501           // These events should not get through to the input stub,
    502           // because the client has disconnected.
    503           InjectKeyEvent(connection_, key_event3),
    504           InjectMouseEvent(connection_, mouse_event3),
    505           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    506   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true)))
    507       .InSequence(s);
    508   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false)))
    509       .InSequence(s);
    510   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201)))
    511       .InSequence(s);
    512   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    513       .InSequence(s);
    514 
    515   // These events should not get through to the input stub,
    516   // because the client isn't authenticated yet.
    517   connection_->input_stub()->InjectKeyEvent(key_event1);
    518   connection_->input_stub()->InjectMouseEvent(mouse_event1);
    519 
    520   ConnectClientSession();
    521   message_loop_.Run();
    522 }
    523 
    524 TEST_F(ClientSessionTest, LocalInputTest) {
    525   protocol::MouseEvent mouse_event1;
    526   mouse_event1.set_x(100);
    527   mouse_event1.set_y(101);
    528   protocol::MouseEvent mouse_event2;
    529   mouse_event2.set_x(200);
    530   mouse_event2.set_y(201);
    531   protocol::MouseEvent mouse_event3;
    532   mouse_event3.set_x(300);
    533   mouse_event3.set_y(301);
    534 
    535   Expectation authenticated =
    536       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    537           .WillOnce(Return(true));
    538   EXPECT_CALL(*input_injector_, StartPtr(_))
    539       .After(authenticated);
    540   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    541       .After(authenticated);
    542 
    543   // Wait for the first video packet to be captured to make sure that
    544   // the injected input will go though. Otherwise mouse events will be blocked
    545   // by the mouse clamping filter.
    546   Sequence s;
    547   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    548       .InSequence(s)
    549       .After(authenticated)
    550       .WillOnce(DoAll(
    551           // This event should get through to the input stub.
    552           InjectMouseEvent(connection_, mouse_event1),
    553 #if !defined(OS_WIN)
    554           // The OS echoes the injected event back.
    555           LocalMouseMoved(client_session_.get(), mouse_event1),
    556 #endif  // !defined(OS_WIN)
    557           // This one should get throught as well.
    558           InjectMouseEvent(connection_, mouse_event2),
    559           // Now this is a genuine local event.
    560           LocalMouseMoved(client_session_.get(), mouse_event1),
    561           // This one should be blocked because of the previous  local input
    562           // event.
    563           InjectMouseEvent(connection_, mouse_event3),
    564           // TODO(jamiewalch): Verify that remote inputs are re-enabled
    565           // eventually (via dependency injection, not sleep!)
    566           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    567           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    568   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(100, 101)))
    569       .InSequence(s);
    570   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201)))
    571       .InSequence(s);
    572   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    573       .InSequence(s);
    574 
    575   ConnectClientSession();
    576   message_loop_.Run();
    577 }
    578 
    579 TEST_F(ClientSessionTest, RestoreEventState) {
    580   protocol::KeyEvent key1;
    581   key1.set_pressed(true);
    582   key1.set_usb_keycode(1);
    583 
    584   protocol::KeyEvent key2;
    585   key2.set_pressed(true);
    586   key2.set_usb_keycode(2);
    587 
    588   protocol::MouseEvent mousedown;
    589   mousedown.set_button(protocol::MouseEvent::BUTTON_LEFT);
    590   mousedown.set_button_down(true);
    591 
    592   Expectation authenticated =
    593       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    594           .WillOnce(Return(true));
    595   EXPECT_CALL(*input_injector_, StartPtr(_))
    596       .After(authenticated);
    597   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    598       .After(authenticated);
    599 
    600   // Wait for the first video packet to be captured to make sure that
    601   // the injected input will go though. Otherwise mouse events will be blocked
    602   // by the mouse clamping filter.
    603   Sequence s;
    604   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    605       .InSequence(s)
    606       .After(authenticated)
    607       .WillOnce(DoAll(
    608           InjectKeyEvent(connection_, key1),
    609           InjectKeyEvent(connection_, key2),
    610           InjectMouseEvent(connection_, mousedown),
    611           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    612           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    613   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, true)))
    614       .InSequence(s);
    615   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true)))
    616       .InSequence(s);
    617   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent(
    618       protocol::MouseEvent::BUTTON_LEFT, true)))
    619       .InSequence(s);
    620   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, false)))
    621       .InSequence(s);
    622   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false)))
    623       .InSequence(s);
    624   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent(
    625       protocol::MouseEvent::BUTTON_LEFT, false)))
    626       .InSequence(s);
    627   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    628       .InSequence(s);
    629 
    630   ConnectClientSession();
    631   message_loop_.Run();
    632 }
    633 
    634 TEST_F(ClientSessionTest, ClampMouseEvents) {
    635   Expectation authenticated =
    636       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    637           .WillOnce(Return(true));
    638   EXPECT_CALL(*input_injector_, StartPtr(_))
    639       .After(authenticated);
    640   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    641       .After(authenticated);
    642   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
    643       .After(authenticated);
    644 
    645   Expectation connected = authenticated;
    646 
    647   int input_x[3] = { -999, 100, 999 };
    648   int expected_x[3] = { 0, 100, ScreenCapturerFake::kWidth - 1 };
    649   int input_y[3] = { -999, 50, 999 };
    650   int expected_y[3] = { 0, 50, ScreenCapturerFake::kHeight - 1 };
    651 
    652   protocol::MouseEvent expected_event;
    653   for (int j = 0; j < 3; j++) {
    654     for (int i = 0; i < 3; i++) {
    655       protocol::MouseEvent injected_event;
    656       injected_event.set_x(input_x[i]);
    657       injected_event.set_y(input_y[j]);
    658 
    659       if (i == 0 && j == 0) {
    660         // Inject the 1st event once a video packet has been received.
    661         connected =
    662             EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
    663                 .After(connected)
    664                 .WillOnce(InjectMouseEvent(connection_, injected_event));
    665       } else {
    666         // Every next event is injected once the previous event has been
    667         // received.
    668         connected =
    669             EXPECT_CALL(*input_injector_,
    670                         InjectMouseEvent(EqualsMouseEvent(expected_event.x(),
    671                                                           expected_event.y())))
    672                 .After(connected)
    673                 .WillOnce(InjectMouseEvent(connection_, injected_event));
    674       }
    675 
    676       expected_event.set_x(expected_x[i]);
    677       expected_event.set_y(expected_y[j]);
    678     }
    679   }
    680 
    681   // Shutdown the connection once the last event has been received.
    682   EXPECT_CALL(*input_injector_,
    683               InjectMouseEvent(EqualsMouseEvent(expected_event.x(),
    684                                                 expected_event.y())))
    685       .After(connected)
    686       .WillOnce(DoAll(
    687           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    688           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    689 
    690   ConnectClientSession();
    691   message_loop_.Run();
    692 }
    693 
    694 TEST_F(ClientSessionTest, NoGnubbyAuth) {
    695   protocol::ExtensionMessage message;
    696   message.set_type("gnubby-auth");
    697   message.set_data("test");
    698 
    699   Expectation authenticated =
    700       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    701           .WillOnce(Return(true));
    702   EXPECT_CALL(*input_injector_, StartPtr(_)).After(authenticated);
    703   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    704       .After(authenticated)
    705       .WillOnce(DoAll(
    706            DeliverClientMessage(client_session_.get(), message),
    707            InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    708            InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    709   EXPECT_CALL(session_event_handler_, OnSessionClosed(_));
    710 
    711   ConnectClientSession();
    712   message_loop_.Run();
    713 }
    714 
    715 TEST_F(ClientSessionTest, EnableGnubbyAuth) {
    716   // Lifetime controlled by object under test.
    717   MockGnubbyAuthHandler* gnubby_auth_handler = new MockGnubbyAuthHandler();
    718 
    719   protocol::ExtensionMessage message;
    720   message.set_type("gnubby-auth");
    721   message.set_data("test");
    722 
    723   Expectation authenticated =
    724       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    725           .WillOnce(Return(true));
    726   EXPECT_CALL(*input_injector_, StartPtr(_)).After(authenticated);
    727   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    728       .After(authenticated)
    729       .WillOnce(DoAll(
    730            SetGnubbyAuthHandlerForTesting(client_session_.get(),
    731                                           gnubby_auth_handler),
    732            DeliverClientMessage(client_session_.get(), message),
    733            InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    734            InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    735   EXPECT_CALL(*gnubby_auth_handler, DeliverClientMessage(_));
    736   EXPECT_CALL(session_event_handler_, OnSessionClosed(_));
    737 
    738   ConnectClientSession();
    739   message_loop_.Run();
    740 }
    741 
    742 // Verifies that messages can be handled by extensions.
    743 TEST_F(ClientSessionTest, ExtensionMessages_MessageHandled) {
    744   FakeExtension extension1("ext1", "cap1");
    745   FakeExtension extension2("ext2", "cap2");
    746   FakeExtension extension3("ext3", "cap3");
    747   HostExtensionList extensions;
    748   extensions.push_back(&extension1);
    749   extensions.push_back(&extension2);
    750   extensions.push_back(&extension3);
    751 
    752   EXPECT_CALL(session_event_handler_, OnSessionClientCapabilities(_))
    753       .WillOnce(Invoke(CreateFunctor(&CreateExtensionSessions, extensions)));
    754 
    755   SetSendMessageAndDisconnectExpectation("ext2");
    756   ConnectClientSession();
    757   message_loop_.Run();
    758 
    759   EXPECT_FALSE(extension1.message_handled());
    760   EXPECT_TRUE(extension2.message_handled());
    761   EXPECT_FALSE(extension3.message_handled());
    762 }
    763 
    764 // Verifies that extension messages not handled by extensions don't result in a
    765 // crash.
    766 TEST_F(ClientSessionTest, ExtensionMessages_MessageNotHandled) {
    767   FakeExtension extension1("ext1", "cap1");
    768   HostExtensionList extensions;
    769   extensions.push_back(&extension1);
    770 
    771   EXPECT_CALL(session_event_handler_, OnSessionClientCapabilities(_))
    772       .WillOnce(Invoke(CreateFunctor(&CreateExtensionSessions, extensions)));
    773 
    774   SetSendMessageAndDisconnectExpectation("extX");
    775   ConnectClientSession();
    776   message_loop_.Run();
    777 
    778   EXPECT_FALSE(extension1.message_handled());
    779 }
    780 
    781 TEST_F(ClientSessionTest, ReportCapabilities) {
    782   Expectation authenticated =
    783       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
    784       .WillOnce(DoAll(
    785           AddHostCapabilities(client_session_.get(), "capX capZ"),
    786           AddHostCapabilities(client_session_.get(), ""),
    787           AddHostCapabilities(client_session_.get(), "capY"),
    788           Return(true)));
    789   EXPECT_CALL(client_stub_,
    790               SetCapabilities(EqCapabilities("capX capY capZ default")));
    791   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
    792       .After(authenticated)
    793       .WillOnce(DoAll(
    794           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
    795           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
    796 
    797   ConnectClientSession();
    798   message_loop_.Run();
    799 }
    800 
    801 }  // namespace remoting
    802