Home | History | Annotate | Download | only in integration
      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 "chrome/browser/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
    414