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 25 using bookmarks_helper::AddFolder; 26 using bookmarks_helper::AddURL; 27 using bookmarks_helper::GetOtherNode; 28 using bookmarks_helper::ModelMatchesVerifier; 29 using bookmarks_helper::Move; 30 using bookmarks_helper::Remove; 31 using sync_integration_test_util::AwaitCommitActivityCompletion; 32 33 namespace { 34 const char kUrl1[] = "http://www.google.com"; 35 const char kUrl2[] = "http://map.google.com"; 36 const char kUrl3[] = "http://plus.google.com"; 37 } // anonymous namespace 38 39 class 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. 78 class 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. 114 class 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 164 IN_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 184 IN_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 204 IN_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 262 IN_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 311 IN_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 357 IN_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 404 IN_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