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 "base/message_loop/message_loop.h" 6 #include "remoting/base/auto_thread_task_runner.h" 7 #include "remoting/base/constants.h" 8 #include "remoting/host/audio_capturer.h" 9 #include "remoting/host/client_session.h" 10 #include "remoting/host/desktop_environment.h" 11 #include "remoting/host/host_mock_objects.h" 12 #include "remoting/host/screen_capturer_fake.h" 13 #include "remoting/protocol/protocol_mock_objects.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" 16 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" 17 18 namespace remoting { 19 20 using protocol::MockConnectionToClient; 21 using protocol::MockClientStub; 22 using protocol::MockHostStub; 23 using protocol::MockInputStub; 24 using protocol::MockSession; 25 using protocol::MockVideoStub; 26 using protocol::SessionConfig; 27 28 using testing::_; 29 using testing::AnyNumber; 30 using testing::AtMost; 31 using testing::DeleteArg; 32 using testing::DoAll; 33 using testing::Expectation; 34 using testing::Return; 35 using testing::ReturnRef; 36 using testing::Sequence; 37 38 namespace { 39 40 ACTION_P2(InjectClipboardEvent, connection, event) { 41 connection->clipboard_stub()->InjectClipboardEvent(event); 42 } 43 44 ACTION_P2(InjectKeyEvent, connection, event) { 45 connection->input_stub()->InjectKeyEvent(event); 46 } 47 48 ACTION_P2(InjectMouseEvent, connection, event) { 49 connection->input_stub()->InjectMouseEvent(event); 50 } 51 52 ACTION_P2(LocalMouseMoved, client_session, event) { 53 client_session->OnLocalMouseMoved(SkIPoint::Make(event.x(), event.y())); 54 } 55 56 } // namespace 57 58 class ClientSessionTest : public testing::Test { 59 public: 60 ClientSessionTest() : client_jid_("user@domain/rest-of-jid") {} 61 62 virtual void SetUp() OVERRIDE; 63 virtual void TearDown() OVERRIDE; 64 65 // Disconnects the client session. 66 void DisconnectClientSession(); 67 68 // Stops and releases the ClientSession, allowing the MessageLoop to quit. 69 void StopClientSession(); 70 71 protected: 72 // Creates a DesktopEnvironment with a fake webrtc::ScreenCapturer, to mock 73 // DesktopEnvironmentFactory::Create(). 74 DesktopEnvironment* CreateDesktopEnvironment(); 75 76 // Returns |input_injector_| created and initialized by SetUp(), to mock 77 // DesktopEnvironment::CreateInputInjector(). 78 InputInjector* CreateInputInjector(); 79 80 // Creates a fake webrtc::ScreenCapturer, to mock 81 // DesktopEnvironment::CreateVideoCapturer(). 82 webrtc::ScreenCapturer* CreateVideoCapturer(); 83 84 // Notifies the client session that the client connection has been 85 // authenticated and channels have been connected. This effectively enables 86 // the input pipe line and starts video capturing. 87 void ConnectClientSession(); 88 89 // Invoked when the last reference to the AutoThreadTaskRunner has been 90 // released and quits the message loop to finish the test. 91 void QuitMainMessageLoop(); 92 93 // Message loop passed to |client_session_| to perform all functions on. 94 base::MessageLoop message_loop_; 95 96 // ClientSession instance under test. 97 scoped_ptr<ClientSession> client_session_; 98 99 // ClientSession::EventHandler mock for use in tests. 100 MockClientSessionEventHandler session_event_handler_; 101 102 // Storage for values to be returned by the protocol::Session mock. 103 SessionConfig session_config_; 104 const std::string client_jid_; 105 106 // Stubs returned to |client_session_| components by |connection_|. 107 MockClientStub client_stub_; 108 MockVideoStub video_stub_; 109 110 // DesktopEnvironment owns |input_injector_|, but input injection tests need 111 // to express expectations on it. 112 scoped_ptr<MockInputInjector> input_injector_; 113 114 // ClientSession owns |connection_| but tests need it to inject fake events. 115 MockConnectionToClient* connection_; 116 117 scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory_; 118 }; 119 120 void ClientSessionTest::SetUp() { 121 // Arrange to run |message_loop_| until no components depend on it. 122 scoped_refptr<AutoThreadTaskRunner> ui_task_runner = new AutoThreadTaskRunner( 123 message_loop_.message_loop_proxy(), 124 base::Bind(&ClientSessionTest::QuitMainMessageLoop, 125 base::Unretained(this))); 126 127 desktop_environment_factory_.reset(new MockDesktopEnvironmentFactory()); 128 EXPECT_CALL(*desktop_environment_factory_, CreatePtr()) 129 .Times(AnyNumber()) 130 .WillRepeatedly(Invoke(this, 131 &ClientSessionTest::CreateDesktopEnvironment)); 132 EXPECT_CALL(*desktop_environment_factory_, SupportsAudioCapture()) 133 .Times(AnyNumber()) 134 .WillRepeatedly(Return(false)); 135 136 input_injector_.reset(new MockInputInjector()); 137 138 session_config_ = SessionConfig::ForTest(); 139 140 // Mock protocol::Session APIs called directly by ClientSession. 141 protocol::MockSession* session = new MockSession(); 142 EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(session_config_)); 143 EXPECT_CALL(*session, jid()).WillRepeatedly(ReturnRef(client_jid_)); 144 EXPECT_CALL(*session, SetEventHandler(_)); 145 146 // Mock protocol::ConnectionToClient APIs called directly by ClientSession. 147 // HostStub is not touched by ClientSession, so we can safely pass NULL. 148 scoped_ptr<MockConnectionToClient> connection( 149 new MockConnectionToClient(session, NULL)); 150 EXPECT_CALL(*connection, session()).WillRepeatedly(Return(session)); 151 EXPECT_CALL(*connection, client_stub()) 152 .WillRepeatedly(Return(&client_stub_)); 153 EXPECT_CALL(*connection, video_stub()).WillRepeatedly(Return(&video_stub_)); 154 EXPECT_CALL(*connection, Disconnect()); 155 connection_ = connection.get(); 156 157 client_session_.reset(new ClientSession( 158 &session_event_handler_, 159 ui_task_runner, // Audio thread. 160 ui_task_runner, // Input thread. 161 ui_task_runner, // Capture thread. 162 ui_task_runner, // Encode thread. 163 ui_task_runner, // Network thread. 164 ui_task_runner, // UI thread. 165 connection.PassAs<protocol::ConnectionToClient>(), 166 desktop_environment_factory_.get(), 167 base::TimeDelta(), 168 NULL)); 169 } 170 171 void ClientSessionTest::TearDown() { 172 // Verify that the client session has been stopped. 173 EXPECT_TRUE(!client_session_); 174 } 175 176 void ClientSessionTest::DisconnectClientSession() { 177 client_session_->DisconnectSession(); 178 // MockSession won't trigger OnConnectionClosed, so fake it. 179 client_session_->OnConnectionClosed(client_session_->connection(), 180 protocol::OK); 181 } 182 183 void ClientSessionTest::StopClientSession() { 184 client_session_.reset(); 185 186 desktop_environment_factory_.reset(); 187 } 188 189 DesktopEnvironment* ClientSessionTest::CreateDesktopEnvironment() { 190 MockDesktopEnvironment* desktop_environment = new MockDesktopEnvironment(); 191 EXPECT_CALL(*desktop_environment, CreateAudioCapturerPtr()) 192 .Times(0); 193 EXPECT_CALL(*desktop_environment, CreateInputInjectorPtr()) 194 .WillOnce(Invoke(this, &ClientSessionTest::CreateInputInjector)); 195 EXPECT_CALL(*desktop_environment, CreateScreenControlsPtr()) 196 .Times(AtMost(1)); 197 EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr()) 198 .WillOnce(Invoke(this, &ClientSessionTest::CreateVideoCapturer)); 199 EXPECT_CALL(*desktop_environment, GetCapabilities()) 200 .Times(AtMost(1)); 201 EXPECT_CALL(*desktop_environment, SetCapabilities(_)) 202 .Times(AtMost(1)); 203 204 return desktop_environment; 205 } 206 207 InputInjector* ClientSessionTest::CreateInputInjector() { 208 EXPECT_TRUE(input_injector_); 209 return input_injector_.release(); 210 } 211 212 webrtc::ScreenCapturer* ClientSessionTest::CreateVideoCapturer() { 213 return new ScreenCapturerFake(); 214 } 215 216 void ClientSessionTest::ConnectClientSession() { 217 client_session_->OnConnectionAuthenticated(client_session_->connection()); 218 client_session_->OnConnectionChannelsConnected(client_session_->connection()); 219 } 220 221 void ClientSessionTest::QuitMainMessageLoop() { 222 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 223 } 224 225 MATCHER_P2(EqualsClipboardEvent, m, d, "") { 226 return (strcmp(arg.mime_type().c_str(), m) == 0 && 227 memcmp(arg.data().data(), d, arg.data().size()) == 0); 228 } 229 230 TEST_F(ClientSessionTest, ClipboardStubFilter) { 231 protocol::ClipboardEvent clipboard_event1; 232 clipboard_event1.set_mime_type(kMimeTypeTextUtf8); 233 clipboard_event1.set_data("a"); 234 235 protocol::ClipboardEvent clipboard_event2; 236 clipboard_event2.set_mime_type(kMimeTypeTextUtf8); 237 clipboard_event2.set_data("b"); 238 239 protocol::ClipboardEvent clipboard_event3; 240 clipboard_event3.set_mime_type(kMimeTypeTextUtf8); 241 clipboard_event3.set_data("c"); 242 243 Expectation authenticated = 244 EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)) 245 .WillOnce(Return(true)); 246 EXPECT_CALL(*input_injector_, StartPtr(_)) 247 .After(authenticated); 248 EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)) 249 .After(authenticated); 250 251 // Wait for the first video packet to be captured to make sure that 252 // the injected input will go though. Otherwise mouse events will be blocked 253 // by the mouse clamping filter. 254 Sequence s; 255 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) 256 .InSequence(s) 257 .After(authenticated) 258 .WillOnce(DoAll( 259 // This event should get through to the clipboard stub. 260 InjectClipboardEvent(connection_, clipboard_event2), 261 InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession), 262 // This event should not get through to the clipboard stub, 263 // because the client has disconnected. 264 InjectClipboardEvent(connection_, clipboard_event3), 265 InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession))); 266 EXPECT_CALL(*input_injector_, InjectClipboardEvent(EqualsClipboardEvent( 267 kMimeTypeTextUtf8, "b"))) 268 .InSequence(s); 269 EXPECT_CALL(session_event_handler_, OnSessionClosed(_)) 270 .InSequence(s); 271 272 // This event should not get through to the clipboard stub, 273 // because the client isn't authenticated yet. 274 connection_->clipboard_stub()->InjectClipboardEvent(clipboard_event1); 275 276 ConnectClientSession(); 277 message_loop_.Run(); 278 } 279 280 namespace { 281 282 MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") { 283 return arg.usb_keycode() == (unsigned int)usb_keycode && 284 arg.pressed() == pressed; 285 } 286 287 MATCHER_P2(EqualsMouseEvent, x, y, "") { 288 return arg.x() == x && arg.y() == y; 289 } 290 291 MATCHER_P2(EqualsMouseButtonEvent, button, down, "") { 292 return arg.button() == button && arg.button_down() == down; 293 } 294 295 } 296 297 TEST_F(ClientSessionTest, InputStubFilter) { 298 protocol::KeyEvent key_event1; 299 key_event1.set_pressed(true); 300 key_event1.set_usb_keycode(1); 301 302 protocol::KeyEvent key_event2_down; 303 key_event2_down.set_pressed(true); 304 key_event2_down.set_usb_keycode(2); 305 306 protocol::KeyEvent key_event2_up; 307 key_event2_up.set_pressed(false); 308 key_event2_up.set_usb_keycode(2); 309 310 protocol::KeyEvent key_event3; 311 key_event3.set_pressed(true); 312 key_event3.set_usb_keycode(3); 313 314 protocol::MouseEvent mouse_event1; 315 mouse_event1.set_x(100); 316 mouse_event1.set_y(101); 317 318 protocol::MouseEvent mouse_event2; 319 mouse_event2.set_x(200); 320 mouse_event2.set_y(201); 321 322 protocol::MouseEvent mouse_event3; 323 mouse_event3.set_x(300); 324 mouse_event3.set_y(301); 325 326 Expectation authenticated = 327 EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)) 328 .WillOnce(Return(true)); 329 EXPECT_CALL(*input_injector_, StartPtr(_)) 330 .After(authenticated); 331 EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)) 332 .After(authenticated); 333 334 // Wait for the first video packet to be captured to make sure that 335 // the injected input will go though. Otherwise mouse events will be blocked 336 // by the mouse clamping filter. 337 Sequence s; 338 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) 339 .InSequence(s) 340 .After(authenticated) 341 .WillOnce(DoAll( 342 // These events should get through to the input stub. 343 InjectKeyEvent(connection_, key_event2_down), 344 InjectKeyEvent(connection_, key_event2_up), 345 InjectMouseEvent(connection_, mouse_event2), 346 InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession), 347 // These events should not get through to the input stub, 348 // because the client has disconnected. 349 InjectKeyEvent(connection_, key_event3), 350 InjectMouseEvent(connection_, mouse_event3), 351 InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession))); 352 EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true))) 353 .InSequence(s); 354 EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false))) 355 .InSequence(s); 356 EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201))) 357 .InSequence(s); 358 EXPECT_CALL(session_event_handler_, OnSessionClosed(_)) 359 .InSequence(s); 360 361 // These events should not get through to the input stub, 362 // because the client isn't authenticated yet. 363 connection_->input_stub()->InjectKeyEvent(key_event1); 364 connection_->input_stub()->InjectMouseEvent(mouse_event1); 365 366 ConnectClientSession(); 367 message_loop_.Run(); 368 } 369 370 TEST_F(ClientSessionTest, LocalInputTest) { 371 protocol::MouseEvent mouse_event1; 372 mouse_event1.set_x(100); 373 mouse_event1.set_y(101); 374 protocol::MouseEvent mouse_event2; 375 mouse_event2.set_x(200); 376 mouse_event2.set_y(201); 377 protocol::MouseEvent mouse_event3; 378 mouse_event3.set_x(300); 379 mouse_event3.set_y(301); 380 381 Expectation authenticated = 382 EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)) 383 .WillOnce(Return(true)); 384 EXPECT_CALL(*input_injector_, StartPtr(_)) 385 .After(authenticated); 386 EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)) 387 .After(authenticated); 388 389 // Wait for the first video packet to be captured to make sure that 390 // the injected input will go though. Otherwise mouse events will be blocked 391 // by the mouse clamping filter. 392 Sequence s; 393 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) 394 .InSequence(s) 395 .After(authenticated) 396 .WillOnce(DoAll( 397 // This event should get through to the input stub. 398 InjectMouseEvent(connection_, mouse_event1), 399 #if !defined(OS_WIN) 400 // The OS echoes the injected event back. 401 LocalMouseMoved(client_session_.get(), mouse_event1), 402 #endif // !defined(OS_WIN) 403 // This one should get throught as well. 404 InjectMouseEvent(connection_, mouse_event2), 405 // Now this is a genuine local event. 406 LocalMouseMoved(client_session_.get(), mouse_event1), 407 // This one should be blocked because of the previous local input 408 // event. 409 InjectMouseEvent(connection_, mouse_event3), 410 // TODO(jamiewalch): Verify that remote inputs are re-enabled 411 // eventually (via dependency injection, not sleep!) 412 InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession), 413 InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession))); 414 EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(100, 101))) 415 .InSequence(s); 416 EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201))) 417 .InSequence(s); 418 EXPECT_CALL(session_event_handler_, OnSessionClosed(_)) 419 .InSequence(s); 420 421 ConnectClientSession(); 422 message_loop_.Run(); 423 } 424 425 TEST_F(ClientSessionTest, RestoreEventState) { 426 protocol::KeyEvent key1; 427 key1.set_pressed(true); 428 key1.set_usb_keycode(1); 429 430 protocol::KeyEvent key2; 431 key2.set_pressed(true); 432 key2.set_usb_keycode(2); 433 434 protocol::MouseEvent mousedown; 435 mousedown.set_button(protocol::MouseEvent::BUTTON_LEFT); 436 mousedown.set_button_down(true); 437 438 Expectation authenticated = 439 EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)) 440 .WillOnce(Return(true)); 441 EXPECT_CALL(*input_injector_, StartPtr(_)) 442 .After(authenticated); 443 EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)) 444 .After(authenticated); 445 446 // Wait for the first video packet to be captured to make sure that 447 // the injected input will go though. Otherwise mouse events will be blocked 448 // by the mouse clamping filter. 449 Sequence s; 450 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) 451 .InSequence(s) 452 .After(authenticated) 453 .WillOnce(DoAll( 454 InjectKeyEvent(connection_, key1), 455 InjectKeyEvent(connection_, key2), 456 InjectMouseEvent(connection_, mousedown), 457 InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession), 458 InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession))); 459 EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, true))) 460 .InSequence(s); 461 EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true))) 462 .InSequence(s); 463 EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent( 464 protocol::MouseEvent::BUTTON_LEFT, true))) 465 .InSequence(s); 466 EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, false))) 467 .InSequence(s); 468 EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false))) 469 .InSequence(s); 470 EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent( 471 protocol::MouseEvent::BUTTON_LEFT, false))) 472 .InSequence(s); 473 EXPECT_CALL(session_event_handler_, OnSessionClosed(_)) 474 .InSequence(s); 475 476 ConnectClientSession(); 477 message_loop_.Run(); 478 } 479 480 TEST_F(ClientSessionTest, ClampMouseEvents) { 481 Expectation authenticated = 482 EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)) 483 .WillOnce(Return(true)); 484 EXPECT_CALL(*input_injector_, StartPtr(_)) 485 .After(authenticated); 486 EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)) 487 .After(authenticated); 488 EXPECT_CALL(session_event_handler_, OnSessionClosed(_)) 489 .After(authenticated); 490 491 Expectation connected = authenticated; 492 493 int input_x[3] = { -999, 100, 999 }; 494 int expected_x[3] = { 0, 100, ScreenCapturerFake::kWidth - 1 }; 495 int input_y[3] = { -999, 50, 999 }; 496 int expected_y[3] = { 0, 50, ScreenCapturerFake::kHeight - 1 }; 497 498 protocol::MouseEvent expected_event; 499 for (int j = 0; j < 3; j++) { 500 for (int i = 0; i < 3; i++) { 501 protocol::MouseEvent injected_event; 502 injected_event.set_x(input_x[i]); 503 injected_event.set_y(input_y[j]); 504 505 if (i == 0 && j == 0) { 506 // Inject the 1st event once a video packet has been received. 507 connected = 508 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) 509 .After(connected) 510 .WillOnce(InjectMouseEvent(connection_, injected_event)); 511 } else { 512 // Every next event is injected once the previous event has been 513 // received. 514 connected = 515 EXPECT_CALL(*input_injector_, 516 InjectMouseEvent(EqualsMouseEvent(expected_event.x(), 517 expected_event.y()))) 518 .After(connected) 519 .WillOnce(InjectMouseEvent(connection_, injected_event)); 520 } 521 522 expected_event.set_x(expected_x[i]); 523 expected_event.set_y(expected_y[j]); 524 } 525 } 526 527 // Shutdown the connection once the last event has been received. 528 EXPECT_CALL(*input_injector_, 529 InjectMouseEvent(EqualsMouseEvent(expected_event.x(), 530 expected_event.y()))) 531 .After(connected) 532 .WillOnce(DoAll( 533 InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession), 534 InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession))); 535 536 ConnectClientSession(); 537 message_loop_.Run(); 538 } 539 540 } // namespace remoting 541