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