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 "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/sync/profile_sync_service.h"
10 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
11 #include "chrome/browser/sync/test/integration/preferences_helper.h"
12 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
13 #include "chrome/browser/sync/test/integration/sync_test.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/pref_names.h"
16 #include "components/bookmarks/browser/bookmark_model.h"
17 #include "sync/test/fake_server/fake_server_verifier.h"
18
19 using bookmarks_helper::AddFolder;
20 using bookmarks_helper::AddURL;
21 using bookmarks_helper::GetOtherNode;
22 using bookmarks_helper::ModelMatchesVerifier;
23 using bookmarks_helper::Move;
24 using bookmarks_helper::Remove;
25 using sync_integration_test_util::AwaitCommitActivityCompletion;
26
27 namespace {
28 const char kUrl1[] = "http://www.google.com";
29 const char kUrl2[] = "http://map.google.com";
30 const char kUrl3[] = "http://plus.google.com";
31 } // anonymous namespace
32
33 class SingleClientBackupRollbackTest : public SyncTest {
34 public:
SingleClientBackupRollbackTest()35 SingleClientBackupRollbackTest() : SyncTest(SINGLE_CLIENT) {}
~SingleClientBackupRollbackTest()36 virtual ~SingleClientBackupRollbackTest() {}
37
DisableBackup()38 void DisableBackup() {
39 CommandLine::ForCurrentProcess()->AppendSwitch(
40 switches::kSyncDisableBackup);
41 }
42
EnableRollback()43 void EnableRollback() {
44 CommandLine::ForCurrentProcess()->AppendSwitch(
45 switches::kSyncEnableRollback);
46 }
47
48 private:
49 DISALLOW_COPY_AND_ASSIGN(SingleClientBackupRollbackTest);
50 };
51
52 class BackupModeChecker {
53 public:
BackupModeChecker(ProfileSyncService * service,base::TimeDelta timeout)54 explicit BackupModeChecker(ProfileSyncService* service,
55 base::TimeDelta timeout)
56 : pss_(service),
57 timeout_(timeout) {}
58
Wait()59 bool Wait() {
60 expiration_ = base::TimeTicks::Now() + timeout_;
61 base::MessageLoop::current()->PostDelayedTask(
62 FROM_HERE,
63 base::Bind(&BackupModeChecker::PeriodicCheck, base::Unretained(this)),
64 base::TimeDelta::FromSeconds(1));
65 base::MessageLoop::current()->Run();
66 return IsBackupComplete();
67 }
68
69 private:
PeriodicCheck()70 void PeriodicCheck() {
71 if (IsBackupComplete() || base::TimeTicks::Now() > expiration_) {
72 base::MessageLoop::current()->Quit();
73 } else {
74 base::MessageLoop::current()->PostDelayedTask(
75 FROM_HERE,
76 base::Bind(&BackupModeChecker::PeriodicCheck, base::Unretained(this)),
77 base::TimeDelta::FromSeconds(1));
78 }
79 }
80
IsBackupComplete()81 bool IsBackupComplete() {
82 return pss_->backend_mode() == ProfileSyncService::BACKUP &&
83 pss_->ShouldPushChanges();
84 }
85
86 ProfileSyncService* pss_;
87 base::TimeDelta timeout_;
88 base::TimeTicks expiration_;
89 };
90
91 #if defined(ENABLE_PRE_SYNC_BACKUP)
92 #define MAYBE_TestBackupRollback TestBackupRollback
93 #else
94 #define MAYBE_TestBackupRollback DISABLED_TestBackupRollback
95 #endif
IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,MAYBE_TestBackupRollback)96 IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
97 MAYBE_TestBackupRollback) {
98 EnableRollback();
99 ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
100
101 // Starting state:
102 // other_node
103 // -> top
104 // -> tier1_a
105 // -> http://mail.google.com "tier1_a_url0"
106 // -> tier1_b
107 // -> http://www.nhl.com "tier1_b_url0"
108 const BookmarkNode* top = AddFolder(0, GetOtherNode(0), 0, "top");
109 const BookmarkNode* tier1_a = AddFolder(0, top, 0, "tier1_a");
110 const BookmarkNode* tier1_b = AddFolder(0, top, 1, "tier1_b");
111 ASSERT_TRUE(AddURL(0, tier1_a, 0, "tier1_a_url0",
112 GURL("http://mail.google.com")));
113 ASSERT_TRUE(AddURL(0, tier1_b, 0, "tier1_b_url0",
114 GURL("http://www.nhl.com")));
115
116 BackupModeChecker checker(GetSyncService(0),
117 base::TimeDelta::FromSeconds(15));
118 ASSERT_TRUE(checker.Wait());
119
120 // Setup sync, wait for its completion, and make sure changes were synced.
121 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
122 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
123 ASSERT_TRUE(ModelMatchesVerifier(0));
124
125 // Made bookmark changes while sync is on.
126 Move(0, tier1_a->GetChild(0), tier1_b, 1);
127 Remove(0, tier1_b, 0);
128 ASSERT_TRUE(AddFolder(0, tier1_b, 1, "tier2_c"));
129 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
130 ASSERT_TRUE(ModelMatchesVerifier(0));
131
132 // Let server to return rollback command on next sync request.
133 GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK);
134
135 // Make another change to trigger downloading of rollback command.
136 Remove(0, tier1_b, 0);
137
138 // Wait for sync to switch to backup mode after finishing rollback.
139 ASSERT_TRUE(checker.Wait());
140
141 // Verify bookmarks are restored.
142 ASSERT_EQ(1, tier1_a->child_count());
143 const BookmarkNode* url1 = tier1_a->GetChild(0);
144 ASSERT_EQ(GURL("http://mail.google.com"), url1->url());
145
146 ASSERT_EQ(1, tier1_b->child_count());
147 const BookmarkNode* url2 = tier1_b->GetChild(0);
148 ASSERT_EQ(GURL("http://www.nhl.com"), url2->url());
149 }
150
151 #if defined(ENABLE_PRE_SYNC_BACKUP)
152 #define MAYBE_TestPrefBackupRollback TestPrefBackupRollback
153 #else
154 #define MAYBE_TestPrefBackupRollback DISABLED_TestPrefBackupRollback
155 #endif
156 // Verify local preferences are not affected by preferences in backup DB under
157 // backup mode.
IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,MAYBE_TestPrefBackupRollback)158 IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
159 MAYBE_TestPrefBackupRollback) {
160 EnableRollback();
161
162 ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
163
164 preferences_helper::ChangeStringPref(0, prefs::kHomePage, kUrl1);
165
166 BackupModeChecker checker(GetSyncService(0),
167 base::TimeDelta::FromSeconds(15));
168 ASSERT_TRUE(checker.Wait());
169
170 // Shut down backup, then change preference.
171 GetSyncService(0)->StartStopBackupForTesting();
172 preferences_helper::ChangeStringPref(0, prefs::kHomePage, kUrl2);
173
174 // Restart backup. Preference shouldn't change after backup starts.
175 GetSyncService(0)->StartStopBackupForTesting();
176 ASSERT_TRUE(checker.Wait());
177 ASSERT_EQ(kUrl2,
178 preferences_helper::GetPrefs(0)->GetString(prefs::kHomePage));
179
180 // Start sync and change preference.
181 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
182 preferences_helper::ChangeStringPref(0, prefs::kHomePage, kUrl3);
183 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
184 ASSERT_TRUE(ModelMatchesVerifier(0));
185
186 // Let server return rollback command on next sync request.
187 GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK);
188
189 // Make another change to trigger downloading of rollback command.
190 preferences_helper::ChangeStringPref(0, prefs::kHomePage, "");
191
192 // Wait for sync to switch to backup mode after finishing rollback.
193 ASSERT_TRUE(checker.Wait());
194
195 // Verify preference is restored.
196 ASSERT_EQ(kUrl2,
197 preferences_helper::GetPrefs(0)->GetString(prefs::kHomePage));
198 }
199
200 #if defined(ENABLE_PRE_SYNC_BACKUP)
201 #define MAYBE_RollbackNoBackup RollbackNoBackup
202 #else
203 #define MAYBE_RollbackNoBackup DISABLED_RollbackNoBackup
204 #endif
IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,MAYBE_RollbackNoBackup)205 IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
206 MAYBE_RollbackNoBackup) {
207 EnableRollback();
208
209 ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
210
211 // Setup sync, wait for its completion, and make sure changes were synced.
212 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
213
214 // Starting state:
215 // other_node
216 // -> http://mail.google.com "url0"
217 // -> http://www.nhl.com "url1"
218 ASSERT_TRUE(AddURL(0, GetOtherNode(0), 0, "url0",
219 GURL("http://mail.google.com")));
220 ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url1",
221 GURL("http://www.nhl.com")));
222
223 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
224 ASSERT_TRUE(ModelMatchesVerifier(0));
225
226 // Let server to return rollback command on next sync request.
227 GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK);
228
229 // Make another change to trigger downloading of rollback command.
230 Remove(0, GetOtherNode(0), 0);
231
232 // Wait for sync to switch to backup mode after finishing rollback.
233 BackupModeChecker checker(GetSyncService(0),
234 base::TimeDelta::FromSeconds(15));
235 ASSERT_TRUE(checker.Wait());
236
237 // Without backup DB, bookmarks added during sync shouldn't be removed.
238 ASSERT_EQ(1, GetOtherNode(0)->child_count());
239 ASSERT_EQ(GURL("http://www.nhl.com"),
240 GetOtherNode(0)->GetChild(0)->url());
241 }
242
243 #if defined(ENABLE_PRE_SYNC_BACKUP)
244 #define MAYBE_DontChangeBookmarkOrdering DontChangeBookmarkOrdering
245 #else
246 #define MAYBE_DontChangeBookmarkOrdering DISABLED_DontChangeBookmarkOrdering
247 #endif
IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,MAYBE_DontChangeBookmarkOrdering)248 IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
249 MAYBE_DontChangeBookmarkOrdering) {
250 ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
251
252 const BookmarkNode* sub_folder = AddFolder(0, GetOtherNode(0), 0, "test");
253 ASSERT_TRUE(AddURL(0, sub_folder, 0, "", GURL(kUrl1)));
254 ASSERT_TRUE(AddURL(0, sub_folder, 1, "", GURL(kUrl2)));
255 ASSERT_TRUE(AddURL(0, sub_folder, 2, "", GURL(kUrl3)));
256
257 BackupModeChecker checker(GetSyncService(0),
258 base::TimeDelta::FromSeconds(15));
259 ASSERT_TRUE(checker.Wait());
260
261 // Restart backup.
262 GetSyncService(0)->StartStopBackupForTesting();
263 GetSyncService(0)->StartStopBackupForTesting();
264 ASSERT_TRUE(checker.Wait());
265
266 // Verify bookmarks are unchanged.
267 ASSERT_EQ(3, sub_folder->child_count());
268 ASSERT_EQ(GURL(kUrl1), sub_folder->GetChild(0)->url());
269 ASSERT_EQ(GURL(kUrl2), sub_folder->GetChild(1)->url());
270 ASSERT_EQ(GURL(kUrl3), sub_folder->GetChild(2)->url());
271 }
272
273