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 #include "chrome/browser/sync/backend_migrator.h" 6 7 #include "base/message_loop/message_loop.h" 8 #include "base/tracked_objects.h" 9 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/sync/profile_sync_service_mock.h" 11 #include "components/sync_driver/data_type_manager_mock.h" 12 #include "sync/internal_api/public/base/model_type_test_util.h" 13 #include "sync/internal_api/public/test/test_user_share.h" 14 #include "sync/internal_api/public/write_transaction.h" 15 #include "sync/protocol/sync.pb.h" 16 #include "sync/syncable/directory.h" // TODO(tim): Remove. Bug 131130. 17 #include "testing/gmock/include/gmock/gmock.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 using ::testing::_; 21 using ::testing::Eq; 22 using ::testing::Mock; 23 using ::testing::NiceMock; 24 using ::testing::Return; 25 using sync_driver::DataTypeManager; 26 using sync_driver::DataTypeManagerMock; 27 28 namespace browser_sync { 29 30 using syncer::sessions::SyncSessionSnapshot; 31 32 class SyncBackendMigratorTest : public testing::Test { 33 public: 34 SyncBackendMigratorTest() : service_(&profile_) { } 35 virtual ~SyncBackendMigratorTest() { } 36 37 virtual void SetUp() { 38 test_user_share_.SetUp(); 39 Mock::VerifyAndClear(manager()); 40 Mock::VerifyAndClear(&service_); 41 preferred_types_.Put(syncer::BOOKMARKS); 42 preferred_types_.Put(syncer::PREFERENCES); 43 preferred_types_.Put(syncer::AUTOFILL); 44 45 ON_CALL(service_, GetPreferredDataTypes()). 46 WillByDefault(Return(preferred_types_)); 47 48 migrator_.reset( 49 new BackendMigrator( 50 "Profile0", test_user_share_.user_share(), service(), manager(), 51 base::Closure())); 52 SetUnsyncedTypes(syncer::ModelTypeSet()); 53 } 54 55 virtual void TearDown() { 56 migrator_.reset(); 57 test_user_share_.TearDown(); 58 } 59 60 // Marks all types in |unsynced_types| as unsynced and all other 61 // types as synced. 62 void SetUnsyncedTypes(syncer::ModelTypeSet unsynced_types) { 63 syncer::WriteTransaction trans(FROM_HERE, 64 test_user_share_.user_share()); 65 for (int i = syncer::FIRST_REAL_MODEL_TYPE; 66 i < syncer::MODEL_TYPE_COUNT; ++i) { 67 syncer::ModelType type = syncer::ModelTypeFromInt(i); 68 sync_pb::DataTypeProgressMarker progress_marker; 69 if (!unsynced_types.Has(type)) { 70 progress_marker.set_token("dummy"); 71 } 72 trans.GetDirectory()->SetDownloadProgress(type, progress_marker); 73 } 74 } 75 76 void SendConfigureDone(DataTypeManager::ConfigureStatus status, 77 syncer::ModelTypeSet requested_types) { 78 if (status == DataTypeManager::OK) { 79 DataTypeManager::ConfigureResult result(status, requested_types); 80 migrator_->OnConfigureDone(result); 81 } else { 82 DataTypeManager::ConfigureResult result( 83 status, 84 requested_types); 85 migrator_->OnConfigureDone(result); 86 } 87 message_loop_.RunUntilIdle(); 88 } 89 90 ProfileSyncService* service() { return &service_; } 91 DataTypeManagerMock* manager() { return &manager_; } 92 syncer::ModelTypeSet preferred_types() { return preferred_types_; } 93 BackendMigrator* migrator() { return migrator_.get(); } 94 void RemovePreferredType(syncer::ModelType type) { 95 preferred_types_.Remove(type); 96 Mock::VerifyAndClear(&service_); 97 ON_CALL(service_, GetPreferredDataTypes()). 98 WillByDefault(Return(preferred_types_)); 99 } 100 101 private: 102 scoped_ptr<SyncSessionSnapshot> snap_; 103 base::MessageLoop message_loop_; 104 syncer::ModelTypeSet preferred_types_; 105 TestingProfile profile_; 106 NiceMock<ProfileSyncServiceMock> service_; 107 NiceMock<DataTypeManagerMock> manager_; 108 syncer::TestUserShare test_user_share_; 109 scoped_ptr<BackendMigrator> migrator_; 110 }; 111 112 class MockMigrationObserver : public MigrationObserver { 113 public: 114 virtual ~MockMigrationObserver() {} 115 116 MOCK_METHOD0(OnMigrationStateChange, void()); 117 }; 118 119 // Test that in the normal case a migration does transition through each state 120 // and wind up back in IDLE. 121 TEST_F(SyncBackendMigratorTest, Sanity) { 122 MockMigrationObserver migration_observer; 123 migrator()->AddMigrationObserver(&migration_observer); 124 EXPECT_CALL(migration_observer, OnMigrationStateChange()).Times(4); 125 126 syncer::ModelTypeSet to_migrate, difference; 127 to_migrate.Put(syncer::PREFERENCES); 128 difference.Put(syncer::AUTOFILL); 129 difference.Put(syncer::BOOKMARKS); 130 131 EXPECT_CALL(*manager(), state()) 132 .WillOnce(Return(DataTypeManager::CONFIGURED)); 133 EXPECT_CALL( 134 *manager(), 135 PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 136 EXPECT_CALL( 137 *manager(), 138 Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 139 140 migrator()->MigrateTypes(to_migrate); 141 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 142 143 SetUnsyncedTypes(to_migrate); 144 SendConfigureDone(DataTypeManager::OK, difference); 145 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state()); 146 147 SetUnsyncedTypes(syncer::ModelTypeSet()); 148 SendConfigureDone(DataTypeManager::OK, preferred_types()); 149 EXPECT_EQ(BackendMigrator::IDLE, migrator()->state()); 150 151 migrator()->RemoveMigrationObserver(&migration_observer); 152 } 153 154 // Test that in the normal case with Nigori a migration transitions through 155 // each state and wind up back in IDLE. 156 TEST_F(SyncBackendMigratorTest, MigrateNigori) { 157 syncer::ModelTypeSet to_migrate, difference; 158 to_migrate.Put(syncer::NIGORI); 159 difference.Put(syncer::AUTOFILL); 160 difference.Put(syncer::BOOKMARKS); 161 162 EXPECT_CALL(*manager(), state()) 163 .WillOnce(Return(DataTypeManager::CONFIGURED)); 164 165 EXPECT_CALL(*manager(), PurgeForMigration(_, 166 syncer::CONFIGURE_REASON_MIGRATION)); 167 168 migrator()->MigrateTypes(to_migrate); 169 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 170 171 SetUnsyncedTypes(to_migrate); 172 SendConfigureDone(DataTypeManager::OK, difference); 173 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state()); 174 175 SetUnsyncedTypes(syncer::ModelTypeSet()); 176 SendConfigureDone(DataTypeManager::OK, preferred_types()); 177 EXPECT_EQ(BackendMigrator::IDLE, migrator()->state()); 178 } 179 180 181 // Test that the migrator waits for the data type manager to be idle before 182 // starting a migration. 183 TEST_F(SyncBackendMigratorTest, WaitToStart) { 184 syncer::ModelTypeSet to_migrate; 185 to_migrate.Put(syncer::PREFERENCES); 186 187 EXPECT_CALL(*manager(), state()) 188 .WillOnce(Return(DataTypeManager::CONFIGURING)); 189 EXPECT_CALL(*manager(), Configure(_, _)).Times(0); 190 migrator()->MigrateTypes(to_migrate); 191 EXPECT_EQ(BackendMigrator::WAITING_TO_START, migrator()->state()); 192 193 Mock::VerifyAndClearExpectations(manager()); 194 EXPECT_CALL(*manager(), state()) 195 .WillOnce(Return(DataTypeManager::CONFIGURED)); 196 EXPECT_CALL(*manager(), 197 PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)); 198 SetUnsyncedTypes(syncer::ModelTypeSet()); 199 SendConfigureDone(DataTypeManager::OK, syncer::ModelTypeSet()); 200 201 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 202 } 203 204 // Test that the migrator can cope with a migration request while a migration 205 // is in progress. 206 TEST_F(SyncBackendMigratorTest, RestartMigration) { 207 syncer::ModelTypeSet to_migrate1, to_migrate2, to_migrate_union, bookmarks; 208 to_migrate1.Put(syncer::PREFERENCES); 209 to_migrate2.Put(syncer::AUTOFILL); 210 to_migrate_union.Put(syncer::PREFERENCES); 211 to_migrate_union.Put(syncer::AUTOFILL); 212 bookmarks.Put(syncer::BOOKMARKS); 213 214 EXPECT_CALL(*manager(), state()) 215 .WillOnce(Return(DataTypeManager::CONFIGURED)); 216 EXPECT_CALL( 217 *manager(), 218 PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(2); 219 migrator()->MigrateTypes(to_migrate1); 220 221 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 222 migrator()->MigrateTypes(to_migrate2); 223 224 const syncer::ModelTypeSet difference1 = 225 Difference(preferred_types(), to_migrate1); 226 227 Mock::VerifyAndClearExpectations(manager()); 228 EXPECT_CALL( 229 *manager(), 230 PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 231 EXPECT_CALL(*manager(), Configure(_, syncer::CONFIGURE_REASON_MIGRATION)) 232 .Times(1); 233 SetUnsyncedTypes(to_migrate1); 234 SendConfigureDone(DataTypeManager::OK, difference1); 235 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 236 237 SetUnsyncedTypes(to_migrate_union); 238 SendConfigureDone(DataTypeManager::OK, bookmarks); 239 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state()); 240 } 241 242 // Test that an external invocation of Configure(...) during a migration results 243 // in a migration reattempt. 244 TEST_F(SyncBackendMigratorTest, InterruptedWhileDisablingTypes) { 245 syncer::ModelTypeSet to_migrate; 246 syncer::ModelTypeSet difference; 247 to_migrate.Put(syncer::PREFERENCES); 248 difference.Put(syncer::AUTOFILL); 249 difference.Put(syncer::BOOKMARKS); 250 251 EXPECT_CALL(*manager(), state()) 252 .WillOnce(Return(DataTypeManager::CONFIGURED)); 253 EXPECT_CALL(*manager(), PurgeForMigration(HasModelTypes(to_migrate), 254 syncer::CONFIGURE_REASON_MIGRATION)); 255 migrator()->MigrateTypes(to_migrate); 256 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 257 258 Mock::VerifyAndClearExpectations(manager()); 259 EXPECT_CALL(*manager(), PurgeForMigration(HasModelTypes(to_migrate), 260 syncer::CONFIGURE_REASON_MIGRATION)); 261 SetUnsyncedTypes(syncer::ModelTypeSet()); 262 SendConfigureDone(DataTypeManager::OK, preferred_types()); 263 264 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 265 } 266 267 // Test that spurious OnConfigureDone events don't confuse the 268 // migrator while it's waiting for disabled types to have been purged 269 // from the sync db. 270 TEST_F(SyncBackendMigratorTest, WaitingForPurge) { 271 syncer::ModelTypeSet to_migrate, difference; 272 to_migrate.Put(syncer::PREFERENCES); 273 to_migrate.Put(syncer::AUTOFILL); 274 difference.Put(syncer::BOOKMARKS); 275 276 EXPECT_CALL(*manager(), state()) 277 .WillOnce(Return(DataTypeManager::CONFIGURED)); 278 EXPECT_CALL( 279 *manager(), 280 PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 281 EXPECT_CALL( 282 *manager(), 283 Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 284 285 migrator()->MigrateTypes(to_migrate); 286 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 287 288 SendConfigureDone(DataTypeManager::OK, difference); 289 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 290 291 syncer::ModelTypeSet prefs; 292 prefs.Put(syncer::PREFERENCES); 293 SetUnsyncedTypes(prefs); 294 SendConfigureDone(DataTypeManager::OK, difference); 295 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state()); 296 297 SetUnsyncedTypes(to_migrate); 298 SendConfigureDone(DataTypeManager::OK, difference); 299 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state()); 300 } 301 302 TEST_F(SyncBackendMigratorTest, MigratedTypeDisabledByUserDuringMigration) { 303 syncer::ModelTypeSet to_migrate; 304 to_migrate.Put(syncer::PREFERENCES); 305 306 EXPECT_CALL(*manager(), state()) 307 .WillOnce(Return(DataTypeManager::CONFIGURED)); 308 EXPECT_CALL( 309 *manager(), 310 PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 311 EXPECT_CALL( 312 *manager(), 313 Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 314 migrator()->MigrateTypes(to_migrate); 315 316 RemovePreferredType(syncer::PREFERENCES); 317 SetUnsyncedTypes(to_migrate); 318 SendConfigureDone(DataTypeManager::OK, preferred_types()); 319 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state()); 320 SetUnsyncedTypes(syncer::ModelTypeSet()); 321 SendConfigureDone(DataTypeManager::OK, preferred_types()); 322 EXPECT_EQ(BackendMigrator::IDLE, migrator()->state()); 323 } 324 325 TEST_F(SyncBackendMigratorTest, ConfigureFailure) { 326 syncer::ModelTypeSet to_migrate; 327 to_migrate.Put(syncer::PREFERENCES); 328 329 EXPECT_CALL(*manager(), state()) 330 .WillOnce(Return(DataTypeManager::CONFIGURED)); 331 EXPECT_CALL( 332 *manager(), 333 PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1); 334 migrator()->MigrateTypes(to_migrate); 335 SetUnsyncedTypes(syncer::ModelTypeSet()); 336 SendConfigureDone(DataTypeManager::ABORTED, syncer::ModelTypeSet()); 337 EXPECT_EQ(BackendMigrator::IDLE, migrator()->state()); 338 } 339 340 }; // namespace browser_sync 341