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