root/remoting/host/chromoting_host_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PostQuitTask
  2. ACTION
  3. SetUp
  4. SimulateClientConnection
  5. TearDown
  6. ChangeSessionRoute
  7. CreateDesktopEnvironment
  8. CreateInputInjector
  9. CreateVideoCapturer
  10. DisconnectAllClients
  11. DisconnectClient1
  12. RejectAuthenticatingClient
  13. NotifyClientSessionClosed
  14. SetEventHandler
  15. NotifyConnectionClosed
  16. ShutdownHost
  17. StopAndReleaseTaskRunner
  18. QuitMainMessageLoop
  19. ExpectHostAndSessionManagerStart
  20. ExpectClientConnected
  21. ExpectClientDisconnected
  22. ExpectClientDisconnectEffects
  23. get_connection
  24. get_client
  25. get_session_jid
  26. get_video_stub
  27. TEST_F
  28. TEST_F
  29. TEST_F
  30. TEST_F
  31. TEST_F
  32. TEST_F
  33. TEST_F
  34. TEST_F
  35. TEST_F
  36. TEST_F
  37. TEST_F
  38. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/host/audio_capturer.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/desktop_environment.h"
#include "remoting/host/host_mock_objects.h"
#include "remoting/host/screen_capturer_fake.h"
#include "remoting/jingle_glue/mock_objects.h"
#include "remoting/proto/video.pb.h"
#include "remoting/protocol/errors.h"
#include "remoting/protocol/protocol_mock_objects.h"
#include "remoting/protocol/session_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::remoting::protocol::MockClientStub;
using ::remoting::protocol::MockConnectionToClient;
using ::remoting::protocol::MockConnectionToClientEventHandler;
using ::remoting::protocol::MockHostStub;
using ::remoting::protocol::MockSession;
using ::remoting::protocol::MockVideoStub;
using ::remoting::protocol::SessionConfig;

using testing::_;
using testing::AnyNumber;
using testing::AtMost;
using testing::AtLeast;
using testing::CreateFunctor;
using testing::DeleteArg;
using testing::DoAll;
using testing::Expectation;
using testing::InSequence;
using testing::Invoke;
using testing::InvokeArgument;
using testing::InvokeWithoutArgs;
using testing::Return;
using testing::ReturnRef;
using testing::Sequence;

namespace remoting {

namespace {

void PostQuitTask(base::MessageLoop* message_loop) {
  message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
}

// Run the task and delete it afterwards. This action is used to deal with
// done callbacks.
ACTION(RunDoneTask) {
  arg1.Run();
}

}  // namespace

class ChromotingHostTest : public testing::Test {
 public:
  ChromotingHostTest() {
  }

