two_client_typed_urls_sync_test.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright (c) 2012 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/i18n/number_formatting.h" 6#include "base/memory/scoped_vector.h" 7#include "base/strings/utf_string_conversions.h" 8#include "chrome/browser/sessions/session_service.h" 9#include "chrome/browser/sync/test/integration/bookmarks_helper.h" 10#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" 11#include "chrome/browser/sync/test/integration/sync_integration_test_util.h" 12#include "chrome/browser/sync/test/integration/sync_test.h" 13#include "chrome/browser/sync/test/integration/typed_urls_helper.h" 14#include "components/history/core/browser/history_types.h" 15 16using base::ASCIIToUTF16; 17using sync_integration_test_util::AwaitCommitActivityCompletion; 18using typed_urls_helper::AddUrlToHistory; 19using typed_urls_helper::AddUrlToHistoryWithTimestamp; 20using typed_urls_helper::AddUrlToHistoryWithTransition; 21using typed_urls_helper::AreVisitsEqual; 22using typed_urls_helper::AreVisitsUnique; 23using typed_urls_helper::AwaitCheckAllProfilesHaveSameURLsAsVerifier; 24using typed_urls_helper::CheckURLRowVectorsAreEqual; 25using typed_urls_helper::DeleteUrlFromHistory; 26using typed_urls_helper::GetTypedUrlsFromClient; 27using typed_urls_helper::GetUrlFromClient; 28using typed_urls_helper::GetVisitsFromClient; 29using typed_urls_helper::RemoveVisitsFromClient; 30 31class TwoClientTypedUrlsSyncTest : public SyncTest { 32 public: 33 TwoClientTypedUrlsSyncTest() : SyncTest(TWO_CLIENT) {} 34 virtual ~TwoClientTypedUrlsSyncTest() {} 35 36 ::testing::AssertionResult CheckClientsEqual() { 37 history::URLRows urls = GetTypedUrlsFromClient(0); 38 history::URLRows urls2 = GetTypedUrlsFromClient(1); 39 if (!CheckURLRowVectorsAreEqual(urls, urls2)) 40 return ::testing::AssertionFailure() << "URLVectors are not equal"; 41 // Now check the visits. 42 for (size_t i = 0; i < urls.size() && i < urls2.size(); i++) { 43 history::VisitVector visit1 = GetVisitsFromClient(0, urls[i].id()); 44 history::VisitVector visit2 = GetVisitsFromClient(1, urls2[i].id()); 45 if (!AreVisitsEqual(visit1, visit2)) 46 return ::testing::AssertionFailure() << "Visits are not equal"; 47 } 48 return ::testing::AssertionSuccess(); 49 } 50 51 bool CheckNoDuplicateVisits() { 52 for (int i = 0; i < num_clients(); ++i) { 53 history::URLRows urls = GetTypedUrlsFromClient(i); 54 for (size_t j = 0; j < urls.size(); ++j) { 55 history::VisitVector visits = GetVisitsFromClient(i, urls[j].id()); 56 if (!AreVisitsUnique(visits)) 57 return false; 58 } 59 } 60 return true; 61 } 62 63 int GetVisitCountForFirstURL(int index) { 64 history::URLRows urls = GetTypedUrlsFromClient(index); 65 if (urls.size() == 0) 66 return 0; 67 else 68 return urls[0].visit_count(); 69 } 70 71 private: 72 DISALLOW_COPY_AND_ASSIGN(TwoClientTypedUrlsSyncTest); 73}; 74 75// TCM: 3728323 76IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, Add) { 77 const base::string16 kHistoryUrl( 78 ASCIIToUTF16("http://www.add-one-history.google.com/")); 79 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 80 81 // Populate one client with a URL, should sync to the other. 82 GURL new_url(kHistoryUrl); 83 AddUrlToHistory(0, new_url); 84 history::URLRows urls = GetTypedUrlsFromClient(0); 85 ASSERT_EQ(1U, urls.size()); 86 ASSERT_EQ(new_url, urls[0].url()); 87 88 // Both clients should have this URL. 89 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 90} 91 92IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddExpired) { 93 const base::string16 kHistoryUrl( 94 ASCIIToUTF16("http://www.add-one-history.google.com/")); 95 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 96 97 // Populate one client with a URL, should sync to the other. 98 GURL new_url(kHistoryUrl); 99 // Create a URL with a timestamp 1 year before today. 100 base::Time timestamp = base::Time::Now() - base::TimeDelta::FromDays(365); 101 AddUrlToHistoryWithTimestamp(0, 102 new_url, 103 ui::PAGE_TRANSITION_TYPED, 104 history::SOURCE_BROWSED, 105 timestamp); 106 history::URLRows urls = GetTypedUrlsFromClient(0); 107 ASSERT_EQ(1U, urls.size()); 108 ASSERT_EQ(new_url, urls[0].url()); 109 110 // Let sync finish. 111 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 112 113 // Second client should still have no URLs since this one is expired. 114 urls = GetTypedUrlsFromClient(1); 115 ASSERT_EQ(0U, urls.size()); 116} 117 118// Flake on mac: http://crbug/115526 119#if defined(OS_MACOSX) 120#define MAYBE_AddExpiredThenUpdate DISABLED_AddExpiredThenUpdate 121#else 122#define MAYBE_AddExpiredThenUpdate AddExpiredThenUpdate 123#endif 124IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, MAYBE_AddExpiredThenUpdate) { 125 const base::string16 kHistoryUrl( 126 ASCIIToUTF16("http://www.add-one-history.google.com/")); 127 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 128 129 // Populate one client with a URL, should sync to the other. 130 GURL new_url(kHistoryUrl); 131 // Create a URL with a timestamp 1 year before today. 132 base::Time timestamp = base::Time::Now() - base::TimeDelta::FromDays(365); 133 AddUrlToHistoryWithTimestamp(0, 134 new_url, 135 ui::PAGE_TRANSITION_TYPED, 136 history::SOURCE_BROWSED, 137 timestamp); 138 std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0); 139 ASSERT_EQ(1U, urls.size()); 140 ASSERT_EQ(new_url, urls[0].url()); 141 142 // Let sync finish. 143 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 144 145 // Second client should still have no URLs since this one is expired. 146 urls = GetTypedUrlsFromClient(1); 147 ASSERT_EQ(0U, urls.size()); 148 149 // Now drive an update on the first client. 150 AddUrlToHistory(0, new_url); 151 152 // Let sync finish again. 153 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 154 155 // Second client should have the URL now. 156 urls = GetTypedUrlsFromClient(1); 157 ASSERT_EQ(1U, urls.size()); 158} 159 160// TCM: 3705291 161// flaky, see crbug.com/108511 162IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, DISABLED_AddThenDelete) { 163 const base::string16 kHistoryUrl( 164 ASCIIToUTF16("http://www.add-one-history.google.com/")); 165 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 166 167 // Populate one client with a URL, should sync to the other. 168 GURL new_url(kHistoryUrl); 169 AddUrlToHistory(0, new_url); 170 history::URLRows urls = GetTypedUrlsFromClient(0); 171 ASSERT_EQ(1U, urls.size()); 172 ASSERT_EQ(new_url, urls[0].url()); 173 174 // Both clients should have this URL. 175 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 176 177 // Delete from first client, should delete from second. 178 DeleteUrlFromHistory(0, new_url); 179 180 // Neither client should have this URL. 181 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 182} 183 184// TCM: 3643277 185IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, DisableEnableSync) { 186 const base::string16 kUrl1(ASCIIToUTF16("http://history1.google.com/")); 187 const base::string16 kUrl2(ASCIIToUTF16("http://history2.google.com/")); 188 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 189 190 // Disable typed url sync for one client, leave it active for the other. 191 GetClient(0)->DisableSyncForDatatype(syncer::TYPED_URLS); 192 193 // Add one URL to non-syncing client, add a different URL to the other, 194 // wait for sync cycle to complete. No data should be exchanged. 195 GURL url1(kUrl1); 196 GURL url2(kUrl2); 197 AddUrlToHistory(0, url1); 198 AddUrlToHistory(1, url2); 199 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((1)))); 200 201 // Make sure that no data was exchanged. 202 history::URLRows post_sync_urls = GetTypedUrlsFromClient(0); 203 ASSERT_EQ(1U, post_sync_urls.size()); 204 ASSERT_EQ(url1, post_sync_urls[0].url()); 205 post_sync_urls = GetTypedUrlsFromClient(1); 206 ASSERT_EQ(1U, post_sync_urls.size()); 207 ASSERT_EQ(url2, post_sync_urls[0].url()); 208 209 // Enable typed url sync, make both URLs are synced to each client. 210 GetClient(0)->EnableSyncForDatatype(syncer::TYPED_URLS); 211 212 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 213} 214 215// flaky, see crbug.com/108511 216IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, DISABLED_AddOneDeleteOther) { 217 const base::string16 kHistoryUrl( 218 ASCIIToUTF16("http://www.add-one-delete-history.google.com/")); 219 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 220 221 // Populate one client with a URL, should sync to the other. 222 GURL new_url(kHistoryUrl); 223 AddUrlToHistory(0, new_url); 224 history::URLRows urls = GetTypedUrlsFromClient(0); 225 ASSERT_EQ(1U, urls.size()); 226 ASSERT_EQ(new_url, urls[0].url()); 227 228 // Both clients should have this URL. 229 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 230 231 // Now, delete the URL from the second client. 232 DeleteUrlFromHistory(1, new_url); 233 urls = GetTypedUrlsFromClient(0); 234 ASSERT_EQ(1U, urls.size()); 235 236 // Both clients should have this URL removed. 237 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 238} 239 240// flaky, see crbug.com/108511 241IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, 242 DISABLED_AddOneDeleteOtherAddAgain) { 243 const base::string16 kHistoryUrl( 244 ASCIIToUTF16("http://www.add-delete-add-history.google.com/")); 245 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 246 247 // Populate one client with a URL, should sync to the other. 248 GURL new_url(kHistoryUrl); 249 AddUrlToHistory(0, new_url); 250 history::URLRows urls = GetTypedUrlsFromClient(0); 251 ASSERT_EQ(1U, urls.size()); 252 ASSERT_EQ(new_url, urls[0].url()); 253 254 // Both clients should have this URL. 255 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 256 257 // Now, delete the URL from the second client. 258 DeleteUrlFromHistory(1, new_url); 259 urls = GetTypedUrlsFromClient(0); 260 ASSERT_EQ(1U, urls.size()); 261 262 // Both clients should have this URL removed. 263 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 264 265 // Add it to the first client again, should succeed (tests that the deletion 266 // properly disassociates that URL). 267 AddUrlToHistory(0, new_url); 268 269 // Both clients should have this URL added again. 270 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 271} 272 273IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, 274 MergeTypedWithNonTypedDuringAssociation) { 275 ASSERT_TRUE(SetupClients()); 276 GURL new_url("http://history.com"); 277 base::Time timestamp = base::Time::Now(); 278 // Put a non-typed URL in both clients with an identical timestamp. 279 // Then add a typed URL to the second client - this test makes sure that 280 // we properly merge both sets of visits together to end up with the same 281 // set of visits on both ends. 282 AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_LINK, 283 history::SOURCE_BROWSED, timestamp); 284 AddUrlToHistoryWithTimestamp(1, new_url, ui::PAGE_TRANSITION_LINK, 285 history::SOURCE_BROWSED, timestamp); 286 AddUrlToHistoryWithTimestamp(1, new_url, ui::PAGE_TRANSITION_TYPED, 287 history::SOURCE_BROWSED, 288 timestamp + base::TimeDelta::FromSeconds(1)); 289 290 // Now start up sync - URLs should get merged. Fully sync client 1 first, 291 // before syncing client 0, so we have both of client 1's URLs in the sync DB 292 // at the time that client 0 does model association. 293 ASSERT_TRUE(GetClient(1)->SetupSync()) << "SetupSync() failed"; 294 AwaitCommitActivityCompletion(GetSyncService((1))); 295 ASSERT_TRUE(GetClient(0)->SetupSync()) << "SetupSync() failed"; 296 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 297 298 ASSERT_TRUE(CheckClientsEqual()); 299 // At this point, we should have no duplicates (total visit count should be 300 // 2). We only need to check client 0 since we already verified that both 301 // clients are identical above. 302 history::URLRows urls = GetTypedUrlsFromClient(0); 303 ASSERT_EQ(1U, urls.size()); 304 ASSERT_EQ(new_url, urls[0].url()); 305 ASSERT_TRUE(CheckNoDuplicateVisits()); 306 ASSERT_EQ(2, GetVisitCountForFirstURL(0)); 307} 308 309// Tests transitioning a URL from non-typed to typed when both clients 310// have already seen that URL (so a merge is required). 311IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, 312 MergeTypedWithNonTypedDuringChangeProcessing) { 313 ASSERT_TRUE(SetupClients()); 314 GURL new_url("http://history.com"); 315 base::Time timestamp = base::Time::Now(); 316 // Setup both clients with the identical typed URL visit. This means we can't 317 // use the verifier in this test, because this will show up as two distinct 318 // visits in the verifier. 319 AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_LINK, 320 history::SOURCE_BROWSED, timestamp); 321 AddUrlToHistoryWithTimestamp(1, new_url, ui::PAGE_TRANSITION_LINK, 322 history::SOURCE_BROWSED, timestamp); 323 324 // Now start up sync. Neither URL should get synced as they do not look like 325 // typed URLs. 326 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 327 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 328 ASSERT_TRUE(CheckClientsEqual()); 329 history::URLRows urls = GetTypedUrlsFromClient(0); 330 ASSERT_EQ(0U, urls.size()); 331 332 // Now, add a typed visit to the first client. 333 AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_TYPED, 334 history::SOURCE_BROWSED, 335 timestamp + base::TimeDelta::FromSeconds(1)); 336 337 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 338 ASSERT_TRUE(CheckClientsEqual()); 339 ASSERT_TRUE(CheckNoDuplicateVisits()); 340 urls = GetTypedUrlsFromClient(0); 341 ASSERT_EQ(1U, urls.size()); 342 ASSERT_EQ(2, GetVisitCountForFirstURL(0)); 343 ASSERT_EQ(2, GetVisitCountForFirstURL(1)); 344} 345 346// Tests transitioning a URL from non-typed to typed when one of the clients 347// has never seen that URL before (so no merge is necessary). 348IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, UpdateToNonTypedURL) { 349 const base::string16 kHistoryUrl( 350 ASCIIToUTF16("http://www.add-delete-add-history.google.com/")); 351 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 352 353 // Populate one client with a non-typed URL, should not be synced. 354 GURL new_url(kHistoryUrl); 355 AddUrlToHistoryWithTransition(0, new_url, ui::PAGE_TRANSITION_LINK, 356 history::SOURCE_BROWSED); 357 history::URLRows urls = GetTypedUrlsFromClient(0); 358 ASSERT_EQ(0U, urls.size()); 359 360 // Both clients should have 0 typed URLs. 361 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 362 urls = GetTypedUrlsFromClient(0); 363 ASSERT_EQ(0U, urls.size()); 364 365 // Now, add a typed visit to this URL. 366 AddUrlToHistory(0, new_url); 367 368 // Let sync finish. 369 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 370 371 // Both clients should have this URL as typed and have two visits synced up. 372 ASSERT_TRUE(CheckClientsEqual()); 373 urls = GetTypedUrlsFromClient(0); 374 ASSERT_EQ(1U, urls.size()); 375 ASSERT_EQ(new_url, urls[0].url()); 376 ASSERT_EQ(2, GetVisitCountForFirstURL(0)); 377} 378 379IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, 380 SkipImportedVisits) { 381 382 GURL imported_url("http://imported_url.com"); 383 GURL browsed_url("http://browsed_url.com"); 384 GURL browsed_and_imported_url("http://browsed_and_imported_url.com"); 385 ASSERT_TRUE(SetupClients()); 386 387 // Create 3 items in our first client - 1 imported, one browsed, one with 388 // both imported and browsed entries. 389 AddUrlToHistoryWithTransition(0, imported_url, 390 ui::PAGE_TRANSITION_TYPED, 391 history::SOURCE_FIREFOX_IMPORTED); 392 AddUrlToHistoryWithTransition(0, browsed_url, 393 ui::PAGE_TRANSITION_TYPED, 394 history::SOURCE_BROWSED); 395 AddUrlToHistoryWithTransition(0, browsed_and_imported_url, 396 ui::PAGE_TRANSITION_TYPED, 397 history::SOURCE_FIREFOX_IMPORTED); 398 399 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 400 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 401 history::URLRows urls = GetTypedUrlsFromClient(1); 402 ASSERT_EQ(1U, urls.size()); 403 ASSERT_EQ(browsed_url, urls[0].url()); 404 405 // Now browse to 3rd URL - this should cause it to be synced, even though it 406 // was initially imported. 407 AddUrlToHistoryWithTransition(0, browsed_and_imported_url, 408 ui::PAGE_TRANSITION_TYPED, 409 history::SOURCE_BROWSED); 410 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 411 urls = GetTypedUrlsFromClient(1); 412 ASSERT_EQ(2U, urls.size()); 413 414 // Make sure the imported URL didn't make it over. 415 for (size_t i = 0; i < urls.size(); ++i) { 416 ASSERT_NE(imported_url, urls[i].url()); 417 } 418} 419 420IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, BookmarksWithTypedVisit) { 421 GURL bookmark_url("http://www.bookmark.google.com/"); 422 GURL bookmark_icon_url("http://www.bookmark.google.com/favicon.ico"); 423 ASSERT_TRUE(SetupClients()); 424 // Create a bookmark. 425 const BookmarkNode* node = bookmarks_helper::AddURL( 426 0, bookmarks_helper::IndexedURLTitle(0), bookmark_url); 427 bookmarks_helper::SetFavicon(0, node, bookmark_icon_url, 428 bookmarks_helper::CreateFavicon(SK_ColorWHITE), 429 bookmarks_helper::FROM_UI); 430 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 431 432 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 433 // A row in the DB for client 1 should have been created as a result of the 434 // sync. 435 history::URLRow row; 436 ASSERT_TRUE(GetUrlFromClient(1, bookmark_url, &row)); 437 438 // Now, add a typed visit for client 0 to the bookmark URL and sync it over 439 // - this should not cause a crash. 440 AddUrlToHistory(0, bookmark_url); 441 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); 442 443 ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier()); 444 history::URLRows urls = GetTypedUrlsFromClient(0); 445 ASSERT_EQ(1U, urls.size()); 446 ASSERT_EQ(bookmark_url, urls[0].url()); 447 ASSERT_EQ(1, GetVisitCountForFirstURL(0)); 448} 449