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