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