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