single_client_backup_rollback_test.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1// Copyright 2014 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 "base/command_line.h"
6#include "base/file_util.h"
7#include "base/message_loop/message_loop.h"
8#include "base/prefs/pref_service.h"
9#include "base/run_loop.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/sync/profile_sync_service.h"
12#include "chrome/browser/sync/test/integration/bookmarks_helper.h"
13#include "chrome/browser/sync/test/integration/preferences_helper.h"
14#include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
15#include "chrome/browser/sync/test/integration/sync_test.h"
16#include "chrome/common/chrome_switches.h"
17#include "chrome/common/pref_names.h"
18#include "components/bookmarks/browser/bookmark_model.h"
19#include "sync/internal_api/public/util/sync_db_util.h"
20#include "sync/test/fake_server/fake_server_verifier.h"
21#include "sync/util/time.h"
22
23using bookmarks_helper::AddFolder;
24using bookmarks_helper::AddURL;
25using bookmarks_helper::GetOtherNode;
26using bookmarks_helper::ModelMatchesVerifier;
27using bookmarks_helper::Move;
28using bookmarks_helper::Remove;
29using sync_integration_test_util::AwaitCommitActivityCompletion;
30
31namespace {
32const char kUrl1[] = "http://www.google.com";
33const char kUrl2[] = "http://map.google.com";
34const char kUrl3[] = "http://plus.google.com";
35}  // anonymous namespace
36
37class SingleClientBackupRollbackTest : public SyncTest {
38 public:
39  SingleClientBackupRollbackTest() : SyncTest(SINGLE_CLIENT) {}
40  virtual ~SingleClientBackupRollbackTest() {}
41
42  void DisableBackup() {
43    CommandLine::ForCurrentProcess()->AppendSwitch(
44          switches::kSyncDisableBackup);
45  }
46
47  void DisableRollback() {
48    CommandLine::ForCurrentProcess()->AppendSwitch(
49          switches::kSyncDisableRollback);
50  }
51
52  base::Time GetBackupDbLastModified() {
53    base::RunLoop run_loop;
54
55    base::Time backup_time;
56    syncer::CheckSyncDbLastModifiedTime(
57        GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup")),
58        base::MessageLoopProxy::current(),
59        base::Bind(&SingleClientBackupRollbackTest::CheckDbCallback,
60                   base::Unretained(this), &backup_time));
61    base::MessageLoopProxy::current()->PostTask(
62        FROM_HERE, run_loop.QuitClosure());
63    run_loop.Run();
64    return backup_time;
65  }
66
67 private:
68  void CheckDbCallback(base::Time* time_out, base::Time time_in) {
69    *time_out = syncer::ProtoTimeToTime(syncer::TimeToProtoTime(time_in));
70  }
71
72  DISALLOW_COPY_AND_ASSIGN(SingleClientBackupRollbackTest);
73};
74
75class SyncBackendStoppedChecker {
76 public:
77  explicit SyncBackendStoppedChecker(ProfileSyncService* service,
78                                     base::TimeDelta timeout)
79      : pss_(service),
80        timeout_(timeout) {}
81
82  bool Wait() {
83    expiration_ = base::TimeTicks::Now() + timeout_;
84    base::MessageLoop::current()->PostDelayedTask(
85        FROM_HERE,
86        base::Bind(&SyncBackendStoppedChecker::PeriodicCheck,
87                   base::Unretained(this)),
88        base::TimeDelta::FromSeconds(1));
89    base::MessageLoop::current()->Run();
90    return ProfileSyncService::IDLE == pss_->backend_mode();
91  }
92
93 private:
94  void PeriodicCheck() {
95    if (ProfileSyncService::IDLE == pss_->backend_mode() ||
96        base::TimeTicks::Now() > expiration_) {
97      base::MessageLoop::current()->Quit();
98    } else {
99      base::MessageLoop::current()->PostDelayedTask(
100          FROM_HERE,
101          base::Bind(&SyncBackendStoppedChecker::PeriodicCheck,
102                     base::Unretained(this)),
103          base::TimeDelta::FromSeconds(1));
104    }
105  }
106
107  ProfileSyncService* pss_;
108  base::TimeDelta timeout_;
109  base::TimeTicks expiration_;
110};
111
112#if defined(ENABLE_PRE_SYNC_BACKUP)
113#define MAYBE_TestBackup TestBackup
114#else
115#define MAYBE_TestBackup DISABLED_TestBackup
116#endif
117IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
118                       MAYBE_TestBackup) {
119  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
120
121  // Setup sync, wait for its completion, and make sure changes were synced.
122  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
123  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
124  ASSERT_TRUE(ModelMatchesVerifier(0));
125
126  // Verify backup DB is created and backup time is set on device info.
127  base::Time backup_time = GetBackupDbLastModified();
128  ASSERT_FALSE(backup_time.is_null());
129  ASSERT_EQ(backup_time, GetSyncService(0)->GetDeviceBackupTimeForTesting());
130}
131
132#if defined(ENABLE_PRE_SYNC_BACKUP)
133#define MAYBE_TestBackupDisabled TestBackupDisabled
134#else
135#define MAYBE_TestBackupDisabled DISABLED_TestBackupDisabled
136#endif
137IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
138                       MAYBE_TestBackupDisabled) {
139  DisableBackup();
140
141  // Setup sync, wait for its completion, and make sure changes were synced.
142  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
143  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
144  ASSERT_TRUE(ModelMatchesVerifier(0));
145
146  // Verify backup DB is not created and backup time is not set on device info.
147  ASSERT_FALSE(base::PathExists(
148      GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup"))));
149  ASSERT_TRUE(GetSyncService(0)->GetDeviceBackupTimeForTesting().is_null());
150}
151
152#if defined(ENABLE_PRE_SYNC_BACKUP)
153#define MAYBE_TestRollback TestRollback
154#else
155#define MAYBE_TestRollback DISABLED_TestRollback
156#endif
157IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
158                       MAYBE_TestRollback) {
159  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
160
161  // Starting state:
162  // other_node
163  //    -> top
164  //      -> tier1_a
165  //        -> http://mail.google.com  "tier1_a_url0"
166  //      -> tier1_b
167  //        -> http://www.nhl.com "tier1_b_url0"
168  const BookmarkNode* top = AddFolder(0, GetOtherNode(0), 0, "top");
169  const BookmarkNode* tier1_a = AddFolder(0, top, 0, "tier1_a");
170  const BookmarkNode* tier1_b = AddFolder(0, top, 1, "tier1_b");
171  ASSERT_TRUE(AddURL(0, tier1_a, 0, "tier1_a_url0",
172                     GURL("http://mail.google.com")));
173  ASSERT_TRUE(AddURL(0, tier1_b, 0, "tier1_b_url0",
174                     GURL("http://www.nhl.com")));
175
176  // Setup sync, wait for its completion, and make sure changes were synced.
177  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
178  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
179  ASSERT_TRUE(ModelMatchesVerifier(0));
180
181  // Made bookmark changes while sync is on.
182  Move(0, tier1_a->GetChild(0), tier1_b, 1);
183  Remove(0, tier1_b, 0);
184  ASSERT_TRUE(AddFolder(0, tier1_b, 1, "tier2_c"));
185  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
186  ASSERT_TRUE(ModelMatchesVerifier(0));
187
188  // Let server to return rollback command on next sync request.
189  GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK);
190
191  // Make another change to trigger downloading of rollback command.
192  Remove(0, tier1_b, 0);
193
194  // Wait for rollback to finish and sync backend is completely shut down.
195  SyncBackendStoppedChecker checker(GetSyncService(0),
196                                    base::TimeDelta::FromSeconds(5));
197  ASSERT_TRUE(checker.Wait());
198
199  // Verify bookmarks are restored.
200  ASSERT_EQ(1, tier1_a->child_count());
201  const BookmarkNode* url1 = tier1_a->GetChild(0);
202  ASSERT_EQ(GURL("http://mail.google.com"), url1->url());
203
204  ASSERT_EQ(1, tier1_b->child_count());
205  const BookmarkNode* url2 = tier1_b->GetChild(0);
206  ASSERT_EQ(GURL("http://www.nhl.com"), url2->url());
207
208  // Backup DB should be deleted after rollback is done.
209  ASSERT_FALSE(base::PathExists(
210      GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup"))));
211}
212
213#if defined(ENABLE_PRE_SYNC_BACKUP)
214#define MAYBE_TestRollbackDisabled TestRollbackDisabled
215#else
216#define MAYBE_TestRollbackDisabled DISABLED_TestRollbackDisabled
217#endif
218IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
219                       MAYBE_TestRollbackDisabled) {
220  DisableRollback();
221
222  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
223
224  // Starting state:
225  // other_node
226  //    -> http://mail.google.com  "url0"
227  //    -> http://www.nhl.com "url1"
228  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 0, "url0",
229                     GURL("http://mail.google.com")));
230  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url1",
231                     GURL("http://www.nhl.com")));
232
233  // Setup sync, wait for its completion, and make sure changes were synced.
234  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
235  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
236  ASSERT_TRUE(ModelMatchesVerifier(0));
237
238  // Made bookmark changes while sync is on.
239  Remove(0, GetOtherNode(0), 1);
240  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url2",
241                     GURL("http://www.yahoo.com")));
242  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
243  ASSERT_TRUE(ModelMatchesVerifier(0));
244
245  // Let server to return rollback command on next sync request.
246  GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK);
247
248  // Make another change to trigger downloading of rollback command.
249  Remove(0, GetOtherNode(0), 0);
250
251  // Wait for rollback to finish and sync backend is completely shut down.
252  SyncBackendStoppedChecker checker(GetSyncService(0),
253                                    base::TimeDelta::FromSeconds(5));
254  ASSERT_TRUE(checker.Wait());
255
256  // With rollback disabled, bookmarks in backup DB should not be restored.
257  // Only bookmark added during sync is present.
258  ASSERT_EQ(1, GetOtherNode(0)->child_count());
259  ASSERT_EQ(GURL("http://www.yahoo.com"),
260            GetOtherNode(0)->GetChild(0)->url());
261
262  // Backup DB should be deleted after.
263  ASSERT_FALSE(base::PathExists(
264      GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup"))));
265}
266
267#if defined(ENABLE_PRE_SYNC_BACKUP)
268#define MAYBE_TestSyncDisabled TestSyncDisabled
269#else
270#define MAYBE_TestSyncDisabled DISABLED_TestSyncDisabled
271#endif
272IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
273                       MAYBE_TestSyncDisabled) {
274  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
275
276  // Starting state:
277  // other_node
278  //    -> http://mail.google.com  "url0"
279  //    -> http://www.nhl.com "url1"
280  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 0, "url0",
281                     GURL("http://mail.google.com")));
282  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url1",
283                     GURL("http://www.nhl.com")));
284
285  // Setup sync, wait for its completion, and make sure changes were synced.
286  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
287  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
288  ASSERT_TRUE(ModelMatchesVerifier(0));
289
290  // Made bookmark changes while sync is on.
291  Remove(0, GetOtherNode(0), 1);
292  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url2",
293                     GURL("http://www.yahoo.com")));
294  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
295  ASSERT_TRUE(ModelMatchesVerifier(0));
296
297  // Let server to return birthday error on next sync request.
298  GetFakeServer()->TriggerError(sync_pb::SyncEnums::NOT_MY_BIRTHDAY);
299
300  // Make another change to trigger downloading of rollback command.
301  Remove(0, GetOtherNode(0), 0);
302
303  // Wait for rollback to finish and sync backend is completely shut down.
304  SyncBackendStoppedChecker checker(GetSyncService(0),
305                                    base::TimeDelta::FromSeconds(5));
306  ASSERT_TRUE(checker.Wait());
307
308  // Shouldn't restore bookmarks with sign-out only.
309  ASSERT_EQ(1, GetOtherNode(0)->child_count());
310  ASSERT_EQ(GURL("http://www.yahoo.com"),
311            GetOtherNode(0)->GetChild(0)->url());
312
313  // Backup DB should be deleted after.
314  ASSERT_FALSE(base::PathExists(
315      GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup"))));
316}
317
318#if defined(ENABLE_PRE_SYNC_BACKUP)
319#define MAYBE_RollbackNoBackup RollbackNoBackup
320#else
321#define MAYBE_RollbackNoBackup DISABLED_RollbackNoBackup
322#endif
323IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
324                       MAYBE_RollbackNoBackup) {
325  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
326
327  // Starting state:
328  // other_node
329  //    -> http://mail.google.com  "url0"
330  //    -> http://www.nhl.com "url1"
331  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 0, "url0",
332                     GURL("http://mail.google.com")));
333
334  // Setup sync, wait for its completion, and make sure changes were synced.
335  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
336  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
337  ASSERT_TRUE(ModelMatchesVerifier(0));
338
339  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url1",
340                     GURL("http://www.nhl.com")));
341
342  // Delete backup DB.
343  base::DeleteFile(
344      GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup")),
345      true);
346
347  // Let server to return rollback command on next sync request.
348  GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK);
349
350  // Make another change to trigger downloading of rollback command.
351  Remove(0, GetOtherNode(0), 0);
352
353  // Wait for backend to completely shut down.
354  SyncBackendStoppedChecker checker(GetSyncService(0),
355                                    base::TimeDelta::FromSeconds(15));
356  ASSERT_TRUE(checker.Wait());
357
358  // Without backup DB, bookmarks remain at the state when sync stops.
359  ASSERT_EQ(1, GetOtherNode(0)->child_count());
360  ASSERT_EQ(GURL("http://www.nhl.com"),
361            GetOtherNode(0)->GetChild(0)->url());
362}
363
364#if defined(ENABLE_PRE_SYNC_BACKUP)
365#define MAYBE_DontChangeBookmarkOrdering DontChangeBookmarkOrdering
366#else
367#define MAYBE_DontChangeBookmarkOrdering DISABLED_DontChangeBookmarkOrdering
368#endif
369IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
370                       MAYBE_DontChangeBookmarkOrdering) {
371  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
372
373  const BookmarkNode* sub_folder = AddFolder(0, GetOtherNode(0), 0, "test");
374  ASSERT_TRUE(AddURL(0, sub_folder, 0, "", GURL(kUrl1)));
375  ASSERT_TRUE(AddURL(0, sub_folder, 1, "", GURL(kUrl2)));
376  ASSERT_TRUE(AddURL(0, sub_folder, 2, "", GURL(kUrl3)));
377
378  // Setup sync, wait for its completion, and make sure changes were synced.
379  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
380  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
381  ASSERT_TRUE(ModelMatchesVerifier(0));
382
383  // Made bookmark changes while sync is on.
384  Remove(0, sub_folder, 0);
385  Remove(0, sub_folder, 0);
386  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
387  ASSERT_TRUE(ModelMatchesVerifier(0));
388
389  // Let server to return rollback command on next sync request.
390  GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK);
391
392  // Make another change to trigger downloading of rollback command.
393  Remove(0, sub_folder, 0);
394
395  // Wait for rollback to finish and sync backend is completely shut down.
396  SyncBackendStoppedChecker checker(GetSyncService(0),
397                                    base::TimeDelta::FromSeconds(5));
398  ASSERT_TRUE(checker.Wait());
399
400  // Verify bookmarks are unchanged.
401  ASSERT_EQ(3, sub_folder->child_count());
402  ASSERT_EQ(GURL(kUrl1), sub_folder->GetChild(0)->url());
403  ASSERT_EQ(GURL(kUrl2), sub_folder->GetChild(1)->url());
404  ASSERT_EQ(GURL(kUrl3), sub_folder->GetChild(2)->url());
405}
406