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