1 // Copyright (c) 2011 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 "chrome/browser/sync/glue/data_type_manager_mock.h" 8 #include "chrome/browser/sync/profile_sync_service_mock.h" 9 #include "chrome/browser/sync/sessions/session_state.h" 10 #include "testing/gmock/include/gmock/gmock.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 using ::testing::_; 14 using ::testing::Eq; 15 using ::testing::Mock; 16 using ::testing::NiceMock; 17 using ::testing::Return; 18 using ::testing::SetArgumentPointee; 19 20 namespace browser_sync { 21 22 using sessions::ErrorCounters; 23 using sessions::SyncerStatus; 24 using sessions::SyncSessionSnapshot; 25 26 class BackendMigratorTest : public testing::Test { 27 public: 28 BackendMigratorTest() { } 29 virtual ~BackendMigratorTest() { } 30 31 virtual void SetUp() { 32 Mock::VerifyAndClear(manager()); 33 Mock::VerifyAndClear(&service_); 34 preferred_types_.insert(syncable::BOOKMARKS); 35 preferred_types_.insert(syncable::PREFERENCES); 36 preferred_types_.insert(syncable::AUTOFILL); 37 38 ON_CALL(service_, GetPreferredDataTypes(_)). 39 WillByDefault(SetArgumentPointee<0>(preferred_types_)); 40 } 41 42 void ReturnEmptyProgressMarkersInSnapshot() { 43 ReturnNonEmptyProgressMarkersInSnapshot(syncable::ModelTypeSet()); 44 } 45 46 void ReturnNonEmptyProgressMarkersInSnapshot( 47 const syncable::ModelTypeSet& for_types) { 48 std::string download_progress_markers[syncable::MODEL_TYPE_COUNT]; 49 for (syncable::ModelTypeSet::const_iterator it = for_types.begin(); 50 it != for_types.end(); ++it) { 51 download_progress_markers[*it] = "foobar"; 52 } 53 54 snap_.reset(new SyncSessionSnapshot(SyncerStatus(), ErrorCounters(), 55 0, false, syncable::ModelTypeBitSet(), download_progress_markers, 56 false, false, 0, 0, false, sessions::SyncSourceInfo())); 57 EXPECT_CALL(service_, GetLastSessionSnapshot()) 58 .WillOnce(Return(snap_.get())); 59 } 60 61 void SendConfigureDone(DataTypeManager::ConfigureResult result, 62 const syncable::ModelTypeSet& types) { 63 DataTypeManager::ConfigureResultWithErrorLocation result_with_location( 64 result, FROM_HERE, types); 65 NotificationService::current()->Notify( 66 NotificationType::SYNC_CONFIGURE_DONE, 67 Source<DataTypeManager>(&manager_), 68 Details<DataTypeManager::ConfigureResultWithErrorLocation>( 69 &result_with_location)); 70 } 71 72 ProfileSyncService* service() { return &service_; } 73 DataTypeManagerMock* manager() { return &manager_; } 74 const syncable::ModelTypeSet& preferred_types() { return preferred_types_; } 75 void RemovePreferredType(syncable::ModelType type) { 76 preferred_types_.erase(type); 77 Mock::VerifyAndClear(&service_); 78 ON_CALL(service_, GetPreferredDataTypes(_)). 79 WillByDefault(SetArgumentPointee<0>(preferred_types_)); 80 } 81 private: 82 scoped_ptr<SyncSessionSnapshot> snap_; 83 syncable::ModelTypeSet preferred_types_; 84 NiceMock<ProfileSyncServiceMock> service_; 85 NiceMock<DataTypeManagerMock> manager_; 86 }; 87 88 // Test that in the normal case a migration does transition through each state 89 // and wind up back in IDLE. 90 TEST_F(BackendMigratorTest, Sanity) { 91 BackendMigrator migrator(service(), manager()); 92 syncable::ModelTypeSet to_migrate, difference; 93 to_migrate.insert(syncable::PREFERENCES); 94 difference.insert(syncable::AUTOFILL); 95 difference.insert(syncable::BOOKMARKS); 96 97 EXPECT_CALL(*manager(), state()) 98 .WillOnce(Return(DataTypeManager::CONFIGURED)); 99 EXPECT_CALL(*manager(), Configure(_)); 100 101 migrator.MigrateTypes(to_migrate); 102 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 103 104 SendConfigureDone(DataTypeManager::OK, difference); 105 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state()); 106 107 ReturnEmptyProgressMarkersInSnapshot(); 108 EXPECT_CALL(*manager(), Configure(preferred_types())); 109 migrator.OnStateChanged(); 110 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state()); 111 112 SendConfigureDone(DataTypeManager::OK, preferred_types()); 113 EXPECT_EQ(BackendMigrator::IDLE, migrator.state()); 114 } 115 116 // Test that the migrator waits for the data type manager to be idle before 117 // starting a migration. 118 TEST_F(BackendMigratorTest, WaitToStart) { 119 BackendMigrator migrator(service(), manager()); 120 syncable::ModelTypeSet to_migrate; 121 to_migrate.insert(syncable::PREFERENCES); 122 123 EXPECT_CALL(*manager(), state()) 124 .WillOnce(Return(DataTypeManager::CONFIGURING)); 125 EXPECT_CALL(*manager(), Configure(_)).Times(0); 126 migrator.MigrateTypes(to_migrate); 127 EXPECT_EQ(BackendMigrator::WAITING_TO_START, migrator.state()); 128 129 Mock::VerifyAndClearExpectations(manager()); 130 EXPECT_CALL(*manager(), state()) 131 .WillOnce(Return(DataTypeManager::CONFIGURED)); 132 EXPECT_CALL(*manager(), Configure(_)); 133 SendConfigureDone(DataTypeManager::OK, syncable::ModelTypeSet()); 134 135 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 136 } 137 138 // Test that the migrator can cope with a migration request while a migration 139 // is in progress. 140 TEST_F(BackendMigratorTest, RestartMigration) { 141 BackendMigrator migrator(service(), manager()); 142 syncable::ModelTypeSet to_migrate1, to_migrate2, bookmarks; 143 to_migrate1.insert(syncable::PREFERENCES); 144 to_migrate2.insert(syncable::AUTOFILL); 145 bookmarks.insert(syncable::BOOKMARKS); 146 147 EXPECT_CALL(*manager(), state()) 148 .WillOnce(Return(DataTypeManager::CONFIGURED)); 149 EXPECT_CALL(*manager(), Configure(_)).Times(1); 150 migrator.MigrateTypes(to_migrate1); 151 152 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 153 migrator.MigrateTypes(to_migrate2); 154 155 syncable::ModelTypeSet difference1; 156 std::set_difference(preferred_types().begin(), preferred_types().end(), 157 to_migrate1.begin(), to_migrate1.end(), 158 std::inserter(difference1, difference1.end())); 159 160 Mock::VerifyAndClearExpectations(manager()); 161 EXPECT_CALL(*manager(), state()) 162 .WillOnce(Return(DataTypeManager::CONFIGURED)); 163 EXPECT_CALL(*manager(), Configure(bookmarks)); 164 SendConfigureDone(DataTypeManager::OK, difference1); 165 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 166 167 SendConfigureDone(DataTypeManager::OK, bookmarks); 168 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state()); 169 } 170 171 // Test that an external invocation of Configure(...) during a migration results 172 // in a migration reattempt. 173 TEST_F(BackendMigratorTest, InterruptedWhileDisablingTypes) { 174 BackendMigrator migrator(service(), manager()); 175 syncable::ModelTypeSet to_migrate; 176 syncable::ModelTypeSet difference; 177 to_migrate.insert(syncable::PREFERENCES); 178 difference.insert(syncable::AUTOFILL); 179 difference.insert(syncable::BOOKMARKS); 180 181 EXPECT_CALL(*manager(), state()) 182 .WillOnce(Return(DataTypeManager::CONFIGURED)); 183 EXPECT_CALL(*manager(), Configure(difference)); 184 migrator.MigrateTypes(to_migrate); 185 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 186 187 Mock::VerifyAndClearExpectations(manager()); 188 EXPECT_CALL(*manager(), state()) 189 .WillOnce(Return(DataTypeManager::CONFIGURED)); 190 EXPECT_CALL(*manager(), Configure(difference)); 191 SendConfigureDone(DataTypeManager::OK, preferred_types()); 192 193 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 194 } 195 196 // Test that spurious OnStateChanged events don't confuse the migrator while 197 // it's waiting for disabled types to have been purged from the sync db. 198 TEST_F(BackendMigratorTest, WaitingForPurge) { 199 BackendMigrator migrator(service(), manager()); 200 syncable::ModelTypeSet to_migrate, difference; 201 to_migrate.insert(syncable::PREFERENCES); 202 to_migrate.insert(syncable::AUTOFILL); 203 difference.insert(syncable::BOOKMARKS); 204 205 EXPECT_CALL(*manager(), state()) 206 .WillOnce(Return(DataTypeManager::CONFIGURED)); 207 EXPECT_CALL(*manager(), Configure(_)); 208 migrator.MigrateTypes(to_migrate); 209 SendConfigureDone(DataTypeManager::OK, difference); 210 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state()); 211 212 ReturnNonEmptyProgressMarkersInSnapshot(to_migrate); 213 migrator.OnStateChanged(); 214 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state()); 215 216 syncable::ModelTypeSet prefs; 217 prefs.insert(syncable::PREFERENCES); 218 ReturnNonEmptyProgressMarkersInSnapshot(prefs); 219 migrator.OnStateChanged(); 220 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state()); 221 222 syncable::ModelTypeSet bookmarks; 223 bookmarks.insert(syncable::BOOKMARKS); 224 ReturnNonEmptyProgressMarkersInSnapshot(bookmarks); 225 EXPECT_CALL(*manager(), Configure(preferred_types())); 226 migrator.OnStateChanged(); 227 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state()); 228 } 229 230 TEST_F(BackendMigratorTest, MigratedTypeDisabledByUserDuringMigration) { 231 BackendMigrator migrator(service(), manager()); 232 syncable::ModelTypeSet to_migrate; 233 to_migrate.insert(syncable::PREFERENCES); 234 235 EXPECT_CALL(*manager(), state()) 236 .WillOnce(Return(DataTypeManager::CONFIGURED)); 237 EXPECT_CALL(*manager(), Configure(_)); 238 migrator.MigrateTypes(to_migrate); 239 240 RemovePreferredType(syncable::PREFERENCES); 241 SendConfigureDone(DataTypeManager::OK, preferred_types()); 242 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state()); 243 244 Mock::VerifyAndClearExpectations(manager()); 245 ReturnEmptyProgressMarkersInSnapshot(); 246 EXPECT_CALL(*manager(), Configure(preferred_types())); 247 migrator.OnStateChanged(); 248 249 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state()); 250 SendConfigureDone(DataTypeManager::OK, preferred_types()); 251 EXPECT_EQ(BackendMigrator::IDLE, migrator.state()); 252 } 253 254 TEST_F(BackendMigratorTest, ConfigureFailure) { 255 BackendMigrator migrator(service(), manager()); 256 syncable::ModelTypeSet to_migrate; 257 to_migrate.insert(syncable::PREFERENCES); 258 259 EXPECT_CALL(*manager(), state()) 260 .WillOnce(Return(DataTypeManager::CONFIGURED)); 261 EXPECT_CALL(*manager(), Configure(_)).Times(1); 262 migrator.MigrateTypes(to_migrate); 263 SendConfigureDone(DataTypeManager::ABORTED, syncable::ModelTypeSet()); 264 EXPECT_EQ(BackendMigrator::IDLE, migrator.state()); 265 } 266 267 }; // namespace browser_sync 268