1 // Copyright 2018 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 "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h"
6
7 #include <memory>
8
9 #include "base/macros.h"
10 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
11 #include "chrome/browser/chromeos/android_sms/fake_android_sms_app_manager.h"
12 #include "chromeos/components/multidevice/remote_device_test_util.h"
13 #include "chromeos/services/multidevice_setup/public/cpp/fake_android_sms_pairing_state_tracker.h"
14 #include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
15 #include "components/content_settings/core/common/content_settings_pattern.h"
16 #include "components/prefs/testing_pref_service.h"
17 #include "content/public/test/test_web_ui.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace chromeos {
21
22 namespace settings {
23
24 namespace {
25
26 class TestMultideviceHandler : public MultideviceHandler {
27 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)28 TestMultideviceHandler(
29 PrefService* prefs,
30 multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
31 multidevice_setup::AndroidSmsPairingStateTracker*
32 android_sms_pairing_state_tracker,
33 android_sms::AndroidSmsAppManager* android_sms_app_manager)
34 : MultideviceHandler(prefs,
35 multidevice_setup_client,
36 android_sms_pairing_state_tracker,
37 android_sms_app_manager) {}
38 ~TestMultideviceHandler() override = default;
39
40 // Make public for testing.
41 using MultideviceHandler::AllowJavascript;
42 using MultideviceHandler::RegisterMessages;
43 using MultideviceHandler::set_web_ui;
44 };
45
46 multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
GenerateDefaultFeatureStatesMap()47 GenerateDefaultFeatureStatesMap() {
48 return multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap{
49 {multidevice_setup::mojom::Feature::kBetterTogetherSuite,
50 multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost},
51 {multidevice_setup::mojom::Feature::kInstantTethering,
52 multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost},
53 {multidevice_setup::mojom::Feature::kMessages,
54 multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost},
55 {multidevice_setup::mojom::Feature::kSmartLock,
56 multidevice_setup::mojom::FeatureState::kUnavailableNoVerifiedHost}};
57 }
58
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)59 void VerifyPageContentDict(
60 const base::Value* value,
61 multidevice_setup::mojom::HostStatus expected_host_status,
62 const base::Optional<multidevice::RemoteDeviceRef>& expected_host_device,
63 const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
64 feature_states_map) {
65 const base::DictionaryValue* page_content_dict;
66 EXPECT_TRUE(value->GetAsDictionary(&page_content_dict));
67
68 int mode;
69 EXPECT_TRUE(page_content_dict->GetInteger("mode", &mode));
70 EXPECT_EQ(static_cast<int>(expected_host_status), mode);
71
72 int better_together_state;
73 EXPECT_TRUE(page_content_dict->GetInteger("betterTogetherState",
74 &better_together_state));
75 auto it = feature_states_map.find(
76 multidevice_setup::mojom::Feature::kBetterTogetherSuite);
77 EXPECT_EQ(static_cast<int>(it->second), better_together_state);
78
79 int instant_tethering_state;
80 EXPECT_TRUE(page_content_dict->GetInteger("instantTetheringState",
81 &instant_tethering_state));
82 it = feature_states_map.find(
83 multidevice_setup::mojom::Feature::kInstantTethering);
84 EXPECT_EQ(static_cast<int>(it->second), instant_tethering_state);
85
86 int messages_state;
87 EXPECT_TRUE(page_content_dict->GetInteger("messagesState", &messages_state));
88 it = feature_states_map.find(multidevice_setup::mojom::Feature::kMessages);
89 EXPECT_EQ(static_cast<int>(it->second), messages_state);
90
91 int smart_lock_state;
92 EXPECT_TRUE(
93 page_content_dict->GetInteger("smartLockState", &smart_lock_state));
94 it = feature_states_map.find(multidevice_setup::mojom::Feature::kSmartLock);
95 EXPECT_EQ(static_cast<int>(it->second), smart_lock_state);
96
97 std::string host_device_name;
98 if (expected_host_device) {
99 EXPECT_TRUE(
100 page_content_dict->GetString("hostDeviceName", &host_device_name));
101 EXPECT_EQ(expected_host_device->name(), host_device_name);
102 } else {
103 EXPECT_FALSE(
104 page_content_dict->GetString("hostDeviceName", &host_device_name));
105 }
106 }
107
108 } // namespace
109
110 class MultideviceHandlerTest : public testing::Test {
111 protected:
MultideviceHandlerTest()112 MultideviceHandlerTest()
113 : test_device_(multidevice::CreateRemoteDeviceRefForTest()) {}
114 ~MultideviceHandlerTest() override = default;
115
116 // testing::Test:
SetUp()117 void SetUp() override {
118 test_web_ui_ = std::make_unique<content::TestWebUI>();
119
120 fake_multidevice_setup_client_ =
121 std::make_unique<multidevice_setup::FakeMultiDeviceSetupClient>();
122 fake_android_sms_pairing_state_tracker_ = std::make_unique<
123 multidevice_setup::FakeAndroidSmsPairingStateTracker>();
124 fake_android_sms_app_manager_ =
125 std::make_unique<android_sms::FakeAndroidSmsAppManager>();
126
127 prefs_ = std::make_unique<TestingPrefServiceSimple>();
128
129 handler_ = std::make_unique<TestMultideviceHandler>(
130 prefs_.get(), fake_multidevice_setup_client_.get(),
131 fake_android_sms_pairing_state_tracker_.get(),
132 fake_android_sms_app_manager_.get());
133 handler_->set_web_ui(test_web_ui_.get());
134 handler_->RegisterMessages();
135 handler_->AllowJavascript();
136 }
137
CallGetPageContentData()138 void CallGetPageContentData() {
139 size_t call_data_count_before_call = test_web_ui()->call_data().size();
140
141 base::ListValue args;
142 args.AppendString("handlerFunctionName");
143 test_web_ui()->HandleReceivedMessage("getPageContentData", &args);
144
145 EXPECT_EQ(call_data_count_before_call + 1u,
146 test_web_ui()->call_data().size());
147
148 const content::TestWebUI::CallData& call_data =
149 CallDataAtIndex(call_data_count_before_call);
150 EXPECT_EQ("cr.webUIResponse", call_data.function_name());
151 EXPECT_EQ("handlerFunctionName", call_data.arg1()->GetString());
152 EXPECT_TRUE(call_data.arg2()->GetBool());
153 VerifyPageContent(call_data.arg3());
154 }
155
CallRemoveHostDevice()156 void CallRemoveHostDevice() {
157 size_t num_remote_host_device_calls_before_call =
158 fake_multidevice_setup_client()->num_remove_host_device_called();
159 base::ListValue empty_args;
160 test_web_ui()->HandleReceivedMessage("removeHostDevice", &empty_args);
161 EXPECT_EQ(num_remote_host_device_calls_before_call + 1u,
162 fake_multidevice_setup_client()->num_remove_host_device_called());
163 }
164
CallGetAndroidSmsInfo(bool expected_enabled,const GURL & expected_url)165 void CallGetAndroidSmsInfo(bool expected_enabled, const GURL& expected_url) {
166 size_t call_data_count_before_call = test_web_ui()->call_data().size();
167
168 base::ListValue args;
169 args.AppendString("handlerFunctionName");
170 test_web_ui()->HandleReceivedMessage("getAndroidSmsInfo", &args);
171
172 ASSERT_EQ(call_data_count_before_call + 1u,
173 test_web_ui()->call_data().size());
174 const content::TestWebUI::CallData& call_data =
175 CallDataAtIndex(call_data_count_before_call);
176 EXPECT_EQ("cr.webUIResponse", call_data.function_name());
177 EXPECT_EQ("handlerFunctionName", call_data.arg1()->GetString());
178 ASSERT_TRUE(call_data.arg2()->GetBool());
179 EXPECT_EQ(
180 ContentSettingsPattern::FromURLNoWildcard(expected_url).ToString(),
181 call_data.arg3()->FindKey("origin")->GetString());
182 EXPECT_EQ(expected_enabled,
183 call_data.arg3()->FindKey("enabled")->GetBool());
184 }
185
SimulateHostStatusUpdate(multidevice_setup::mojom::HostStatus host_status,const base::Optional<multidevice::RemoteDeviceRef> & host_device)186 void SimulateHostStatusUpdate(
187 multidevice_setup::mojom::HostStatus host_status,
188 const base::Optional<multidevice::RemoteDeviceRef>& host_device) {
189 size_t call_data_count_before_call = test_web_ui()->call_data().size();
190
191 fake_multidevice_setup_client_->SetHostStatusWithDevice(
192 std::make_pair(host_status, host_device));
193 EXPECT_EQ(call_data_count_before_call + 2u,
194 test_web_ui()->call_data().size());
195
196 const content::TestWebUI::CallData& call_data =
197 CallDataAtIndex(call_data_count_before_call);
198 EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
199 EXPECT_EQ("settings.updateMultidevicePageContentData",
200 call_data.arg1()->GetString());
201 VerifyPageContent(call_data.arg2());
202 }
203
SimulateFeatureStatesUpdate(const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap & feature_states_map)204 void SimulateFeatureStatesUpdate(
205 const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
206 feature_states_map) {
207 size_t call_data_count_before_call = test_web_ui()->call_data().size();
208
209 fake_multidevice_setup_client_->SetFeatureStates(feature_states_map);
210 EXPECT_EQ(call_data_count_before_call + 2u,
211 test_web_ui()->call_data().size());
212
213 const content::TestWebUI::CallData& call_data =
214 CallDataAtIndex(call_data_count_before_call);
215 EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
216 EXPECT_EQ("settings.updateMultidevicePageContentData",
217 call_data.arg1()->GetString());
218 VerifyPageContent(call_data.arg2());
219 }
220
SimulatePairingStateUpdate(bool is_android_sms_pairing_complete)221 void SimulatePairingStateUpdate(bool is_android_sms_pairing_complete) {
222 size_t call_data_count_before_call = test_web_ui()->call_data().size();
223
224 fake_android_sms_pairing_state_tracker_->SetPairingComplete(
225 is_android_sms_pairing_complete);
226 EXPECT_EQ(call_data_count_before_call + 2u,
227 test_web_ui()->call_data().size());
228
229 const content::TestWebUI::CallData& call_data =
230 CallDataAtIndex(call_data_count_before_call);
231 EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
232 EXPECT_EQ("settings.updateMultidevicePageContentData",
233 call_data.arg1()->GetString());
234 VerifyPageContent(call_data.arg2());
235 }
236
CallRetryPendingHostSetup(bool success)237 void CallRetryPendingHostSetup(bool success) {
238 base::ListValue empty_args;
239 test_web_ui()->HandleReceivedMessage("retryPendingHostSetup", &empty_args);
240 fake_multidevice_setup_client()->InvokePendingRetrySetHostNowCallback(
241 success);
242 }
243
CallSetUpAndroidSms()244 void CallSetUpAndroidSms() {
245 base::ListValue empty_args;
246 test_web_ui()->HandleReceivedMessage("setUpAndroidSms", &empty_args);
247 }
248
CallSetFeatureEnabledState(multidevice_setup::mojom::Feature feature,bool enabled,const base::Optional<std::string> & auth_token,bool success)249 void CallSetFeatureEnabledState(multidevice_setup::mojom::Feature feature,
250 bool enabled,
251 const base::Optional<std::string>& auth_token,
252 bool success) {
253 size_t call_data_count_before_call = test_web_ui()->call_data().size();
254
255 base::ListValue args;
256 args.AppendString("handlerFunctionName");
257 args.AppendInteger(static_cast<int>(feature));
258 args.AppendBoolean(enabled);
259 if (auth_token)
260 args.AppendString(*auth_token);
261
262 base::ListValue empty_args;
263 test_web_ui()->HandleReceivedMessage("setFeatureEnabledState", &args);
264 fake_multidevice_setup_client()
265 ->InvokePendingSetFeatureEnabledStateCallback(
266 feature /* expected_feature */, enabled /* expected_enabled */,
267 auth_token /* expected_auth_token */, success);
268
269 EXPECT_EQ(call_data_count_before_call + 1u,
270 test_web_ui()->call_data().size());
271 const content::TestWebUI::CallData& call_data =
272 CallDataAtIndex(call_data_count_before_call);
273 EXPECT_EQ("cr.webUIResponse", call_data.function_name());
274 EXPECT_EQ("handlerFunctionName", call_data.arg1()->GetString());
275 EXPECT_TRUE(call_data.arg2()->GetBool());
276 EXPECT_EQ(success, call_data.arg3()->GetBool());
277 }
278
CallDataAtIndex(size_t index)279 const content::TestWebUI::CallData& CallDataAtIndex(size_t index) {
280 return *test_web_ui_->call_data()[index];
281 }
282
test_web_ui()283 content::TestWebUI* test_web_ui() { return test_web_ui_.get(); }
284
285 multidevice_setup::FakeMultiDeviceSetupClient*
fake_multidevice_setup_client()286 fake_multidevice_setup_client() {
287 return fake_multidevice_setup_client_.get();
288 }
289
fake_android_sms_app_manager()290 android_sms::FakeAndroidSmsAppManager* fake_android_sms_app_manager() {
291 return fake_android_sms_app_manager_.get();
292 }
293
294 const multidevice::RemoteDeviceRef test_device_;
295
296 private:
VerifyPageContent(const base::Value * value)297 void VerifyPageContent(const base::Value* value) {
298 VerifyPageContentDict(
299 value, fake_multidevice_setup_client_->GetHostStatus().first,
300 fake_multidevice_setup_client_->GetHostStatus().second,
301 fake_multidevice_setup_client_->GetFeatureStates());
302 }
303
304 std::unique_ptr<TestingPrefServiceSimple> prefs_;
305 std::unique_ptr<content::TestWebUI> test_web_ui_;
306 std::unique_ptr<multidevice_setup::FakeMultiDeviceSetupClient>
307 fake_multidevice_setup_client_;
308 std::unique_ptr<multidevice_setup::FakeAndroidSmsPairingStateTracker>
309 fake_android_sms_pairing_state_tracker_;
310
311 multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice
312 host_status_with_device_;
313 multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
314 feature_states_map_;
315 std::unique_ptr<android_sms::FakeAndroidSmsAppManager>
316 fake_android_sms_app_manager_;
317
318 std::unique_ptr<TestMultideviceHandler> handler_;
319
320 DISALLOW_COPY_AND_ASSIGN(MultideviceHandlerTest);
321 };
322
TEST_F(MultideviceHandlerTest,PageContentData)323 TEST_F(MultideviceHandlerTest, PageContentData) {
324 CallGetPageContentData();
325 CallGetPageContentData();
326
327 SimulateHostStatusUpdate(
328 multidevice_setup::mojom::HostStatus::kEligibleHostExistsButNoHostSet,
329 base::nullopt /* host_device */);
330 SimulateHostStatusUpdate(multidevice_setup::mojom::HostStatus::
331 kHostSetLocallyButWaitingForBackendConfirmation,
332 test_device_);
333 SimulateHostStatusUpdate(
334 multidevice_setup::mojom::HostStatus::kHostSetButNotYetVerified,
335 test_device_);
336 SimulateHostStatusUpdate(multidevice_setup::mojom::HostStatus::kHostVerified,
337 test_device_);
338
339 multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
340 feature_states_map = GenerateDefaultFeatureStatesMap();
341 feature_states_map[multidevice_setup::mojom::Feature::kBetterTogetherSuite] =
342 multidevice_setup::mojom::FeatureState::kEnabledByUser;
343 SimulateFeatureStatesUpdate(feature_states_map);
344
345 feature_states_map[multidevice_setup::mojom::Feature::kBetterTogetherSuite] =
346 multidevice_setup::mojom::FeatureState::kDisabledByUser;
347 SimulateFeatureStatesUpdate(feature_states_map);
348
349 SimulatePairingStateUpdate(/*is_android_sms_pairing_complete=*/true);
350 }
351
TEST_F(MultideviceHandlerTest,RetryPendingHostSetup)352 TEST_F(MultideviceHandlerTest, RetryPendingHostSetup) {
353 CallRetryPendingHostSetup(true /* success */);
354 CallRetryPendingHostSetup(false /* success */);
355 }
356
TEST_F(MultideviceHandlerTest,SetUpAndroidSms)357 TEST_F(MultideviceHandlerTest, SetUpAndroidSms) {
358 EXPECT_FALSE(fake_android_sms_app_manager()->has_installed_app());
359 EXPECT_FALSE(fake_android_sms_app_manager()->has_launched_app());
360 CallSetUpAndroidSms();
361 EXPECT_TRUE(fake_android_sms_app_manager()->has_installed_app());
362 EXPECT_TRUE(fake_android_sms_app_manager()->has_launched_app());
363 }
364
TEST_F(MultideviceHandlerTest,SetFeatureEnabledState)365 TEST_F(MultideviceHandlerTest, SetFeatureEnabledState) {
366 CallSetFeatureEnabledState(
367 multidevice_setup::mojom::Feature::kBetterTogetherSuite,
368 true /* enabled */, "authToken" /* auth_token */, true /* success */);
369 CallSetFeatureEnabledState(
370 multidevice_setup::mojom::Feature::kBetterTogetherSuite,
371 false /* enabled */, "authToken" /* auth_token */, false /* success */);
372 CallSetFeatureEnabledState(
373 multidevice_setup::mojom::Feature::kBetterTogetherSuite,
374 false /* enabled */, "authToken" /* auth_token */, true /* success */);
375 }
376
TEST_F(MultideviceHandlerTest,RemoveHostDevice)377 TEST_F(MultideviceHandlerTest, RemoveHostDevice) {
378 CallRemoveHostDevice();
379 CallRemoveHostDevice();
380 CallRemoveHostDevice();
381 }
382
TEST_F(MultideviceHandlerTest,GetAndroidSmsInfo)383 TEST_F(MultideviceHandlerTest, GetAndroidSmsInfo) {
384 // Check that getAndroidSmsInfo returns correct value.
385 CallGetAndroidSmsInfo(false /* expected_enabled */,
386 android_sms::GetAndroidMessagesURL(
387 true /* use_install_url */) /* expected_url */);
388
389 // Change messages feature state and assert that the change
390 // callback is fired.
391 multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap
392 feature_states_map = GenerateDefaultFeatureStatesMap();
393 feature_states_map[multidevice_setup::mojom::Feature::kMessages] =
394 multidevice_setup::mojom::FeatureState::kEnabledByUser;
395
396 size_t call_data_count_before_call = test_web_ui()->call_data().size();
397 SimulateFeatureStatesUpdate(feature_states_map);
398 const content::TestWebUI::CallData& call_data_1 =
399 CallDataAtIndex(call_data_count_before_call + 1);
400 EXPECT_EQ("cr.webUIListenerCallback", call_data_1.function_name());
401 EXPECT_EQ("settings.onAndroidSmsInfoChange", call_data_1.arg1()->GetString());
402
403 // Check that getAndroidSmsInfo returns update value.
404 CallGetAndroidSmsInfo(true /* enabled */, android_sms::GetAndroidMessagesURL(
405 true) /* expected_url */);
406
407 // Now, update the installed URL. This should have resulted in another call.
408 fake_android_sms_app_manager()->SetInstalledAppUrl(
409 android_sms::GetAndroidMessagesURL(true /* use_install_url */,
410 android_sms::PwaDomain::kStaging));
411 const content::TestWebUI::CallData& call_data_2 =
412 CallDataAtIndex(call_data_count_before_call + 4);
413 EXPECT_EQ("cr.webUIListenerCallback", call_data_2.function_name());
414 EXPECT_EQ("settings.onAndroidSmsInfoChange", call_data_2.arg1()->GetString());
415 CallGetAndroidSmsInfo(
416 true /* enabled */,
417 android_sms::GetAndroidMessagesURL(
418 true /* use_install_url */,
419 android_sms::PwaDomain::kStaging) /* expected_url */);
420 }
421
422 } // namespace settings
423
424 } // namespace chromeos
425