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