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