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.
5 #include "chrome/browser/sync/backend_migrator.h"
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"
22 using ::testing::Mock
;
23 using ::testing::NiceMock
;
24 using ::testing::Return
;
26 namespace browser_sync
{
28 using syncer::sessions::SyncSessionSnapshot
;
30 class SyncBackendMigratorTest
: public testing::Test
{
32 SyncBackendMigratorTest() : service_(&profile_
) { }
33 virtual ~SyncBackendMigratorTest() { }
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
);
43 ON_CALL(service_
, GetPreferredDataTypes()).
44 WillByDefault(Return(preferred_types_
));
48 "Profile0", test_user_share_
.user_share(), service(), manager(),
50 SetUnsyncedTypes(syncer::ModelTypeSet());
53 virtual void TearDown() {
55 test_user_share_
.TearDown();
58 // Marks all types in |unsynced_types| as unsynced and all other
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");
70 trans
.GetDirectory()->SetDownloadProgress(type
, progress_marker
);
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
);
80 std::map
<syncer::ModelType
, syncer::SyncError
> errors
;
81 DataTypeManager::ConfigureResult
result(
85 syncer::ModelTypeSet(),
86 syncer::ModelTypeSet());
87 migrator_
->OnConfigureDone(result
);
89 message_loop_
.RunUntilIdle();
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_
));
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_
;
114 class MockMigrationObserver
: public MigrationObserver
{
116 virtual ~MockMigrationObserver() {}
118 MOCK_METHOD0(OnMigrationStateChange
, void());
121 // Test that in the normal case a migration does transition through each state
122 // and wind up back in IDLE.
123 TEST_F(SyncBackendMigratorTest
, Sanity
) {
124 MockMigrationObserver migration_observer
;
125 migrator()->AddMigrationObserver(&migration_observer
);
126 EXPECT_CALL(migration_observer
, OnMigrationStateChange()).Times(4);
128 syncer::ModelTypeSet to_migrate
, difference
;
129 to_migrate
.Put(syncer::PREFERENCES
);
130 difference
.Put(syncer::AUTOFILL
);
131 difference
.Put(syncer::BOOKMARKS
);
133 EXPECT_CALL(*manager(), state())
134 .WillOnce(Return(DataTypeManager::CONFIGURED
));
137 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
140 Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
142 migrator()->MigrateTypes(to_migrate
);
143 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
145 SetUnsyncedTypes(to_migrate
);
146 SendConfigureDone(DataTypeManager::OK
, difference
);
147 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
149 SetUnsyncedTypes(syncer::ModelTypeSet());
150 SendConfigureDone(DataTypeManager::OK
, preferred_types());
151 EXPECT_EQ(BackendMigrator::IDLE
, migrator()->state());
153 migrator()->RemoveMigrationObserver(&migration_observer
);
156 // Test that in the normal case with Nigori a migration transitions through
157 // each state and wind up back in IDLE.
158 TEST_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
);
164 EXPECT_CALL(*manager(), state())
165 .WillOnce(Return(DataTypeManager::CONFIGURED
));
167 EXPECT_CALL(*manager(), PurgeForMigration(_
,
168 syncer::CONFIGURE_REASON_MIGRATION
));
170 migrator()->MigrateTypes(to_migrate
);
171 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
173 SetUnsyncedTypes(to_migrate
);
174 SendConfigureDone(DataTypeManager::OK
, difference
);
175 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
177 SetUnsyncedTypes(syncer::ModelTypeSet());
178 SendConfigureDone(DataTypeManager::OK
, preferred_types());
179 EXPECT_EQ(BackendMigrator::IDLE
, migrator()->state());
183 // Test that the migrator waits for the data type manager to be idle before
184 // starting a migration.
185 TEST_F(SyncBackendMigratorTest
, WaitToStart
) {
186 syncer::ModelTypeSet to_migrate
;
187 to_migrate
.Put(syncer::PREFERENCES
);
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());
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());
203 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
206 // Test that the migrator can cope with a migration request while a migration
208 TEST_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
);
216 EXPECT_CALL(*manager(), state())
217 .WillOnce(Return(DataTypeManager::CONFIGURED
));
220 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(2);
221 migrator()->MigrateTypes(to_migrate1
);
223 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
224 migrator()->MigrateTypes(to_migrate2
);
226 const syncer::ModelTypeSet difference1
=
227 Difference(preferred_types(), to_migrate1
);
229 Mock::VerifyAndClearExpectations(manager());
232 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
233 EXPECT_CALL(*manager(), Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
))
235 SetUnsyncedTypes(to_migrate1
);
236 SendConfigureDone(DataTypeManager::OK
, difference1
);
237 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
239 SetUnsyncedTypes(to_migrate_union
);
240 SendConfigureDone(DataTypeManager::OK
, bookmarks
);
241 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
244 // Test that an external invocation of Configure(...) during a migration results
245 // in a migration reattempt.
246 TEST_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
);
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());
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());
266 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
269 // Test that spurious OnConfigureDone events don't confuse the
270 // migrator while it's waiting for disabled types to have been purged
272 TEST_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
);
278 EXPECT_CALL(*manager(), state())
279 .WillOnce(Return(DataTypeManager::CONFIGURED
));
282 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
285 Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
287 migrator()->MigrateTypes(to_migrate
);
288 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
290 SendConfigureDone(DataTypeManager::OK
, difference
);
291 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
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());
299 SetUnsyncedTypes(to_migrate
);
300 SendConfigureDone(DataTypeManager::OK
, difference
);
301 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
304 TEST_F(SyncBackendMigratorTest
, MigratedTypeDisabledByUserDuringMigration
) {
305 syncer::ModelTypeSet to_migrate
;
306 to_migrate
.Put(syncer::PREFERENCES
);
308 EXPECT_CALL(*manager(), state())
309 .WillOnce(Return(DataTypeManager::CONFIGURED
));
312 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
315 Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
316 migrator()->MigrateTypes(to_migrate
);
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());
327 TEST_F(SyncBackendMigratorTest
, ConfigureFailure
) {
328 syncer::ModelTypeSet to_migrate
;
329 to_migrate
.Put(syncer::PREFERENCES
);
331 EXPECT_CALL(*manager(), state())
332 .WillOnce(Return(DataTypeManager::CONFIGURED
));
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());
342 }; // namespace browser_sync