migration_test.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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/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"
19
20using bookmarks_helper::AddURL;
21using bookmarks_helper::IndexedURL;
22using bookmarks_helper::IndexedURLTitle;
23
24using preferences_helper::BooleanPrefMatches;
25using preferences_helper::ChangeBooleanPref;
26
27namespace {
28
29// Utility functions to make a model type set out of a small number of
30// model types.
31
32syncer::ModelTypeSet MakeSet(syncer::ModelType type) {
33  return syncer::ModelTypeSet(type);
34}
35
36syncer::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().
43typedef 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
48MigrationList MakeList(syncer::ModelTypeSet model_types) {
49  return MigrationList(1, model_types);
50}
51
52MigrationList 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
60MigrationList MakeList(syncer::ModelType type) {
61  return MakeList(MakeSet(type));
62}
63
64MigrationList MakeList(syncer::ModelType type1,
65                       syncer::ModelType type2) {
66  return MakeList(MakeSet(type1), MakeSet(type2));
67}
68
69
70class MigrationTest : public SyncTest  {
71 public:
72  explicit MigrationTest(TestType test_type) : SyncTest(test_type) {}
73  virtual ~MigrationTest() {}
74
75  enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_NOTIFICATION };
76
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())
82      return false;
83
84    for (int i = 0; i < num_clients(); ++i) {
85      MigrationWatcher* watcher = new MigrationWatcher(GetClient(i));
86      migration_watchers_.push_back(watcher);
87    }
88    return true;
89  }
90
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());
98
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);
102
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));
108    }
109    return preferred_data_types;
110  }
111
112  // Returns a MigrationList with every enabled data type in its own
113  // set.
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()));
121    }
122    return migration_list;
123  }
124
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) {
129      case MODIFY_PREF:
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);
137        break;
138      case MODIFY_BOOKMARK:
139        ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))));
140        break;
141      case TRIGGER_NOTIFICATION:
142        TriggerNotification(model_types);
143        break;
144      default:
145        ADD_FAILURE();
146    }
147  }
148
149  // Block until all clients have completed migration for the given
150  // types.
151  void AwaitMigration(syncer::ModelTypeSet migrate_types) {
152    for (int i = 0; i < num_clients(); ++i) {
153      MigrationWaiter waiter(migrate_types, migration_watchers_[i]);
154      waiter.Wait();
155      ASSERT_FALSE(waiter.TimedOut());
156    }
157  }
158
159  // Makes sure migration works with the given migration list and
160  // trigger method.
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);
167
168    if (do_test_without_notifications) {
169      DisableNotifications();
170    }
171
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());
175    }
176
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);
181    }
182
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);
190      AwaitMigration(*it);
191    }
192
193    // Phase 3: Wait for all clients to catch up.
194    //
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.
198    //
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) {
202      AwaitQuiescence();
203    }
204
205    // TODO(rlarocque): It should be possible to re-enable notifications
206    // here, but doing so makes some windows tests flaky.
207  }
208
209 private:
210  // Used to keep track of the migration progress for each sync client.
211  ScopedVector<MigrationWatcher> migration_watchers_;
212
213  DISALLOW_COPY_AND_ASSIGN(MigrationTest);
214};
215
216class MigrationSingleClientTest : public MigrationTest {
217 public:
218  MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT_LEGACY) {}
219  virtual ~MigrationSingleClientTest() {}
220
221  void RunSingleClientMigrationTest(const MigrationList& migration_list,
222                                    TriggerMethod trigger_method) {
223    ASSERT_TRUE(SetupSync());
224    RunMigrationTest(migration_list, trigger_method);
225  }
226
227 private:
228  DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest);
229};
230
231// The simplest possible migration tests -- a single data type.
232
233IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) {
234  RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES), MODIFY_PREF);
235}
236
237IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) {
238  RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
239                               MODIFY_BOOKMARK);
240}
241
242IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
243                       PrefsOnlyTriggerNotification) {
244  RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
245                               TRIGGER_NOTIFICATION);
246}
247
248// Nigori is handled specially, so we test that separately.
249
250IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) {
251  RunSingleClientMigrationTest(MakeList(syncer::PREFERENCES),
252                               TRIGGER_NOTIFICATION);
253}
254
255// A little more complicated -- two data types.
256
257IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsIndividually) {
258  RunSingleClientMigrationTest(
259      MakeList(syncer::BOOKMARKS, syncer::PREFERENCES),
260      MODIFY_PREF);
261}
262
263IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) {
264  RunSingleClientMigrationTest(
265      MakeList(MakeSet(syncer::BOOKMARKS, syncer::PREFERENCES)),
266      MODIFY_BOOKMARK);
267}
268
269// Two data types with one being nigori.
270
271// See crbug.com/124480.
272IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
273                       DISABLED_PrefsNigoriIndividiaully) {
274  RunSingleClientMigrationTest(
275      MakeList(syncer::PREFERENCES, syncer::NIGORI),
276      TRIGGER_NOTIFICATION);
277}
278
279IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) {
280  RunSingleClientMigrationTest(
281      MakeList(MakeSet(syncer::PREFERENCES, syncer::NIGORI)),
282      MODIFY_PREF);
283}
284
285// The whole shebang -- all data types.
286#if defined(OS_WIN)
287// http://crbug.com/403778
288#define MAYBE_AllTypesIndividually DISABLED_AllTypesIndividually
289#else
290#define MAYBE_AllTypesIndividually AllTypesIndividually
291#endif
292IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, MAYBE_AllTypesIndividually) {
293  ASSERT_TRUE(SetupClients());
294  RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK);
295}
296
297#if defined(OS_WIN)
298// http://crbug.com/403778
299#define MAYBE_AllTypesIndividuallyTriggerNotification DISABLED_AllTypesIndividuallyTriggerNotification
300#else
301#define MAYBE_AllTypesIndividuallyTriggerNotification AllTypesIndividuallyTriggerNotification
302#endif
303IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
304                       MAYBE_AllTypesIndividuallyTriggerNotification) {
305  ASSERT_TRUE(SetupClients());
306  RunSingleClientMigrationTest(GetPreferredDataTypesList(),
307                               TRIGGER_NOTIFICATION);
308}
309
310IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) {
311  ASSERT_TRUE(SetupClients());
312  RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
313                               MODIFY_PREF);
314}
315
316IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest,
317                       AllTypesAtOnceTriggerNotification) {
318  ASSERT_TRUE(SetupClients());
319  RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()),
320                               TRIGGER_NOTIFICATION);
321}
322
323// All data types plus nigori.
324
325// See crbug.com/124480.
326IN_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);
332}
333
334IN_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);
339}
340
341class MigrationTwoClientTest : public MigrationTest {
342 public:
343  MigrationTwoClientTest() : MigrationTest(TWO_CLIENT_LEGACY) {}
344  virtual ~MigrationTwoClientTest() {}
345
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));
352  }
353
354  void RunTwoClientMigrationTest(const MigrationList& migration_list,
355                                 TriggerMethod trigger_method) {
356    ASSERT_TRUE(SetupSync());
357
358    // Make sure pref sync works before running the migration test.
359    VerifyPrefSync();
360
361    RunMigrationTest(migration_list, trigger_method);
362
363    // Make sure pref sync still works after running the migration
364    // test.
365    VerifyPrefSync();
366  }
367
368 private:
369  DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest);
370};
371
372// Easiest possible test of migration errors: triggers a server
373// migration on one datatype, then modifies some other datatype.
374IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigratePrefsThenModifyBookmark) {
375  RunTwoClientMigrationTest(MakeList(syncer::PREFERENCES),
376                            MODIFY_BOOKMARK);
377}
378
379// Triggers a server migration on two datatypes, then makes a local
380// modification to one of them.
381IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest,
382                       MigratePrefsAndBookmarksThenModifyBookmark) {
383  RunTwoClientMigrationTest(
384      MakeList(syncer::PREFERENCES, syncer::BOOKMARKS),
385      MODIFY_BOOKMARK);
386}
387
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
393// to zero.
394IN_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
399  // bookmarks.
400  migration_list.push_front(MakeSet(syncer::THEMES));
401  RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK);
402}
403
404// See crbug.com/124480.
405IN_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
410  // bookmarks.
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);
418}
419
420class MigrationReconfigureTest : public MigrationTwoClientTest {
421 public:
422  MigrationReconfigureTest() {}
423
424  virtual void SetUpCommandLine(base::CommandLine* cl) OVERRIDE {
425    AddTestSwitches(cl);
426    // Do not add optional datatypes.
427  }
428
429  virtual ~MigrationReconfigureTest() {}
430
431 private:
432  DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest);
433};
434
435}  // namespace
436