| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/sync_preferences/synced_set_up/utils.h" |
| |
| #include <optional> |
| #include <string> |
| |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "components/sync/protocol/sync_enums.pb.h" |
| #include "components/sync_device_info/device_info.h" |
| #include "components/sync_device_info/device_info_util.h" |
| #include "components/sync_device_info/fake_device_info_tracker.h" |
| #include "components/sync_preferences/cross_device_pref_tracker/cross_device_pref_tracker.h" |
| #include "components/sync_preferences/cross_device_pref_tracker/timestamped_pref_value.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/platform_test.h" |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "base/android/scoped_java_ref.h" |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| namespace { |
| |
| using ServiceStatus = ::sync_preferences::CrossDevicePrefTracker::ServiceStatus; |
| |
| // Test implementation of `CrossDevicePrefTracker`. |
| class TestCrossDevicePrefTracker |
| : public sync_preferences::CrossDevicePrefTracker { |
| public: |
| TestCrossDevicePrefTracker() = default; |
| ~TestCrossDevicePrefTracker() override = default; |
| |
| // `KeyedService` overrides. |
| void Shutdown() override {} |
| |
| // `CrossDevicePrefTracker` overrides. |
| void AddObserver(Observer* observer) override {} |
| void RemoveObserver(Observer* observer) override {} |
| ServiceStatus GetServiceStatus() const override { return service_status_; } |
| |
| std::vector<sync_preferences::TimestampedPrefValue> GetValues( |
| std::string_view pref_name, |
| const DeviceFilter& filter) const override { |
| auto it = pref_values_.find(pref_name); |
| if (it == pref_values_.end()) { |
| return {}; |
| } |
| |
| std::vector<sync_preferences::TimestampedPrefValue> result; |
| for (const auto& timestamped_value : it->second) { |
| sync_preferences::TimestampedPrefValue copied_value = |
| timestamped_value.Clone(); |
| result.push_back(std::move(copied_value)); |
| } |
| return result; |
| } |
| |
| std::optional<sync_preferences::TimestampedPrefValue> GetMostRecentValue( |
| std::string_view pref_name, |
| const DeviceFilter& filter) const override { |
| return std::nullopt; |
| } |
| |
| // Testing Method for injecting pref values into the tracker. |
| void AddSyncedPrefValue(std::string_view pref_name, |
| sync_preferences::TimestampedPrefValue& value) { |
| pref_values_[pref_name].push_back(std::move(value)); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override { |
| return base::android::ScopedJavaLocalRef<jobject>(); |
| } |
| |
| base::android::ScopedJavaLocalRef<jobjectArray> GetValues( |
| JNIEnv* env, |
| const base::android::JavaRef<jstring>& pref_name, |
| std::optional<int> os_type, |
| std::optional<int> form_factor, |
| std::optional<int64_t> max_sync_recency_microseconds) const override { |
| return base::android::ScopedJavaLocalRef<jobjectArray>(); |
| } |
| |
| base::android::ScopedJavaLocalRef<jobject> GetMostRecentValue( |
| JNIEnv* env, |
| const base::android::JavaRef<jstring>& pref_name, |
| std::optional<int> os_type, |
| std::optional<int> form_factor, |
| std::optional<int64_t> max_sync_recency_microseconds) const override { |
| return base::android::ScopedJavaLocalRef<jobject>(); |
| } |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| private: |
| // Testing member. Map containing TimestampedPrefValues mapped to their |
| // associated pref's name. |
| std::map<std::string_view, |
| std::vector<sync_preferences::TimestampedPrefValue>> |
| pref_values_; |
| ServiceStatus service_status_ = ServiceStatus::kAvailable; |
| }; |
| |
| } // namespace |
| |
| // Test suite for Synced Set Up utility functions. |
| class SyncedSetUpUtilsTest : public PlatformTest { |
| public: |
| // Creates a DeviceInfo object. |
| std::unique_ptr<syncer::DeviceInfo> CreateDeviceInfoForTesting( |
| std::string guid, |
| syncer::DeviceInfo::FormFactor form_factor, |
| syncer::DeviceInfo::OsType os_type, |
| base::Time last_updated_timestamp = base::Time::Now()) { |
| return CreateFakeDeviceInfo(guid, "Device Name", std::nullopt, |
| sync_pb::SyncEnums::TYPE_UNSET, os_type, |
| form_factor, "manufacturer", "model", |
| std::string(), last_updated_timestamp); |
| } |
| |
| // Helper for creating a DeviceInfo object. |
| std::unique_ptr<syncer::DeviceInfo> CreateFakeDeviceInfo( |
| const std::string& guid, |
| const std::string& name = "name", |
| const std::optional<syncer::DeviceInfo::SharingInfo>& sharing_info = |
| std::nullopt, |
| sync_pb::SyncEnums_DeviceType device_type = |
| sync_pb::SyncEnums_DeviceType_TYPE_UNSET, |
| syncer::DeviceInfo::OsType os_type = syncer::DeviceInfo::OsType::kUnknown, |
| syncer::DeviceInfo::FormFactor form_factor = |
| syncer::DeviceInfo::FormFactor::kUnknown, |
| const std::string& manufacturer_name = "manufacturer", |
| const std::string& model_name = "model", |
| const std::string& full_hardware_class = std::string(), |
| base::Time last_updated_timestamp = base::Time::Now()) { |
| return std::make_unique<syncer::DeviceInfo>( |
| guid, name, "chrome_version", "user_agent", device_type, os_type, |
| form_factor, "device_id", manufacturer_name, model_name, |
| full_hardware_class, last_updated_timestamp, |
| syncer::DeviceInfoUtil::GetPulseInterval(), |
| /*send_tab_to_self_receiving_enabled=*/ |
| false, |
| sync_pb:: |
| SyncEnums_SendTabReceivingType_SEND_TAB_RECEIVING_TYPE_CHROME_OR_UNSPECIFIED, |
| sharing_info, |
| /*paask_info=*/std::nullopt, |
| /*fcm_registration_token=*/std::string(), |
| /*interested_data_types=*/syncer::DataTypeSet(), |
| /*auto_sign_out_last_signin_timestamp=*/std::nullopt, |
| /*desktop_to_ios_promo_receiving_enabled=*/false); |
| } |
| |
| // Helper for configuring a TimestampedPrefValue. |
| void ConfigureTimestampedPrefValue( |
| sync_preferences::TimestampedPrefValue& timestamped_value, |
| base::Value value, |
| std::string device_sync_cache_guid, |
| base::Time last_observed_change_time = base::Time::Now()) { |
| timestamped_value.value = value.Clone(); |
| timestamped_value.last_observed_change_time = last_observed_change_time; |
| timestamped_value.device_sync_cache_guid = device_sync_cache_guid; |
| } |
| |
| protected: |
| base::test::TaskEnvironment task_environment_; |
| TestCrossDevicePrefTracker pref_tracker_; |
| syncer::FakeDeviceInfoTracker device_info_tracker_; |
| }; |
| |
| namespace sync_preferences { |
| |
| // Test that a device with a matching form factor is chosen as the best fit |
| // device. |
| TEST_F(SyncedSetUpUtilsTest, TestMatchPrefsByFormFactor) { |
| // Local device (iOS phone). |
| std::unique_ptr<syncer::DeviceInfo> local_device = CreateDeviceInfoForTesting( |
| "local_device", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| // Android tablet. |
| std::unique_ptr<syncer::DeviceInfo> android_tablet = |
| CreateDeviceInfoForTesting("android_tablet", |
| syncer::DeviceInfo::FormFactor::kTablet, |
| syncer::DeviceInfo::OsType::kAndroid); |
| |
| // Android phone (match). |
| std::unique_ptr<syncer::DeviceInfo> android_phone = |
| CreateDeviceInfoForTesting("android_phone", |
| syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kAndroid); |
| |
| // iOS tablet. |
| std::unique_ptr<syncer::DeviceInfo> ios_tablet = CreateDeviceInfoForTesting( |
| "ios_tablet", syncer::DeviceInfo::FormFactor::kTablet, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| device_info_tracker_.Add(local_device.get()); |
| device_info_tracker_.SetLocalCacheGuid(local_device.get()->guid()); |
| device_info_tracker_.Add(android_tablet.get()); |
| device_info_tracker_.Add(android_phone.get()); |
| device_info_tracker_.Add(ios_tablet.get()); |
| |
| // Configure some `TimestampedPrefValue` objects associated with the tracked |
| // device GUID's and add them to the pref tracker. |
| TimestampedPrefValue local_device_magic_stack_enabled; |
| ConfigureTimestampedPrefValue(local_device_magic_stack_enabled, |
| base::Value(true), local_device.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| local_device_magic_stack_enabled); |
| |
| TimestampedPrefValue android_tablet_magic_stack_enabled; |
| TimestampedPrefValue android_tablet_most_visited_enabled; |
| ConfigureTimestampedPrefValue(android_tablet_magic_stack_enabled, |
| base::Value(true), |
| android_tablet.get()->guid()); |
| ConfigureTimestampedPrefValue(android_tablet_most_visited_enabled, |
| base::Value(false), |
| android_tablet.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| android_tablet_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| android_tablet_most_visited_enabled); |
| |
| TimestampedPrefValue android_phone_magic_stack_enabled; |
| TimestampedPrefValue android_phone_most_visited_enabled; |
| ConfigureTimestampedPrefValue(android_phone_magic_stack_enabled, |
| base::Value(false), |
| android_phone.get()->guid()); |
| ConfigureTimestampedPrefValue(android_phone_most_visited_enabled, |
| base::Value(true), android_phone.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| android_phone_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| android_phone_most_visited_enabled); |
| |
| TimestampedPrefValue ios_tablet_magic_stack_enabled; |
| TimestampedPrefValue ios_tablet_most_visited_enabled; |
| ConfigureTimestampedPrefValue(ios_tablet_magic_stack_enabled, |
| base::Value(false), ios_tablet.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_tablet_most_visited_enabled, |
| base::Value(false), ios_tablet.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_tablet_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_tablet_most_visited_enabled); |
| |
| // Expect that the prefs from the Android phone are returned. |
| std::map<std::string_view, base::Value> expected_result; |
| expected_result.insert({prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| android_phone_magic_stack_enabled.value.Clone()}); |
| expected_result.insert({prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| android_phone_most_visited_enabled.value.Clone()}); |
| |
| std::map<std::string_view, base::Value> result = |
| synced_set_up::GetCrossDevicePrefsFromRemoteDevice( |
| &pref_tracker_, &device_info_tracker_, local_device.get()); |
| ASSERT_TRUE(!result.empty()); |
| ASSERT_EQ(result.size(), expected_result.size()); |
| |
| // Compare the resultant map to the expected map. |
| for (const auto& [pref_name, pref_value] : expected_result) { |
| auto it = result.find(pref_name); |
| ASSERT_NE(it, result.end()); |
| EXPECT_EQ(it->second, pref_value); |
| } |
| } |
| |
| // Test that a device with a matching OS is chosen as the best fit device if |
| // there is no device with a matching form factor. |
| TEST_F(SyncedSetUpUtilsTest, TestMatchPrefsByOsType) { |
| // Local device (iOS phone). |
| std::unique_ptr<syncer::DeviceInfo> local_device = CreateDeviceInfoForTesting( |
| "local_device", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| // Android tablet. |
| std::unique_ptr<syncer::DeviceInfo> android_tablet = |
| CreateDeviceInfoForTesting("android_tablet", |
| syncer::DeviceInfo::FormFactor::kTablet, |
| syncer::DeviceInfo::OsType::kAndroid); |
| |
| // iOS tablet (match). |
| std::unique_ptr<syncer::DeviceInfo> ios_tablet = CreateDeviceInfoForTesting( |
| "ios_tablet", syncer::DeviceInfo::FormFactor::kTablet, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| device_info_tracker_.Add(local_device.get()); |
| device_info_tracker_.SetLocalCacheGuid(local_device.get()->guid()); |
| device_info_tracker_.Add(android_tablet.get()); |
| device_info_tracker_.Add(ios_tablet.get()); |
| |
| // Configure some `TimestampedPrefValue` objects associated with the tracked |
| // device GUID's and add them to the pref tracker. |
| TimestampedPrefValue local_device_magic_stack_enabled; |
| ConfigureTimestampedPrefValue(local_device_magic_stack_enabled, |
| base::Value(true), local_device.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| local_device_magic_stack_enabled); |
| |
| TimestampedPrefValue android_tablet_magic_stack_enabled; |
| TimestampedPrefValue android_tablet_most_visited_enabled; |
| ConfigureTimestampedPrefValue(android_tablet_magic_stack_enabled, |
| base::Value(true), |
| android_tablet.get()->guid()); |
| ConfigureTimestampedPrefValue(android_tablet_most_visited_enabled, |
| base::Value(false), |
| android_tablet.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| android_tablet_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| android_tablet_most_visited_enabled); |
| |
| TimestampedPrefValue ios_tablet_magic_stack_enabled; |
| TimestampedPrefValue ios_tablet_most_visited_enabled; |
| ConfigureTimestampedPrefValue(ios_tablet_magic_stack_enabled, |
| base::Value(false), ios_tablet.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_tablet_most_visited_enabled, |
| base::Value(false), ios_tablet.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_tablet_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_tablet_most_visited_enabled); |
| |
| // Expect that the prefs from the iOS tablet are returned. |
| std::map<std::string_view, base::Value> expected_result; |
| expected_result.insert({prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_tablet_magic_stack_enabled.value.Clone()}); |
| expected_result.insert({prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_tablet_most_visited_enabled.value.Clone()}); |
| |
| std::map<std::string_view, base::Value> result = |
| synced_set_up::GetCrossDevicePrefsFromRemoteDevice( |
| &pref_tracker_, &device_info_tracker_, local_device.get()); |
| ASSERT_TRUE(!result.empty()); |
| ASSERT_EQ(result.size(), expected_result.size()); |
| |
| // compare the returned map to the expected map |
| for (const auto& [pref_name, pref_value] : expected_result) { |
| auto it = result.find(pref_name); |
| ASSERT_NE(it, result.end()); |
| EXPECT_EQ(it->second, pref_value); |
| } |
| } |
| |
| // Test that a device with the highest volume of observed pref changes is chosen |
| // as the best fit device if the synced devices score the same against the |
| // current device on form factor and OS. |
| TEST_F(SyncedSetUpUtilsTest, TestMatchPrefsByObservedChangeCount) { |
| // Local device (iOS phone). |
| std::unique_ptr<syncer::DeviceInfo> local_device = CreateDeviceInfoForTesting( |
| "local_device", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| // Android phone. |
| std::unique_ptr<syncer::DeviceInfo> android_phone = |
| CreateDeviceInfoForTesting("android_phone", |
| syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kAndroid); |
| |
| // iOS phone. |
| std::unique_ptr<syncer::DeviceInfo> ios_phone = CreateDeviceInfoForTesting( |
| "ios_phone", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| // iOS phone (match). |
| std::unique_ptr<syncer::DeviceInfo> ios_phone_2 = CreateDeviceInfoForTesting( |
| "ios_phone_2", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| device_info_tracker_.Add(local_device.get()); |
| device_info_tracker_.SetLocalCacheGuid(local_device.get()->guid()); |
| device_info_tracker_.Add(android_phone.get()); |
| device_info_tracker_.Add(ios_phone.get()); |
| device_info_tracker_.Add(ios_phone_2.get()); |
| |
| // Configure some `TimestampedPrefValue` objects associated with the tracked |
| // device GUID's and add them to the pref tracker. |
| TimestampedPrefValue local_device_magic_stack_enabled; |
| ConfigureTimestampedPrefValue(local_device_magic_stack_enabled, |
| base::Value(true), local_device.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| local_device_magic_stack_enabled); |
| |
| TimestampedPrefValue android_phone_magic_stack_enabled; |
| TimestampedPrefValue android_phone_most_visited_enabled; |
| ConfigureTimestampedPrefValue(android_phone_magic_stack_enabled, |
| base::Value(true), android_phone.get()->guid()); |
| ConfigureTimestampedPrefValue(android_phone_most_visited_enabled, |
| base::Value(false), |
| android_phone.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| android_phone_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| android_phone_most_visited_enabled); |
| |
| TimestampedPrefValue ios_phone_1_magic_stack_enabled; |
| TimestampedPrefValue ios_phone_1_most_visited_enabled; |
| ConfigureTimestampedPrefValue(ios_phone_1_magic_stack_enabled, |
| base::Value(false), ios_phone.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_phone_1_most_visited_enabled, |
| base::Value(false), ios_phone.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_phone_1_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_phone_1_most_visited_enabled); |
| |
| TimestampedPrefValue ios_phone_2_magic_stack_enabled; |
| TimestampedPrefValue ios_phone_2_most_visited_enabled; |
| TimestampedPrefValue ios_phone_2_price_tracking_enabled; |
| ConfigureTimestampedPrefValue(ios_phone_2_magic_stack_enabled, |
| base::Value(true), ios_phone_2.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_phone_2_most_visited_enabled, |
| base::Value(true), ios_phone_2.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_phone_2_price_tracking_enabled, |
| base::Value(true), ios_phone_2.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_phone_2_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_phone_2_most_visited_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDevicePriceTrackingHomeModuleEnabled, |
| ios_phone_2_price_tracking_enabled); |
| |
| // Expect that the prefs from the second iOS phone with more changes are |
| // returned. |
| std::map<std::string_view, base::Value> expected_result; |
| expected_result.insert({prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_phone_2_magic_stack_enabled.value.Clone()}); |
| expected_result.insert({prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_phone_2_most_visited_enabled.value.Clone()}); |
| expected_result.insert({prefs::kCrossDevicePriceTrackingHomeModuleEnabled, |
| ios_phone_2_price_tracking_enabled.value.Clone()}); |
| |
| std::map<std::string_view, base::Value> result = |
| synced_set_up::GetCrossDevicePrefsFromRemoteDevice( |
| &pref_tracker_, &device_info_tracker_, local_device.get()); |
| ASSERT_TRUE(!result.empty()); |
| ASSERT_EQ(result.size(), expected_result.size()); |
| |
| // Compare the resultant map to the expected map. |
| for (const auto& [pref_name, pref_value] : expected_result) { |
| auto it = result.find(pref_name); |
| ASSERT_NE(it, result.end()); |
| EXPECT_EQ(it->second, pref_value); |
| } |
| } |
| |
| // Tests that no new prefs to apply are returned if the local device has a |
| // higher volume of observed pref changes than the otherwise best fitting |
| // device. |
| TEST_F(SyncedSetUpUtilsTest, TestKeepLocalPrefsByChangeActivity) { |
| // Local device (iOS phone). |
| std::unique_ptr<syncer::DeviceInfo> local_device = CreateDeviceInfoForTesting( |
| "local_device", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| // Android phone. |
| std::unique_ptr<syncer::DeviceInfo> android_phone = |
| CreateDeviceInfoForTesting("android_phone", |
| syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kAndroid); |
| |
| // iOS phone. |
| std::unique_ptr<syncer::DeviceInfo> ios_phone = CreateDeviceInfoForTesting( |
| "ios_phone", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| // iOS phone (match). |
| std::unique_ptr<syncer::DeviceInfo> ios_phone_2 = CreateDeviceInfoForTesting( |
| "ios_phone_2", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| device_info_tracker_.Add(local_device.get()); |
| device_info_tracker_.SetLocalCacheGuid(local_device.get()->guid()); |
| device_info_tracker_.Add(android_phone.get()); |
| device_info_tracker_.Add(ios_phone.get()); |
| device_info_tracker_.Add(ios_phone_2.get()); |
| |
| // Configure some `TimestampedPrefValue` objects associated with the tracked |
| // device GUID's and add them to the pref tracker. |
| TimestampedPrefValue local_device_magic_stack_enabled; |
| TimestampedPrefValue local_device_most_visited_enabled; |
| TimestampedPrefValue local_device_price_tracking_enabled; |
| TimestampedPrefValue local_device_safety_check_enabled; |
| ConfigureTimestampedPrefValue(local_device_magic_stack_enabled, |
| base::Value(true), local_device.get()->guid()); |
| ConfigureTimestampedPrefValue(local_device_most_visited_enabled, |
| base::Value(true), local_device.get()->guid()); |
| ConfigureTimestampedPrefValue(local_device_price_tracking_enabled, |
| base::Value(true), local_device.get()->guid()); |
| ConfigureTimestampedPrefValue(local_device_safety_check_enabled, |
| base::Value(true), local_device.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| local_device_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| local_device_most_visited_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDevicePriceTrackingHomeModuleEnabled, |
| local_device_price_tracking_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceSafetyCheckHomeModuleEnabled, |
| local_device_safety_check_enabled); |
| |
| TimestampedPrefValue android_phone_magic_stack_enabled; |
| TimestampedPrefValue android_phone_most_visited_enabled; |
| ConfigureTimestampedPrefValue(android_phone_magic_stack_enabled, |
| base::Value(true), android_phone.get()->guid()); |
| ConfigureTimestampedPrefValue(android_phone_most_visited_enabled, |
| base::Value(false), |
| android_phone.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| android_phone_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| android_phone_most_visited_enabled); |
| |
| TimestampedPrefValue ios_phone_1_magic_stack_enabled; |
| TimestampedPrefValue ios_phone_1_most_visited_enabled; |
| ConfigureTimestampedPrefValue(ios_phone_1_magic_stack_enabled, |
| base::Value(false), ios_phone.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_phone_1_most_visited_enabled, |
| base::Value(false), ios_phone.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_phone_1_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_phone_1_most_visited_enabled); |
| |
| TimestampedPrefValue ios_phone_2_magic_stack_enabled; |
| TimestampedPrefValue ios_phone_2_most_visited_enabled; |
| TimestampedPrefValue ios_phone_2_price_tracking_enabled; |
| ConfigureTimestampedPrefValue(ios_phone_2_magic_stack_enabled, |
| base::Value(true), ios_phone_2.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_phone_2_most_visited_enabled, |
| base::Value(true), ios_phone_2.get()->guid()); |
| ConfigureTimestampedPrefValue(ios_phone_2_price_tracking_enabled, |
| base::Value(true), ios_phone_2.get()->guid()); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| ios_phone_2_magic_stack_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMostVisitedHomeModuleEnabled, |
| ios_phone_2_most_visited_enabled); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDevicePriceTrackingHomeModuleEnabled, |
| ios_phone_2_price_tracking_enabled); |
| |
| // Expect that no new prefs are returned. |
| std::map<std::string_view, base::Value> result = |
| synced_set_up::GetCrossDevicePrefsFromRemoteDevice( |
| &pref_tracker_, &device_info_tracker_, local_device.get()); |
| EXPECT_TRUE(result.empty()); |
| } |
| |
| // Tests that if a pref has multiple observed changes only the most recently |
| // observed pref change is retrieved. |
| TEST_F(SyncedSetUpUtilsTest, TestReturnsMostRecentObservedPrefChanges) { |
| const base::Time kNow = base::Time::Now(); |
| |
| // Local device (iOS phone). |
| std::unique_ptr<syncer::DeviceInfo> local_device = CreateDeviceInfoForTesting( |
| "local_device", syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kIOS); |
| |
| // Android phone (match). |
| std::unique_ptr<syncer::DeviceInfo> android_phone = |
| CreateDeviceInfoForTesting("android_phone", |
| syncer::DeviceInfo::FormFactor::kPhone, |
| syncer::DeviceInfo::OsType::kAndroid); |
| |
| device_info_tracker_.Add(local_device.get()); |
| device_info_tracker_.SetLocalCacheGuid(local_device.get()->guid()); |
| device_info_tracker_.Add(android_phone.get()); |
| |
| // Configure some `TimestampedPrefValue` objects for the same pref associated |
| // with the Android phone GUID's and add them to the pref tracker. These |
| // represent the same pref being changed several times over a period of time. |
| TimestampedPrefValue magic_stack_enabled_day; |
| TimestampedPrefValue magic_stack_enabled_now; |
| TimestampedPrefValue magic_stack_enabled_week; |
| ConfigureTimestampedPrefValue(magic_stack_enabled_day, base::Value(true), |
| android_phone.get()->guid(), |
| kNow - base::Days(1)); |
| ConfigureTimestampedPrefValue(magic_stack_enabled_now, base::Value(false), |
| android_phone.get()->guid(), kNow); |
| ConfigureTimestampedPrefValue(magic_stack_enabled_week, base::Value(true), |
| android_phone.get()->guid(), |
| kNow - base::Days(7)); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, magic_stack_enabled_day); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, magic_stack_enabled_now); |
| pref_tracker_.AddSyncedPrefValue( |
| prefs::kCrossDeviceMagicStackHomeModuleEnabled, magic_stack_enabled_week); |
| |
| // Expect that the pref is returned with its most recently set value. |
| std::map<std::string_view, base::Value> expected_result; |
| expected_result.insert({prefs::kCrossDeviceMagicStackHomeModuleEnabled, |
| magic_stack_enabled_now.value.Clone()}); |
| |
| std::map<std::string_view, base::Value> result = |
| synced_set_up::GetCrossDevicePrefsFromRemoteDevice( |
| &pref_tracker_, &device_info_tracker_, local_device.get()); |
| ASSERT_TRUE(!result.empty()); |
| ASSERT_EQ(result.size(), expected_result.size()); |
| |
| // Compare the resultant map to the expected map. |
| for (const auto& [pref_name, pref_value] : expected_result) { |
| auto it = result.find(pref_name); |
| ASSERT_NE(it, result.end()); |
| EXPECT_EQ(it->second, pref_value); |
| } |
| } |
| |
| } // namespace sync_preferences |