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