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