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 "chrome/browser/sync/backend_migrator.h"
6
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"
19
20using ::testing::_;
21using ::testing::Eq;
22using ::testing::Mock;
23using ::testing::NiceMock;
24using ::testing::Return;
25using sync_driver::DataTypeManager;
26using sync_driver::DataTypeManagerMock;
27
28namespace browser_sync {
29
30using syncer::sessions::SyncSessionSnapshot;
31
32class SyncBackendMigratorTest : public testing::Test {
33 public:
34  SyncBackendMigratorTest() : service_(&profile_) { }
35  virtual ~SyncBackendMigratorTest() { }
36
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);
44
45    ON_CALL(service_, GetPreferredDataTypes()).
46        WillByDefault(Return(preferred_types_));
47
48    migrator_.reset(
49        new BackendMigrator(
50            "Profile0", test_user_share_.user_share(), service(), manager(),
51            base::Closure()));
52    SetUnsyncedTypes(syncer::ModelTypeSet());
53  }
54
55  virtual void TearDown() {
56    migrator_.reset();
57    test_user_share_.TearDown();
58  }
59
60  // Marks all types in |unsynced_types| as unsynced  and all other
61  // types as synced.
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");
71      }
72      trans.GetDirectory()->SetDownloadProgress(type, progress_marker);
73    }
74  }
75
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);
81    } else {
82      DataTypeManager::ConfigureResult result(
83          status,
84          requested_types);
85      migrator_->OnConfigureDone(result);
86    }
87    message_loop_.RunUntilIdle();
88  }
89
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_));
99  }
100
101 private:
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_;
110};
111
112class MockMigrationObserver : public MigrationObserver {
113 public:
114  virtual ~MockMigrationObserver() {}
115
116  MOCK_METHOD0(OnMigrationStateChange, void());
117};
118
119// Test that in the normal case a migration does transition through each state
120// and wind up back in IDLE.
121TEST_F(SyncBackendMigratorTest, Sanity) {
122  MockMigrationObserver migration_observer;
123  migrator()->AddMigrationObserver(&migration_observer);
124  EXPECT_CALL(migration_observer, OnMigrationStateChange()).Times(4);
125
126  syncer::ModelTypeSet to_migrate, difference;
127  to_migrate.Put(syncer::PREFERENCES);
128  difference.Put(syncer::AUTOFILL);
129  difference.Put(syncer::BOOKMARKS);
130
131  EXPECT_CALL(*manager(), state())
132      .WillOnce(Return(DataTypeManager::CONFIGURED));
133  EXPECT_CALL(
134      *manager(),
135      PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
136  EXPECT_CALL(
137      *manager(),
138      Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
139
140  migrator()->MigrateTypes(to_migrate);
141  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
142
143  SetUnsyncedTypes(to_migrate);
144  SendConfigureDone(DataTypeManager::OK, difference);
145  EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
146
147  SetUnsyncedTypes(syncer::ModelTypeSet());
148  SendConfigureDone(DataTypeManager::OK, preferred_types());
149  EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
150
151  migrator()->RemoveMigrationObserver(&migration_observer);
152}
153
154// Test that in the normal case with Nigori a migration transitions through
155// each state and wind up back in IDLE.
156TEST_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);
161
162  EXPECT_CALL(*manager(), state())
163      .WillOnce(Return(DataTypeManager::CONFIGURED));
164
165  EXPECT_CALL(*manager(), PurgeForMigration(_,
166      syncer::CONFIGURE_REASON_MIGRATION));
167
168  migrator()->MigrateTypes(to_migrate);
169  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
170
171  SetUnsyncedTypes(to_migrate);
172  SendConfigureDone(DataTypeManager::OK, difference);
173  EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
174
175  SetUnsyncedTypes(syncer::ModelTypeSet());
176  SendConfigureDone(DataTypeManager::OK, preferred_types());
177  EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
178}
179
180
181// Test that the migrator waits for the data type manager to be idle before
182// starting a migration.
183TEST_F(SyncBackendMigratorTest, WaitToStart) {
184  syncer::ModelTypeSet to_migrate;
185  to_migrate.Put(syncer::PREFERENCES);
186
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());
192
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());
200
201  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
202}
203
204// Test that the migrator can cope with a migration request while a migration
205// is in progress.
206TEST_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);
213
214  EXPECT_CALL(*manager(), state())
215      .WillOnce(Return(DataTypeManager::CONFIGURED));
216  EXPECT_CALL(
217      *manager(),
218      PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(2);
219  migrator()->MigrateTypes(to_migrate1);
220
221  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
222  migrator()->MigrateTypes(to_migrate2);
223
224  const syncer::ModelTypeSet difference1 =
225      Difference(preferred_types(), to_migrate1);
226
227  Mock::VerifyAndClearExpectations(manager());
228  EXPECT_CALL(
229      *manager(),
230      PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
231  EXPECT_CALL(*manager(), Configure(_, syncer::CONFIGURE_REASON_MIGRATION))
232      .Times(1);
233  SetUnsyncedTypes(to_migrate1);
234  SendConfigureDone(DataTypeManager::OK, difference1);
235  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
236
237  SetUnsyncedTypes(to_migrate_union);
238  SendConfigureDone(DataTypeManager::OK, bookmarks);
239  EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
240}
241
242// Test that an external invocation of Configure(...) during a migration results
243// in a migration reattempt.
244TEST_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);
250
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());
257
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());
263
264  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
265}
266
267// Test that spurious OnConfigureDone events don't confuse the
268// migrator while it's waiting for disabled types to have been purged
269// from the sync db.
270TEST_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);
275
276  EXPECT_CALL(*manager(), state())
277      .WillOnce(Return(DataTypeManager::CONFIGURED));
278  EXPECT_CALL(
279      *manager(),
280      PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
281  EXPECT_CALL(
282      *manager(),
283      Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
284
285  migrator()->MigrateTypes(to_migrate);
286  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
287
288  SendConfigureDone(DataTypeManager::OK, difference);
289  EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
290
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());
296
297  SetUnsyncedTypes(to_migrate);
298  SendConfigureDone(DataTypeManager::OK, difference);
299  EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
300}
301
302TEST_F(SyncBackendMigratorTest, MigratedTypeDisabledByUserDuringMigration) {
303  syncer::ModelTypeSet to_migrate;
304  to_migrate.Put(syncer::PREFERENCES);
305
306  EXPECT_CALL(*manager(), state())
307      .WillOnce(Return(DataTypeManager::CONFIGURED));
308  EXPECT_CALL(
309      *manager(),
310      PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
311  EXPECT_CALL(
312      *manager(),
313      Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
314  migrator()->MigrateTypes(to_migrate);
315
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());
323}
324
325TEST_F(SyncBackendMigratorTest, ConfigureFailure) {
326  syncer::ModelTypeSet to_migrate;
327  to_migrate.Put(syncer::PREFERENCES);
328
329  EXPECT_CALL(*manager(), state())
330      .WillOnce(Return(DataTypeManager::CONFIGURED));
331  EXPECT_CALL(
332      *manager(),
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());
338}
339
340};  // namespace browser_sync
341