1 // Copyright 2020 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 "base/test/scoped_feature_list.h"
6 #include "chrome/browser/sync/sync_invalidations_service_factory.h"
7 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
8 #include "chrome/browser/sync/test/integration/device_info_helper.h"
9 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
10 #include "chrome/browser/sync/test/integration/sync_test.h"
11 #include "components/bookmarks/browser/bookmark_model.h"
12 #include "components/sync/base/model_type.h"
13 #include "components/sync/invalidations/switches.h"
14 #include "components/sync/invalidations/sync_invalidations_service.h"
15 #include "components/sync/protocol/sync.pb.h"
16 #include "components/sync/test/fake_server/bookmark_entity_builder.h"
17 #include "components/sync/test/fake_server/entity_builder_factory.h"
18 #include "content/public/test/browser_test.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 namespace {
23 
24 using testing::AllOf;
25 using testing::ElementsAre;
26 using testing::Not;
27 using testing::NotNull;
28 using testing::UnorderedElementsAre;
29 
30 const char kSyncedBookmarkURL[] = "http://www.mybookmark.com";
31 
32 MATCHER_P(InterestedDataTypesAre, expected_data_types, "") {
33   syncer::ModelTypeSet data_types;
34   for (const int field_number : arg.specifics()
35                                     .device_info()
36                                     .invalidation_fields()
37                                     .interested_data_type_ids()) {
38     syncer::ModelType data_type =
39         syncer::GetModelTypeFromSpecificsFieldNumber(field_number);
40     if (!syncer::IsRealDataType(data_type)) {
41       return false;
42     }
43     data_types.Put(data_type);
44   }
45   return data_types == expected_data_types;
46 }
47 
48 MATCHER_P(InterestedDataTypesContain, expected_data_types, "") {
49   syncer::ModelTypeSet data_types;
50   for (const int field_number : arg.specifics()
51                                     .device_info()
52                                     .invalidation_fields()
53                                     .interested_data_type_ids()) {
54     syncer::ModelType data_type =
55         syncer::GetModelTypeFromSpecificsFieldNumber(field_number);
56     if (!syncer::IsRealDataType(data_type)) {
57       return false;
58     }
59     data_types.Put(data_type);
60   }
61   return data_types.HasAll(expected_data_types);
62 }
63 
64 MATCHER(HasInstanceIdToken, "") {
65   return arg.specifics()
66       .device_info()
67       .invalidation_fields()
68       .has_instance_id_token();
69 }
70 
71 MATCHER_P(HasInstanceIdToken, expected_token, "") {
72   return arg.specifics()
73              .device_info()
74              .invalidation_fields()
75              .instance_id_token() == expected_token;
76 }
77 
78 class SingleClientWithSyncSendInterestedDataTypesTest : public SyncTest {
79  public:
SingleClientWithSyncSendInterestedDataTypesTest()80   SingleClientWithSyncSendInterestedDataTypesTest() : SyncTest(SINGLE_CLIENT) {
81     override_features_.InitWithFeatures(
82         /*enabled_features=*/{switches::kSyncSendInterestedDataTypes},
83         /*disabled_features=*/{
84             switches::kUseSyncInvalidations,
85             switches::kUseSyncInvalidationsForWalletAndOffer});
86   }
87   ~SingleClientWithSyncSendInterestedDataTypesTest() override = default;
88 
89  private:
90   base::test::ScopedFeatureList override_features_;
91 
92   DISALLOW_COPY_AND_ASSIGN(SingleClientWithSyncSendInterestedDataTypesTest);
93 };
94 
IN_PROC_BROWSER_TEST_F(SingleClientWithSyncSendInterestedDataTypesTest,SendInterestedDataTypesAsPartOfDeviceInfo)95 IN_PROC_BROWSER_TEST_F(SingleClientWithSyncSendInterestedDataTypesTest,
96                        SendInterestedDataTypesAsPartOfDeviceInfo) {
97   ASSERT_TRUE(SetupSync());
98 
99   syncer::SyncInvalidationsService* sync_invalidations_service =
100       SyncInvalidationsServiceFactory::GetForProfile(GetProfile(0));
101   ASSERT_THAT(sync_invalidations_service, NotNull());
102   syncer::ModelTypeSet interested_data_types =
103       sync_invalidations_service->GetInterestedDataTypes();
104 
105   // Check that some "standard" data types are included.
106   EXPECT_TRUE(
107       interested_data_types.HasAll({syncer::NIGORI, syncer::BOOKMARKS}));
108   // Wallet and Offer data types are excluded unless
109   // kUseSyncInvalidationsForWalletAndOffer is also enabled.
110   EXPECT_FALSE(interested_data_types.Has(syncer::AUTOFILL_WALLET_DATA));
111   EXPECT_FALSE(interested_data_types.Has(syncer::AUTOFILL_WALLET_OFFER));
112 
113   // The local device should eventually be committed to the server.
114   // The InstanceID token should only be uploaded if kUseSyncInvalidations is
115   // also enabled.
116   EXPECT_TRUE(
117       ServerDeviceInfoMatchChecker(
118           GetFakeServer(),
119           ElementsAre(AllOf(InterestedDataTypesAre(interested_data_types),
120                             Not(HasInstanceIdToken()))))
121           .Wait());
122 }
123 
124 class SingleClientWithUseSyncInvalidationsTest : public SyncTest {
125  public:
SingleClientWithUseSyncInvalidationsTest()126   SingleClientWithUseSyncInvalidationsTest() : SyncTest(SINGLE_CLIENT) {
127     override_features_.InitWithFeatures(
128         /*enabled_features=*/{switches::kSyncSendInterestedDataTypes,
129                               switches::kUseSyncInvalidations},
130         /*disabled_features=*/{
131             switches::kUseSyncInvalidationsForWalletAndOffer});
132   }
133   ~SingleClientWithUseSyncInvalidationsTest() override = default;
134 
135  private:
136   base::test::ScopedFeatureList override_features_;
137 
138   DISALLOW_COPY_AND_ASSIGN(SingleClientWithUseSyncInvalidationsTest);
139 };
140 
IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsTest,SendInterestedDataTypesAndFCMTokenAsPartOfDeviceInfo)141 IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsTest,
142                        SendInterestedDataTypesAndFCMTokenAsPartOfDeviceInfo) {
143   ASSERT_TRUE(SetupSync());
144 
145   syncer::SyncInvalidationsService* sync_invalidations_service =
146       SyncInvalidationsServiceFactory::GetForProfile(GetProfile(0));
147   ASSERT_THAT(sync_invalidations_service, NotNull());
148   syncer::ModelTypeSet interested_data_types =
149       sync_invalidations_service->GetInterestedDataTypes();
150   std::string fcm_token = sync_invalidations_service->GetFCMRegistrationToken();
151 
152   // Check that some "standard" data types are included.
153   EXPECT_TRUE(
154       interested_data_types.HasAll({syncer::NIGORI, syncer::BOOKMARKS}));
155   // Wallet and Offer data types are excluded unless
156   // kUseSyncInvalidationsForWalletAndOffer is also enabled.
157   EXPECT_FALSE(interested_data_types.Has(syncer::AUTOFILL_WALLET_DATA));
158   EXPECT_FALSE(interested_data_types.Has(syncer::AUTOFILL_WALLET_OFFER));
159   EXPECT_FALSE(fcm_token.empty());
160 
161   // The local device should eventually be committed to the server.
162   EXPECT_TRUE(
163       ServerDeviceInfoMatchChecker(
164           GetFakeServer(),
165           ElementsAre(AllOf(InterestedDataTypesAre(interested_data_types),
166                             HasInstanceIdToken(fcm_token))))
167           .Wait());
168 }
169 
170 class SingleClientWithUseSyncInvalidationsForWalletAndOfferTest
171     : public SyncTest {
172  public:
SingleClientWithUseSyncInvalidationsForWalletAndOfferTest()173   SingleClientWithUseSyncInvalidationsForWalletAndOfferTest()
174       : SyncTest(SINGLE_CLIENT) {
175     override_features_.InitWithFeatures(
176         /*enabled_features=*/{switches::kSyncSendInterestedDataTypes,
177                               switches::kUseSyncInvalidations,
178                               switches::kUseSyncInvalidationsForWalletAndOffer},
179         /*disabled_features=*/{});
180   }
181   ~SingleClientWithUseSyncInvalidationsForWalletAndOfferTest() override =
182       default;
183 
InjectSyncedBookmark()184   void InjectSyncedBookmark() {
185     fake_server::BookmarkEntityBuilder bookmark_builder =
186         entity_builder_factory_.NewBookmarkEntityBuilder("My Bookmark");
187     GetFakeServer()->InjectEntity(
188         bookmark_builder.BuildBookmark(GURL(kSyncedBookmarkURL)));
189   }
190 
191  private:
192   base::test::ScopedFeatureList override_features_;
193   fake_server::EntityBuilderFactory entity_builder_factory_;
194 
195   DISALLOW_COPY_AND_ASSIGN(
196       SingleClientWithUseSyncInvalidationsForWalletAndOfferTest);
197 };
198 
IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsForWalletAndOfferTest,SendInterestedDataTypesAndFCMTokenAsPartOfDeviceInfo)199 IN_PROC_BROWSER_TEST_F(
200     SingleClientWithUseSyncInvalidationsForWalletAndOfferTest,
201     SendInterestedDataTypesAndFCMTokenAsPartOfDeviceInfo) {
202   ASSERT_TRUE(SetupSync());
203 
204   syncer::SyncInvalidationsService* sync_invalidations_service =
205       SyncInvalidationsServiceFactory::GetForProfile(GetProfile(0));
206   ASSERT_THAT(sync_invalidations_service, NotNull());
207   syncer::ModelTypeSet interested_data_types =
208       sync_invalidations_service->GetInterestedDataTypes();
209   std::string fcm_token = sync_invalidations_service->GetFCMRegistrationToken();
210 
211   // Check that some "standard" data types are included.
212   EXPECT_TRUE(
213       interested_data_types.HasAll({syncer::NIGORI, syncer::BOOKMARKS}));
214   // Wallet data type should be included by default if
215   // kUseSyncInvalidationsForWalletAndOffer is enabled.
216   EXPECT_TRUE(interested_data_types.Has(syncer::AUTOFILL_WALLET_DATA));
217   EXPECT_FALSE(fcm_token.empty());
218 
219   // The local device should eventually be committed to the server.
220   EXPECT_TRUE(
221       ServerDeviceInfoMatchChecker(
222           GetFakeServer(),
223           ElementsAre(AllOf(InterestedDataTypesAre(interested_data_types),
224                             HasInstanceIdToken(fcm_token))))
225           .Wait());
226 }
227 
IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsForWalletAndOfferTest,EnableAndDisableADataType)228 IN_PROC_BROWSER_TEST_F(
229     SingleClientWithUseSyncInvalidationsForWalletAndOfferTest,
230     EnableAndDisableADataType) {
231   ASSERT_TRUE(SetupSync());
232 
233   // The local device should eventually be committed to the server. BOOKMARKS
234   // should be included in interested types, since it's enabled by default.
235   EXPECT_TRUE(ServerDeviceInfoMatchChecker(
236                   GetFakeServer(),
237                   ElementsAre(InterestedDataTypesContain(syncer::BOOKMARKS)))
238                   .Wait());
239 
240   // Disable BOOKMARKS.
241   ASSERT_TRUE(
242       GetClient(0)->DisableSyncForType(syncer::UserSelectableType::kBookmarks));
243   // The local device should eventually be committed to the server. BOOKMARKS
244   // should not be included in interested types, as it was disabled.
245   EXPECT_TRUE(
246       ServerDeviceInfoMatchChecker(
247           GetFakeServer(),
248           ElementsAre(Not(InterestedDataTypesContain(syncer::BOOKMARKS))))
249           .Wait());
250 
251   // Create a bookmark on the server.
252   InjectSyncedBookmark();
253   // Enable BOOKMARKS again.
254   ASSERT_TRUE(
255       GetClient(0)->EnableSyncForType(syncer::UserSelectableType::kBookmarks));
256   // The local device should eventually be committed to the server. BOOKMARKS
257   // should now be included in interested types.
258   EXPECT_TRUE(ServerDeviceInfoMatchChecker(
259                   GetFakeServer(),
260                   ElementsAre(InterestedDataTypesContain(syncer::BOOKMARKS)))
261                   .Wait());
262   // The bookmark should get synced now.
263   EXPECT_TRUE(bookmarks_helper::GetBookmarkModel(0)->IsBookmarked(
264       GURL(kSyncedBookmarkURL)));
265 }
266 
267 // ChromeOS doesn't have the concept of sign-out.
268 #if !defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsForWalletAndOfferTest,SignoutAndSignin)269 IN_PROC_BROWSER_TEST_F(
270     SingleClientWithUseSyncInvalidationsForWalletAndOfferTest,
271     SignoutAndSignin) {
272   ASSERT_TRUE(SetupSync());
273 
274   // The local device should eventually be committed to the server. The FCM
275   // token should be present in device info.
276   std::string old_token =
277       SyncInvalidationsServiceFactory::GetForProfile(GetProfile(0))
278           ->GetFCMRegistrationToken();
279   EXPECT_TRUE(ServerDeviceInfoMatchChecker(
280                   GetFakeServer(), ElementsAre(HasInstanceIdToken(old_token)))
281                   .Wait());
282 
283   // Sign out. The FCM token should be cleared.
284   GetClient(0)->SignOutPrimaryAccount();
285   EXPECT_TRUE(SyncInvalidationsServiceFactory::GetForProfile(GetProfile(0))
286                   ->GetFCMRegistrationToken()
287                   .empty());
288 
289   // Sign in again.
290   ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
291   std::string new_token =
292       SyncInvalidationsServiceFactory::GetForProfile(GetProfile(0))
293           ->GetFCMRegistrationToken();
294   EXPECT_NE(new_token, old_token);
295   EXPECT_FALSE(new_token.empty());
296   // New device info should eventually be committed to the server (but the old
297   // device info will remain on the server). The FCM token should be present.
298   EXPECT_TRUE(ServerDeviceInfoMatchChecker(
299                   GetFakeServer(), UnorderedElementsAre(HasInstanceIdToken(old_token),
300                                                         HasInstanceIdToken(new_token)))
301                   .Wait());
302 }
303 #endif  // !OS_CHROMEOS
304 
305 }  // namespace
306