• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ACTION_P2(InjectClipboardEvent,connection,event)56 ACTION_P2(InjectClipboardEvent, connection, event) {
57   connection->clipboard_stub()->InjectClipboardEvent(event);
58 }
59 
ACTION_P2(InjectKeyEvent,connection,event)60 ACTION_P2(InjectKeyEvent, connection, event) {
61   connection->input_stub()->InjectKeyEvent(event);
62 }
63 
ACTION_P2(InjectMouseEvent,connection,event)64 ACTION_P2(InjectMouseEvent, connection, event) {
65   connection->input_stub()->InjectMouseEvent(event);
66 }
67 
ACTION_P2(LocalMouseMoved,client_session,event)68 ACTION_P2(LocalMouseMoved, client_session, event) {
69   client_session->OnLocalMouseMoved(
70       webrtc::DesktopVector(event.x(), event.y()));
71 }
72 
ACTION_P2(SetGnubbyAuthHandlerForTesting,client_session,gnubby_auth_handler)73 ACTION_P2(SetGnubbyAuthHandlerForTesting, client_session, gnubby_auth_handler) {
74   client_session->SetGnubbyAuthHandlerForTesting(gnubby_auth_handler);
75 }
76 
ACTION_P2(DeliverClientMessage,client_session,message)77 ACTION_P2(DeliverClientMessage, client_session, message) {
78   client_session->DeliverClientMessage(message);
79 }
80 
ACTION_P2(AddHostCapabilities,client_session,capability)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 
message_handled()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 
CreateExtensionSessions(const HostExtensionList & extensions,ClientSession * client_session)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:
ClientSessionTest()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 
FakeExtension(const std::string & message_type,const std::string & capabilities)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 
~FakeExtension()223 FakeExtension::~FakeExtension() {}
224 
GetCapabilities()225 std::string FakeExtension::GetCapabilities() {
226   return capabilities_;
227 }
228 
CreateExtensionSession(ClientSession * client_session)229 scoped_ptr<HostExtensionSession> FakeExtension::CreateExtensionSession(
230     ClientSession* client_session) {
231   return scoped_ptr<HostExtensionSession>(new FakeExtensionSession(this));
232 }
233 
FakeExtensionSession(FakeExtension * extension)234 FakeExtension::FakeExtensionSession::FakeExtensionSession(
235     FakeExtension* extension)
236     : extension_(extension) {
237 }
238 
~FakeExtensionSession()239 FakeExtension::FakeExtensionSession::~FakeExtensionSession() {}
240 
OnExtensionMessage(ClientSession * client_session,const protocol::ExtensionMessage & message)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 
SetUp()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 
TearDown()307 void ClientSessionTest::TearDown() {
308   // Verify that the client session has been stopped.
309   EXPECT_TRUE(!client_session_);
310 }
311 
DisconnectClientSession()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 
StopClientSession()319 void ClientSessionTest::StopClientSession() {
320   client_session_.reset();
321 
322   desktop_environment_factory_.reset();
323 }
324 
CreateDesktopEnvironment()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 
CreateInputInjector()344 InputInjector* ClientSessionTest::CreateInputInjector() {
345   EXPECT_TRUE(input_injector_);
346   return input_injector_.release();
347 }
348 
CreateVideoCapturer()349 webrtc::ScreenCapturer* ClientSessionTest::CreateVideoCapturer() {
350   return new ScreenCapturerFake();
351 }
352 
ConnectClientSession()353 void ClientSessionTest::ConnectClientSession() {
354   client_session_->OnConnectionAuthenticated(client_session_->connection());
355   client_session_->OnConnectionChannelsConnected(client_session_->connection());
356 }
357 
SetSendMessageAndDisconnectExpectation(const std::string & message_type)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 
QuitMainMessageLoop()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 
TEST_F(ClientSessionTest,ClipboardStubFilter)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 
TEST_F(ClientSessionTest,InputStubFilter)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 
TEST_F(ClientSessionTest,LocalInputTest)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 
TEST_F(ClientSessionTest,RestoreEventState)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 
TEST_F(ClientSessionTest,ClampMouseEvents)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 
TEST_F(ClientSessionTest,NoGnubbyAuth)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 
TEST_F(ClientSessionTest,EnableGnubbyAuth)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.
TEST_F(ClientSessionTest,ExtensionMessages_MessageHandled)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.
TEST_F(ClientSessionTest,ExtensionMessages_MessageNotHandled)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 
TEST_F(ClientSessionTest,ReportCapabilities)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