blob: 8af51c0572567d73b233f532f21bbc1b57fd39e4 [file] [log] [blame]
// Copyright 2018 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 "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h"
#include <memory>
#include "base/macros.h"
#include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
#include "chrome/browser/chromeos/android_sms/fake_android_sms_app_manager.h"
#include "chromeos/components/multidevice/remote_device_test_util.h"
#include "chromeos/services/multidevice_setup/public/cpp/fake_android_sms_pairing_state_tracker.h"
#include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/test_web_ui.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace settings {
namespace {
class TestMultideviceHandler : public MultideviceHandler {
public:
TestMultideviceHandler(
PrefService* prefs,
multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
multidevice_setup::AndroidSmsPairingStateTracker*
android_sms_pairing_state_tracker,
android_sms::AndroidSmsAppManager* android_sms_app_manager)
: MultideviceHandler(prefs,
multidevice_setup_client,
android_sms_pairing_state_tracker,
android_sms_app_manager) {}
~TestMultideviceHandler() override = default;
// Make public for testing.
using MultideviceHandler::AllowJavascript;
using MultideviceHandler::RegisterMessages;
using MultideviceHandler::set_web_ui;
};
multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
GenerateDefaultFeatureStatesMap() {
return multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap{
{multidevice_setup::mojom::Feature::kBetterTogetherSuite,
multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost},
{multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost},
{multidevice_setup::mojom::Feature::kMessages,
multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost},
{multidevice_setup::mojom::Feature::kSmartLock,
multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost}};
}
void VerifyPageContentDict(
const base::Value* value,
multidevice_setup::mojom::HostStatus expected_host_status,
const base::Optional<multidevice::RemoteDeviceRef>& expected_host_device,
const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
feature_states_map) {
const base::DictionaryValue* page_content_dict;
EXPECT_TRUE(value->GetAsDictionary(&page_content_dict));
int mode;
EXPECT_TRUE(page_content_dict->GetInteger("mode", &mode));
EXPECT_EQ(static_cast<int>(expected_host_status), mode);
int better_together_state;
EXPECT_TRUE(page_content_dict->GetInteger("betterTogetherState",
&better_together_state));
auto it = feature_states_map.find(
multidevice_setup::mojom::Feature::kBetterTogetherSuite);
EXPECT_EQ(static_cast<int>(it->second), better_together_state);
int instant_tethering_state;
EXPECT_TRUE(page_content_dict->GetInteger("instantTetheringState",
&instant_tethering_state));
it = feature_states_map.find(
multidevice_setup::mojom::Feature::kInstantTethering);
EXPECT_EQ(static_cast<int>(it->second), instant_tethering_state);
int messages_state;
EXPECT_TRUE(page_content_dict->GetInteger("messagesState", &messages_state));
it = feature_states_map.find(multidevice_setup::mojom::Feature::kMessages);
EXPECT_EQ(static_cast<int>(it->second), messages_state);
int smart_lock_state;
EXPECT_TRUE(
page_content_dict->GetInteger("smartLockState", &smart_lock_state));
it = feature_states_map.find(multidevice_setup::mojom::Feature::kSmartLock);
EXPECT_EQ(static_cast<int>(it->second), smart_lock_state);
std::string host_device_name;
if (expected_host_device) {
EXPECT_TRUE(
page_content_dict->GetString("hostDeviceName", &host_device_name));
EXPECT_EQ(expected_host_device->name(), host_device_name);
} else {
EXPECT_FALSE(
page_content_dict->GetString("hostDeviceName", &host_device_name));
}
}
} // namespace
class MultideviceHandlerTest : public testing::Test {
protected:
MultideviceHandlerTest()
: test_device_(multidevice::CreateRemoteDeviceRefForTest()) {}
~MultideviceHandlerTest() override = default;
// testing::Test:
void SetUp() override {
test_web_ui_ = std::make_unique<content::TestWebUI>();
fake_multidevice_setup_client_ =
std::make_unique<multidevice_setup::FakeMultiDeviceSetupClient>();
fake_android_sms_pairing_state_tracker_ = std::make_unique<
multidevice_setup::FakeAndroidSmsPairingStateTracker>();
fake_android_sms_app_manager_ =
std::make_unique<android_sms::FakeAndroidSmsAppManager>();
prefs_.reset(new TestingPrefServiceSimple());
handler_ = std::make_unique<TestMultideviceHandler>(
prefs_.get(), fake_multidevice_setup_client_.get(),
fake_android_sms_pairing_state_tracker_.get(),
fake_android_sms_app_manager_.get());
handler_->set_web_ui(test_web_ui_.get());
handler_->RegisterMessages();
handler_->AllowJavascript();
}
void CallGetPageContentData() {
size_t call_data_count_before_call = test_web_ui()->call_data().size();
base::ListValue args;
args.AppendString("handlerFunctionName");
test_web_ui()->HandleReceivedMessage("getPageContentData", &args);
EXPECT_EQ(call_data_count_before_call + 1u,
test_web_ui()->call_data().size());
const content::TestWebUI::CallData& call_data =
CallDataAtIndex(call_data_count_before_call);
EXPECT_EQ("cr.webUIResponse", call_data.function_name());
EXPECT_EQ("handlerFunctionName", call_data.arg1()->GetString());
EXPECT_TRUE(call_data.arg2()->GetBool());
VerifyPageContent(call_data.arg3());
}
void CallRemoveHostDevice() {
size_t num_remote_host_device_calls_before_call =
fake_multidevice_setup_client()->num_remove_host_device_called();
base::ListValue empty_args;
test_web_ui()->HandleReceivedMessage("removeHostDevice", &empty_args);
EXPECT_EQ(num_remote_host_device_calls_before_call + 1u,
fake_multidevice_setup_client()->num_remove_host_device_called());
}
void CallGetAndroidSmsInfo(bool expected_enabled, const GURL& expected_url) {
size_t call_data_count_before_call = test_web_ui()->call_data().size();
base::ListValue args;
args.AppendString("handlerFunctionName");
test_web_ui()->HandleReceivedMessage("getAndroidSmsInfo", &args);
ASSERT_EQ(call_data_count_before_call + 1u,
test_web_ui()->call_data().size());
const content::TestWebUI::CallData& call_data =
CallDataAtIndex(call_data_count_before_call);
EXPECT_EQ("cr.webUIResponse", call_data.function_name());
EXPECT_EQ("handlerFunctionName", call_data.arg1()->GetString());
ASSERT_TRUE(call_data.arg2()->GetBool());
EXPECT_EQ(
ContentSettingsPattern::FromURLNoWildcard(expected_url).ToString(),
call_data.arg3()->FindKey("origin")->GetString());
EXPECT_EQ(expected_enabled,
call_data.arg3()->FindKey("enabled")->GetBool());
}
void SimulateHostStatusUpdate(
multidevice_setup::mojom::HostStatus host_status,
const base::Optional<multidevice::RemoteDeviceRef>& host_device) {
size_t call_data_count_before_call = test_web_ui()->call_data().size();
fake_multidevice_setup_client_->SetHostStatusWithDevice(
std::make_pair(host_status, host_device));
EXPECT_EQ(call_data_count_before_call + 2u,
test_web_ui()->call_data().size());
const content::TestWebUI::CallData& call_data =
CallDataAtIndex(call_data_count_before_call);
EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
EXPECT_EQ("settings.updateMultidevicePageContentData",
call_data.arg1()->GetString());
VerifyPageContent(call_data.arg2());
}
void SimulateFeatureStatesUpdate(
const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
feature_states_map) {
size_t call_data_count_before_call = test_web_ui()->call_data().size();
fake_multidevice_setup_client_->SetFeatureStates(feature_states_map);
EXPECT_EQ(call_data_count_before_call + 2u,
test_web_ui()->call_data().size());
const content::TestWebUI::CallData& call_data =
CallDataAtIndex(call_data_count_before_call);
EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
EXPECT_EQ("settings.updateMultidevicePageContentData",
call_data.arg1()->GetString());
VerifyPageContent(call_data.arg2());
}
void SimulatePairingStateUpdate(bool is_android_sms_pairing_complete) {
size_t call_data_count_before_call = test_web_ui()->call_data().size();
fake_android_sms_pairing_state_tracker_->SetPairingComplete(
is_android_sms_pairing_complete);
EXPECT_EQ(call_data_count_before_call + 2u,
test_web_ui()->call_data().size());
const content::TestWebUI::CallData& call_data =
CallDataAtIndex(call_data_count_before_call);
EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
EXPECT_EQ("settings.updateMultidevicePageContentData",
call_data.arg1()->GetString());
VerifyPageContent(call_data.arg2());
}
void CallRetryPendingHostSetup(bool success) {
base::ListValue empty_args;
test_web_ui()->HandleReceivedMessage("retryPendingHostSetup", &empty_args);
fake_multidevice_setup_client()->InvokePendingRetrySetHostNowCallback(
success);
}
void CallSetUpAndroidSms() {
base::ListValue empty_args;
test_web_ui()->HandleReceivedMessage("setUpAndroidSms", &empty_args);
}
void CallSetFeatureEnabledState(multidevice_setup::mojom::Feature feature,
bool enabled,
const base::Optional<std::string>& auth_token,
bool success) {
size_t call_data_count_before_call = test_web_ui()->call_data().size();
base::ListValue args;
args.AppendString("handlerFunctionName");
args.AppendInteger(static_cast<int>(feature));
args.AppendBoolean(enabled);
if (auth_token)
args.AppendString(*auth_token);
base::ListValue empty_args;
test_web_ui()->HandleReceivedMessage("setFeatureEnabledState", &args);
fake_multidevice_setup_client()
->InvokePendingSetFeatureEnabledStateCallback(
feature /* expected_feature */, enabled /* expected_enabled */,
auth_token /* expected_auth_token */, success);
EXPECT_EQ(call_data_count_before_call + 1u,
test_web_ui()->call_data().size());
const content::TestWebUI::CallData& call_data =
CallDataAtIndex(call_data_count_before_call);
EXPECT_EQ("cr.webUIResponse", call_data.function_name());
EXPECT_EQ("handlerFunctionName", call_data.arg1()->GetString());
EXPECT_TRUE(call_data.arg2()->GetBool());
EXPECT_EQ(success, call_data.arg3()->GetBool());
}
const content::TestWebUI::CallData& CallDataAtIndex(size_t index) {
return *test_web_ui_->call_data()[index];
}
content::TestWebUI* test_web_ui() { return test_web_ui_.get(); }
multidevice_setup::FakeMultiDeviceSetupClient*
fake_multidevice_setup_client() {
return fake_multidevice_setup_client_.get();
}
android_sms::FakeAndroidSmsAppManager* fake_android_sms_app_manager() {
return fake_android_sms_app_manager_.get();
}
const multidevice::RemoteDeviceRef test_device_;
private:
void VerifyPageContent(const base::Value* value) {
VerifyPageContentDict(
value, fake_multidevice_setup_client_->GetHostStatus().first,
fake_multidevice_setup_client_->GetHostStatus().second,
fake_multidevice_setup_client_->GetFeatureStates());
}
std::unique_ptr<TestingPrefServiceSimple> prefs_;
std::unique_ptr<content::TestWebUI> test_web_ui_;
std::unique_ptr<multidevice_setup::FakeMultiDeviceSetupClient>
fake_multidevice_setup_client_;
std::unique_ptr<multidevice_setup::FakeAndroidSmsPairingStateTracker>
fake_android_sms_pairing_state_tracker_;
multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice
host_status_with_device_;
multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
feature_states_map_;
std::unique_ptr<android_sms::FakeAndroidSmsAppManager>
fake_android_sms_app_manager_;
std::unique_ptr<TestMultideviceHandler> handler_;
DISALLOW_COPY_AND_ASSIGN(MultideviceHandlerTest);
};
TEST_F(MultideviceHandlerTest, PageContentData) {
CallGetPageContentData();
CallGetPageContentData();
SimulateHostStatusUpdate(
multidevice_setup::mojom::HostStatus::kEligibleHostExistsButNoHostSet,
base::nullopt /* host_device */);
SimulateHostStatusUpdate(multidevice_setup::mojom::HostStatus::
kHostSetLocallyButWaitingForBackendConfirmation,
test_device_);
SimulateHostStatusUpdate(
multidevice_setup::mojom::HostStatus::kHostSetButNotYetVerified,
test_device_);
SimulateHostStatusUpdate(multidevice_setup::mojom::HostStatus::kHostVerified,
test_device_);
multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
feature_states_map = GenerateDefaultFeatureStatesMap();
feature_states_map[multidevice_setup::mojom::Feature::kBetterTogetherSuite] =
multidevice_setup::mojom::FeatureState::kEnabledByUser;
SimulateFeatureStatesUpdate(feature_states_map);
feature_states_map[multidevice_setup::mojom::Feature::kBetterTogetherSuite] =
multidevice_setup::mojom::FeatureState::kDisabledByUser;
SimulateFeatureStatesUpdate(feature_states_map);
SimulatePairingStateUpdate(/*is_android_sms_pairing_complete=*/true);
}
TEST_F(MultideviceHandlerTest, RetryPendingHostSetup) {
CallRetryPendingHostSetup(true /* success */);
CallRetryPendingHostSetup(false /* success */);
}
TEST_F(MultideviceHandlerTest, SetUpAndroidSms) {
EXPECT_FALSE(fake_android_sms_app_manager()->has_installed_app());
EXPECT_FALSE(fake_android_sms_app_manager()->has_launched_app());
CallSetUpAndroidSms();
EXPECT_TRUE(fake_android_sms_app_manager()->has_installed_app());
EXPECT_TRUE(fake_android_sms_app_manager()->has_launched_app());
}
TEST_F(MultideviceHandlerTest, SetFeatureEnabledState) {
CallSetFeatureEnabledState(
multidevice_setup::mojom::Feature::kBetterTogetherSuite,
true /* enabled */, "authToken" /* auth_token */, true /* success */);
CallSetFeatureEnabledState(
multidevice_setup::mojom::Feature::kBetterTogetherSuite,
false /* enabled */, "authToken" /* auth_token */, false /* success */);
CallSetFeatureEnabledState(
multidevice_setup::mojom::Feature::kBetterTogetherSuite,
false /* enabled */, "authToken" /* auth_token */, true /* success */);
}
TEST_F(MultideviceHandlerTest, RemoveHostDevice) {
CallRemoveHostDevice();
CallRemoveHostDevice();
CallRemoveHostDevice();
}
TEST_F(MultideviceHandlerTest, GetAndroidSmsInfo) {
// Check that getAndroidSmsInfo returns correct value.
CallGetAndroidSmsInfo(false /* expected_enabled */,
android_sms::GetAndroidMessagesURL(
true /* use_install_url */) /* expected_url */);
// Change messages feature state and assert that the change
// callback is fired.
multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
feature_states_map = GenerateDefaultFeatureStatesMap();
feature_states_map[multidevice_setup::mojom::Feature::kMessages] =
multidevice_setup::mojom::FeatureState::kEnabledByUser;
size_t call_data_count_before_call = test_web_ui()->call_data().size();
SimulateFeatureStatesUpdate(feature_states_map);
const content::TestWebUI::CallData& call_data_1 =
CallDataAtIndex(call_data_count_before_call + 1);
EXPECT_EQ("cr.webUIListenerCallback", call_data_1.function_name());
EXPECT_EQ("settings.onAndroidSmsInfoChange", call_data_1.arg1()->GetString());
// Check that getAndroidSmsInfo returns update value.
CallGetAndroidSmsInfo(true /* enabled */, android_sms::GetAndroidMessagesURL(
true) /* expected_url */);
// Now, update the installed URL. This should have resulted in another call.
fake_android_sms_app_manager()->SetInstalledAppUrl(
android_sms::GetAndroidMessagesURL(true /* use_install_url */,
android_sms::PwaDomain::kStaging));
const content::TestWebUI::CallData& call_data_2 =
CallDataAtIndex(call_data_count_before_call + 4);
EXPECT_EQ("cr.webUIListenerCallback", call_data_2.function_name());
EXPECT_EQ("settings.onAndroidSmsInfoChange", call_data_2.arg1()->GetString());
CallGetAndroidSmsInfo(
true /* enabled */,
android_sms::GetAndroidMessagesURL(
true /* use_install_url */,
android_sms::PwaDomain::kStaging) /* expected_url */);
}
} // namespace settings
} // namespace chromeos