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