#include "remoting/host/client_session.h"
#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/strings/string_split.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/base/constants.h"
#include "remoting/base/errors.h"
#include "remoting/base/local_session_policies_provider.h"
#include "remoting/base/session_policies.h"
#include "remoting/host/base/desktop_environment_options.h"
#include "remoting/host/desktop_display_info.h"
#include "remoting/host/fake_desktop_environment.h"
#include "remoting/host/fake_host_extension.h"
#include "remoting/host/host_extension.h"
#include "remoting/host/host_extension_session.h"
#include "remoting/host/host_mock_objects.h"
#include "remoting/proto/control.pb.h"
#include "remoting/proto/event.pb.h"
#include "remoting/protocol/capability_names.h"
#include "remoting/protocol/fake_connection_to_client.h"
#include "remoting/protocol/fake_desktop_capturer.h"
#include "remoting/protocol/fake_message_pipe.h"
#include "remoting/protocol/fake_session.h"
#include "remoting/protocol/message_pipe.h"
#include "remoting/protocol/protocol_mock_objects.h"
#include "remoting/protocol/session_config.h"
#include "remoting/protocol/test_event_matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libjingle_xmpp/xmllite/qname.h"
#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
#include "ui/events/types/event_type.h"
namespace remoting {
using protocol::FakeSession;
using protocol::MockClientStub;
using protocol::MockHostStub;
using protocol::MockInputStub;
using protocol::MockVideoStub;
using protocol::SessionConfig;
using protocol::test::EqualsClipboardEvent;
using protocol::test::EqualsKeyEvent;
using protocol::test::EqualsMouseButtonEvent;
using protocol::test::EqualsMouseMoveEvent;
using testing::_;
using testing::AtLeast;
using testing::Eq;
using testing::Not;
using testing::Return;
using testing::ReturnRef;
using testing::StrictMock;
namespace {
constexpr char kTestDataChannelCallbackName[] = "test_channel_name";
constexpr bool kUse64BitDisplayId = (sizeof(webrtc::ScreenId) >= 8);
MATCHER_P(IncludesCapabilities, expected_capabilities, "") {
if (!arg.has_capabilities()) {
return false;
}
std::vector<std::string> words_args =
base::SplitString(arg.capabilities(), " ", base::KEEP_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
std::vector<std::string> words_expected =
base::SplitString(expected_capabilities, " ", base::KEEP_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
for (const auto& word : words_expected) {
if (!base::Contains(words_args, word)) {
return false;
}
}
return true;
}
MATCHER_P(ScreenIdMatches, expected_id, "") {
return arg.screen_id() == expected_id;
}
protocol::MouseEvent MakeMouseMoveEvent(int x, int y) {
protocol::MouseEvent result;
result.set_x(x);
result.set_y(y);
return result;
}
protocol::KeyEvent MakeKeyEvent(bool pressed, std::uint32_t keycode) {
protocol::KeyEvent result;
result.set_pressed(pressed);
result.set_usb_keycode(keycode);
return result;
}
protocol::ClipboardEvent MakeClipboardEvent(const std::string& text) {
protocol::ClipboardEvent result;
result.set_mime_type(kMimeTypeTextUtf8);
result.set_data(text);
return result;
}
}
class ClientSessionTest : public testing::Test {
public:
ClientSessionTest() = default;
void SetUp() override;
void TearDown() override;
protected:
static const int kDisplay1Width =
protocol::FakeDesktopCapturer::kWidth;
static const int kDisplay1Height =
protocol::FakeDesktopCapturer::kHeight;
static const std::int64_t kDisplay1Id =
kUse64BitDisplayId ? 1111111111111111 : 11111111;
static const int kDisplay2Width = 1024;
static const int kDisplay2Height = 768;
static const int kDisplay2YOffset = 35;
static const std::int64_t kDisplay2Id =
kUse64BitDisplayId ? 2222222222222222 : 22222222;
void CreateClientSession(std::unique_ptr<protocol::FakeSession> session);
void CreateClientSession();
void ConnectClientSession(const SessionPolicies* session_policies = nullptr);
void AddDisplayToLayout(protocol::VideoLayout* displays,
int x,
int y,
int width,
int height,
int dpi_x,
int dpi_y,
std::int64_t display_id);
void NotifyDesktopDisplaySize(
std::unique_ptr<protocol::VideoLayout> displays);
void NotifySelectDesktopDisplay(std::string id);
void ResetDisplayInfo();
void SetupSingleDisplay();
void SetupMultiDisplay();
void SetupMultiDisplay_SameSize();
void MultiMon_SelectFirstDisplay();
void MultiMon_SelectSecondDisplay();
void MultiMon_SelectAllDisplays();
void MultiMon_SelectDisplay(std::string display_id);
webrtc::ScreenId GetSelectedSourceDisplayId();
DesktopDisplayInfo displays_;
int curr_display_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
scoped_refptr<AutoThreadTaskRunner> task_runner_;
base::RunLoop run_loop_;
std::vector<raw_ptr<HostExtension, VectorExperimental>> extensions_;
std::vector<protocol::KeyEvent> key_events_;
std::vector<protocol::MouseEvent> mouse_events_;
std::vector<protocol::ClipboardEvent> clipboard_events_;
SessionPolicies initial_local_policies_;
LocalSessionPoliciesProvider local_session_policies_provider_;
std::unique_ptr<ClientSession> client_session_;
MockClientSessionEventHandler session_event_handler_;
MockClientStub client_stub_;
raw_ptr<protocol::FakeConnectionToClient, DanglingUntriaged> connection_;
std::unique_ptr<FakeDesktopEnvironmentFactory> desktop_environment_factory_;
DesktopEnvironmentOptions desktop_environment_options_;
};
void ClientSessionTest::SetUp() {
task_runner_ = new AutoThreadTaskRunner(
task_environment_.GetMainThreadTaskRunner(), run_loop_.QuitClosure());
desktop_environment_factory_ =
std::make_unique<FakeDesktopEnvironmentFactory>(
task_environment_.GetMainThreadTaskRunner());
desktop_environment_options_ = DesktopEnvironmentOptions::CreateDefault();
initial_local_policies_.maximum_session_duration = base::Hours(10);
local_session_policies_provider_.set_local_policies(initial_local_policies_);
EXPECT_CALL(client_stub_, SetCursorShape(_)).Times(testing::AnyNumber());
}
void ClientSessionTest::TearDown() {
if (client_session_) {
if (connection_->is_connected()) {
client_session_->DisconnectSession(ErrorCode::OK, {}, FROM_HERE);
}
client_session_.reset();
desktop_environment_factory_.reset();
}
task_runner_ = nullptr;
run_loop_.Run();
}
void ClientSessionTest::CreateClientSession(
std::unique_ptr<protocol::FakeSession> session) {
DCHECK(session);
std::unique_ptr<protocol::FakeConnectionToClient> connection(
new protocol::FakeConnectionToClient(std::move(session)));
connection->set_client_stub(&client_stub_);
connection_ = connection.get();
client_session_ = std::make_unique<ClientSession>(
&session_event_handler_, std::move(connection),
desktop_environment_factory_.get(), desktop_environment_options_, nullptr,
extensions_, &local_session_policies_provider_);
}
void ClientSessionTest::CreateClientSession() {
CreateClientSession(std::make_unique<protocol::FakeSession>());
}
void ClientSessionTest::ConnectClientSession(
const SessionPolicies* session_policies) {
EXPECT_CALL(session_event_handler_, OnSessionPoliciesReceived(_))
.WillOnce(Return(std::nullopt));
EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_));
base::test::TestFuture<void> future;
EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
.WillOnce([&future] { future.SetValue(); });
EXPECT_FALSE(connection_->clipboard_stub());
EXPECT_FALSE(connection_->input_stub());
client_session_->OnConnectionAuthenticated(session_policies);
client_session_->CreateMediaStreams();
client_session_->OnConnectionChannelsConnected();
future.Get();
EXPECT_TRUE(connection_->clipboard_stub());
EXPECT_TRUE(connection_->input_stub());
}
void ClientSessionTest::AddDisplayToLayout(protocol::VideoLayout* displays,
int x,
int y,
int width,
int height,
int dpi_x,
int dpi_y,
std::int64_t display_id) {
protocol::VideoTrackLayout* video_track = displays->add_video_track();
video_track->set_position_x(x);
video_track->set_position_y(y);
video_track->set_width(width);
video_track->set_height(height);
video_track->set_x_dpi(dpi_x);
video_track->set_y_dpi(dpi_y);
video_track->set_screen_id(display_id);
displays_.AddDisplayFrom(*video_track);
}
void ClientSessionTest::NotifyDesktopDisplaySize(
std::unique_ptr<protocol::VideoLayout> displays) {
client_session_->OnDesktopDisplayChanged(std::move(displays));
}
void ClientSessionTest::NotifySelectDesktopDisplay(std::string id) {
protocol::SelectDesktopDisplayRequest req;
req.set_id(id);
client_session_->SelectDesktopDisplay(req);
}
void ClientSessionTest::ResetDisplayInfo() {
displays_.Reset();
curr_display_ = webrtc::kInvalidScreenId;
}
void ClientSessionTest::SetupSingleDisplay() {
ResetDisplayInfo();
auto displays = std::make_unique<protocol::VideoLayout>();
AddDisplayToLayout(displays.get(), 0, 0, kDisplay1Width, kDisplay1Height,
kDefaultDpi, kDefaultDpi, kDisplay1Id);
NotifyDesktopDisplaySize(std::move(displays));
}
void ClientSessionTest::SetupMultiDisplay() {
ResetDisplayInfo();
auto displays = std::make_unique<protocol::VideoLayout>();
AddDisplayToLayout(displays.get(), 0, 0, kDisplay1Width, kDisplay1Height,
kDefaultDpi, kDefaultDpi, kDisplay1Id);
AddDisplayToLayout(displays.get(), kDisplay1Width, kDisplay2YOffset,
kDisplay2Width, kDisplay2Height, kDefaultDpi, kDefaultDpi,
kDisplay2Id);
NotifyDesktopDisplaySize(std::move(displays));
}
void ClientSessionTest::SetupMultiDisplay_SameSize() {
ResetDisplayInfo();
auto displays = std::make_unique<protocol::VideoLayout>();
AddDisplayToLayout(displays.get(), 0, 0, kDisplay1Width, kDisplay1Height,
kDefaultDpi, kDefaultDpi, kDisplay1Id);
AddDisplayToLayout(displays.get(), kDisplay1Width, kDisplay2YOffset,
kDisplay1Width, kDisplay1Height, kDefaultDpi, kDefaultDpi,
kDisplay2Id);
NotifyDesktopDisplaySize(std::move(displays));
}
void ClientSessionTest::MultiMon_SelectFirstDisplay() {
NotifySelectDesktopDisplay("0");
}
void ClientSessionTest::MultiMon_SelectSecondDisplay() {
NotifySelectDesktopDisplay("1");
}
void ClientSessionTest::MultiMon_SelectAllDisplays() {
NotifySelectDesktopDisplay("all");
}
void ClientSessionTest::MultiMon_SelectDisplay(std::string display_id) {
NotifySelectDesktopDisplay(display_id);
}
webrtc::ScreenId ClientSessionTest::GetSelectedSourceDisplayId() {
return connection_->last_video_stream()->selected_source();
}
TEST_F(
ClientSessionTest,
OnLocalPoliciesChanged_DoesNotDisconnectIfEffectivePoliciesComeFromRemotePolicies) {
SessionPolicies remote_policies;
remote_policies.maximum_session_duration = base::Hours(8);
CreateClientSession();
ConnectClientSession(&remote_policies);
EXPECT_TRUE(connection_->is_connected());
SessionPolicies new_policies;
new_policies.maximum_session_duration = base::Hours(23);
local_session_policies_provider_.set_local_policies(new_policies);
EXPECT_TRUE(connection_->is_connected());
}
TEST_F(ClientSessionTest,
OnLocalPoliciesChanged_DoesNotDisconnectIfEffectivePoliciesNotChanged) {
CreateClientSession();
ConnectClientSession();
EXPECT_TRUE(connection_->is_connected());
local_session_policies_provider_.set_local_policies(initial_local_policies_);
EXPECT_TRUE(connection_->is_connected());
}
TEST_F(ClientSessionTest,
OnLocalPoliciesChanged_DisconnectsIfEffectivePoliciesChanged) {
CreateClientSession();
ConnectClientSession();
EXPECT_TRUE(connection_->is_connected());
SessionPolicies local_policies;
local_policies.maximum_session_duration = base::Hours(23);
local_session_policies_provider_.set_local_policies(local_policies);
EXPECT_FALSE(connection_->is_connected());
}
TEST_F(ClientSessionTest, DisconnectsAfterMaxSessionDurationIsReached) {
CreateClientSession();
ConnectClientSession();
EXPECT_TRUE(connection_->is_connected());
task_environment_.AdvanceClock(
*initial_local_policies_.maximum_session_duration + base::Minutes(1));
task_environment_.RunUntilIdle();
EXPECT_FALSE(connection_->is_connected());
}
TEST_F(ClientSessionTest, DisconnectsIfOnSessionPoliciesReceivedReturnsError) {
EXPECT_CALL(session_event_handler_,
OnSessionPoliciesReceived(initial_local_policies_))
.WillOnce(Return(ErrorCode::DISALLOWED_BY_POLICY));
CreateClientSession();
client_session_->OnConnectionAuthenticated(nullptr);
EXPECT_FALSE(connection_->is_connected());
EXPECT_EQ(connection_->disconnect_error(), ErrorCode::DISALLOWED_BY_POLICY);
}
TEST_F(ClientSessionTest,
EffectivePoliciesImplicitlyAllowFileTransfer_HasCapability) {
local_session_policies_provider_.set_local_policies({});
EXPECT_CALL(
client_stub_,
SetCapabilities(IncludesCapabilities(protocol::kFileTransferCapability)));
CreateClientSession();
ConnectClientSession();
}
TEST_F(ClientSessionTest,
EffectivePoliciesExplicitlyAllowFileTransfer_HasCapability) {
SessionPolicies local_policies;
local_policies.allow_file_transfer = true;
local_session_policies_provider_.set_local_policies(local_policies);
EXPECT_CALL(
client_stub_,
SetCapabilities(IncludesCapabilities(protocol::kFileTransferCapability)));
CreateClientSession();
ConnectClientSession();
}
TEST_F(ClientSessionTest,
EffectivePoliciesDisallowFileTransfer_DoesNotHaveCapability) {
SessionPolicies local_policies;
local_policies.allow_file_transfer = false;
local_session_policies_provider_.set_local_policies(local_policies);
EXPECT_CALL(client_stub_, SetCapabilities(Not(IncludesCapabilities(
protocol::kFileTransferCapability))));
CreateClientSession();
ConnectClientSession();
}
TEST_F(ClientSessionTest, ApplyPoliciesFromRemotePolicies) {
SessionPolicies local_policies;
local_policies.allow_file_transfer = true;
local_policies.allow_uri_forwarding = true;
local_session_policies_provider_.set_local_policies(local_policies);
SessionPolicies remote_policies;
remote_policies.allow_file_transfer = false;
remote_policies.allow_uri_forwarding = false;
EXPECT_CALL(client_stub_,
SetCapabilities(Not(IncludesCapabilities(
std::string() + protocol::kFileTransferCapability + " " +
protocol::kRemoteOpenUrlCapability))));
CreateClientSession();
ConnectClientSession(&remote_policies);
}
TEST_F(ClientSessionTest, DisableInputs) {
CreateClientSession();
ConnectClientSession();
SetupSingleDisplay();
FakeInputInjector* input_injector =
desktop_environment_factory_->last_desktop_environment()
->last_input_injector()
.get();
input_injector->set_key_events(&key_events_);
input_injector->set_mouse_events(&mouse_events_);
input_injector->set_clipboard_events(&clipboard_events_);
connection_->clipboard_stub()->InjectClipboardEvent(MakeClipboardEvent("a"));
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(true, 1));
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(100, 101));
client_session_->SetDisableInputs(true);
connection_->clipboard_stub()->InjectClipboardEvent(MakeClipboardEvent("b"));
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(true, 2));
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(false, 2));
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(200, 201));
client_session_->SetDisableInputs(false);
connection_->clipboard_stub()->InjectClipboardEvent(MakeClipboardEvent("c"));
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(true, 3));
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(300, 301));
client_session_->DisconnectSession(ErrorCode::OK, {}, FROM_HERE);
client_session_.reset();
EXPECT_EQ(2U, mouse_events_.size());
EXPECT_THAT(mouse_events_[0], EqualsMouseMoveEvent(100, 101));
EXPECT_THAT(mouse_events_[1], EqualsMouseMoveEvent(300, 301));
EXPECT_EQ(4U, key_events_.size());
EXPECT_THAT(key_events_[0], EqualsKeyEvent(1, true));
EXPECT_THAT(key_events_[1], EqualsKeyEvent(1, false));
EXPECT_THAT(key_events_[2], EqualsKeyEvent(3, true));
EXPECT_THAT(key_events_[3], EqualsKeyEvent(3, false));
EXPECT_EQ(2U, clipboard_events_.size());
EXPECT_THAT(clipboard_events_[0],
EqualsClipboardEvent(kMimeTypeTextUtf8, "a"));
EXPECT_THAT(clipboard_events_[1],
EqualsClipboardEvent(kMimeTypeTextUtf8, "c"));
}
TEST_F(ClientSessionTest, InputAllowedFromRemotePolicy) {
SessionPolicies remote_policies;
remote_policies.allow_remote_input = true;
CreateClientSession();
ConnectClientSession(&remote_policies);
SetupSingleDisplay();
FakeInputInjector* input_injector =
desktop_environment_factory_->last_desktop_environment()
->last_input_injector()
.get();
input_injector->set_key_events(&key_events_);
input_injector->set_mouse_events(&mouse_events_);
input_injector->set_clipboard_events(&clipboard_events_);
connection_->clipboard_stub()->InjectClipboardEvent(MakeClipboardEvent("a"));
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(true, 1));
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(100, 101));
client_session_->DisconnectSession(ErrorCode::OK, {}, FROM_HERE);
client_session_.reset();
EXPECT_EQ(1U, mouse_events_.size());
EXPECT_THAT(mouse_events_[0], EqualsMouseMoveEvent(100, 101));
EXPECT_EQ(2U, key_events_.size());
EXPECT_THAT(key_events_[0], EqualsKeyEvent(1, true));
EXPECT_THAT(key_events_[1], EqualsKeyEvent(1, false));
EXPECT_EQ(1U, clipboard_events_.size());
EXPECT_THAT(clipboard_events_[0],
EqualsClipboardEvent(kMimeTypeTextUtf8, "a"));
}
TEST_F(ClientSessionTest, InputDisabledFromRemotePolicy) {
SessionPolicies remote_policies;
remote_policies.allow_remote_input = false;
CreateClientSession();
ConnectClientSession(&remote_policies);
SetupSingleDisplay();
FakeInputInjector* input_injector =
desktop_environment_factory_->last_desktop_environment()
->last_input_injector()
.get();
input_injector->set_key_events(&key_events_);
input_injector->set_mouse_events(&mouse_events_);
input_injector->set_clipboard_events(&clipboard_events_);
connection_->clipboard_stub()->InjectClipboardEvent(MakeClipboardEvent("a"));
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(true, 1));
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(100, 101));
client_session_->DisconnectSession(ErrorCode::OK, {}, FROM_HERE);
client_session_.reset();
EXPECT_EQ(0U, mouse_events_.size());
EXPECT_EQ(0U, key_events_.size());
EXPECT_EQ(0U, clipboard_events_.size());
}
TEST_F(ClientSessionTest, LocalInputTest) {
CreateClientSession();
ConnectClientSession();
SetupSingleDisplay();
desktop_environment_factory_->last_desktop_environment()
->last_input_injector()
->set_mouse_events(&mouse_events_);
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(100, 101));
#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_CHROMEOS)
client_session_->OnLocalPointerMoved(webrtc::DesktopVector(100, 101),
ui::EventType::kMouseMoved);
#endif
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(200, 201));
client_session_->OnLocalPointerMoved(webrtc::DesktopVector(100, 101),
ui::EventType::kMouseMoved);
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(300, 301));
ASSERT_EQ(2U, mouse_events_.size());
EXPECT_THAT(mouse_events_[0], EqualsMouseMoveEvent(100, 101));
EXPECT_THAT(mouse_events_[1], EqualsMouseMoveEvent(200, 201));
EXPECT_TRUE(connection_->is_connected());
}
TEST_F(ClientSessionTest, DisconnectOnLocalInputTest) {
desktop_environment_options_.set_terminate_upon_input(true);
CreateClientSession();
ConnectClientSession();
SetupSingleDisplay();
client_session_->OnLocalPointerMoved(webrtc::DesktopVector(100, 101),
ui::EventType::kMouseMoved);
EXPECT_FALSE(connection_->is_connected());
}
TEST_F(ClientSessionTest, RestoreEventState) {
CreateClientSession();
ConnectClientSession();
SetupSingleDisplay();
FakeInputInjector* input_injector =
desktop_environment_factory_->last_desktop_environment()
->last_input_injector()
.get();
input_injector->set_key_events(&key_events_);
input_injector->set_mouse_events(&mouse_events_);
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(true, 1));
connection_->input_stub()->InjectKeyEvent(MakeKeyEvent(true, 2));
protocol::MouseEvent mousedown;
mousedown.set_button(protocol::MouseEvent::BUTTON_LEFT);
mousedown.set_button_down(true);
connection_->input_stub()->InjectMouseEvent(mousedown);
client_session_->DisconnectSession(ErrorCode::OK, {}, FROM_HERE);
client_session_.reset();
EXPECT_EQ(2U, mouse_events_.size());
EXPECT_THAT(mouse_events_[0],
EqualsMouseButtonEvent(protocol::MouseEvent::BUTTON_LEFT, true));
EXPECT_THAT(mouse_events_[1],
EqualsMouseButtonEvent(protocol::MouseEvent::BUTTON_LEFT, false));
EXPECT_EQ(4U, key_events_.size());
EXPECT_THAT(key_events_[0], EqualsKeyEvent(1, true));
EXPECT_THAT(key_events_[1], EqualsKeyEvent(2, true));
EXPECT_THAT(key_events_[2], EqualsKeyEvent(1, false));
EXPECT_THAT(key_events_[3], EqualsKeyEvent(2, false));
}
TEST_F(ClientSessionTest, ClampMouseEvents) {
CreateClientSession();
ConnectClientSession();
SetupSingleDisplay();
desktop_environment_factory_->last_desktop_environment()
->last_input_injector()
->set_mouse_events(&mouse_events_);
std::array<int, 3> input_x = {-999, 100, 999};
std::array<int, 3> expected_x = {
0,
100,
protocol::FakeDesktopCapturer::kWidth - 1,
};
std::array<int, 3> input_y = {-999, 50, 999};
std::array<int, 3> expected_y = {
0,
50,
protocol::FakeDesktopCapturer::kHeight - 1,
};
protocol::MouseEvent expected_event;
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 3; i++) {
mouse_events_.clear();
connection_->input_stub()->InjectMouseEvent(
MakeMouseMoveEvent(input_x[i], input_y[j]));
EXPECT_EQ(1U, mouse_events_.size());
EXPECT_THAT(mouse_events_[0],
EqualsMouseMoveEvent(expected_x[i], expected_y[j]));
}
}
}
TEST_F(ClientSessionTest, Extensions) {
FakeExtension extension1("ext1", "cap1");
extensions_.push_back(&extension1);
FakeExtension extension2("ext2", "");
extensions_.push_back(&extension2);
FakeExtension extension3("ext3", "cap3");
extensions_.push_back(&extension3);
EXPECT_CALL(client_stub_, SetCapabilities(IncludesCapabilities("cap1 cap3")));
CreateClientSession();
ConnectClientSession();
testing::Mock::VerifyAndClearExpectations(&client_stub_);
protocol::Capabilities capabilities_message;
capabilities_message.set_capabilities("cap1 cap4 default");
client_session_->SetCapabilities(capabilities_message);
protocol::ExtensionMessage message1;
message1.set_type("ext1");
message1.set_data("data");
client_session_->DeliverClientMessage(message1);
protocol::ExtensionMessage message3;
message3.set_type("ext3");
message3.set_data("data");
client_session_->DeliverClientMessage(message3);
protocol::ExtensionMessage message4;
message4.set_type("ext4");
message4.set_data("data");
client_session_->DeliverClientMessage(message4);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(extension1.was_instantiated());
EXPECT_TRUE(extension1.has_handled_message());
EXPECT_TRUE(extension2.was_instantiated());
EXPECT_FALSE(extension2.has_handled_message());
EXPECT_FALSE(extension3.was_instantiated());
extensions_.clear();
}
TEST_F(ClientSessionTest, DataChannelCallbackIsCalled) {
bool callback_called = false;
CreateClientSession();
client_session_->RegisterCreateHandlerCallbackForTesting(
kTestDataChannelCallbackName,
base::BindRepeating([](bool* callback_was_called, const std::string& name,
std::unique_ptr<protocol::MessagePipe> pipe)
-> void { *callback_was_called = true; },
&callback_called));
ConnectClientSession();
std::unique_ptr<protocol::MessagePipe> pipe =
base::WrapUnique(new protocol::FakeMessagePipe(false));
client_session_->OnIncomingDataChannel(kTestDataChannelCallbackName,
std::move(pipe));
ASSERT_TRUE(callback_called);
}
TEST_F(ClientSessionTest, ForwardHostSessionOptions1) {
auto session = std::make_unique<protocol::FakeSession>();
auto configuration = std::make_unique<jingle_xmpp::XmlElement>(
jingle_xmpp::QName(kChromotingXmlNamespace, "host-configuration"));
configuration->SetBodyText("Detect-Updated-Region:true");
session->SetAttachment(0, std::move(configuration));
CreateClientSession(std::move(session));
ConnectClientSession();
ASSERT_TRUE(desktop_environment_factory_->last_desktop_environment()
->options()
.desktop_capture_options()
->detect_updated_region());
}
TEST_F(ClientSessionTest, ForwardHostSessionOptions2) {
auto session = std::make_unique<protocol::FakeSession>();
auto configuration = std::make_unique<jingle_xmpp::XmlElement>(
jingle_xmpp::QName(kChromotingXmlNamespace, "host-configuration"));
configuration->SetBodyText("Detect-Updated-Region:false");
session->SetAttachment(0, std::move(configuration));
CreateClientSession(std::move(session));
ConnectClientSession();
ASSERT_FALSE(desktop_environment_factory_->last_desktop_environment()
->options()
.desktop_capture_options()
->detect_updated_region());
}
TEST_F(ClientSessionTest, ActiveDisplayMessageSent) {
EXPECT_CALL(client_stub_, SetActiveDisplay(ScreenIdMatches(kDisplay1Id)));
desktop_environment_factory_->set_capabilities(
protocol::kMultiStreamCapability);
CreateClientSession();
ConnectClientSession();
protocol::Capabilities client_capabilities;
client_capabilities.set_capabilities(protocol::kMultiStreamCapability);
client_session_->SetCapabilities(client_capabilities);
auto monitor = desktop_environment_factory_->last_desktop_environment()
->last_active_display_monitor();
ASSERT_TRUE(monitor);
monitor->SetActiveDisplay(static_cast<webrtc::ScreenId>(kDisplay1Id));
}
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(ClientSessionTest, ShouldSelectFirstDesktopByDefault) {
CreateClientSession();
ConnectClientSession();
SetupMultiDisplay();
EXPECT_THAT(GetSelectedSourceDisplayId(), Eq(kDisplay1Id));
}
TEST_F(ClientSessionTest,
ShouldChangeSelectedSourceDisplayWhenSwitchingDisplay) {
CreateClientSession();
ConnectClientSession();
SetupMultiDisplay();
MultiMon_SelectSecondDisplay();
EXPECT_THAT(GetSelectedSourceDisplayId(), Eq(kDisplay2Id));
MultiMon_SelectFirstDisplay();
EXPECT_THAT(GetSelectedSourceDisplayId(), Eq(kDisplay1Id));
}
TEST_F(ClientSessionTest,
ShouldFallBackToPrimaryDisplayWhenSwitchingToInvalidDisplay) {
CreateClientSession();
ConnectClientSession();
SetupMultiDisplay();
MultiMon_SelectDisplay("Not an integer");
EXPECT_THAT(GetSelectedSourceDisplayId(), Eq(kDisplay1Id));
MultiMon_SelectDisplay("123456");
EXPECT_THAT(GetSelectedSourceDisplayId(), Eq(kDisplay1Id));
MultiMon_SelectDisplay("all");
EXPECT_THAT(GetSelectedSourceDisplayId(), Eq(kDisplay1Id));
}
TEST_F(ClientSessionTest,
ShouldFallBackToPrimaryDisplayWhenSelectedDisplayIsDisconnected) {
CreateClientSession();
ConnectClientSession();
SetupMultiDisplay();
MultiMon_SelectSecondDisplay();
SetupSingleDisplay();
EXPECT_THAT(GetSelectedSourceDisplayId(), Eq(kDisplay1Id));
}
#endif
}