- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / test / integration / migration_errors_test.cc
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.
4
5 // TODO(akalin): Rename this file to migration_test.cc.
6
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"
17
18 using bookmarks_helper::AddURL;
19 using bookmarks_helper::IndexedURL;
20 using bookmarks_helper::IndexedURLTitle;
21
22 using preferences_helper::BooleanPrefMatches;
23 using preferences_helper::ChangeBooleanPref;
24
25 namespace {
26
27 // Utility functions to make a model type set out of a small number of
28 // model types.
29
30 syncer::ModelTypeSet MakeSet(syncer::ModelType type) {
31   return syncer::ModelTypeSet(type);
32 }
33
34 syncer::ModelTypeSet MakeSet(syncer::ModelType type1,
35                              syncer::ModelType type2) {
36   return syncer::ModelTypeSet(type1, type2);
37 }
38
39 // An ordered list of model types sets to migrate.  Used by
40 // RunMigrationTest().
41 typedef std::deque<syncer::ModelTypeSet> MigrationList;
42
43 // Utility functions to make a MigrationList out of a small number of
44 // model types / model type sets.
45
46 MigrationList MakeList(syncer::ModelTypeSet model_types) {
47   return MigrationList(1, model_types);
48 }
49
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;
56 }
57
58 MigrationList MakeList(syncer::ModelType type) {
59   return MakeList(MakeSet(type));
60 }
61
62 MigrationList MakeList(syncer::ModelType type1,
63                        syncer::ModelType type2) {
64   return MakeList(MakeSet(type1), MakeSet(type2));
65 }
66
67 class MigrationTest : public SyncTest {
68  public:
69   explicit MigrationTest(TestType test_type) : SyncTest(test_type) {}
70   virtual ~MigrationTest() {}
71
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 };
75
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));
88     }
89     return preferred_data_types;
90   }
91
92   // Returns a MigrationList with every enabled data type in its own
93   // set.
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()));
101     }
102     return migration_list;
103   }
104
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) {
109       case MODIFY_PREF:
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);
117         break;
118       case MODIFY_BOOKMARK:
119         ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))));
120         break;
121       case TRIGGER_NOTIFICATION:
122         TriggerNotification(model_types);
123         break;
124       default:
125         ADD_FAILURE();
126     }
127   }
128
129   // Block until all clients have completed migration for the given
130   // types.
131   void AwaitMigration(syncer::ModelTypeSet migrate_types) {
132     for (int i = 0; i < num_clients(); ++i) {
133       ASSERT_TRUE(GetClient(i)->AwaitMigration(migrate_types));
134     }
135   }
136
137   bool ShouldRunMigrationTest() const {
138     if (!ServerSupportsNotificationControl() ||
139         !ServerSupportsErrorTriggering()) {
140       LOG(WARNING) << "Test skipped in this server environment.";
141       return false;
142     }
143     return true;
144   }
145
146   // Makes sure migration works with the given migration list and
147   // trigger method.
148   void RunMigrationTest(const MigrationList& migration_list,
149                        TriggerMethod trigger_method) {
150     ASSERT_TRUE(ShouldRunMigrationTest());
151
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);
156
157     if (do_test_without_notifications) {
158       DisableNotifications();
159     }
160
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);
165     }
166
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);
174       AwaitMigration(*it);
175     }
176
177     // Phase 3: Wait for all clients to catch up.
178     //
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.
182     //
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) {
186       AwaitQuiescence();
187     }
188
189     // TODO(rlarocque): It should be possible to re-enable notifications
190     // here, but doing so makes some windows tests flaky.
191   }
192
193  private:
194   DISALLOW_COPY_AND_ASSIGN(MigrationTest);
195 };
196
197 class MigrationSingleClientTest : public MigrationTest {
198  public:
199   MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT) {}
200   virtual ~MigrationSingleClientTest() {}
201
202   void RunSingleClientMigrationTest(const MigrationList& migration_list,
203                                     TriggerMethod trigger_method) {
204     if (!ShouldRunMigrationTest()) {
205       return;
206     }
207     ASSERT_TRUE(SetupSync());
208     RunMigrationTest(migration_list, trigger_method);
209   }
210
211  private:
212   DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest);
213 };
214
215 // The simplest possible migration tests -- a single data type.
216
217 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) {
218   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), MODIFY_PREF);
219 }
220
221 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) {
222   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
223                                MODIFY_BOOKMARK);
224 }
225
226 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
227                        PrefsOnlyTriggerNotification) {
228   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
229                                TRIGGER_NOTIFICATION);
230 }
231
232 // Nigori is handled specially, so we test that separately.
233
234 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) {
235   RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
236                                TRIGGER_NOTIFICATION);
237 }
238
239 // A little more complicated -- two data types.
240
241 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
242                        BookmarksPrefsIndividually) {
243   RunSingleClientMigrationTest(
244       MakeList(syncer::BOOKMARKS, syncer::PREFERENCES),
245       MODIFY_PREF);
246 }
247
248 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) {
249   RunSingleClientMigrationTest(
250       MakeList(MakeSet(syncer::BOOKMARKS, syncer::PREFERENCES)),
251       MODIFY_BOOKMARK);
252 }
253
254 // Two data types with one being nigori.
255
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);
262 }
263
264 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) {
265   RunSingleClientMigrationTest(
266       MakeList(MakeSet(syncer::PREFERENCES, syncer::NIGORI)),
267       MODIFY_PREF);
268 }
269
270 // The whole shebang -- all data types.
271
272 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesIndividually) {
273   ASSERT_TRUE(SetupClients());
274   RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK);
275 }
276
277 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
278                        AllTypesIndividuallyTriggerNotification) {
279   ASSERT_TRUE(SetupClients());
280   RunSingleClientMigrationTest(GetPreferredDataTypesList(),
281                                TRIGGER_NOTIFICATION);
282 }
283
284 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) {
285   ASSERT_TRUE(SetupClients());
286   RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
287                                MODIFY_PREF);
288 }
289
290 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
291                        AllTypesAtOnceTriggerNotification) {
292   ASSERT_TRUE(SetupClients());
293   RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
294                                TRIGGER_NOTIFICATION);
295 }
296
297 // All data types plus nigori.
298
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);
306 }
307
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);
314 }
315
316 class MigrationTwoClientTest : public MigrationTest {
317  public:
318   MigrationTwoClientTest() : MigrationTest(TWO_CLIENT) {}
319   virtual ~MigrationTwoClientTest() {}
320
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));
327   }
328
329   void RunTwoClientMigrationTest(const MigrationList& migration_list,
330                                     TriggerMethod trigger_method) {
331     if (!ShouldRunMigrationTest()) {
332       return;
333     }
334     ASSERT_TRUE(SetupSync());
335
336     // Make sure pref sync works before running the migration test.
337     VerifyPrefSync();
338
339     RunMigrationTest(migration_list, trigger_method);
340
341     // Make sure pref sync still works after running the migration
342     // test.
343     VerifyPrefSync();
344   }
345
346  private:
347   DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest);
348 };
349
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),
354                             MODIFY_BOOKMARK);
355 }
356
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),
363       MODIFY_BOOKMARK);
364 }
365
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
371 // to zero.
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
377   // bookmarks.
378   migration_list.push_front(MakeSet(syncer::THEMES));
379   RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
380 }
381
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
388   // bookmarks.
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);
396 }
397
398 class MigrationReconfigureTest : public MigrationTwoClientTest {
399  public:
400   MigrationReconfigureTest() {}
401
402   virtual void SetUpCommandLine(CommandLine* cl) OVERRIDE {
403     AddTestSwitches(cl);
404     // Do not add optional datatypes.
405   }
406
407   virtual ~MigrationReconfigureTest() {}
408
409  private:
410   DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest);
411 };
412
413 }  // namespace