  virtual void SetUp() OVERRIDE {
    task_runner_ = new AutoThreadTaskRunner(
        message_loop_.message_loop_proxy(),
        base::Bind(&ChromotingHostTest::QuitMainMessageLoop,
                   base::Unretained(this)));

    desktop_environment_factory_.reset(new MockDesktopEnvironmentFactory());
    EXPECT_CALL(*desktop_environment_factory_, CreatePtr())
        .Times(AnyNumber())
        .WillRepeatedly(Invoke(this,
                               &ChromotingHostTest::CreateDesktopEnvironment));
    EXPECT_CALL(*desktop_environment_factory_, SupportsAudioCapture())
        .Times(AnyNumber())
        .WillRepeatedly(Return(false));

    session_manager_ = new protocol::MockSessionManager();

    host_.reset(new ChromotingHost(
        &signal_strategy_,
        desktop_environment_factory_.get(),
        scoped_ptr<protocol::SessionManager>(session_manager_),
        task_runner_,   // Audio
        task_runner_,   // Input
        task_runner_,   // Video capture
        task_runner_,   // Video encode
        task_runner_,   // Network
        task_runner_)); // UI
    host_->AddStatusObserver(&host_status_observer_);

    xmpp_login_ = "host@domain";
    session1_ = new MockSession();
    session2_ = new MockSession();
    session_unowned1_.reset(new MockSession());
    session_unowned2_.reset(new MockSession());
    session_config1_ = SessionConfig::ForTest();
    session_jid1_ = "user@domain/rest-of-jid";
    session_config2_ = SessionConfig::ForTest();
    session_jid2_ = "user2@domain/rest-of-jid";
    session_unowned_config1_ = SessionConfig::ForTest();
    session_unowned_jid1_ = "user3@doman/rest-of-jid";
    session_unowned_config2_ = SessionConfig::ForTest();
    session_unowned_jid2_ = "user4@doman/rest-of-jid";

    EXPECT_CALL(*session1_, jid())
        .WillRepeatedly(ReturnRef(session_jid1_));
    EXPECT_CALL(*session2_, jid())
        .WillRepeatedly(ReturnRef(session_jid2_));
    EXPECT_CALL(*session_unowned1_, jid())
        .WillRepeatedly(ReturnRef(session_unowned_jid1_));
    EXPECT_CALL(*session_unowned2_, jid())
        .WillRepeatedly(ReturnRef(session_unowned_jid2_));
    EXPECT_CALL(*session1_, SetEventHandler(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session2_, SetEventHandler(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session_unowned1_, SetEventHandler(_))
        .Times(AnyNumber())
        .WillRepeatedly(Invoke(this, &ChromotingHostTest::SetEventHandler));
    EXPECT_CALL(*session_unowned2_, SetEventHandler(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session1_, config())
        .WillRepeatedly(ReturnRef(session_config1_));
    EXPECT_CALL(*session2_, config())
        .WillRepeatedly(ReturnRef(session_config2_));

    owned_connection1_.reset(new MockConnectionToClient(session1_,
                                                        &host_stub1_));
    connection1_ = owned_connection1_.get();
    owned_connection2_.reset(new MockConnectionToClient(session2_,
                                                        &host_stub2_));
    connection2_ = owned_connection2_.get();

    ON_CALL(video_stub1_, ProcessVideoPacketPtr(_, _))
        .WillByDefault(DeleteArg<0>());
    ON_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
        .WillByDefault(DeleteArg<0>());
    ON_CALL(*connection1_, video_stub())
        .WillByDefault(Return(&video_stub1_));
    ON_CALL(*connection1_, client_stub())
        .WillByDefault(Return(&client_stub1_));
    ON_CALL(*connection1_, session())
        .WillByDefault(Return(session1_));
    ON_CALL(*connection2_, video_stub())
        .WillByDefault(Return(&video_stub2_));
    ON_CALL(*connection2_, client_stub())
        .WillByDefault(Return(&client_stub2_));
    ON_CALL(*connection2_, session())
        .WillByDefault(Return(session2_));
    EXPECT_CALL(*connection1_, video_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection1_, client_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection1_, session())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, video_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, client_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, session())
        .Times(AnyNumber());

    empty_candidate_config_ =
        protocol::CandidateSessionConfig::CreateEmpty();
    default_candidate_config_ =
        protocol::CandidateSessionConfig::CreateDefault();
  }

  // Helper method to pretend a client is connected to ChromotingHost.
  void SimulateClientConnection(int connection_index, bool authenticate,
                                bool reject) {
    scoped_ptr<protocol::ConnectionToClient> connection =
        ((connection_index == 0) ? owned_connection1_ : owned_connection2_).
        PassAs<protocol::ConnectionToClient>();
    protocol::ConnectionToClient* connection_ptr = connection.get();
    scoped_ptr<ClientSession> client(new ClientSession(
        host_.get(),
        task_runner_, // Audio
        task_runner_, // Input
        task_runner_, // Video capture
        task_runner_, // Video encode
        task_runner_, // Network
        task_runner_, // UI
        connection.Pass(),
        desktop_environment_factory_.get(),
        base::TimeDelta(),
        NULL));

    connection_ptr->set_host_stub(client.get());

    if (authenticate) {
      task_runner_->PostTask(
          FROM_HERE,
          base::Bind(&ClientSession::OnConnectionAuthenticated,
                     base::Unretained(client.get()), connection_ptr));
      if (!reject) {
        task_runner_->PostTask(
            FROM_HERE,
            base::Bind(&ClientSession::OnConnectionChannelsConnected,
                       base::Unretained(client.get()), connection_ptr));
      }
    } else {
      task_runner_->PostTask(
          FROM_HERE, base::Bind(&ClientSession::OnConnectionClosed,
                                base::Unretained(client.get()), connection_ptr,
                                protocol::AUTHENTICATION_FAILED));
    }

    get_client(connection_index) = client.get();

    // |host| is responsible for deleting |client| from now on.
    host_->clients_.push_back(client.release());
  }

  virtual void TearDown() OVERRIDE {
    // Make sure that the host has been properly deleted.
    DCHECK(host_.get() == NULL);
  }

  // Change the session route for |client1_|.
  void ChangeSessionRoute(const std::string& channel_name,
                          const protocol::TransportRoute& route) {
    host_->OnSessionRouteChange(get_client(0), channel_name, route);
  }

  // Creates a DesktopEnvironment with a fake webrtc::ScreenCapturer, to mock
  // DesktopEnvironmentFactory::Create().
  DesktopEnvironment* CreateDesktopEnvironment() {
    MockDesktopEnvironment* desktop_environment = new MockDesktopEnvironment();
    EXPECT_CALL(*desktop_environment, CreateAudioCapturerPtr())
        .Times(0);
    EXPECT_CALL(*desktop_environment, CreateInputInjectorPtr())
        .Times(AtMost(1))
        .WillOnce(Invoke(this, &ChromotingHostTest::CreateInputInjector));
    EXPECT_CALL(*desktop_environment, CreateScreenControlsPtr())
        .Times(AtMost(1));
    EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr())
        .Times(AtMost(1))
        .WillOnce(Invoke(this, &ChromotingHostTest::CreateVideoCapturer));
    EXPECT_CALL(*desktop_environment, GetCapabilities())
        .Times(AtMost(1));
    EXPECT_CALL(*desktop_environment, SetCapabilities(_))
        .Times(AtMost(1));

    return desktop_environment;
  }

  // Creates a dummy InputInjector, to mock
  // DesktopEnvironment::CreateInputInjector().
  InputInjector* CreateInputInjector() {
    MockInputInjector* input_injector = new MockInputInjector();
    EXPECT_CALL(*input_injector, StartPtr(_));
    return input_injector;
  }

  // Creates a fake webrtc::ScreenCapturer, to mock
  // DesktopEnvironment::CreateVideoCapturer().
  webrtc::ScreenCapturer* CreateVideoCapturer() {
    return new ScreenCapturerFake();
  }

  void DisconnectAllClients() {
    host_->DisconnectAllClients();
  }

  // Helper method to disconnect client 1 from the host.
  void DisconnectClient1() {
    NotifyClientSessionClosed(0);
  }

  // Notify |host_| that the authenticating client has been rejected.
  void RejectAuthenticatingClient() {
    host_->RejectAuthenticatingClient();
  }

  // Notify |host_| that a client session has closed.
  void NotifyClientSessionClosed(int connection_index) {
    get_client(connection_index)->OnConnectionClosed(
        get_connection(connection_index), protocol::OK);
  }

  void SetEventHandler(protocol::Session::EventHandler* event_handler) {
    session_event_handler_ = event_handler;
  }

  void NotifyConnectionClosed() {
    if (session_event_handler_) {
      session_event_handler_->OnSessionStateChange(protocol::Session::CLOSED);
    }
  }

  void ShutdownHost() {
    task_runner_->PostTask(
        FROM_HERE,
        base::Bind(&ChromotingHostTest::StopAndReleaseTaskRunner,
                   base::Unretained(this)));
  }

  void StopAndReleaseTaskRunner() {
    host_.reset();
    task_runner_ = NULL;
    desktop_environment_factory_.reset();
  }

  void QuitMainMessageLoop() {
    PostQuitTask(&message_loop_);
  }

  // Expect the host and session manager to start, and return the expectation
  // that the session manager has started.
  Expectation ExpectHostAndSessionManagerStart() {
    EXPECT_CALL(host_status_observer_, OnStart(xmpp_login_));
    return EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  }

  // Expect a client to connect.
  // Return an expectation that a session has started, and that the first
  // video packet has been sent to the client.
  // Do |action| when that happens.
  template <class A>
  Expectation ExpectClientConnected(int connection_index, A action) {
    const std::string& session_jid = get_session_jid(connection_index);
    MockVideoStub& video_stub = get_video_stub(connection_index);

    Expectation client_authenticated =
        EXPECT_CALL(host_status_observer_, OnClientAuthenticated(session_jid));
    EXPECT_CALL(host_status_observer_, OnClientConnected(session_jid))
        .After(client_authenticated);
    Expectation video_packet_sent =
        EXPECT_CALL(video_stub, ProcessVideoPacketPtr(_, _))
        .After(client_authenticated)
        .WillOnce(DoAll(
            action,
            RunDoneTask()))
        .RetiresOnSaturation();
    EXPECT_CALL(video_stub, ProcessVideoPacketPtr(_, _))
        .Times(AnyNumber())
        .After(video_packet_sent)
        .WillRepeatedly(RunDoneTask());
    return video_packet_sent;
  }

  // Return an expectation that a client will disconnect after a given
  // expectation. The given action will be done after the event executor is
  // notified that the session has finished.
  template <class A>
  Expectation ExpectClientDisconnected(int connection_index,
                                       bool expect_host_status_change,
                                       Expectation after,
                                       A action) {
    MockConnectionToClient* connection = get_connection(connection_index);

    Expectation client_disconnected =
        EXPECT_CALL(*connection, Disconnect())
            .After(after)
            .WillOnce(InvokeWithoutArgs(CreateFunctor(
                this, &ChromotingHostTest::NotifyClientSessionClosed,
                connection_index)))
            .RetiresOnSaturation();
    ExpectClientDisconnectEffects(connection_index,
                                  expect_host_status_change,
                                  after,
                                  action);
    return client_disconnected;
  }

  // Expect the side-effects of a client disconnection, after a given
  // expectation. The given action will be done after the event executor is
  // notifed that the session has finished.
  template <class A>
  void ExpectClientDisconnectEffects(int connection_index,
                                     bool expect_host_status_change,
                                     Expectation after,
                                     A action) {
    const std::string& session_jid = get_session_jid(connection_index);

    if (expect_host_status_change) {
      EXPECT_CALL(host_status_observer_, OnClientDisconnected(session_jid))
          .After(after)
          .WillOnce(action)
          .RetiresOnSaturation();
    }
  }

 protected:
  base::MessageLoop message_loop_;
  scoped_refptr<AutoThreadTaskRunner> task_runner_;
  MockConnectionToClientEventHandler handler_;
  MockSignalStrategy signal_strategy_;
  scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory_;
  scoped_ptr<ChromotingHost> host_;
  MockHostStatusObserver host_status_observer_;
  protocol::MockSessionManager* session_manager_;
  std::string xmpp_login_;
  MockConnectionToClient* connection1_;
  scoped_ptr<MockConnectionToClient> owned_connection1_;
  ClientSession* client1_;
  std::string session_jid1_;
  MockSession* session1_;  // Owned by |connection_|.
  SessionConfig session_config1_;
  MockVideoStub video_stub1_;
  MockClientStub client_stub1_;
  MockHostStub host_stub1_;
  MockConnectionToClient* connection2_;
  scoped_ptr<MockConnectionToClient> owned_connection2_;
  ClientSession* client2_;
  std::string session_jid2_;
  MockSession* session2_;  // Owned by |connection2_|.
  SessionConfig session_config2_;
  MockVideoStub video_stub2_;
  MockClientStub client_stub2_;
  MockHostStub host_stub2_;
  scoped_ptr<MockSession> session_unowned1_;  // Not owned by a connection.
  SessionConfig session_unowned_config1_;
  std::string session_unowned_jid1_;
  scoped_ptr<MockSession> session_unowned2_;  // Not owned by a connection.
  SessionConfig session_unowned_config2_;
  std::string session_unowned_jid2_;
  protocol::Session::EventHandler* session_event_handler_;
  scoped_ptr<protocol::CandidateSessionConfig> empty_candidate_config_;
  scoped_ptr<protocol::CandidateSessionConfig> default_candidate_config_;

  MockConnectionToClient*& get_connection(int connection_index) {
    return (connection_index == 0) ? connection1_ : connection2_;
  }

  ClientSession*& get_client(int connection_index) {
    return (connection_index == 0) ? client1_ : client2_;
  }

  const std::string& get_session_jid(int connection_index) {
    return (connection_index == 0) ? session_jid1_ : session_jid2_;
  }

  MockVideoStub& get_video_stub(int connection_index) {
    return (connection_index == 0) ? video_stub1_ : video_stub2_;
  }
};

TEST_F(ChromotingHostTest, StartAndShutdown) {
  Expectation start = ExpectHostAndSessionManagerStart();
  EXPECT_CALL(host_status_observer_, OnShutdown()).After(start);

  host_->Start(xmpp_login_);
  ShutdownHost();
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, Connect) {
  ExpectHostAndSessionManagerStart();

  // Shut down the host when the first video packet is received.
  Expectation video_packet_sent = ExpectClientConnected(
      0, InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost));
  Expectation client_disconnected = ExpectClientDisconnected(
      0, true, video_packet_sent, InvokeWithoutArgs(base::DoNothing));
  EXPECT_CALL(host_status_observer_, OnShutdown()).After(client_disconnected);

