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.
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/profile_sync_service.h"
10 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
11 #include "chrome/browser/sync/test/integration/migration_waiter.h"
12 #include "chrome/browser/sync/test/integration/migration_watcher.h"
13 #include "chrome/browser/sync/test/integration/preferences_helper.h"
14 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
15 #include "chrome/browser/sync/test/integration/sync_test.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "components/translate/core/browser/translate_prefs.h"
20 using bookmarks_helper::AddURL;
21 using bookmarks_helper::IndexedURL;
22 using bookmarks_helper::IndexedURLTitle;
24 using preferences_helper::BooleanPrefMatches;
25 using preferences_helper::ChangeBooleanPref;
29 // Utility functions to make a model type set out of a small number of
32 syncer::ModelTypeSet MakeSet(syncer::ModelType type) {
33 return syncer::ModelTypeSet(type);
36 syncer::ModelTypeSet MakeSet(syncer::ModelType type1,
37 syncer::ModelType type2) {
38 return syncer::ModelTypeSet(type1, type2);
41 // An ordered list of model types sets to migrate. Used by
42 // RunMigrationTest().
43 typedef std::deque<syncer::ModelTypeSet> MigrationList;
45 // Utility functions to make a MigrationList out of a small number of
46 // model types / model type sets.
48 MigrationList MakeList(syncer::ModelTypeSet model_types) {
49 return MigrationList(1, model_types);
52 MigrationList MakeList(syncer::ModelTypeSet model_types1,
53 syncer::ModelTypeSet model_types2) {
54 MigrationList migration_list;
55 migration_list.push_back(model_types1);
56 migration_list.push_back(model_types2);
57 return migration_list;
60 MigrationList MakeList(syncer::ModelType type) {
61 return MakeList(MakeSet(type));
64 MigrationList MakeList(syncer::ModelType type1,
65 syncer::ModelType type2) {
66 return MakeList(MakeSet(type1), MakeSet(type2));
70 class MigrationTest : public SyncTest {
72 explicit MigrationTest(TestType test_type) : SyncTest(test_type) {}
73 virtual ~MigrationTest() {}
75 enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_NOTIFICATION };
77 // Set up sync for all profiles and initialize all MigrationWatchers. This
78 // helps ensure that all migration events are captured, even if they were to
79 // occur before a test calls AwaitMigration for a specific profile.
80 virtual bool SetupSync() OVERRIDE {
81 if (!SyncTest::SetupSync())
84 for (int i = 0; i < num_clients(); ++i) {
85 MigrationWatcher* watcher = new MigrationWatcher(GetClient(i));
86 migration_watchers_.push_back(watcher);
91 syncer::ModelTypeSet GetPreferredDataTypes() {
92 // ProfileSyncService must already have been created before we can call
93 // GetPreferredDataTypes().
94 DCHECK(GetSyncService((0)));
95 syncer::ModelTypeSet preferred_data_types =
96 GetSyncService((0))->GetPreferredDataTypes();
97 preferred_data_types.RemoveAll(syncer::ProxyTypes());
99 // The managed user settings will be "unready" during this test, so we
100 // should not request that they be migrated.
101 preferred_data_types.Remove(syncer::SUPERVISED_USER_SETTINGS);
103 // Make sure all clients have the same preferred data types.
104 for (int i = 1; i < num_clients(); ++i) {
105 const syncer::ModelTypeSet other_preferred_data_types =
106 GetSyncService((i))->GetPreferredDataTypes();
107 EXPECT_TRUE(preferred_data_types.Equals(other_preferred_data_types));
109 return preferred_data_types;
112 // Returns a MigrationList with every enabled data type in its own
114 MigrationList GetPreferredDataTypesList() {
115 MigrationList migration_list;
116 const syncer::ModelTypeSet preferred_data_types =
117 GetPreferredDataTypes();
118 for (syncer::ModelTypeSet::Iterator it =
119 preferred_data_types.First(); it.Good(); it.Inc()) {
120 migration_list.push_back(MakeSet(it.Get()));
122 return migration_list;
125 // Trigger a migration for the given types with the given method.
126 void TriggerMigration(syncer::ModelTypeSet model_types,
127 TriggerMethod trigger_method) {
128 switch (trigger_method) {
130 // Unlike MODIFY_BOOKMARK, MODIFY_PREF doesn't cause a
131 // notification to happen (since model association on a
132 // boolean pref clobbers the local value), so it doesn't work
133 // for anything but single-client tests.
134 ASSERT_EQ(1, num_clients());
135 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
136 ChangeBooleanPref(0, prefs::kShowHomeButton);
138 case MODIFY_BOOKMARK:
139 ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))));
141 case TRIGGER_NOTIFICATION:
142 TriggerNotification(model_types);
149 // Block until all clients have completed migration for the given
151 void AwaitMigration(syncer::ModelTypeSet migrate_types) {
152 for (int i = 0; i < num_clients(); ++i) {
153 MigrationWaiter waiter(migrate_types, migration_watchers_[i]);
155 ASSERT_FALSE(waiter.TimedOut());
159 // Makes sure migration works with the given migration list and
161 void RunMigrationTest(const MigrationList& migration_list,
162 TriggerMethod trigger_method) {
163 // If we have only one client, turn off notifications to avoid the
164 // possibility of spurious sync cycles.
165 bool do_test_without_notifications =
166 (trigger_method != TRIGGER_NOTIFICATION && num_clients() == 1);
168 if (do_test_without_notifications) {
169 DisableNotifications();
172 // Make sure migration hasn't been triggered prematurely.
173 for (int i = 0; i < num_clients(); ++i) {
174 ASSERT_TRUE(migration_watchers_[i]->GetMigratedTypes().Empty());
177 // Phase 1: Trigger the migrations on the server.
178 for (MigrationList::const_iterator it = migration_list.begin();
179 it != migration_list.end(); ++it) {
180 TriggerMigrationDoneError(*it);
183 // Phase 2: Trigger each migration individually and wait for it to
184 // complete. (Multiple migrations may be handled by each
185 // migration cycle, but there's no guarantee of that, so we have
186 // to trigger each migration individually.)
187 for (MigrationList::const_iterator it = migration_list.begin();
188 it != migration_list.end(); ++it) {
189 TriggerMigration(*it, trigger_method);
193 // Phase 3: Wait for all clients to catch up.
195 // AwaitQuiescence() will not succeed when notifications are disabled. We
196 // can safely avoid calling it because we know that, in the single client
197 // case, there is no one else to wait for.
199 // TODO(rlarocque, 97780): Remove the if condition when the test harness
200 // supports calling AwaitQuiescence() when notifications are disabled.
201 if (!do_test_without_notifications) {
205 // TODO(rlarocque): It should be possible to re-enable notifications
206 // here, but doing so makes some windows tests flaky.
210 // Used to keep track of the migration progress for each sync client.
211 ScopedVector<MigrationWatcher> migration_watchers_;
213 DISALLOW_COPY_AND_ASSIGN(MigrationTest);
216 class MigrationSingleClientTest : public MigrationTest {
218 MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT_LEGACY) {}
219 virtual ~MigrationSingleClientTest() {}
221 void RunSingleClientMigrationTest(const MigrationList& migration_list,
222 TriggerMethod trigger_method) {
223 ASSERT_TRUE(SetupSync());
224 RunMigrationTest(migration_list, trigger_method);
228 DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest);
231 // The simplest possible migration tests -- a single data type.
233 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) {
234 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), MODIFY_PREF);
237 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) {
238 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
242 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
243 PrefsOnlyTriggerNotification) {
244 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
245 TRIGGER_NOTIFICATION);
248 // Nigori is handled specially, so we test that separately.
250 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) {
251 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
252 TRIGGER_NOTIFICATION);
255 // A little more complicated -- two data types.
257 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsIndividually) {
258 RunSingleClientMigrationTest(
259 MakeList(syncer::BOOKMARKS, syncer::PREFERENCES),
263 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) {
264 RunSingleClientMigrationTest(
265 MakeList(MakeSet(syncer::BOOKMARKS, syncer::PREFERENCES)),
269 // Two data types with one being nigori.
271 // See crbug.com/124480.
272 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
273 DISABLED_PrefsNigoriIndividiaully) {
274 RunSingleClientMigrationTest(
275 MakeList(syncer::PREFERENCES, syncer::NIGORI),
276 TRIGGER_NOTIFICATION);
279 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) {
280 RunSingleClientMigrationTest(
281 MakeList(MakeSet(syncer::PREFERENCES, syncer::NIGORI)),
285 // The whole shebang -- all data types.
287 // http://crbug.com/403778
288 #define MAYBE_AllTypesIndividually DISABLED_AllTypesIndividually
290 #define MAYBE_AllTypesIndividually AllTypesIndividually
292 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, MAYBE_AllTypesIndividually) {
293 ASSERT_TRUE(SetupClients());
294 RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK);
298 // http://crbug.com/403778
299 #define MAYBE_AllTypesIndividuallyTriggerNotification DISABLED_AllTypesIndividuallyTriggerNotification
301 #define MAYBE_AllTypesIndividuallyTriggerNotification AllTypesIndividuallyTriggerNotification
303 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
304 MAYBE_AllTypesIndividuallyTriggerNotification) {
305 ASSERT_TRUE(SetupClients());
306 RunSingleClientMigrationTest(GetPreferredDataTypesList(),
307 TRIGGER_NOTIFICATION);
310 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) {
311 ASSERT_TRUE(SetupClients());
312 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
316 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
317 AllTypesAtOnceTriggerNotification) {
318 ASSERT_TRUE(SetupClients());
319 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
320 TRIGGER_NOTIFICATION);
323 // All data types plus nigori.
325 // See crbug.com/124480.
326 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
327 DISABLED_AllTypesWithNigoriIndividually) {
328 ASSERT_TRUE(SetupClients());
329 MigrationList migration_list = GetPreferredDataTypesList();
330 migration_list.push_front(MakeSet(syncer::NIGORI));
331 RunSingleClientMigrationTest(migration_list, MODIFY_BOOKMARK);
334 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesWithNigoriAtOnce) {
335 ASSERT_TRUE(SetupClients());
336 syncer::ModelTypeSet all_types = GetPreferredDataTypes();
337 all_types.Put(syncer::NIGORI);
338 RunSingleClientMigrationTest(MakeList(all_types), MODIFY_PREF);
341 class MigrationTwoClientTest : public MigrationTest {
343 MigrationTwoClientTest() : MigrationTest(TWO_CLIENT_LEGACY) {}
344 virtual ~MigrationTwoClientTest() {}
346 // Helper function that verifies that preferences sync still works.
347 void VerifyPrefSync() {
348 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
349 ChangeBooleanPref(0, prefs::kShowHomeButton);
350 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
351 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
354 void RunTwoClientMigrationTest(const MigrationList& migration_list,
355 TriggerMethod trigger_method) {
356 ASSERT_TRUE(SetupSync());
358 // Make sure pref sync works before running the migration test.
361 RunMigrationTest(migration_list, trigger_method);
363 // Make sure pref sync still works after running the migration
369 DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest);
372 // Easiest possible test of migration errors: triggers a server
373 // migration on one datatype, then modifies some other datatype.
374 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigratePrefsThenModifyBookmark) {
375 RunTwoClientMigrationTest(MakeList(syncer::PREFERENCES),
379 // Triggers a server migration on two datatypes, then makes a local
380 // modification to one of them.
381 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
382 MigratePrefsAndBookmarksThenModifyBookmark) {
383 RunTwoClientMigrationTest(
384 MakeList(syncer::PREFERENCES, syncer::BOOKMARKS),
388 // Migrate every datatype in sequence; the catch being that the server
389 // will only tell the client about the migrations one at a time.
390 // TODO(rsimha): This test takes longer than 60 seconds, and will cause tree
391 // redness due to sharding.
392 // Re-enable this test after syncer::kInitialBackoffShortRetrySeconds is reduced
394 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
395 DISABLED_MigrationHellWithoutNigori) {
396 ASSERT_TRUE(SetupClients());
397 MigrationList migration_list = GetPreferredDataTypesList();
398 // Let the first nudge be a datatype that's neither prefs nor
400 migration_list.push_front(MakeSet(syncer::THEMES));
401 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
404 // See crbug.com/124480.
405 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
406 DISABLED_MigrationHellWithNigori) {
407 ASSERT_TRUE(SetupClients());
408 MigrationList migration_list = GetPreferredDataTypesList();
409 // Let the first nudge be a datatype that's neither prefs nor
411 migration_list.push_front(MakeSet(syncer::THEMES));
412 // Pop off one so that we don't migrate all data types; the syncer
413 // freaks out if we do that (see http://crbug.com/94882).
414 ASSERT_GE(migration_list.size(), 2u);
415 ASSERT_FALSE(migration_list.back().Equals(MakeSet(syncer::NIGORI)));
416 migration_list.back() = MakeSet(syncer::NIGORI);
417 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
420 class MigrationReconfigureTest : public MigrationTwoClientTest {
422 MigrationReconfigureTest() {}
424 virtual void SetUpCommandLine(base::CommandLine* cl) OVERRIDE {
426 // Do not add optional datatypes.
429 virtual ~MigrationReconfigureTest() {}
432 DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest);