1 // Copyright 2012 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 <memory>
6 #include <vector>
7 
8 #include "base/compiler_specific.h"
9 #include "base/containers/circular_deque.h"
10 #include "base/macros.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
13 #include "chrome/browser/sync/test/integration/migration_waiter.h"
14 #include "chrome/browser/sync/test/integration/migration_watcher.h"
15 #include "chrome/browser/sync/test/integration/preferences_helper.h"
16 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
17 #include "chrome/browser/sync/test/integration/sync_test.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/prefs/scoped_user_pref_update.h"
20 #include "components/sync/driver/profile_sync_service.h"
21 #include "components/translate/core/browser/translate_prefs.h"
22 #include "content/public/test/browser_test.h"
23 
24 using bookmarks_helper::AddURL;
25 using bookmarks_helper::IndexedURL;
26 using bookmarks_helper::IndexedURLTitle;
27 
28 using preferences_helper::BooleanPrefMatches;
29 using preferences_helper::ChangeBooleanPref;
30 
31 namespace {
32 
33 // Utility functions to make a model type set out of a small number of
34 // model types.
35 
MakeSet(syncer::ModelType type)36 syncer::ModelTypeSet MakeSet(syncer::ModelType type) {
37   return syncer::ModelTypeSet(type);
38 }
39 
MakeSet(syncer::ModelType type1,syncer::ModelType type2)40 syncer::ModelTypeSet MakeSet(syncer::ModelType type1,
41                              syncer::ModelType type2) {
42   return syncer::ModelTypeSet(type1, type2);
43 }
44 
45 // An ordered list of model types sets to migrate.  Used by
46 // RunMigrationTest().
47 using MigrationList = base::circular_deque<syncer::ModelTypeSet>;
48 
49 // Utility functions to make a MigrationList out of a small number of
50 // model types / model type sets.
51 
MakeList(syncer::ModelTypeSet model_types)52 MigrationList MakeList(syncer::ModelTypeSet model_types) {
53   return MigrationList(1, model_types);
54 }
55 
MakeList(syncer::ModelTypeSet model_types1,syncer::ModelTypeSet model_types2)56 MigrationList MakeList(syncer::ModelTypeSet model_types1,
57                        syncer::ModelTypeSet model_types2) {
58   MigrationList migration_list;
59   migration_list.push_back(model_types1);
60   migration_list.push_back(model_types2);
61   return migration_list;
62 }
63 
MakeList(syncer::ModelType type)64 MigrationList MakeList(syncer::ModelType type) {
65   return MakeList(MakeSet(type));
66 }
67 
MakeList(syncer::ModelType type1,syncer::ModelType type2)68 MigrationList MakeList(syncer::ModelType type1,
69                        syncer::ModelType type2) {
70   return MakeList(MakeSet(type1), MakeSet(type2));
71 }
72 
73 class MigrationTest : public SyncTest  {
74  public:
MigrationTest(TestType test_type)75   explicit MigrationTest(TestType test_type) : SyncTest(test_type) {}
~MigrationTest()76   ~MigrationTest() override {}
77 
78   enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_REFRESH };
79 
80   // Set up sync for all profiles and initialize all MigrationWatchers. This
81   // helps ensure that all migration events are captured, even if they were to
82   // occur before a test calls AwaitMigration for a specific profile.
SetupSync()83   bool SetupSync() override {
84     if (!SyncTest::SetupSync())
85       return false;
86 
87     for (int i = 0; i < num_clients(); ++i) {
88       migration_watchers_.push_back(
89           std::make_unique<MigrationWatcher>(GetClient(i)));
90     }
91     return true;
92   }
93 
GetPreferredDataTypes()94   syncer::ModelTypeSet GetPreferredDataTypes() {
95     // ProfileSyncService must already have been created before we can call
96     // GetPreferredDataTypes().
97     DCHECK(GetSyncService(0));
98     syncer::ModelTypeSet preferred_data_types =
99         GetSyncService(0)->GetPreferredDataTypes();
100 
101     // Make sure all clients have the same preferred data types.
102     for (int i = 1; i < num_clients(); ++i) {
103       const syncer::ModelTypeSet other_preferred_data_types =
104           GetSyncService(i)->GetPreferredDataTypes();
105       EXPECT_EQ(other_preferred_data_types, preferred_data_types);
106     }
107 
108     preferred_data_types.RemoveAll(syncer::ProxyTypes());
109 
110     // Supervised user data types will be "unready" during this test, so we
111     // should not request that they be migrated.
112     preferred_data_types.Remove(syncer::SUPERVISED_USER_SETTINGS);
113     preferred_data_types.Remove(syncer::SUPERVISED_USER_ALLOWLISTS);
114 
115     // Autofill wallet will be unready during this test, so we should not
116     // request that it be migrated.
117     preferred_data_types.Remove(syncer::AUTOFILL_WALLET_DATA);
118     preferred_data_types.Remove(syncer::AUTOFILL_WALLET_METADATA);
119 
120     // ARC package will be unready during this test, so we should not request
121     // that it be migrated.
122     preferred_data_types.Remove(syncer::ARC_PACKAGE);
123 
124     // Doesn't make sense to migrate commit only types.
125     preferred_data_types.RemoveAll(syncer::CommitOnlyTypes());
126 
127     return preferred_data_types;
128   }
129 
130   // Returns a MigrationList with every enabled data type in its own
131   // set.
GetPreferredDataTypesList()132   MigrationList GetPreferredDataTypesList() {
133     MigrationList migration_list;
134     const syncer::ModelTypeSet preferred_data_types =
135         GetPreferredDataTypes();
136     for (syncer::ModelType type : preferred_data_types) {
137       migration_list.push_back(MakeSet(type));
138     }
139     return migration_list;
140   }
141 
142   // Trigger a migration for the given types with the given method.
TriggerMigration(syncer::ModelTypeSet model_types,TriggerMethod trigger_method)143   void TriggerMigration(syncer::ModelTypeSet model_types,
144                         TriggerMethod trigger_method) {
145     switch (trigger_method) {
146       case MODIFY_PREF:
147         // Unlike MODIFY_BOOKMARK, MODIFY_PREF doesn't cause a
148         // notification to happen (since model association on a
149         // boolean pref clobbers the local value), so it doesn't work
150         // for anything but single-client tests.
151         ASSERT_EQ(1, num_clients());
152         ChangeBooleanPref(0, prefs::kShowHomeButton);
153         break;
154       case MODIFY_BOOKMARK:
155         ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))));
156         break;
157       case TRIGGER_REFRESH:
158         TriggerSyncForModelTypes(/*index=*/0, model_types);
159         break;
160       default:
161         ADD_FAILURE();
162     }
163   }
164 
165   // Block until all clients have completed migration for the given
166   // types.
AwaitMigration(syncer::ModelTypeSet migrate_types)167   void AwaitMigration(syncer::ModelTypeSet migrate_types) {
168     for (int i = 0; i < num_clients(); ++i) {
169       ASSERT_TRUE(
170           MigrationWaiter(migrate_types, migration_watchers_[i].get()).Wait());
171     }
172   }
173 
174   // Makes sure migration works with the given migration list and
175   // trigger method.
RunMigrationTest(const MigrationList & migration_list,TriggerMethod trigger_method)176   void RunMigrationTest(const MigrationList& migration_list,
177                         TriggerMethod trigger_method) {
178     // Make sure migration hasn't been triggered prematurely.
179     for (int i = 0; i < num_clients(); ++i) {
180       ASSERT_TRUE(migration_watchers_[i]->GetMigratedTypes().Empty());
181     }
182 
183     // Phase 1: Trigger the migrations on the server.
184     for (MigrationList::const_iterator it = migration_list.begin();
185          it != migration_list.end(); ++it) {
186       TriggerMigrationDoneError(*it);
187     }
188 
189     // Phase 2: Trigger each migration individually and wait for it to
190     // complete.  (Multiple migrations may be handled by each
191     // migration cycle, but there's no guarantee of that, so we have
192     // to trigger each migration individually.)
193     for (MigrationList::const_iterator it = migration_list.begin();
194          it != migration_list.end(); ++it) {
195       TriggerMigration(*it, trigger_method);
196       AwaitMigration(*it);
197     }
198 
199     // Phase 3: Wait for all clients to catch up.
200     AwaitQuiescence();
201   }
202 
203  private:
204   // Used to keep track of the migration progress for each sync client.
205   std::vector<std::unique_ptr<MigrationWatcher>> migration_watchers_;
206 
207   DISALLOW_COPY_AND_ASSIGN(MigrationTest);
208 };
209 
210 class MigrationSingleClientTest : public MigrationTest {
211  public:
MigrationSingleClientTest()212   MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT) {}
~MigrationSingleClientTest()213   ~MigrationSingleClientTest() override {}
214 
RunSingleClientMigrationTest(const MigrationList & migration_list,TriggerMethod trigger_method)215   void RunSingleClientMigrationTest(const MigrationList& migration_list,
216                                     TriggerMethod trigger_method) {
217     ASSERT_TRUE(SetupSync());
218     RunMigrationTest(migration_list, trigger_method);
219   }
220 
221  private:
222   DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest);
223 };
224 
225 // The simplest possible migration tests -- a single data type.
226 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,PrefsOnlyModifyPref)227 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) {
228   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), MODIFY_PREF);
229 }
230 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,PrefsOnlyModifyBookmark)231 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) {
232   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
233                                MODIFY_BOOKMARK);
234 }
235 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,PrefsOnlyTriggerRefresh)236 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyTriggerRefresh) {
237   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), TRIGGER_REFRESH);
238 }
239 
240 // Nigori is handled specially, so we test that separately.
241 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,NigoriOnly)242 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) {
243   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), TRIGGER_REFRESH);
244 }
245 
246 // A little more complicated -- two data types.
247 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,BookmarksPrefsIndividually)248 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsIndividually) {
249   RunSingleClientMigrationTest(
250       MakeList(syncer::BOOKMARKS, syncer::PREFERENCES),
251       MODIFY_PREF);
252 }
253 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,BookmarksPrefsBoth)254 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) {
255   RunSingleClientMigrationTest(
256       MakeList(MakeSet(syncer::BOOKMARKS, syncer::PREFERENCES)),
257       MODIFY_BOOKMARK);
258 }
259 
260 // Two data types with one being nigori.
261 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,PrefsNigoriIndividiaully)262 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriIndividiaully) {
263   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES, syncer::NIGORI),
264                                TRIGGER_REFRESH);
265 }
266 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,PrefsNigoriBoth)267 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) {
268   RunSingleClientMigrationTest(
269       MakeList(MakeSet(syncer::PREFERENCES, syncer::NIGORI)),
270       MODIFY_PREF);
271 }
272 
273 // The whole shebang -- all data types.
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,AllTypesIndividually)274 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesIndividually) {
275   ASSERT_TRUE(SetupClients());
276   RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK);
277 }
278 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,AllTypesIndividuallyTriggerRefresh)279 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
280                        AllTypesIndividuallyTriggerRefresh) {
281   ASSERT_TRUE(SetupClients());
282   RunSingleClientMigrationTest(GetPreferredDataTypesList(), TRIGGER_REFRESH);
283 }
284 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,AllTypesAtOnce)285 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) {
286   ASSERT_TRUE(SetupClients());
287   RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
288                                MODIFY_PREF);
289 }
290 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,AllTypesAtOnceTriggerRefresh)291 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
292                        AllTypesAtOnceTriggerRefresh) {
293   ASSERT_TRUE(SetupClients());
294   RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
295                                TRIGGER_REFRESH);
296 }
297 
298 // All data types plus nigori.
299 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,AllTypesWithNigoriIndividually)300 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
301                        AllTypesWithNigoriIndividually) {
302   ASSERT_TRUE(SetupClients());
303   MigrationList migration_list = GetPreferredDataTypesList();
304   migration_list.push_front(MakeSet(syncer::NIGORI));
305   RunSingleClientMigrationTest(migration_list, MODIFY_BOOKMARK);
306 }
307 
IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,AllTypesWithNigoriAtOnce)308 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesWithNigoriAtOnce) {
309   ASSERT_TRUE(SetupClients());
310   syncer::ModelTypeSet all_types = GetPreferredDataTypes();
311   all_types.Put(syncer::NIGORI);
312   RunSingleClientMigrationTest(MakeList(all_types), MODIFY_PREF);
313 }
314 
315 class MigrationTwoClientTest : public MigrationTest {
316  public:
MigrationTwoClientTest()317   MigrationTwoClientTest() : MigrationTest(TWO_CLIENT) {}
~MigrationTwoClientTest()318   ~MigrationTwoClientTest() override {}
319 
320   // Helper function that verifies that preferences sync still works.
VerifyPrefSync()321   void VerifyPrefSync() {
322     ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
323     ChangeBooleanPref(0, prefs::kShowHomeButton);
324     ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
325     ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
326   }
327 
RunTwoClientMigrationTest(const MigrationList & migration_list,TriggerMethod trigger_method)328   void RunTwoClientMigrationTest(const MigrationList& migration_list,
329                                  TriggerMethod trigger_method) {
330     ASSERT_TRUE(SetupSync());
331 
332     // Make sure pref sync works before running the migration test.
333     VerifyPrefSync();
334 
335     RunMigrationTest(migration_list, trigger_method);
336 
337     // Make sure pref sync still works after running the migration
338     // test.
339     VerifyPrefSync();
340   }
341 
342  private:
343   DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest);
344 };
345 
346 // Easiest possible test of migration errors: triggers a server
347 // migration on one datatype, then modifies some other datatype.
IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,MigratePrefsThenModifyBookmark)348 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigratePrefsThenModifyBookmark) {
349   RunTwoClientMigrationTest(MakeList(syncer::PREFERENCES),
350                             MODIFY_BOOKMARK);
351 }
352 
353 // Triggers a server migration on two datatypes, then makes a local
354 // modification to one of them.
IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,MigratePrefsAndBookmarksThenModifyBookmark)355 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
356                        MigratePrefsAndBookmarksThenModifyBookmark) {
357   RunTwoClientMigrationTest(
358       MakeList(syncer::PREFERENCES, syncer::BOOKMARKS),
359       MODIFY_BOOKMARK);
360 }
361 
362 // Migrate every datatype in sequence; the catch being that the server
363 // will only tell the client about the migrations one at a time.
IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,MigrationHellWithoutNigori)364 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigrationHellWithoutNigori) {
365   ASSERT_TRUE(SetupClients());
366   MigrationList migration_list = GetPreferredDataTypesList();
367   // Let the first nudge be a datatype that's neither prefs nor bookmarks.
368   migration_list.push_front(MakeSet(syncer::THEMES));
369   ASSERT_EQ(MakeSet(syncer::NIGORI), migration_list.back());
370   migration_list.pop_back();
371   RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
372 }
373 
IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,MigrationHellWithNigori)374 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigrationHellWithNigori) {
375   ASSERT_TRUE(SetupClients());
376   MigrationList migration_list = GetPreferredDataTypesList();
377   // Let the first nudge be a datatype that's neither prefs nor bookmarks.
378   migration_list.push_front(MakeSet(syncer::THEMES));
379   ASSERT_EQ(MakeSet(syncer::NIGORI), migration_list.back());
380   RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
381 }
382 
383 class MigrationReconfigureTest : public MigrationTwoClientTest {
384  public:
MigrationReconfigureTest()385   MigrationReconfigureTest() {}
386 
SetUpCommandLine(base::CommandLine * cl)387   void SetUpCommandLine(base::CommandLine* cl) override {
388     AddTestSwitches(cl);
389     // Do not add optional datatypes.
390   }
391 
~MigrationReconfigureTest()392   ~MigrationReconfigureTest() override {}
393 
394  private:
395   DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest);
396 };
397 
398 }  // namespace
399