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 // TODO(akalin): Rename this file to migration_test.cc.
7 #include "base/compiler_specific.h"
8 #include "base/prefs/scoped_user_pref_update.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/sync/profile_sync_service_harness.h"
11 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
12 #include "chrome/browser/sync/test/integration/preferences_helper.h"
13 #include "chrome/browser/sync/test/integration/sync_test.h"
14 #include "chrome/browser/translate/translate_prefs.h"
15 #include "chrome/common/pref_names.h"
16 #include "chrome/test/base/ui_test_utils.h"
18 using bookmarks_helper::AddURL;
19 using bookmarks_helper::IndexedURL;
20 using bookmarks_helper::IndexedURLTitle;
22 using preferences_helper::BooleanPrefMatches;
23 using preferences_helper::ChangeBooleanPref;
27 // Utility functions to make a model type set out of a small number of
30 syncer::ModelTypeSet MakeSet(syncer::ModelType type) {
31 return syncer::ModelTypeSet(type);
34 syncer::ModelTypeSet MakeSet(syncer::ModelType type1,
35 syncer::ModelType type2) {
36 return syncer::ModelTypeSet(type1, type2);
39 // An ordered list of model types sets to migrate. Used by
40 // RunMigrationTest().
41 typedef std::deque<syncer::ModelTypeSet> MigrationList;
43 // Utility functions to make a MigrationList out of a small number of
44 // model types / model type sets.
46 MigrationList MakeList(syncer::ModelTypeSet model_types) {
47 return MigrationList(1, model_types);
50 MigrationList MakeList(syncer::ModelTypeSet model_types1,
51 syncer::ModelTypeSet model_types2) {
52 MigrationList migration_list;
53 migration_list.push_back(model_types1);
54 migration_list.push_back(model_types2);
55 return migration_list;
58 MigrationList MakeList(syncer::ModelType type) {
59 return MakeList(MakeSet(type));
62 MigrationList MakeList(syncer::ModelType type1,
63 syncer::ModelType type2) {
64 return MakeList(MakeSet(type1), MakeSet(type2));
67 class MigrationTest : public SyncTest {
69 explicit MigrationTest(TestType test_type) : SyncTest(test_type) {}
70 virtual ~MigrationTest() {}
72 // TODO(akalin): Add more MODIFY_(data type) trigger methods, as
73 // well as a poll-based trigger method.
74 enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_NOTIFICATION };
76 syncer::ModelTypeSet GetPreferredDataTypes() {
77 // ProfileSyncService must already have been created before we can call
78 // GetPreferredDataTypes().
79 DCHECK(GetClient(0)->IsSyncAlreadySetup());
80 syncer::ModelTypeSet preferred_data_types =
81 GetClient(0)->service()->GetPreferredDataTypes();
82 preferred_data_types.RemoveAll(syncer::ProxyTypes());
83 // Make sure all clients have the same preferred data types.
84 for (int i = 1; i < num_clients(); ++i) {
85 const syncer::ModelTypeSet other_preferred_data_types =
86 GetClient(i)->service()->GetPreferredDataTypes();
87 EXPECT_TRUE(preferred_data_types.Equals(other_preferred_data_types));
89 return preferred_data_types;
92 // Returns a MigrationList with every enabled data type in its own
94 MigrationList GetPreferredDataTypesList() {
95 MigrationList migration_list;
96 const syncer::ModelTypeSet preferred_data_types =
97 GetPreferredDataTypes();
98 for (syncer::ModelTypeSet::Iterator it =
99 preferred_data_types.First(); it.Good(); it.Inc()) {
100 migration_list.push_back(MakeSet(it.Get()));
102 return migration_list;
105 // Trigger a migration for the given types with the given method.
106 void TriggerMigration(syncer::ModelTypeSet model_types,
107 TriggerMethod trigger_method) {
108 switch (trigger_method) {
110 // Unlike MODIFY_BOOKMARK, MODIFY_PREF doesn't cause a
111 // notification to happen (since model association on a
112 // boolean pref clobbers the local value), so it doesn't work
113 // for anything but single-client tests.
114 ASSERT_EQ(1, num_clients());
115 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
116 ChangeBooleanPref(0, prefs::kShowHomeButton);
118 case MODIFY_BOOKMARK:
119 ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))));
121 case TRIGGER_NOTIFICATION:
122 TriggerNotification(model_types);
129 // Block until all clients have completed migration for the given
131 void AwaitMigration(syncer::ModelTypeSet migrate_types) {
132 for (int i = 0; i < num_clients(); ++i) {
133 ASSERT_TRUE(GetClient(i)->AwaitMigration(migrate_types));
137 bool ShouldRunMigrationTest() const {
138 if (!ServerSupportsNotificationControl() ||
139 !ServerSupportsErrorTriggering()) {
140 LOG(WARNING) << "Test skipped in this server environment.";
146 // Makes sure migration works with the given migration list and
148 void RunMigrationTest(const MigrationList& migration_list,
149 TriggerMethod trigger_method) {
150 ASSERT_TRUE(ShouldRunMigrationTest());
152 // If we have only one client, turn off notifications to avoid the
153 // possibility of spurious sync cycles.
154 bool do_test_without_notifications =
155 (trigger_method != TRIGGER_NOTIFICATION && num_clients() == 1);
157 if (do_test_without_notifications) {
158 DisableNotifications();
161 // Phase 1: Trigger the migrations on the server.
162 for (MigrationList::const_iterator it = migration_list.begin();
163 it != migration_list.end(); ++it) {
164 TriggerMigrationDoneError(*it);
167 // Phase 2: Trigger each migration individually and wait for it to
168 // complete. (Multiple migrations may be handled by each
169 // migration cycle, but there's no guarantee of that, so we have
170 // to trigger each migration individually.)
171 for (MigrationList::const_iterator it = migration_list.begin();
172 it != migration_list.end(); ++it) {
173 TriggerMigration(*it, trigger_method);
177 // Phase 3: Wait for all clients to catch up.
179 // AwaitQuiescence() will not succeed when notifications are disabled. We
180 // can safely avoid calling it because we know that, in the single client
181 // case, there is no one else to wait for.
183 // TODO(rlarocque, 97780): Remove the if condition when the test harness
184 // supports calling AwaitQuiescence() when notifications are disabled.
185 if (!do_test_without_notifications) {
189 // TODO(rlarocque): It should be possible to re-enable notifications
190 // here, but doing so makes some windows tests flaky.
194 DISALLOW_COPY_AND_ASSIGN(MigrationTest);
197 class MigrationSingleClientTest : public MigrationTest {
199 MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT) {}
200 virtual ~MigrationSingleClientTest() {}
202 void RunSingleClientMigrationTest(const MigrationList& migration_list,
203 TriggerMethod trigger_method) {
204 if (!ShouldRunMigrationTest()) {
207 ASSERT_TRUE(SetupSync());
208 RunMigrationTest(migration_list, trigger_method);
212 DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest);
215 // The simplest possible migration tests -- a single data type.
217 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) {
218 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), MODIFY_PREF);
221 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) {
222 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
226 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
227 PrefsOnlyTriggerNotification) {
228 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
229 TRIGGER_NOTIFICATION);
232 // Nigori is handled specially, so we test that separately.
234 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) {
235 RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
236 TRIGGER_NOTIFICATION);
239 // A little more complicated -- two data types.
241 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
242 BookmarksPrefsIndividually) {
243 RunSingleClientMigrationTest(
244 MakeList(syncer::BOOKMARKS, syncer::PREFERENCES),
248 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) {
249 RunSingleClientMigrationTest(
250 MakeList(MakeSet(syncer::BOOKMARKS, syncer::PREFERENCES)),
254 // Two data types with one being nigori.
256 // See crbug.com/124480.
257 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
258 DISABLED_PrefsNigoriIndividiaully) {
259 RunSingleClientMigrationTest(
260 MakeList(syncer::PREFERENCES, syncer::NIGORI),
261 TRIGGER_NOTIFICATION);
264 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) {
265 RunSingleClientMigrationTest(
266 MakeList(MakeSet(syncer::PREFERENCES, syncer::NIGORI)),
270 // The whole shebang -- all data types.
272 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesIndividually) {
273 ASSERT_TRUE(SetupClients());
274 RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK);
277 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
278 AllTypesIndividuallyTriggerNotification) {
279 ASSERT_TRUE(SetupClients());
280 RunSingleClientMigrationTest(GetPreferredDataTypesList(),
281 TRIGGER_NOTIFICATION);
284 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) {
285 ASSERT_TRUE(SetupClients());
286 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
290 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
291 AllTypesAtOnceTriggerNotification) {
292 ASSERT_TRUE(SetupClients());
293 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
294 TRIGGER_NOTIFICATION);
297 // All data types plus nigori.
299 // See crbug.com/124480.
300 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
301 DISABLED_AllTypesWithNigoriIndividually) {
302 ASSERT_TRUE(SetupClients());
303 MigrationList migration_list = GetPreferredDataTypesList();
304 migration_list.push_front(MakeSet(syncer::NIGORI));
305 RunSingleClientMigrationTest(migration_list, MODIFY_BOOKMARK);
308 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
309 AllTypesWithNigoriAtOnce) {
310 ASSERT_TRUE(SetupClients());
311 syncer::ModelTypeSet all_types = GetPreferredDataTypes();
312 all_types.Put(syncer::NIGORI);
313 RunSingleClientMigrationTest(MakeList(all_types), MODIFY_PREF);
316 class MigrationTwoClientTest : public MigrationTest {
318 MigrationTwoClientTest() : MigrationTest(TWO_CLIENT) {}
319 virtual ~MigrationTwoClientTest() {}
321 // Helper function that verifies that preferences sync still works.
322 void VerifyPrefSync() {
323 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
324 ChangeBooleanPref(0, prefs::kShowHomeButton);
325 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
326 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton));
329 void RunTwoClientMigrationTest(const MigrationList& migration_list,
330 TriggerMethod trigger_method) {
331 if (!ShouldRunMigrationTest()) {
334 ASSERT_TRUE(SetupSync());
336 // Make sure pref sync works before running the migration test.
339 RunMigrationTest(migration_list, trigger_method);
341 // Make sure pref sync still works after running the migration
347 DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest);
350 // Easiest possible test of migration errors: triggers a server
351 // migration on one datatype, then modifies some other datatype.
352 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigratePrefsThenModifyBookmark) {
353 RunTwoClientMigrationTest(MakeList(syncer::PREFERENCES),
357 // Triggers a server migration on two datatypes, then makes a local
358 // modification to one of them.
359 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
360 MigratePrefsAndBookmarksThenModifyBookmark) {
361 RunTwoClientMigrationTest(
362 MakeList(syncer::PREFERENCES, syncer::BOOKMARKS),
366 // Migrate every datatype in sequence; the catch being that the server
367 // will only tell the client about the migrations one at a time.
368 // TODO(rsimha): This test takes longer than 60 seconds, and will cause tree
369 // redness due to sharding.
370 // Re-enable this test after syncer::kInitialBackoffShortRetrySeconds is reduced
372 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
373 DISABLED_MigrationHellWithoutNigori) {
374 ASSERT_TRUE(SetupClients());
375 MigrationList migration_list = GetPreferredDataTypesList();
376 // Let the first nudge be a datatype that's neither prefs nor
378 migration_list.push_front(MakeSet(syncer::THEMES));
379 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
382 // See crbug.com/124480.
383 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
384 DISABLED_MigrationHellWithNigori) {
385 ASSERT_TRUE(SetupClients());
386 MigrationList migration_list = GetPreferredDataTypesList();
387 // Let the first nudge be a datatype that's neither prefs nor
389 migration_list.push_front(MakeSet(syncer::THEMES));
390 // Pop off one so that we don't migrate all data types; the syncer
391 // freaks out if we do that (see http://crbug.com/94882).
392 ASSERT_GE(migration_list.size(), 2u);
393 ASSERT_FALSE(migration_list.back().Equals(MakeSet(syncer::NIGORI)));
394 migration_list.back() = MakeSet(syncer::NIGORI);
395 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
398 class MigrationReconfigureTest : public MigrationTwoClientTest {
400 MigrationReconfigureTest() {}
402 virtual void SetUpCommandLine(CommandLine* cl) OVERRIDE {
404 // Do not add optional datatypes.
407 virtual ~MigrationReconfigureTest() {}
410 DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest);