Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / migration_test.cc
blobb1956c26180c108396a8aa7f5fa509cf2d084fd5
1 // Copyright (c) 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.
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/browser/translate/translate_prefs.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/ui_test_utils.h"
19 using bookmarks_helper::AddURL;
20 using bookmarks_helper::IndexedURL;
21 using bookmarks_helper::IndexedURLTitle;
23 using preferences_helper::BooleanPrefMatches;
24 using preferences_helper::ChangeBooleanPref;
26 namespace {
28 // Utility functions to make a model type set out of a small number of
29 // model types.
31 syncer::ModelTypeSet MakeSet(syncer::ModelType type) {
32 return syncer::ModelTypeSet(type);
35 syncer::ModelTypeSet MakeSet(syncer::ModelType type1,
36 syncer::ModelType type2) {
37 return syncer::ModelTypeSet(type1, type2);
40 // An ordered list of model types sets to migrate. Used by
41 // RunMigrationTest().
42 typedef std::deque<syncer::ModelTypeSet> MigrationList;
44 // Utility functions to make a MigrationList out of a small number of
45 // model types / model type sets.
47 MigrationList MakeList(syncer::ModelTypeSet model_types) {
48 return MigrationList(1, model_types);
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;
59 MigrationList MakeList(syncer::ModelType type) {
60 return MakeList(MakeSet(type));
63 MigrationList MakeList(syncer::ModelType type1,
64 syncer::ModelType type2) {
65 return MakeList(MakeSet(type1), MakeSet(type2));
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);
85 virtual ~MigrationChecker() {}
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 !harness_->HasPendingBackendMigration();
101 void set_expected_types(syncer::ModelTypeSet expected_types) {
102 expected_types_ = expected_types;
105 syncer::ModelTypeSet migrated_types() const {
106 return migrated_types_;
109 virtual void OnMigrationStateChange() OVERRIDE {
110 if (harness_->HasPendingBackendMigration()) {
111 // A new bunch of data types are in the process of being migrated. Merge
112 // them into |pending_types_|.
113 pending_types_.PutAll(
114 harness_->service()->GetBackendMigratorForTest()->
115 GetPendingMigrationTypesForTest());
116 DVLOG(1) << harness_->profile_debug_name()
117 << ": new pending migration types "
118 << syncer::ModelTypeSetToString(pending_types_);
119 } else {
120 // Migration just finished for a bunch of data types. Merge them into
121 // |migrated_types_|.
122 migrated_types_.PutAll(pending_types_);
123 pending_types_.Clear();
124 DVLOG(1) << harness_->profile_debug_name() << ": new migrated types "
125 << syncer::ModelTypeSetToString(migrated_types_);
128 // Nudge ProfileSyncServiceHarness to inspect the exit condition provided by
129 // AwaitMigration.
130 harness_->OnStateChanged();
133 private:
134 // The sync client for which migration is being verified.
135 ProfileSyncServiceHarness* harness_;
137 // The set of data types that are expected to eventually undergo migration.
138 syncer::ModelTypeSet expected_types_;
140 // The set of data types currently undergoing migration.
141 syncer::ModelTypeSet pending_types_;
143 // The set of data types for which migration is complete. Accumulated by
144 // successive calls to OnMigrationStateChanged.
145 syncer::ModelTypeSet migrated_types_;
147 DISALLOW_COPY_AND_ASSIGN(MigrationChecker);
150 class MigrationTest : public SyncTest {
151 public:
152 explicit MigrationTest(TestType test_type) : SyncTest(test_type) {}
153 virtual ~MigrationTest() {}
155 enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_NOTIFICATION };
157 // Set up sync for all profiles and initialize all MigrationCheckers. This
158 // helps ensure that all migration events are captured, even if they were to
159 // occur before a test calls AwaitMigration for a specific profile.
160 virtual bool SetupSync() OVERRIDE {
161 if (!SyncTest::SetupSync())
162 return false;
164 for (int i = 0; i < num_clients(); ++i) {
165 MigrationChecker* checker = new MigrationChecker(GetClient(i));
166 migration_checkers_.push_back(checker);
168 return true;
171 syncer::ModelTypeSet GetPreferredDataTypes() {
172 // ProfileSyncService must already have been created before we can call
173 // GetPreferredDataTypes().
174 DCHECK(GetClient(0)->service());
175 syncer::ModelTypeSet preferred_data_types =
176 GetClient(0)->service()->GetPreferredDataTypes();
177 preferred_data_types.RemoveAll(syncer::ProxyTypes());
178 // Make sure all clients have the same preferred data types.
179 for (int i = 1; i < num_clients(); ++i) {
180 const syncer::ModelTypeSet other_preferred_data_types =
181 GetClient(i)->service()->GetPreferredDataTypes();
182 EXPECT_TRUE(preferred_data_types.Equals(other_preferred_data_types));
184 return preferred_data_types;
187 // Returns a MigrationList with every enabled data type in its own
188 // set.
189 MigrationList GetPreferredDataTypesList() {
190 MigrationList migration_list;
191 const syncer::ModelTypeSet preferred_data_types =
192 GetPreferredDataTypes();
193 for (syncer::ModelTypeSet::Iterator it =
194 preferred_data_types.First(); it.Good(); it.Inc()) {
195 migration_list.push_back(MakeSet(it.Get()));
197 return migration_list;
200 // Trigger a migration for the given types with the given method.
201 void TriggerMigration(syncer::ModelTypeSet model_types,
202 TriggerMethod trigger_method) {
203 switch (trigger_method) {
204 case MODIFY_PREF:
205 // Unlike MODIFY_BOOKMARK, MODIFY_PREF doesn't cause a
206 // notification to happen (since model association on a
207 // boolean pref clobbers the local value), so it doesn't work
208 // for anything but single-client tests.
209 ASSERT_EQ(1, num_clients());
210 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
211 ChangeBooleanPref(0, prefs::kShowHomeButton);
212 break;
213 case MODIFY_BOOKMARK:
214 ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))));
215 break;
216 case TRIGGER_NOTIFICATION:
217 TriggerNotification(model_types);
218 break;
219 default:
220 ADD_FAILURE();
224 // Block until all clients have completed migration for the given
225 // types.
226 void AwaitMigration(syncer::ModelTypeSet migrate_types) {
227 for (int i = 0; i < num_clients(); ++i) {
228 MigrationChecker* checker = migration_checkers_[i];
229 checker->set_expected_types(migrate_types);
230 if (!checker->IsExitConditionSatisfied())
231 ASSERT_TRUE(GetClient(i)->AwaitStatusChange(checker, "AwaitMigration"));
232 // We must use AwaitDataSyncCompletion rather than the more common
233 // AwaitFullSyncCompletion. As long as crbug.com/97780 is open, we will
234 // rely on self-notifications to ensure that progress markers are updated,
235 // which allows AwaitFullSyncCompletion to return. However, in some
236 // migration tests these notifications are completely disabled, so the
237 // progress markers do not get updated. This is why we must use the less
238 // strict condition, AwaitDataSyncCompletion.
239 ASSERT_TRUE(GetClient(i)->AwaitDataSyncCompletion());
243 bool ShouldRunMigrationTest() const {
244 if (!ServerSupportsNotificationControl() ||
245 !ServerSupportsErrorTriggering()) {
246 LOG(WARNING) << "Test skipped in this server environment.";
247 return false;
249 return true;
252 // Makes sure migration works with the given migration list and
253 // trigger method.
254 void RunMigrationTest(const MigrationList& migration_list,
255 TriggerMethod trigger_method) {
256 ASSERT_TRUE(ShouldRunMigrationTest());
258 // If we have only one client, turn off notifications to avoid the
259 // possibility of spurious sync cycles.
260 bool do_test_without_notifications =
261 (trigger_method != TRIGGER_NOTIFICATION && num_clients() == 1);
263 if (do_test_without_notifications) {
264 DisableNotifications();
267 // Make sure migration hasn't been triggered prematurely.
268 for (int i = 0; i < num_clients(); ++i) {
269 ASSERT_TRUE(migration_checkers_[i]->migrated_types().Empty());
272 // Phase 1: Trigger the migrations on the server.
273 for (MigrationList::const_iterator it = migration_list.begin();
274 it != migration_list.end(); ++it) {
275 TriggerMigrationDoneError(*it);
278 // Phase 2: Trigger each migration individually and wait for it to
279 // complete. (Multiple migrations may be handled by each
280 // migration cycle, but there's no guarantee of that, so we have
281 // to trigger each migration individually.)
282 for (MigrationList::const_iterator it = migration_list.begin();
283 it != migration_list.end(); ++it) {
284 TriggerMigration(*it, trigger_method);
285 AwaitMigration(*it);
288 // Phase 3: Wait for all clients to catch up.
290 // AwaitQuiescence() will not succeed when notifications are disabled. We
291 // can safely avoid calling it because we know that, in the single client
292 // case, there is no one else to wait for.
294 // TODO(rlarocque, 97780): Remove the if condition when the test harness
295 // supports calling AwaitQuiescence() when notifications are disabled.
296 if (!do_test_without_notifications) {
297 AwaitQuiescence();
300 // TODO(rlarocque): It should be possible to re-enable notifications
301 // here, but doing so makes some windows tests flaky.
304 private:
305 // Used to keep track of the migration progress for each sync client.
306 ScopedVector<MigrationChecker> migration_checkers_;
308 DISALLOW_COPY_AND_ASSIGN(MigrationTest);
311 class MigrationSingleClientTest : public MigrationTest {
312 public:
313 MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT) {}
314 virtual ~MigrationSingleClientTest() {}
316 void RunSingleClientMigrationTest(const MigrationList& migration_list,
317 TriggerMethod trigger_method) {
318 if (!ShouldRunMigrationTest()) {
319 return;
321 ASSERT_TRUE(SetupSync());
322 RunMigrationTest(migration_list, trigger_method);
325 private:
326 DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest);
329 // The simplest possible migration tests -- a single data type.
331 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) {
332 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), MODIFY_PREF);
335 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) {
336 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
337 MODIFY_BOOKMARK);
340 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
341 PrefsOnlyTriggerNotification) {
342 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
343 TRIGGER_NOTIFICATION);
346 // Nigori is handled specially, so we test that separately.
348 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) {
349 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
350 TRIGGER_NOTIFICATION);
353 // A little more complicated -- two data types.
355 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
356 BookmarksPrefsIndividually) {
357 RunSingleClientMigrationTest(
358 MakeList(syncer::BOOKMARKS, syncer::PREFERENCES),
359 MODIFY_PREF);
362 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) {
363 RunSingleClientMigrationTest(
364 MakeList(MakeSet(syncer::BOOKMARKS, syncer::PREFERENCES)),
365 MODIFY_BOOKMARK);
368 // Two data types with one being nigori.
370 // See crbug.com/124480.
371 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
372 DISABLED_PrefsNigoriIndividiaully) {
373 RunSingleClientMigrationTest(
374 MakeList(syncer::PREFERENCES, syncer::NIGORI),
375 TRIGGER_NOTIFICATION);
378 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) {
379 RunSingleClientMigrationTest(
380 MakeList(MakeSet(syncer::PREFERENCES, syncer::NIGORI)),
381 MODIFY_PREF);
384 // The whole shebang -- all data types.
386 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesIndividually) {
387 ASSERT_TRUE(SetupClients());
388 RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK);
391 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
392 AllTypesIndividuallyTriggerNotification) {
393 ASSERT_TRUE(SetupClients());
394 RunSingleClientMigrationTest(GetPreferredDataTypesList(),
395 TRIGGER_NOTIFICATION);
398 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) {
399 ASSERT_TRUE(SetupClients());
400 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
401 MODIFY_PREF);
404 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
405 AllTypesAtOnceTriggerNotification) {
406 ASSERT_TRUE(SetupClients());
407 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
408 TRIGGER_NOTIFICATION);
411 // All data types plus nigori.
413 // See crbug.com/124480.
414 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
415 DISABLED_AllTypesWithNigoriIndividually) {
416 ASSERT_TRUE(SetupClients());
417 MigrationList migration_list = GetPreferredDataTypesList();
418 migration_list.push_front(MakeSet(syncer::NIGORI));
419 RunSingleClientMigrationTest(migration_list, MODIFY_BOOKMARK);
422 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
423 AllTypesWithNigoriAtOnce) {
424 ASSERT_TRUE(SetupClients());
425 syncer::ModelTypeSet all_types = GetPreferredDataTypes();
426 all_types.Put(syncer::NIGORI);
427 RunSingleClientMigrationTest(MakeList(all_types), MODIFY_PREF);
430 class MigrationTwoClientTest : public MigrationTest {
431 public:
432 MigrationTwoClientTest() : MigrationTest(TWO_CLIENT) {}
433 virtual ~MigrationTwoClientTest() {}
435 // Helper function that verifies that preferences sync still works.
436 void VerifyPrefSync() {
437 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
438 ChangeBooleanPref(0, prefs::kShowHomeButton);
439 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
440 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
443 void RunTwoClientMigrationTest(const MigrationList& migration_list,
444 TriggerMethod trigger_method) {
445 if (!ShouldRunMigrationTest()) {
446 return;
448 ASSERT_TRUE(SetupSync());
450 // Make sure pref sync works before running the migration test.
451 VerifyPrefSync();
453 RunMigrationTest(migration_list, trigger_method);
455 // Make sure pref sync still works after running the migration
456 // test.
457 VerifyPrefSync();
460 private:
461 DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest);
464 // Easiest possible test of migration errors: triggers a server
465 // migration on one datatype, then modifies some other datatype.
466 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigratePrefsThenModifyBookmark) {
467 RunTwoClientMigrationTest(MakeList(syncer::PREFERENCES),
468 MODIFY_BOOKMARK);
471 // Triggers a server migration on two datatypes, then makes a local
472 // modification to one of them.
473 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
474 MigratePrefsAndBookmarksThenModifyBookmark) {
475 RunTwoClientMigrationTest(
476 MakeList(syncer::PREFERENCES, syncer::BOOKMARKS),
477 MODIFY_BOOKMARK);
480 // Migrate every datatype in sequence; the catch being that the server
481 // will only tell the client about the migrations one at a time.
482 // TODO(rsimha): This test takes longer than 60 seconds, and will cause tree
483 // redness due to sharding.
484 // Re-enable this test after syncer::kInitialBackoffShortRetrySeconds is reduced
485 // to zero.
486 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
487 DISABLED_MigrationHellWithoutNigori) {
488 ASSERT_TRUE(SetupClients());
489 MigrationList migration_list = GetPreferredDataTypesList();
490 // Let the first nudge be a datatype that's neither prefs nor
491 // bookmarks.
492 migration_list.push_front(MakeSet(syncer::THEMES));
493 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
496 // See crbug.com/124480.
497 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
498 DISABLED_MigrationHellWithNigori) {
499 ASSERT_TRUE(SetupClients());
500 MigrationList migration_list = GetPreferredDataTypesList();
501 // Let the first nudge be a datatype that's neither prefs nor
502 // bookmarks.
503 migration_list.push_front(MakeSet(syncer::THEMES));
504 // Pop off one so that we don't migrate all data types; the syncer
505 // freaks out if we do that (see http://crbug.com/94882).
506 ASSERT_GE(migration_list.size(), 2u);
507 ASSERT_FALSE(migration_list.back().Equals(MakeSet(syncer::NIGORI)));
508 migration_list.back() = MakeSet(syncer::NIGORI);
509 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
512 class MigrationReconfigureTest : public MigrationTwoClientTest {
513 public:
514 MigrationReconfigureTest() {}
516 virtual void SetUpCommandLine(CommandLine* cl) OVERRIDE {
517 AddTestSwitches(cl);
518 // Do not add optional datatypes.
521 virtual ~MigrationReconfigureTest() {}
523 private:
524 DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest);
527 } // namespace