Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / test / integration / migration_test.cc
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 "base/compiler_specific.h"
6 #include "base/memory/scoped_vector.h"
7 #include "base/prefs/scoped_user_pref_update.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/sync/backend_migrator.h"
10 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
11 #include "chrome/browser/sync/test/integration/preferences_helper.h"
12 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
13 #include "chrome/browser/sync/test/integration/status_change_checker.h"
14 #include "chrome/browser/sync/test/integration/sync_test.h"
15 #include "chrome/common/pref_names.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "components/translate/core/browser/translate_prefs.h"
18
19 using bookmarks_helper::AddURL;
20 using bookmarks_helper::IndexedURL;
21 using bookmarks_helper::IndexedURLTitle;
22
23 using preferences_helper::BooleanPrefMatches;
24 using preferences_helper::ChangeBooleanPref;
25
26 namespace {
27
28 // Utility functions to make a model type set out of a small number of
29 // model types.
30
31 syncer::ModelTypeSet MakeSet(syncer::ModelType type) {
32   return syncer::ModelTypeSet(type);
33 }
34
35 syncer::ModelTypeSet MakeSet(syncer::ModelType type1,
36                              syncer::ModelType type2) {
37   return syncer::ModelTypeSet(type1, type2);
38 }
39
40 // An ordered list of model types sets to migrate.  Used by
41 // RunMigrationTest().
42 typedef std::deque<syncer::ModelTypeSet> MigrationList;
43
44 // Utility functions to make a MigrationList out of a small number of
45 // model types / model type sets.
46
47 MigrationList MakeList(syncer::ModelTypeSet model_types) {
48   return MigrationList(1, model_types);
49 }
50
51 MigrationList MakeList(syncer::ModelTypeSet model_types1,
52                        syncer::ModelTypeSet model_types2) {
53   MigrationList migration_list;
54   migration_list.push_back(model_types1);
55   migration_list.push_back(model_types2);
56   return migration_list;
57 }
58
59 MigrationList MakeList(syncer::ModelType type) {
60   return MakeList(MakeSet(type));
61 }
62
63 MigrationList MakeList(syncer::ModelType type1,
64                        syncer::ModelType type2) {
65   return MakeList(MakeSet(type1), MakeSet(type2));
66 }
67
68 // Helper class that checks if the sync backend has successfully completed
69 // migration for a set of data types.
70 class MigrationChecker : public StatusChangeChecker,
71                          public browser_sync::MigrationObserver {
72  public:
73   explicit MigrationChecker(ProfileSyncServiceHarness* harness)
74       : StatusChangeChecker("MigrationChecker"),
75         harness_(harness) {
76     DCHECK(harness_);
77     browser_sync::BackendMigrator* migrator =
78         harness_->service()->GetBackendMigratorForTest();
79     // PSS must have a migrator after sync is setup and initial data type
80     // configuration is complete.
81     DCHECK(migrator);
82     migrator->AddMigrationObserver(this);
83   }
84
85   virtual ~MigrationChecker() {}
86
87   // Returns true when sync reports that there is no pending migration, and
88   // migration is complete for all data types in |expected_types_|.
89   virtual bool IsExitConditionSatisfied() OVERRIDE {
90     DCHECK(!expected_types_.Empty());
91     bool all_expected_types_migrated = migrated_types_.HasAll(expected_types_);
92     DVLOG(1) << harness_->profile_debug_name() << ": Migrated types "
93              << syncer::ModelTypeSetToString(migrated_types_)
94              << (all_expected_types_migrated ? " contains " :
95                                                " does not contain ")
96              << syncer::ModelTypeSetToString(expected_types_);
97     return all_expected_types_migrated &&
98            !HasPendingBackendMigration();
99   }
100
101   bool HasPendingBackendMigration() const {
102     browser_sync::BackendMigrator* migrator =
103         harness_->service()->GetBackendMigratorForTest();
104     return migrator && migrator->state() != browser_sync::BackendMigrator::IDLE;
105   }
106
107   void set_expected_types(syncer::ModelTypeSet expected_types) {
108     expected_types_ = expected_types;
109   }
110
111   syncer::ModelTypeSet migrated_types() const {
112     return migrated_types_;
113   }
114
115   virtual void OnMigrationStateChange() OVERRIDE {
116     if (HasPendingBackendMigration()) {
117       // A new bunch of data types are in the process of being migrated. Merge
118       // them into |pending_types_|.
119       pending_types_.PutAll(
120           harness_->service()->GetBackendMigratorForTest()->
121               GetPendingMigrationTypesForTest());
122       DVLOG(1) << harness_->profile_debug_name()
123                << ": new pending migration types "
124                << syncer::ModelTypeSetToString(pending_types_);
125     } else {
126       // Migration just finished for a bunch of data types. Merge them into
127       // |migrated_types_|.
128       migrated_types_.PutAll(pending_types_);
129       pending_types_.Clear();
130       DVLOG(1) << harness_->profile_debug_name() << ": new migrated types "
131                << syncer::ModelTypeSetToString(migrated_types_);
132     }
133
134     // Nudge ProfileSyncServiceHarness to inspect the exit condition provided by
135     // AwaitMigration.
136     harness_->OnStateChanged();
137   }
138
139  private:
140   // The sync client for which migration is being verified.
141   ProfileSyncServiceHarness* harness_;
142
143   // The set of data types that are expected to eventually undergo migration.
144   syncer::ModelTypeSet expected_types_;
145
146   // The set of data types currently undergoing migration.
147   syncer::ModelTypeSet pending_types_;
148
149   // The set of data types for which migration is complete. Accumulated by
150   // successive calls to OnMigrationStateChanged.
151   syncer::ModelTypeSet migrated_types_;
152
153   DISALLOW_COPY_AND_ASSIGN(MigrationChecker);
154 };
155
156 class MigrationTest : public SyncTest  {
157  public:
158   explicit MigrationTest(TestType test_type) : SyncTest(test_type) {}
159   virtual ~MigrationTest() {}
160
161   enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_NOTIFICATION };
162
163   // Set up sync for all profiles and initialize all MigrationCheckers. This
164   // helps ensure that all migration events are captured, even if they were to
165   // occur before a test calls AwaitMigration for a specific profile.
166   virtual bool SetupSync() OVERRIDE {
167     if (!SyncTest::SetupSync())
168       return false;
169
170     for (int i = 0; i < num_clients(); ++i) {
171       MigrationChecker* checker = new MigrationChecker(GetClient(i));
172       migration_checkers_.push_back(checker);
173     }
174     return true;
175   }
176
177   syncer::ModelTypeSet GetPreferredDataTypes() {
178     // ProfileSyncService must already have been created before we can call
179     // GetPreferredDataTypes().
180     DCHECK(GetClient(0)->service());
181     syncer::ModelTypeSet preferred_data_types =
182         GetClient(0)->service()->GetPreferredDataTypes();
183     preferred_data_types.RemoveAll(syncer::ProxyTypes());
184     // Make sure all clients have the same preferred data types.
185     for (int i = 1; i < num_clients(); ++i) {
186       const syncer::ModelTypeSet other_preferred_data_types =
187           GetClient(i)->service()->GetPreferredDataTypes();
188       EXPECT_TRUE(preferred_data_types.Equals(other_preferred_data_types));
189     }
190     return preferred_data_types;
191   }
192
193   // Returns a MigrationList with every enabled data type in its own
194   // set.
195   MigrationList GetPreferredDataTypesList() {
196     MigrationList migration_list;
197     const syncer::ModelTypeSet preferred_data_types =
198         GetPreferredDataTypes();
199     for (syncer::ModelTypeSet::Iterator it =
200              preferred_data_types.First(); it.Good(); it.Inc()) {
201       migration_list.push_back(MakeSet(it.Get()));
202     }
203     return migration_list;
204   }
205
206   // Trigger a migration for the given types with the given method.
207   void TriggerMigration(syncer::ModelTypeSet model_types,
208                         TriggerMethod trigger_method) {
209     switch (trigger_method) {
210       case MODIFY_PREF:
211         // Unlike MODIFY_BOOKMARK, MODIFY_PREF doesn't cause a
212         // notification to happen (since model association on a
213         // boolean pref clobbers the local value), so it doesn't work
214         // for anything but single-client tests.
215         ASSERT_EQ(1, num_clients());
216         ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
217         ChangeBooleanPref(0, prefs::kShowHomeButton);
218         break;
219       case MODIFY_BOOKMARK:
220         ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))));
221         break;
222       case TRIGGER_NOTIFICATION:
223         TriggerNotification(model_types);
224         break;
225       default:
226         ADD_FAILURE();
227     }
228   }
229
230   // Block until all clients have completed migration for the given
231   // types.
232   void AwaitMigration(syncer::ModelTypeSet migrate_types) {
233     for (int i = 0; i < num_clients(); ++i) {
234       MigrationChecker* checker = migration_checkers_[i];
235       checker->set_expected_types(migrate_types);
236       if (!checker->IsExitConditionSatisfied())
237         ASSERT_TRUE(GetClient(i)->AwaitStatusChange(checker, "AwaitMigration"));
238     }
239   }
240
241   bool ShouldRunMigrationTest() const {
242     if (!ServerSupportsNotificationControl() ||
243         !ServerSupportsErrorTriggering()) {
244       LOG(WARNING) << "Test skipped in this server environment.";
245       return false;
246     }
247     return true;
248   }
249
250   // Makes sure migration works with the given migration list and
251   // trigger method.
252   void RunMigrationTest(const MigrationList& migration_list,
253                         TriggerMethod trigger_method) {
254     ASSERT_TRUE(ShouldRunMigrationTest());
255
256     // If we have only one client, turn off notifications to avoid the
257     // possibility of spurious sync cycles.
258     bool do_test_without_notifications =
259         (trigger_method != TRIGGER_NOTIFICATION && num_clients() == 1);
260
261     if (do_test_without_notifications) {
262       DisableNotifications();
263     }
264
265     // Make sure migration hasn't been triggered prematurely.
266     for (int i = 0; i < num_clients(); ++i) {
267       ASSERT_TRUE(migration_checkers_[i]->migrated_types().Empty());
268     }
269
270     // Phase 1: Trigger the migrations on the server.
271     for (MigrationList::const_iterator it = migration_list.begin();
272          it != migration_list.end(); ++it) {
273       TriggerMigrationDoneError(*it);
274     }
275
276     // Phase 2: Trigger each migration individually and wait for it to
277     // complete.  (Multiple migrations may be handled by each
278     // migration cycle, but there's no guarantee of that, so we have
279     // to trigger each migration individually.)
280     for (MigrationList::const_iterator it = migration_list.begin();
281          it != migration_list.end(); ++it) {
282       TriggerMigration(*it, trigger_method);
283       AwaitMigration(*it);
284     }
285
286     // Phase 3: Wait for all clients to catch up.
287     //
288     // AwaitQuiescence() will not succeed when notifications are disabled.  We
289     // can safely avoid calling it because we know that, in the single client
290     // case, there is no one else to wait for.
291     //
292     // TODO(rlarocque, 97780): Remove the if condition when the test harness
293     // supports calling AwaitQuiescence() when notifications are disabled.
294     if (!do_test_without_notifications) {
295       AwaitQuiescence();
296     }
297
298     // TODO(rlarocque): It should be possible to re-enable notifications
299     // here, but doing so makes some windows tests flaky.
300   }
301
302  private:
303   // Used to keep track of the migration progress for each sync client.
304   ScopedVector<MigrationChecker> migration_checkers_;
305
306   DISALLOW_COPY_AND_ASSIGN(MigrationTest);
307 };
308
309 class MigrationSingleClientTest : public MigrationTest {
310  public:
311   MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT) {}
312   virtual ~MigrationSingleClientTest() {}
313
314   void RunSingleClientMigrationTest(const MigrationList& migration_list,
315                                     TriggerMethod trigger_method) {
316     if (!ShouldRunMigrationTest()) {
317       return;
318     }
319     ASSERT_TRUE(SetupSync());
320     RunMigrationTest(migration_list, trigger_method);
321   }
322
323  private:
324   DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest);
325 };
326
327 // The simplest possible migration tests -- a single data type.
328
329 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) {
330   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), MODIFY_PREF);
331 }
332
333 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) {
334   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
335                                MODIFY_BOOKMARK);
336 }
337
338 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
339                        PrefsOnlyTriggerNotification) {
340   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
341                                TRIGGER_NOTIFICATION);
342 }
343
344 // Nigori is handled specially, so we test that separately.
345
346 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) {
347   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
348                                TRIGGER_NOTIFICATION);
349 }
350
351 // A little more complicated -- two data types.
352
353 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
354                        BookmarksPrefsIndividually) {
355   RunSingleClientMigrationTest(
356       MakeList(syncer::BOOKMARKS, syncer::PREFERENCES),
357       MODIFY_PREF);
358 }
359
360 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) {
361   RunSingleClientMigrationTest(
362       MakeList(MakeSet(syncer::BOOKMARKS, syncer::PREFERENCES)),
363       MODIFY_BOOKMARK);
364 }
365
366 // Two data types with one being nigori.
367
368 // See crbug.com/124480.
369 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
370                        DISABLED_PrefsNigoriIndividiaully) {
371   RunSingleClientMigrationTest(
372       MakeList(syncer::PREFERENCES, syncer::NIGORI),
373       TRIGGER_NOTIFICATION);
374 }
375
376 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) {
377   RunSingleClientMigrationTest(
378       MakeList(MakeSet(syncer::PREFERENCES, syncer::NIGORI)),
379       MODIFY_PREF);
380 }
381
382 // The whole shebang -- all data types.
383
384 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesIndividually) {
385   ASSERT_TRUE(SetupClients());
386   RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK);
387 }
388
389 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
390                        AllTypesIndividuallyTriggerNotification) {
391   ASSERT_TRUE(SetupClients());
392   RunSingleClientMigrationTest(GetPreferredDataTypesList(),
393                                TRIGGER_NOTIFICATION);
394 }
395
396 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) {
397   ASSERT_TRUE(SetupClients());
398   RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
399                                MODIFY_PREF);
400 }
401
402 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
403                        AllTypesAtOnceTriggerNotification) {
404   ASSERT_TRUE(SetupClients());
405   RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
406                                TRIGGER_NOTIFICATION);
407 }
408
409 // All data types plus nigori.
410
411 // See crbug.com/124480.
412 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
413                        DISABLED_AllTypesWithNigoriIndividually) {
414   ASSERT_TRUE(SetupClients());
415   MigrationList migration_list = GetPreferredDataTypesList();
416   migration_list.push_front(MakeSet(syncer::NIGORI));
417   RunSingleClientMigrationTest(migration_list, MODIFY_BOOKMARK);
418 }
419
420 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
421                        AllTypesWithNigoriAtOnce) {
422   ASSERT_TRUE(SetupClients());
423   syncer::ModelTypeSet all_types = GetPreferredDataTypes();
424   all_types.Put(syncer::NIGORI);
425   RunSingleClientMigrationTest(MakeList(all_types), MODIFY_PREF);
426 }
427
428 class MigrationTwoClientTest : public MigrationTest {
429  public:
430   MigrationTwoClientTest() : MigrationTest(TWO_CLIENT) {}
431   virtual ~MigrationTwoClientTest() {}
432
433   // Helper function that verifies that preferences sync still works.
434   void VerifyPrefSync() {
435     ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
436     ChangeBooleanPref(0, prefs::kShowHomeButton);
437     ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
438     ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
439   }
440
441   void RunTwoClientMigrationTest(const MigrationList& migration_list,
442                                  TriggerMethod trigger_method) {
443     if (!ShouldRunMigrationTest()) {
444       return;
445     }
446     ASSERT_TRUE(SetupSync());
447
448     // Make sure pref sync works before running the migration test.
449     VerifyPrefSync();
450
451     RunMigrationTest(migration_list, trigger_method);
452
453     // Make sure pref sync still works after running the migration
454     // test.
455     VerifyPrefSync();
456   }
457
458  private:
459   DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest);
460 };
461
462 // Easiest possible test of migration errors: triggers a server
463 // migration on one datatype, then modifies some other datatype.
464 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigratePrefsThenModifyBookmark) {
465   RunTwoClientMigrationTest(MakeList(syncer::PREFERENCES),
466                             MODIFY_BOOKMARK);
467 }
468
469 // Triggers a server migration on two datatypes, then makes a local
470 // modification to one of them.
471 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
472                        MigratePrefsAndBookmarksThenModifyBookmark) {
473   RunTwoClientMigrationTest(
474       MakeList(syncer::PREFERENCES, syncer::BOOKMARKS),
475       MODIFY_BOOKMARK);
476 }
477
478 // Migrate every datatype in sequence; the catch being that the server
479 // will only tell the client about the migrations one at a time.
480 // TODO(rsimha): This test takes longer than 60 seconds, and will cause tree
481 // redness due to sharding.
482 // Re-enable this test after syncer::kInitialBackoffShortRetrySeconds is reduced
483 // to zero.
484 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
485                        DISABLED_MigrationHellWithoutNigori) {
486   ASSERT_TRUE(SetupClients());
487   MigrationList migration_list = GetPreferredDataTypesList();
488   // Let the first nudge be a datatype that's neither prefs nor
489   // bookmarks.
490   migration_list.push_front(MakeSet(syncer::THEMES));
491   RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
492 }
493
494 // See crbug.com/124480.
495 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
496                        DISABLED_MigrationHellWithNigori) {
497   ASSERT_TRUE(SetupClients());
498   MigrationList migration_list = GetPreferredDataTypesList();
499   // Let the first nudge be a datatype that's neither prefs nor
500   // bookmarks.
501   migration_list.push_front(MakeSet(syncer::THEMES));
502   // Pop off one so that we don't migrate all data types; the syncer
503   // freaks out if we do that (see http://crbug.com/94882).
504   ASSERT_GE(migration_list.size(), 2u);
505   ASSERT_FALSE(migration_list.back().Equals(MakeSet(syncer::NIGORI)));
506   migration_list.back() = MakeSet(syncer::NIGORI);
507   RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
508 }
509
510 class MigrationReconfigureTest : public MigrationTwoClientTest {
511  public:
512   MigrationReconfigureTest() {}
513
514   virtual void SetUpCommandLine(CommandLine* cl) OVERRIDE {
515     AddTestSwitches(cl);
516     // Do not add optional datatypes.
517   }
518
519   virtual ~MigrationReconfigureTest() {}
520
521  private:
522   DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest);
523 };
524
525 }  // namespace