chromoting_host_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/bind.h" 6#include "base/memory/scoped_ptr.h" 7#include "base/message_loop_proxy.h" 8#include "remoting/base/auto_thread_task_runner.h" 9#include "remoting/jingle_glue/mock_objects.h" 10#include "remoting/host/audio_capturer.h" 11#include "remoting/host/chromoting_host_context.h" 12#include "remoting/host/chromoting_host.h" 13#include "remoting/host/desktop_environment.h" 14#include "remoting/host/desktop_environment_factory.h" 15#include "remoting/host/event_executor_fake.h" 16#include "remoting/host/host_mock_objects.h" 17#include "remoting/host/it2me_host_user_interface.h" 18#include "remoting/host/video_frame_capturer_fake.h" 19#include "remoting/proto/video.pb.h" 20#include "remoting/protocol/errors.h" 21#include "remoting/protocol/protocol_mock_objects.h" 22#include "remoting/protocol/session_config.h" 23#include "testing/gmock_mutant.h" 24#include "testing/gmock/include/gmock/gmock.h" 25#include "testing/gtest/include/gtest/gtest.h" 26 27using ::remoting::protocol::MockClientStub; 28using ::remoting::protocol::MockConnectionToClient; 29using ::remoting::protocol::MockConnectionToClientEventHandler; 30using ::remoting::protocol::MockHostStub; 31using ::remoting::protocol::MockSession; 32using ::remoting::protocol::MockVideoStub; 33using ::remoting::protocol::SessionConfig; 34 35using testing::_; 36using testing::AnyNumber; 37using testing::AtLeast; 38using testing::CreateFunctor; 39using testing::DeleteArg; 40using testing::DoAll; 41using testing::Expectation; 42using testing::InSequence; 43using testing::Invoke; 44using testing::InvokeArgument; 45using testing::InvokeWithoutArgs; 46using testing::Return; 47using testing::ReturnRef; 48using testing::Sequence; 49 50namespace remoting { 51 52namespace { 53 54void PostQuitTask(MessageLoop* message_loop) { 55 message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 56} 57 58// Run the task and delete it afterwards. This action is used to deal with 59// done callbacks. 60ACTION(RunDoneTask) { 61 arg1.Run(); 62} 63 64void DoNothing() { 65} 66 67} // namespace 68 69class MockIt2MeHostUserInterface : public It2MeHostUserInterface { 70 public: 71 MockIt2MeHostUserInterface( 72 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, 73 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); 74 75 void InitFrom( 76 scoped_ptr<DisconnectWindow> disconnect_window, 77 scoped_ptr<ContinueWindow> continue_window, 78 scoped_ptr<LocalInputMonitor> local_input_monitor); 79 80 // A test-only version of Start that does not register a HostStatusObserver. 81 // TODO(rmsousa): Make the unit tests work with the regular Start(). 82 virtual void Start(ChromotingHost* host, 83 const base::Closure& disconnect_callback) OVERRIDE; 84}; 85 86MockIt2MeHostUserInterface::MockIt2MeHostUserInterface( 87 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, 88 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) 89 : It2MeHostUserInterface(network_task_runner, ui_task_runner) { 90} 91 92void MockIt2MeHostUserInterface::InitFrom( 93 scoped_ptr<DisconnectWindow> disconnect_window, 94 scoped_ptr<ContinueWindow> continue_window, 95 scoped_ptr<LocalInputMonitor> local_input_monitor) { 96 DCHECK(ui_task_runner()->BelongsToCurrentThread()); 97 98 disconnect_window_ = disconnect_window.Pass(); 99 continue_window_ = continue_window.Pass(); 100 local_input_monitor_ = local_input_monitor.Pass(); 101} 102 103void MockIt2MeHostUserInterface::Start( 104 ChromotingHost* host, const base::Closure& disconnect_callback) { 105 DCHECK(network_task_runner()->BelongsToCurrentThread()); 106 DCHECK(host_ == NULL); 107 108 host_ = host; 109 disconnect_callback_ = disconnect_callback; 110} 111 112class ChromotingHostTest : public testing::Test { 113 public: 114 ChromotingHostTest() { 115 } 116 117 virtual void SetUp() OVERRIDE { 118 ui_task_runner_ = new AutoThreadTaskRunner( 119 message_loop_.message_loop_proxy(), 120 base::Bind(&ChromotingHostTest::QuitMainMessageLoop, 121 base::Unretained(this))); 122 123 EXPECT_CALL(context_, ui_task_runner()) 124 .Times(AnyNumber()) 125 .WillRepeatedly(Return(ui_task_runner_.get())); 126 EXPECT_CALL(context_, capture_task_runner()) 127 .Times(AnyNumber()) 128 .WillRepeatedly(Return(ui_task_runner_.get())); 129 EXPECT_CALL(context_, encode_task_runner()) 130 .Times(AnyNumber()) 131 .WillRepeatedly(Return(ui_task_runner_.get())); 132 EXPECT_CALL(context_, network_task_runner()) 133 .Times(AnyNumber()) 134 .WillRepeatedly(Return(ui_task_runner_.get())); 135 136 desktop_environment_factory_.reset(new MockDesktopEnvironmentFactory()); 137 EXPECT_CALL(*desktop_environment_factory_, CreatePtr(_)) 138 .Times(AnyNumber()) 139 .WillRepeatedly(Invoke(this, 140 &ChromotingHostTest::CreateDesktopEnvironment)); 141 142 session_manager_ = new protocol::MockSessionManager(); 143 144 host_ = new ChromotingHost( 145 &signal_strategy_, 146 desktop_environment_factory_.get(), 147 scoped_ptr<protocol::SessionManager>(session_manager_), 148 context_.audio_task_runner(), 149 context_.capture_task_runner(), 150 context_.encode_task_runner(), 151 context_.network_task_runner()); 152 host_->AddStatusObserver(&host_status_observer_); 153 154 disconnect_window_ = new MockDisconnectWindow(); 155 continue_window_ = new MockContinueWindow(); 156 local_input_monitor_ = new MockLocalInputMonitor(); 157 it2me_host_user_interface_.reset( 158 new MockIt2MeHostUserInterface(context_.network_task_runner(), 159 context_.ui_task_runner())); 160 it2me_host_user_interface_->InitFrom( 161 scoped_ptr<DisconnectWindow>(disconnect_window_), 162 scoped_ptr<ContinueWindow>(continue_window_), 163 scoped_ptr<LocalInputMonitor>(local_input_monitor_)); 164 165 it2me_host_user_interface_->Start( 166 host_, base::Bind(&ChromotingHost::Shutdown, host_, base::Closure())); 167 168 xmpp_login_ = "host@domain"; 169 session1_ = new MockSession(); 170 session2_ = new MockSession(); 171 session_unowned1_.reset(new MockSession()); 172 session_unowned2_.reset(new MockSession()); 173 session_config1_ = SessionConfig::ForTest(); 174 session_jid1_ = "user@domain/rest-of-jid"; 175 session_config2_ = SessionConfig::ForTest(); 176 session_jid2_ = "user2@domain/rest-of-jid"; 177 session_unowned_config1_ = SessionConfig::ForTest(); 178 session_unowned_jid1_ = "user3@doman/rest-of-jid"; 179 session_unowned_config2_ = SessionConfig::ForTest(); 180 session_unowned_jid2_ = "user4@doman/rest-of-jid"; 181 182 EXPECT_CALL(*session1_, jid()) 183 .WillRepeatedly(ReturnRef(session_jid1_)); 184 EXPECT_CALL(*session2_, jid()) 185 .WillRepeatedly(ReturnRef(session_jid2_)); 186 EXPECT_CALL(*session_unowned1_, jid()) 187 .WillRepeatedly(ReturnRef(session_unowned_jid1_)); 188 EXPECT_CALL(*session_unowned2_, jid()) 189 .WillRepeatedly(ReturnRef(session_unowned_jid2_)); 190 EXPECT_CALL(*session1_, SetEventHandler(_)) 191 .Times(AnyNumber()); 192 EXPECT_CALL(*session2_, SetEventHandler(_)) 193 .Times(AnyNumber()); 194 EXPECT_CALL(*session_unowned1_, SetEventHandler(_)) 195 .Times(AnyNumber()) 196 .WillRepeatedly(Invoke(this, &ChromotingHostTest::SetEventHandler)); 197 EXPECT_CALL(*session_unowned2_, SetEventHandler(_)) 198 .Times(AnyNumber()); 199 EXPECT_CALL(*session1_, config()) 200 .WillRepeatedly(ReturnRef(session_config1_)); 201 EXPECT_CALL(*session2_, config()) 202 .WillRepeatedly(ReturnRef(session_config2_)); 203 204 owned_connection1_.reset(new MockConnectionToClient(session1_, 205 &host_stub1_)); 206 connection1_ = owned_connection1_.get(); 207 owned_connection2_.reset(new MockConnectionToClient(session2_, 208 &host_stub2_)); 209 connection2_ = owned_connection2_.get(); 210 211 ON_CALL(video_stub1_, ProcessVideoPacketPtr(_, _)) 212 .WillByDefault(DeleteArg<0>()); 213 ON_CALL(video_stub2_, ProcessVideoPacketPtr(_, _)) 214 .WillByDefault(DeleteArg<0>()); 215 ON_CALL(*connection1_, video_stub()) 216 .WillByDefault(Return(&video_stub1_)); 217 ON_CALL(*connection1_, client_stub()) 218 .WillByDefault(Return(&client_stub1_)); 219 ON_CALL(*connection1_, session()) 220 .WillByDefault(Return(session1_)); 221 ON_CALL(*connection2_, video_stub()) 222 .WillByDefault(Return(&video_stub2_)); 223 ON_CALL(*connection2_, client_stub()) 224 .WillByDefault(Return(&client_stub2_)); 225 ON_CALL(*connection2_, session()) 226 .WillByDefault(Return(session2_)); 227 EXPECT_CALL(*connection1_, video_stub()) 228 .Times(AnyNumber()); 229 EXPECT_CALL(*connection1_, client_stub()) 230 .Times(AnyNumber()); 231 EXPECT_CALL(*connection1_, session()) 232 .Times(AnyNumber()); 233 EXPECT_CALL(*connection2_, video_stub()) 234 .Times(AnyNumber()); 235 EXPECT_CALL(*connection2_, client_stub()) 236 .Times(AnyNumber()); 237 EXPECT_CALL(*connection2_, session()) 238 .Times(AnyNumber()); 239 240 empty_candidate_config_ = 241 protocol::CandidateSessionConfig::CreateEmpty(); 242 default_candidate_config_ = 243 protocol::CandidateSessionConfig::CreateDefault(); 244 } 245 246 // Helper method to pretend a client is connected to ChromotingHost. 247 void SimulateClientConnection(int connection_index, bool authenticate, 248 bool reject) { 249 scoped_ptr<protocol::ConnectionToClient> connection = 250 ((connection_index == 0) ? owned_connection1_ : owned_connection2_). 251 PassAs<protocol::ConnectionToClient>(); 252 protocol::ConnectionToClient* connection_ptr = connection.get(); 253 scoped_refptr<ClientSession> client = new ClientSession( 254 host_.get(), 255 context_.audio_task_runner(), 256 context_.capture_task_runner(), 257 context_.encode_task_runner(), 258 context_.network_task_runner(), 259 connection.Pass(), 260 desktop_environment_factory_.get(), 261 base::TimeDelta()); 262 connection_ptr->set_host_stub(client); 263 connection_ptr->set_input_stub( 264 client->desktop_environment()->event_executor()); 265 266 context_.network_task_runner()->PostTask( 267 FROM_HERE, base::Bind(&ChromotingHostTest::AddClientToHost, 268 host_, client)); 269 270 if (authenticate) { 271 context_.network_task_runner()->PostTask( 272 FROM_HERE, base::Bind(&ClientSession::OnConnectionAuthenticated, 273 client, connection_ptr)); 274 if (!reject) { 275 context_.network_task_runner()->PostTask( 276 FROM_HERE, 277 base::Bind(&ClientSession::OnConnectionChannelsConnected, 278 client, connection_ptr)); 279 } 280 } else { 281 context_.network_task_runner()->PostTask( 282 FROM_HERE, base::Bind(&ClientSession::OnConnectionClosed, 283 client, connection_ptr, 284 protocol::AUTHENTICATION_FAILED)); 285 } 286 287 get_client(connection_index) = client; 288 } 289 290 virtual void TearDown() OVERRIDE { 291 // Make sure that the host has been properly deleted. 292 DCHECK(host_.get() == NULL); 293 } 294 295 // Change the session route for |client1_|. 296 void ChangeSessionRoute(const std::string& channel_name, 297 const protocol::TransportRoute& route) { 298 host_->OnSessionRouteChange(get_client(0), channel_name, route); 299 } 300 301 DesktopEnvironment* CreateDesktopEnvironment(ClientSession* client) { 302 scoped_ptr<EventExecutor> event_executor(new EventExecutorFake()); 303 scoped_ptr<VideoFrameCapturer> video_capturer(new VideoFrameCapturerFake()); 304 return new DesktopEnvironment(scoped_ptr<AudioCapturer>(NULL), 305 event_executor.Pass(), 306 video_capturer.Pass()); 307 } 308 309 void DisconnectAllClients() { 310 host_->DisconnectAllClients(); 311 } 312 313 // Helper method to disconnect client 1 from the host. 314 void DisconnectClient1() { 315 client1_->OnConnectionClosed(connection1_, protocol::OK); 316 } 317 318 // Notify |host_| that the authenticating client has been rejected. 319 void RejectAuthenticatingClient() { 320 host_->RejectAuthenticatingClient(); 321 } 322 323 // Notify |host_| that a client session has closed. 324 void NotifyClientSessionClosed(int connection_index) { 325 host_->OnSessionClosed(get_client(connection_index)); 326 } 327 328 void SetEventHandler(protocol::Session::EventHandler* event_handler) { 329 session_event_handler_ = event_handler; 330 } 331 332 void NotifyConnectionClosed() { 333 if (session_event_handler_) { 334 session_event_handler_->OnSessionStateChange(protocol::Session::CLOSED); 335 } 336 } 337 338 static void AddClientToHost(scoped_refptr<ChromotingHost> host, 339 ClientSession* session) { 340 host->clients_.push_back(session); 341 host->clients_count_++; 342 } 343 344 void ShutdownHost() { 345 ui_task_runner_->PostTask( 346 FROM_HERE, 347 base::Bind(&ChromotingHost::Shutdown, host_, 348 base::Bind(&ChromotingHostTest::ReleaseUiTaskRunner, 349 base::Unretained(this)))); 350 } 351 352 void ReleaseUiTaskRunner() { 353 it2me_host_user_interface_.reset(); 354 ui_task_runner_ = NULL; 355 host_ = NULL; 356 } 357 358 void QuitMainMessageLoop() { 359 PostQuitTask(&message_loop_); 360 } 361 362 // Expect the host to start. 363 void ExpectHostStart() { 364 EXPECT_CALL(*disconnect_window_, Hide()); 365 EXPECT_CALL(*continue_window_, Hide()); 366 } 367 368 // Expect the host and session manager to start, and return the expectation 369 // that the session manager has started. 370 Expectation ExpectHostAndSessionManagerStart() { 371 ExpectHostStart(); 372 EXPECT_CALL(host_status_observer_, OnStart(xmpp_login_)); 373 return EXPECT_CALL(*session_manager_, Init(_, host_.get())); 374 } 375 376 // Expect a client to connect. 377 // Return an expectation that a session has started, and that the first 378 // video packet has been sent to the client. 379 // Do |action| when that happens. 380 template <class A> 381 Expectation ExpectClientConnected(int connection_index, A action) { 382 const std::string& session_jid = get_session_jid(connection_index); 383 MockVideoStub& video_stub = get_video_stub(connection_index); 384 385 Expectation client_authenticated = 386 EXPECT_CALL(host_status_observer_, OnClientAuthenticated(session_jid)); 387 EXPECT_CALL(host_status_observer_, OnClientConnected(session_jid)) 388 .After(client_authenticated); 389 Expectation video_packet_sent = 390 EXPECT_CALL(video_stub, ProcessVideoPacketPtr(_, _)) 391 .After(client_authenticated) 392 .WillOnce(DoAll( 393 action, 394 RunDoneTask())) 395 .RetiresOnSaturation(); 396 EXPECT_CALL(video_stub, ProcessVideoPacketPtr(_, _)) 397 .Times(AnyNumber()) 398 .After(video_packet_sent) 399 .WillRepeatedly(RunDoneTask()); 400 return video_packet_sent; 401 } 402 403 // Return an expectation that a client will disconnect after a given 404 // expectation. The given action will be done after the event executor is 405 // notified that the session has finished. 406 template <class A> 407 Expectation ExpectClientDisconnected(int connection_index, 408 bool expect_host_status_change, 409 Expectation after, 410 A action) { 411 MockConnectionToClient* connection = get_connection(connection_index); 412 413 Expectation client_disconnected = 414 EXPECT_CALL(*connection, Disconnect()) 415 .After(after) 416 .WillOnce(InvokeWithoutArgs(CreateFunctor( 417 this, &ChromotingHostTest::NotifyClientSessionClosed, 418 connection_index))) 419 .RetiresOnSaturation(); 420 ExpectClientDisconnectEffects(connection_index, 421 expect_host_status_change, 422 after, 423 action); 424 return client_disconnected; 425 } 426 427 // Expect the side-effects of a client disconnection, after a given 428 // expectation. The given action will be done after the event executor is 429 // notifed that the session has finished. 430 template <class A> 431 void ExpectClientDisconnectEffects(int connection_index, 432 bool expect_host_status_change, 433 Expectation after, 434 A action) { 435 const std::string& session_jid = get_session_jid(connection_index); 436 437 if (expect_host_status_change) { 438 EXPECT_CALL(host_status_observer_, OnClientDisconnected(session_jid)) 439 .After(after) 440 .WillOnce(action) 441 .RetiresOnSaturation(); 442 } 443 } 444 445 protected: 446 MessageLoop message_loop_; 447 scoped_refptr<AutoThreadTaskRunner> ui_task_runner_; 448 MockChromotingHostContext context_; 449 MockConnectionToClientEventHandler handler_; 450 MockSignalStrategy signal_strategy_; 451 scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory_; 452 scoped_ptr<MockIt2MeHostUserInterface> it2me_host_user_interface_; 453 scoped_refptr<ChromotingHost> host_; 454 MockHostStatusObserver host_status_observer_; 455 protocol::MockSessionManager* session_manager_; 456 std::string xmpp_login_; 457 MockConnectionToClient* connection1_; 458 scoped_ptr<MockConnectionToClient> owned_connection1_; 459 ClientSession* client1_; 460 std::string session_jid1_; 461 MockSession* session1_; // Owned by |connection_|. 462 SessionConfig session_config1_; 463 MockVideoStub video_stub1_; 464 MockClientStub client_stub1_; 465 MockHostStub host_stub1_; 466 MockConnectionToClient* connection2_; 467 scoped_ptr<MockConnectionToClient> owned_connection2_; 468 ClientSession* client2_; 469 std::string session_jid2_; 470 MockSession* session2_; // Owned by |connection2_|. 471 SessionConfig session_config2_; 472 MockVideoStub video_stub2_; 473 MockClientStub client_stub2_; 474 MockHostStub host_stub2_; 475 scoped_ptr<MockSession> session_unowned1_; // Not owned by a connection. 476 SessionConfig session_unowned_config1_; 477 std::string session_unowned_jid1_; 478 scoped_ptr<MockSession> session_unowned2_; // Not owned by a connection. 479 SessionConfig session_unowned_config2_; 480 std::string session_unowned_jid2_; 481 protocol::Session::EventHandler* session_event_handler_; 482 scoped_ptr<protocol::CandidateSessionConfig> empty_candidate_config_; 483 scoped_ptr<protocol::CandidateSessionConfig> default_candidate_config_; 484 485 // Owned by |host_|. 486 MockDisconnectWindow* disconnect_window_; 487 MockContinueWindow* continue_window_; 488 MockLocalInputMonitor* local_input_monitor_; 489 490 MockConnectionToClient*& get_connection(int connection_index) { 491 return (connection_index == 0) ? connection1_ : connection2_; 492 } 493 494 ClientSession*& get_client(int connection_index) { 495 return (connection_index == 0) ? client1_ : client2_; 496 } 497 498 const std::string& get_session_jid(int connection_index) { 499 return (connection_index == 0) ? session_jid1_ : session_jid2_; 500 } 501 502 MockVideoStub& get_video_stub(int connection_index) { 503 return (connection_index == 0) ? video_stub1_ : video_stub2_; 504 } 505}; 506 507TEST_F(ChromotingHostTest, StartAndShutdown) { 508 Expectation start = ExpectHostAndSessionManagerStart(); 509 EXPECT_CALL(host_status_observer_, OnShutdown()).After(start); 510 511 host_->Start(xmpp_login_); 512 ShutdownHost(); 513 message_loop_.Run(); 514} 515 516TEST_F(ChromotingHostTest, Connect) { 517 ExpectHostAndSessionManagerStart(); 518 519 // Shut down the host when the first video packet is received. 520 Expectation video_packet_sent = ExpectClientConnected( 521 0, InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost)); 522 Expectation client_disconnected = ExpectClientDisconnected( 523 0, true, video_packet_sent, InvokeWithoutArgs(DoNothing)); 524 EXPECT_CALL(host_status_observer_, OnShutdown()).After(client_disconnected); 525 526 host_->Start(xmpp_login_); 527 SimulateClientConnection(0, true, false); 528 message_loop_.Run(); 529} 530 531TEST_F(ChromotingHostTest, RejectAuthenticatingClient) { 532 Expectation start = ExpectHostAndSessionManagerStart(); 533 EXPECT_CALL(host_status_observer_, OnClientAuthenticated(session_jid1_)) 534 .WillOnce(InvokeWithoutArgs( 535 this, &ChromotingHostTest::RejectAuthenticatingClient)); 536 ExpectClientDisconnected( 537 0, true, start, 538 InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost)); 539 EXPECT_CALL(host_status_observer_, OnShutdown()); 540 541 host_->Start(xmpp_login_); 542 SimulateClientConnection(0, true, true); 543 message_loop_.Run(); 544} 545 546TEST_F(ChromotingHostTest, AuthenticationFailed) { 547 ExpectHostAndSessionManagerStart(); 548 EXPECT_CALL(host_status_observer_, OnAccessDenied(session_jid1_)) 549 .WillOnce(InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost)); 550 EXPECT_CALL(host_status_observer_, OnShutdown()); 551 552 host_->Start(xmpp_login_); 553 SimulateClientConnection(0, false, false); 554 message_loop_.Run(); 555} 556 557TEST_F(ChromotingHostTest, Reconnect) { 558 ExpectHostAndSessionManagerStart(); 559 560 // When a video packet is received on the first connection, disconnect it, 561 // then quit the message loop. 562 Expectation video_packet_sent1 = ExpectClientConnected(0, DoAll( 563 InvokeWithoutArgs(this, &ChromotingHostTest::DisconnectClient1), 564 InvokeWithoutArgs(this, &ChromotingHostTest::QuitMainMessageLoop))); 565 ExpectClientDisconnectEffects( 566 0, true, video_packet_sent1, InvokeWithoutArgs(DoNothing)); 567 568 // When a video packet is received on the second connection, shut down the 569 // host. 570 Expectation video_packet_sent2 = ExpectClientConnected( 571 1, InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost)); 572 Expectation client_disconnected2 = ExpectClientDisconnected( 573 1, true, video_packet_sent2, InvokeWithoutArgs(DoNothing)); 574 EXPECT_CALL(host_status_observer_, OnShutdown()).After(client_disconnected2); 575 576 host_->Start(xmpp_login_); 577 SimulateClientConnection(0, true, false); 578 message_loop_.Run(); 579 SimulateClientConnection(1, true, false); 580 message_loop_.Run(); 581} 582 583TEST_F(ChromotingHostTest, ConnectWhenAnotherClientIsConnected) { 584 ExpectHostAndSessionManagerStart(); 585 586 // When a video packet is received, connect the second connection. 587 // This should disconnect the first connection. 588 Expectation video_packet_sent1 = ExpectClientConnected( 589 0, 590 InvokeWithoutArgs( 591 CreateFunctor( 592 this, 593 &ChromotingHostTest::SimulateClientConnection, 1, true, false))); 594 ExpectClientDisconnected( 595 0, true, video_packet_sent1, InvokeWithoutArgs(DoNothing)); 596 Expectation video_packet_sent2 = ExpectClientConnected( 597 1, InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost)); 598 Expectation client_disconnected2 = ExpectClientDisconnected( 599 1, true, video_packet_sent2, InvokeWithoutArgs(DoNothing)); 600 EXPECT_CALL(host_status_observer_, OnShutdown()).After(client_disconnected2); 601 602 host_->Start(xmpp_login_); 603 SimulateClientConnection(0, true, false); 604 message_loop_.Run(); 605} 606 607TEST_F(ChromotingHostTest, IncomingSessionDeclined) { 608 ExpectHostStart(); 609 protocol::SessionManager::IncomingSessionResponse response = 610 protocol::SessionManager::ACCEPT; 611 host_->OnIncomingSession(session1_, &response); 612 EXPECT_EQ(protocol::SessionManager::DECLINE, response); 613 614 ShutdownHost(); 615 message_loop_.Run(); 616} 617 618TEST_F(ChromotingHostTest, IncomingSessionIncompatible) { 619 ExpectHostAndSessionManagerStart(); 620 EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce(Return( 621 empty_candidate_config_.get())); 622 EXPECT_CALL(host_status_observer_, OnShutdown()); 623 624 host_->Start(xmpp_login_); 625 626 protocol::SessionManager::IncomingSessionResponse response = 627 protocol::SessionManager::ACCEPT; 628 host_->OnIncomingSession(session_unowned1_.get(), &response); 629 EXPECT_EQ(protocol::SessionManager::INCOMPATIBLE, response); 630 631 ShutdownHost(); 632 message_loop_.Run(); 633} 634 635TEST_F(ChromotingHostTest, IncomingSessionAccepted) { 636 ExpectHostAndSessionManagerStart(); 637 EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce(Return( 638 default_candidate_config_.get())); 639 EXPECT_CALL(*session_unowned1_, set_config(_)); 640 EXPECT_CALL(*session_unowned1_, Close()).WillOnce(InvokeWithoutArgs( 641 this, &ChromotingHostTest::NotifyConnectionClosed)); 642 EXPECT_CALL(host_status_observer_, OnAccessDenied(_)); 643 EXPECT_CALL(host_status_observer_, OnShutdown()); 644 645 host_->Start(xmpp_login_); 646 647 protocol::SessionManager::IncomingSessionResponse response = 648 protocol::SessionManager::DECLINE; 649 host_->OnIncomingSession(session_unowned1_.release(), &response); 650 EXPECT_EQ(protocol::SessionManager::ACCEPT, response); 651 652 ShutdownHost(); 653 message_loop_.Run(); 654} 655 656TEST_F(ChromotingHostTest, IncomingSessionOverload) { 657 ExpectHostAndSessionManagerStart(); 658 EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce(Return( 659 default_candidate_config_.get())); 660 EXPECT_CALL(*session_unowned1_, set_config(_)); 661 EXPECT_CALL(*session_unowned1_, Close()).WillOnce(InvokeWithoutArgs( 662 this, &ChromotingHostTest::NotifyConnectionClosed)); 663 EXPECT_CALL(host_status_observer_, OnAccessDenied(_)); 664 EXPECT_CALL(host_status_observer_, OnShutdown()); 665 666 host_->Start(xmpp_login_); 667 668 protocol::SessionManager::IncomingSessionResponse response = 669 protocol::SessionManager::DECLINE; 670 host_->OnIncomingSession(session_unowned1_.release(), &response); 671 EXPECT_EQ(protocol::SessionManager::ACCEPT, response); 672 673 host_->OnIncomingSession(session_unowned2_.get(), &response); 674 EXPECT_EQ(protocol::SessionManager::OVERLOAD, response); 675 676 ShutdownHost(); 677 message_loop_.Run(); 678} 679 680TEST_F(ChromotingHostTest, OnSessionRouteChange) { 681 std::string channel_name("ChannelName"); 682 protocol::TransportRoute route; 683 684 ExpectHostAndSessionManagerStart(); 685 Expectation video_packet_sent = ExpectClientConnected( 686 0, InvokeWithoutArgs(CreateFunctor( 687 this, &ChromotingHostTest::ChangeSessionRoute, channel_name, route))); 688 Expectation route_change = 689 EXPECT_CALL(host_status_observer_, OnClientRouteChange( 690 session_jid1_, channel_name, _)) 691 .After(video_packet_sent) 692 .WillOnce(InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost)); 693 ExpectClientDisconnected(0, true, route_change, InvokeWithoutArgs(DoNothing)); 694 EXPECT_CALL(host_status_observer_, OnShutdown()); 695 696 host_->Start(xmpp_login_); 697 SimulateClientConnection(0, true, false); 698 message_loop_.Run(); 699} 700 701TEST_F(ChromotingHostTest, DisconnectAllClients) { 702 ExpectHostAndSessionManagerStart(); 703 Expectation video_packet_sent = ExpectClientConnected( 704 0, InvokeWithoutArgs(this, &ChromotingHostTest::DisconnectAllClients)); 705 ExpectClientDisconnected(0, true, video_packet_sent, 706 InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost)); 707 EXPECT_CALL(host_status_observer_, OnShutdown()); 708 709 host_->Start(xmpp_login_); 710 SimulateClientConnection(0, true, false); 711 message_loop_.Run(); 712} 713 714} // namespace remoting 715