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