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 "components/sync/driver/backend_migrator.h"
6
7 #include <memory>
8
9 #include "base/run_loop.h"
10 #include "base/test/mock_callback.h"
11 #include "base/test/task_environment.h"
12 #include "components/sync/base/model_type_test_util.h"
13 #include "components/sync/driver/data_type_manager_mock.h"
14 #include "components/sync/protocol/sync.pb.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 using ::testing::_;
19 using ::testing::Eq;
20 using ::testing::Mock;
21 using ::testing::NiceMock;
22 using ::testing::Return;
23
24 namespace syncer {
25
26 class SyncBackendMigratorTest : public testing::Test {
27 public:
SyncBackendMigratorTest()28 SyncBackendMigratorTest() {}
~SyncBackendMigratorTest()29 ~SyncBackendMigratorTest() override {}
30
SetUp()31 void SetUp() override {
32 Mock::VerifyAndClear(manager());
33 preferred_types_.Put(BOOKMARKS);
34 preferred_types_.Put(PREFERENCES);
35 preferred_types_.Put(AUTOFILL);
36
37 migrator_ = std::make_unique<BackendMigrator>(
38 "Profile0", manager(), reconfigure_callback()->Get(),
39 migration_done_callback()->Get());
40 SetUnsyncedTypes(ModelTypeSet());
41 }
42
TearDown()43 void TearDown() override {
44 migrator_.reset();
45 }
46
47 // Marks all types in |unsynced_types| as unsynced and all other
48 // types as synced.
SetUnsyncedTypes(ModelTypeSet unsynced_types)49 void SetUnsyncedTypes(ModelTypeSet unsynced_types) {
50 ON_CALL(manager_, GetPurgedDataTypes())
51 .WillByDefault(Return(unsynced_types));
52 }
53
SendConfigureDone(DataTypeManager::ConfigureStatus status,ModelTypeSet requested_types)54 void SendConfigureDone(DataTypeManager::ConfigureStatus status,
55 ModelTypeSet requested_types) {
56 if (status == DataTypeManager::OK) {
57 DataTypeManager::ConfigureResult result(status, requested_types);
58 migrator_->OnConfigureDone(result);
59 } else {
60 DataTypeManager::ConfigureResult result(status, requested_types);
61 migrator_->OnConfigureDone(result);
62 }
63 base::RunLoop run_loop;
64 run_loop.RunUntilIdle();
65 }
66
manager()67 DataTypeManagerMock* manager() { return &manager_; }
preferred_types()68 ModelTypeSet preferred_types() { return preferred_types_; }
reconfigure_callback()69 base::MockCallback<base::RepeatingClosure>* reconfigure_callback() {
70 return &reconfigure_callback_;
71 }
migration_done_callback()72 base::MockCallback<base::RepeatingClosure>* migration_done_callback() {
73 return &migration_done_callback_;
74 }
migrator()75 BackendMigrator* migrator() { return migrator_.get(); }
76
77 private:
78 base::test::SingleThreadTaskEnvironment task_environment_;
79 ModelTypeSet preferred_types_;
80 NiceMock<DataTypeManagerMock> manager_;
81 NiceMock<base::MockCallback<base::RepeatingClosure>> reconfigure_callback_;
82 NiceMock<base::MockCallback<base::RepeatingClosure>> migration_done_callback_;
83 std::unique_ptr<BackendMigrator> migrator_;
84 };
85
86 class MockMigrationObserver : public MigrationObserver {
87 public:
~MockMigrationObserver()88 ~MockMigrationObserver() override {}
89
90 MOCK_METHOD(void, OnMigrationStateChange, ());
91 };
92
93 // Test that in the normal case a migration does transition through each state
94 // and wind up back in IDLE.
TEST_F(SyncBackendMigratorTest,Sanity)95 TEST_F(SyncBackendMigratorTest, Sanity) {
96 EXPECT_CALL(*migration_done_callback(), Run()).Times(0);
97
98 MockMigrationObserver migration_observer;
99 migrator()->AddMigrationObserver(&migration_observer);
100 EXPECT_CALL(migration_observer, OnMigrationStateChange()).Times(4);
101
102 ModelTypeSet to_migrate, difference;
103 to_migrate.Put(PREFERENCES);
104 difference.Put(AUTOFILL);
105 difference.Put(BOOKMARKS);
106
107 EXPECT_CALL(*manager(), state())
108 .WillOnce(Return(DataTypeManager::CONFIGURED));
109 EXPECT_CALL(*manager(), PurgeForMigration(_));
110 EXPECT_CALL(*reconfigure_callback(), Run());
111
112 migrator()->MigrateTypes(to_migrate);
113 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
114
115 SetUnsyncedTypes(to_migrate);
116 SendConfigureDone(DataTypeManager::OK, difference);
117 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
118
119 EXPECT_CALL(*migration_done_callback(), Run());
120 SetUnsyncedTypes(ModelTypeSet());
121 SendConfigureDone(DataTypeManager::OK, preferred_types());
122 EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
123
124 migrator()->RemoveMigrationObserver(&migration_observer);
125 }
126
127 // Test that in the normal case with Nigori a migration transitions through
128 // each state and wind up back in IDLE.
TEST_F(SyncBackendMigratorTest,MigrateNigori)129 TEST_F(SyncBackendMigratorTest, MigrateNigori) {
130 EXPECT_CALL(*migration_done_callback(), Run()).Times(0);
131
132 ModelTypeSet to_migrate, difference;
133 to_migrate.Put(NIGORI);
134 difference.Put(AUTOFILL);
135 difference.Put(BOOKMARKS);
136
137 EXPECT_CALL(*manager(), state())
138 .WillOnce(Return(DataTypeManager::CONFIGURED));
139
140 EXPECT_CALL(*manager(), PurgeForMigration(_));
141
142 migrator()->MigrateTypes(to_migrate);
143 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
144
145 EXPECT_CALL(*reconfigure_callback(), Run());
146 SetUnsyncedTypes(to_migrate);
147 SendConfigureDone(DataTypeManager::OK, difference);
148 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
149
150 EXPECT_CALL(*migration_done_callback(), Run());
151 SetUnsyncedTypes(ModelTypeSet());
152 SendConfigureDone(DataTypeManager::OK, preferred_types());
153 EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
154 }
155
156 // Test that the migrator waits for the data type manager to be idle before
157 // starting a migration.
TEST_F(SyncBackendMigratorTest,WaitToStart)158 TEST_F(SyncBackendMigratorTest, WaitToStart) {
159 ModelTypeSet to_migrate;
160 to_migrate.Put(PREFERENCES);
161
162 EXPECT_CALL(*manager(), state())
163 .WillOnce(Return(DataTypeManager::CONFIGURING));
164 EXPECT_CALL(*reconfigure_callback(), Run()).Times(0);
165 migrator()->MigrateTypes(to_migrate);
166 EXPECT_EQ(BackendMigrator::WAITING_TO_START, migrator()->state());
167
168 Mock::VerifyAndClearExpectations(manager());
169 EXPECT_CALL(*manager(), state())
170 .WillOnce(Return(DataTypeManager::CONFIGURED));
171 EXPECT_CALL(*manager(), PurgeForMigration(_));
172 SetUnsyncedTypes(ModelTypeSet());
173 SendConfigureDone(DataTypeManager::OK, ModelTypeSet());
174
175 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
176 }
177
178 // Test that the migrator can cope with a migration request while a migration
179 // is in progress.
TEST_F(SyncBackendMigratorTest,RestartMigration)180 TEST_F(SyncBackendMigratorTest, RestartMigration) {
181 ModelTypeSet to_migrate1, to_migrate2, to_migrate_union, bookmarks;
182 to_migrate1.Put(PREFERENCES);
183 to_migrate2.Put(AUTOFILL);
184 to_migrate_union.Put(PREFERENCES);
185 to_migrate_union.Put(AUTOFILL);
186 bookmarks.Put(BOOKMARKS);
187
188 EXPECT_CALL(*manager(), state())
189 .WillOnce(Return(DataTypeManager::CONFIGURED));
190 EXPECT_CALL(*manager(), PurgeForMigration(_)).Times(2);
191 migrator()->MigrateTypes(to_migrate1);
192
193 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
194 migrator()->MigrateTypes(to_migrate2);
195
196 const ModelTypeSet difference1 = Difference(preferred_types(), to_migrate1);
197
198 Mock::VerifyAndClearExpectations(manager());
199 EXPECT_CALL(*manager(), PurgeForMigration(_));
200 EXPECT_CALL(*reconfigure_callback(), Run());
201 SetUnsyncedTypes(to_migrate1);
202 SendConfigureDone(DataTypeManager::OK, difference1);
203 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
204
205 SetUnsyncedTypes(to_migrate_union);
206 SendConfigureDone(DataTypeManager::OK, bookmarks);
207 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
208 }
209
210 // Test that an external invocation of Configure(...) during a migration results
211 // in a migration reattempt.
TEST_F(SyncBackendMigratorTest,InterruptedWhileDisablingTypes)212 TEST_F(SyncBackendMigratorTest, InterruptedWhileDisablingTypes) {
213 ModelTypeSet to_migrate;
214 ModelTypeSet difference;
215 to_migrate.Put(PREFERENCES);
216 difference.Put(AUTOFILL);
217 difference.Put(BOOKMARKS);
218
219 EXPECT_CALL(*manager(), state())
220 .WillOnce(Return(DataTypeManager::CONFIGURED));
221 EXPECT_CALL(*manager(), PurgeForMigration(HasModelTypes(to_migrate)));
222 migrator()->MigrateTypes(to_migrate);
223 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
224
225 Mock::VerifyAndClearExpectations(manager());
226 EXPECT_CALL(*manager(), PurgeForMigration(HasModelTypes(to_migrate)));
227 SetUnsyncedTypes(ModelTypeSet());
228 SendConfigureDone(DataTypeManager::OK, preferred_types());
229
230 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
231 }
232
233 // Test that spurious OnConfigureDone events don't confuse the
234 // migrator while it's waiting for disabled types to have been purged
235 // from the sync db.
TEST_F(SyncBackendMigratorTest,WaitingForPurge)236 TEST_F(SyncBackendMigratorTest, WaitingForPurge) {
237 ModelTypeSet to_migrate, difference;
238 to_migrate.Put(PREFERENCES);
239 to_migrate.Put(AUTOFILL);
240 difference.Put(BOOKMARKS);
241
242 EXPECT_CALL(*manager(), state())
243 .WillOnce(Return(DataTypeManager::CONFIGURED));
244 EXPECT_CALL(*manager(), PurgeForMigration(_));
245 EXPECT_CALL(*reconfigure_callback(), Run());
246
247 migrator()->MigrateTypes(to_migrate);
248 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
249
250 SendConfigureDone(DataTypeManager::OK, difference);
251 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
252
253 ModelTypeSet prefs;
254 prefs.Put(PREFERENCES);
255 SetUnsyncedTypes(prefs);
256 SendConfigureDone(DataTypeManager::OK, difference);
257 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
258
259 SetUnsyncedTypes(to_migrate);
260 SendConfigureDone(DataTypeManager::OK, difference);
261 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
262 }
263
TEST_F(SyncBackendMigratorTest,ConfigureFailure)264 TEST_F(SyncBackendMigratorTest, ConfigureFailure) {
265 ModelTypeSet to_migrate;
266 to_migrate.Put(PREFERENCES);
267
268 EXPECT_CALL(*manager(), state())
269 .WillOnce(Return(DataTypeManager::CONFIGURED));
270 EXPECT_CALL(*manager(), PurgeForMigration(_));
271 migrator()->MigrateTypes(to_migrate);
272 SetUnsyncedTypes(ModelTypeSet());
273 SendConfigureDone(DataTypeManager::ABORTED, ModelTypeSet());
274 EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
275 }
276
277 } // namespace syncer
278