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/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"
22 using ::testing::Mock
;
23 using ::testing::NiceMock
;
24 using ::testing::Return
;
25 using sync_driver::DataTypeManager
;
26 using sync_driver::DataTypeManagerMock
;
28 namespace browser_sync
{
30 using syncer::sessions::SyncSessionSnapshot
;
32 class SyncBackendMigratorTest
: public testing::Test
{
34 SyncBackendMigratorTest() : service_(&profile_
) { }
35 virtual ~SyncBackendMigratorTest() { }
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
);
45 ON_CALL(service_
, GetPreferredDataTypes()).
46 WillByDefault(Return(preferred_types_
));
50 "Profile0", test_user_share_
.user_share(), service(), manager(),
52 SetUnsyncedTypes(syncer::ModelTypeSet());
55 virtual void TearDown() {
57 test_user_share_
.TearDown();
60 // Marks all types in |unsynced_types| as unsynced and all other
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");
72 trans
.GetDirectory()->SetDownloadProgress(type
, progress_marker
);
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
);
82 DataTypeManager::ConfigureResult
result(
85 migrator_
->OnConfigureDone(result
);
87 message_loop_
.RunUntilIdle();
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_
));
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_
;
112 class MockMigrationObserver
: public MigrationObserver
{
114 virtual ~MockMigrationObserver() {}
116 MOCK_METHOD0(OnMigrationStateChange
, void());
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);
126 syncer::ModelTypeSet to_migrate
, difference
;
127 to_migrate
.Put(syncer::PREFERENCES
);
128 difference
.Put(syncer::AUTOFILL
);
129 difference
.Put(syncer::BOOKMARKS
);
131 EXPECT_CALL(*manager(), state())
132 .WillOnce(Return(DataTypeManager::CONFIGURED
));
135 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
138 Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
140 migrator()->MigrateTypes(to_migrate
);
141 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
143 SetUnsyncedTypes(to_migrate
);
144 SendConfigureDone(DataTypeManager::OK
, difference
);
145 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
147 SetUnsyncedTypes(syncer::ModelTypeSet());
148 SendConfigureDone(DataTypeManager::OK
, preferred_types());
149 EXPECT_EQ(BackendMigrator::IDLE
, migrator()->state());
151 migrator()->RemoveMigrationObserver(&migration_observer
);
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
);
162 EXPECT_CALL(*manager(), state())
163 .WillOnce(Return(DataTypeManager::CONFIGURED
));
165 EXPECT_CALL(*manager(), PurgeForMigration(_
,
166 syncer::CONFIGURE_REASON_MIGRATION
));
168 migrator()->MigrateTypes(to_migrate
);
169 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
171 SetUnsyncedTypes(to_migrate
);
172 SendConfigureDone(DataTypeManager::OK
, difference
);
173 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
175 SetUnsyncedTypes(syncer::ModelTypeSet());
176 SendConfigureDone(DataTypeManager::OK
, preferred_types());
177 EXPECT_EQ(BackendMigrator::IDLE
, migrator()->state());
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
);
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());
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());
201 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
204 // Test that the migrator can cope with a migration request while a migration
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
);
214 EXPECT_CALL(*manager(), state())
215 .WillOnce(Return(DataTypeManager::CONFIGURED
));
218 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(2);
219 migrator()->MigrateTypes(to_migrate1
);
221 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
222 migrator()->MigrateTypes(to_migrate2
);
224 const syncer::ModelTypeSet difference1
=
225 Difference(preferred_types(), to_migrate1
);
227 Mock::VerifyAndClearExpectations(manager());
230 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
231 EXPECT_CALL(*manager(), Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
))
233 SetUnsyncedTypes(to_migrate1
);
234 SendConfigureDone(DataTypeManager::OK
, difference1
);
235 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
237 SetUnsyncedTypes(to_migrate_union
);
238 SendConfigureDone(DataTypeManager::OK
, bookmarks
);
239 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
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
);
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());
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());
264 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
267 // Test that spurious OnConfigureDone events don't confuse the
268 // migrator while it's waiting for disabled types to have been purged
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
);
276 EXPECT_CALL(*manager(), state())
277 .WillOnce(Return(DataTypeManager::CONFIGURED
));
280 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
283 Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
285 migrator()->MigrateTypes(to_migrate
);
286 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
288 SendConfigureDone(DataTypeManager::OK
, difference
);
289 EXPECT_EQ(BackendMigrator::DISABLING_TYPES
, migrator()->state());
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());
297 SetUnsyncedTypes(to_migrate
);
298 SendConfigureDone(DataTypeManager::OK
, difference
);
299 EXPECT_EQ(BackendMigrator::REENABLING_TYPES
, migrator()->state());
302 TEST_F(SyncBackendMigratorTest
, MigratedTypeDisabledByUserDuringMigration
) {
303 syncer::ModelTypeSet to_migrate
;
304 to_migrate
.Put(syncer::PREFERENCES
);
306 EXPECT_CALL(*manager(), state())
307 .WillOnce(Return(DataTypeManager::CONFIGURED
));
310 PurgeForMigration(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
313 Configure(_
, syncer::CONFIGURE_REASON_MIGRATION
)).Times(1);
314 migrator()->MigrateTypes(to_migrate
);
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());
325 TEST_F(SyncBackendMigratorTest
, ConfigureFailure
) {
326 syncer::ModelTypeSet to_migrate
;
327 to_migrate
.Put(syncer::PREFERENCES
);
329 EXPECT_CALL(*manager(), state())
330 .WillOnce(Return(DataTypeManager::CONFIGURED
));
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());
340 }; // namespace browser_sync