  host_->Start(xmpp_login_);
  SimulateClientConnection(0, true, false);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, RejectAuthenticatingClient) {
  Expectation start = ExpectHostAndSessionManagerStart();
  EXPECT_CALL(host_status_observer_, OnClientAuthenticated(session_jid1_))
      .WillOnce(InvokeWithoutArgs(
      this, &ChromotingHostTest::RejectAuthenticatingClient));
  ExpectClientDisconnected(
      0, true, start,
      InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost));
  EXPECT_CALL(host_status_observer_, OnShutdown());

  host_->Start(xmpp_login_);
  SimulateClientConnection(0, true, true);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, AuthenticationFailed) {
  ExpectHostAndSessionManagerStart();
  EXPECT_CALL(host_status_observer_, OnAccessDenied(session_jid1_))
      .WillOnce(InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost));
  EXPECT_CALL(host_status_observer_, OnShutdown());

  host_->Start(xmpp_login_);
  SimulateClientConnection(0, false, false);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, Reconnect) {
  ExpectHostAndSessionManagerStart();

  // When a video packet is received on the first connection, disconnect it,
  // then quit the message loop.
  Expectation video_packet_sent1 = ExpectClientConnected(0, DoAll(
      InvokeWithoutArgs(this, &ChromotingHostTest::DisconnectClient1),
      InvokeWithoutArgs(this, &ChromotingHostTest::QuitMainMessageLoop)));
  ExpectClientDisconnectEffects(
      0, true, video_packet_sent1, InvokeWithoutArgs(base::DoNothing));

  // When a video packet is received on the second connection, shut down the
  // host.
  Expectation video_packet_sent2 = ExpectClientConnected(
      1, InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost));
  Expectation client_disconnected2 = ExpectClientDisconnected(
      1, true, video_packet_sent2, InvokeWithoutArgs(base::DoNothing));
  EXPECT_CALL(host_status_observer_, OnShutdown()).After(client_disconnected2);

  host_->Start(xmpp_login_);
  SimulateClientConnection(0, true, false);
  message_loop_.Run();
  SimulateClientConnection(1, true, false);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, ConnectWhenAnotherClientIsConnected) {
  ExpectHostAndSessionManagerStart();

  // When a video packet is received, connect the second connection.
  // This should disconnect the first connection.
  Expectation video_packet_sent1 = ExpectClientConnected(
      0,
      InvokeWithoutArgs(
          CreateFunctor(
              this,
              &ChromotingHostTest::SimulateClientConnection, 1, true, false)));
  ExpectClientDisconnected(
      0, true, video_packet_sent1, InvokeWithoutArgs(base::DoNothing));
  Expectation video_packet_sent2 = ExpectClientConnected(
      1, InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost));
  Expectation client_disconnected2 = ExpectClientDisconnected(
      1, true, video_packet_sent2, InvokeWithoutArgs(base::DoNothing));
  EXPECT_CALL(host_status_observer_, OnShutdown()).After(client_disconnected2);

  host_->Start(xmpp_login_);
  SimulateClientConnection(0, true, false);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, IncomingSessionDeclined) {
  protocol::SessionManager::IncomingSessionResponse response =
      protocol::SessionManager::ACCEPT;
  host_->OnIncomingSession(session1_, &response);
  EXPECT_EQ(protocol::SessionManager::DECLINE, response);

  ShutdownHost();
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, IncomingSessionIncompatible) {
  ExpectHostAndSessionManagerStart();
  EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce(Return(
      empty_candidate_config_.get()));
  EXPECT_CALL(host_status_observer_, OnShutdown());

  host_->Start(xmpp_login_);

  protocol::SessionManager::IncomingSessionResponse response =
      protocol::SessionManager::ACCEPT;
  host_->OnIncomingSession(session_unowned1_.get(), &response);
  EXPECT_EQ(protocol::SessionManager::INCOMPATIBLE, response);

  ShutdownHost();
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, IncomingSessionAccepted) {
  ExpectHostAndSessionManagerStart();
  EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce(Return(
      default_candidate_config_.get()));
  EXPECT_CALL(*session_unowned1_, set_config(_));
  EXPECT_CALL(*session_unowned1_, Close()).WillOnce(InvokeWithoutArgs(
      this, &ChromotingHostTest::NotifyConnectionClosed));
  EXPECT_CALL(host_status_observer_, OnAccessDenied(_));
  EXPECT_CALL(host_status_observer_, OnShutdown());

  host_->Start(xmpp_login_);

  protocol::SessionManager::IncomingSessionResponse response =
      protocol::SessionManager::DECLINE;
  host_->OnIncomingSession(session_unowned1_.release(), &response);
  EXPECT_EQ(protocol::SessionManager::ACCEPT, response);

  ShutdownHost();
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, IncomingSessionOverload) {
  ExpectHostAndSessionManagerStart();
  EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce(Return(
      default_candidate_config_.get()));
  EXPECT_CALL(*session_unowned1_, set_config(_));
  EXPECT_CALL(*session_unowned1_, Close()).WillOnce(InvokeWithoutArgs(
      this, &ChromotingHostTest::NotifyConnectionClosed));
  EXPECT_CALL(host_status_observer_, OnAccessDenied(_));
  EXPECT_CALL(host_status_observer_, OnShutdown());

  host_->Start(xmpp_login_);

  protocol::SessionManager::IncomingSessionResponse response =
      protocol::SessionManager::DECLINE;
  host_->OnIncomingSession(session_unowned1_.release(), &response);
  EXPECT_EQ(protocol::SessionManager::ACCEPT, response);

  host_->OnIncomingSession(session_unowned2_.get(), &response);
  EXPECT_EQ(protocol::SessionManager::OVERLOAD, response);

  ShutdownHost();
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, OnSessionRouteChange) {
  std::string channel_name("ChannelName");
  protocol::TransportRoute route;

  ExpectHostAndSessionManagerStart();
  Expectation video_packet_sent = ExpectClientConnected(
      0, InvokeWithoutArgs(CreateFunctor(
          this, &ChromotingHostTest::ChangeSessionRoute, channel_name, route)));
  Expectation route_change =
      EXPECT_CALL(host_status_observer_, OnClientRouteChange(
          session_jid1_, channel_name, _))
      .After(video_packet_sent)
      .WillOnce(InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost));
  ExpectClientDisconnected(0, true, route_change,
                           InvokeWithoutArgs(base::DoNothing));
  EXPECT_CALL(host_status_observer_, OnShutdown());

  host_->Start(xmpp_login_);
  SimulateClientConnection(0, true, false);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, DisconnectAllClients) {
  ExpectHostAndSessionManagerStart();
  Expectation video_packet_sent = ExpectClientConnected(
      0, InvokeWithoutArgs(this, &ChromotingHostTest::DisconnectAllClients));
  ExpectClientDisconnected(0, true, video_packet_sent,
      InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost));
  EXPECT_CALL(host_status_observer_, OnShutdown());

  host_->Start(xmpp_login_);
  SimulateClientConnection(0, true, false);
  message_loop_.Run();
}

}  // namespace remoting

/* [<][>][^][v][top][bottom][index][help] */