blob: 31c9057a71d1bc346017be0b40eb2e44641f2457 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include "base/guid.h"
#include "base/i18n/number_formatting.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sync/test/integration/bookmarks_helper.h"
#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/sync/test/integration/typed_urls_helper.h"
#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
#include "components/history/core/browser/history_types.h"
using base::ASCIIToUTF16;
using bookmarks::BookmarkNode;
using typed_urls_helper::AddUrlToHistory;
using typed_urls_helper::AddUrlToHistoryWithTimestamp;
using typed_urls_helper::AddUrlToHistoryWithTransition;
using typed_urls_helper::AreVisitsEqual;
using typed_urls_helper::AreVisitsUnique;
using typed_urls_helper::CheckSyncHasMetadataForURLID;
using typed_urls_helper::CheckSyncHasURLMetadata;
using typed_urls_helper::CheckURLRowVectorsAreEqualForTypedURLs;
using typed_urls_helper::DeleteUrlFromHistory;
using typed_urls_helper::ExpireHistoryBefore;
using typed_urls_helper::ExpireHistoryBetween;
using typed_urls_helper::GetTypedUrlsFromClient;
using typed_urls_helper::GetUrlFromClient;
using typed_urls_helper::GetVisitsFromClient;
using typed_urls_helper::RemoveVisitsFromClient;
namespace {
const std::string kDummyUrl = "http://dummy-history.google.com/";
} // namespace
class TwoClientTypedUrlsSyncTest : public SyncTest {
public:
TwoClientTypedUrlsSyncTest() : SyncTest(TWO_CLIENT) {}
~TwoClientTypedUrlsSyncTest() override {}
::testing::AssertionResult CheckClientsEqual() {
history::URLRows urls = GetTypedUrlsFromClient(0);
history::URLRows urls2 = GetTypedUrlsFromClient(1);
if (!CheckURLRowVectorsAreEqualForTypedURLs(urls, urls2))
return ::testing::AssertionFailure() << "URLVectors are not equal";
// Now check the visits.
for (size_t i = 0; i < urls.size() && i < urls2.size(); i++) {
history::VisitVector visit1 = GetVisitsFromClient(0, urls[i].id());
history::VisitVector visit2 = GetVisitsFromClient(1, urls2[i].id());
if (!AreVisitsEqual(visit1, visit2))
return ::testing::AssertionFailure() << "Visits are not equal";
}
return ::testing::AssertionSuccess();
}
bool CheckNoDuplicateVisits() {
for (int i = 0; i < num_clients(); ++i) {
history::URLRows urls = GetTypedUrlsFromClient(i);
for (size_t j = 0; j < urls.size(); ++j) {
history::VisitVector visits = GetVisitsFromClient(i, urls[j].id());
if (!AreVisitsUnique(visits))
return false;
}
}
return true;
}
int GetVisitCountForFirstURL(int index) {
history::URLRows urls = GetTypedUrlsFromClient(index);
if (urls.empty())
return 0;
else
return urls[0].visit_count();
}
private:
DISALLOW_COPY_AND_ASSIGN(TwoClientTypedUrlsSyncTest);
};
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, E2E_ENABLED(Add)) {
// Use a randomized URL to prevent test collisions.
const base::string16 kHistoryUrl = ASCIIToUTF16(base::StringPrintf(
"http://www.add-history.google.com/%s", base::GenerateGUID().c_str()));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
size_t initial_count = GetTypedUrlsFromClient(0).size();
// Populate one client with a URL, wait for it to sync to the other.
GURL new_url(kHistoryUrl);
AddUrlToHistory(0, new_url);
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Assert that the second client has the correct new URL.
history::URLRows urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(initial_count + 1, urls.size());
ASSERT_EQ(new_url, urls.back().url());
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddExpired) {
const base::string16 kHistoryUrl(
ASCIIToUTF16("http://www.add-one-history.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Populate one client with a URL, should sync to the other.
GURL new_url(kHistoryUrl);
// Create a URL with a timestamp 1 year before today.
base::Time timestamp = base::Time::Now() - base::TimeDelta::FromDays(365);
AddUrlToHistoryWithTimestamp(0,
new_url,
ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED,
timestamp);
history::URLRows urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(new_url, urls[0].url());
// Let sync finish.
// Add a dummy url and sync it.
AddUrlToHistory(0, GURL(kDummyUrl));
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(2U, urls.size());
ASSERT_TRUE(TypedURLChecker(1, kDummyUrl).Wait());
// Second client should only have dummy URL since kHistoryUrl is expired.
urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(GURL(kDummyUrl), urls.back().url());
EXPECT_TRUE(CheckSyncHasURLMetadata(1, GURL(kDummyUrl)));
// Sync on both clients should not receive expired visits.
EXPECT_FALSE(CheckSyncHasURLMetadata(0, new_url));
EXPECT_FALSE(CheckSyncHasURLMetadata(1, new_url));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddExpiredThenUpdate) {
const base::string16 kHistoryUrl(
ASCIIToUTF16("http://www.add-one-history.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Populate one client with a URL, should sync to the other.
GURL new_url(kHistoryUrl);
// Create a URL with a timestamp 1 year before today.
base::Time timestamp = base::Time::Now() - base::TimeDelta::FromDays(365);
AddUrlToHistoryWithTimestamp(0,
new_url,
ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED,
timestamp);
std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(new_url, urls[0].url());
// Let sync finish.
// Add a dummy url and sync it.
AddUrlToHistory(0, GURL(kDummyUrl));
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(2U, urls.size());
ASSERT_TRUE(TypedURLChecker(1, kDummyUrl).Wait());
// Second client should only have dummy URL since kHistoryUrl is expired.
urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(1U, urls.size());
EXPECT_TRUE(CheckSyncHasURLMetadata(0, GURL(kDummyUrl)));
// Sync should not receive expired visits.
EXPECT_FALSE(CheckSyncHasURLMetadata(0, new_url));
// Now drive an update on the first client.
AddUrlToHistory(0, new_url);
// Let sync finish again.
ASSERT_TRUE(TypedURLChecker(1, new_url.spec()).Wait());
// Second client should have kHistoryUrl now.
urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(2U, urls.size());
// Sync should receive the new visit.
EXPECT_TRUE(CheckSyncHasURLMetadata(0, new_url));
EXPECT_TRUE(CheckSyncHasURLMetadata(1, new_url));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
AddThenExpireOnSecondClient) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
base::Time now = base::Time::Now();
// Populate one client with a URL, should sync to the other.
GURL url("http://www.add-one-history.google.com/");
base::Time insertion_time = now - base::TimeDelta::FromDays(1);
AddUrlToHistoryWithTimestamp(0, url, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED, insertion_time);
std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(url, urls[0].url());
history::URLID url_id_on_first_client = urls[0].id();
// Wait for sync to finish.
ASSERT_TRUE(TypedURLChecker(1, url.spec()).Wait());
// Second client should have the url.
ASSERT_EQ(1U, GetTypedUrlsFromClient(1).size());
EXPECT_TRUE(CheckSyncHasURLMetadata(1, url));
// Expire the url on the second client.
ExpireHistoryBefore(1, insertion_time + base::TimeDelta::FromSeconds(1));
// The data and the metadata should be gone on the second client.
ASSERT_EQ(0U, GetTypedUrlsFromClient(1).size());
EXPECT_FALSE(CheckSyncHasURLMetadata(1, url));
// Let sync finish; Add a dummy url to the second client and sync it.
AddUrlToHistory(1, GURL(kDummyUrl));
ASSERT_EQ(1U, GetTypedUrlsFromClient(1).size());
ASSERT_TRUE(TypedURLChecker(0, kDummyUrl).Wait());
// The expiration should not get synced up, the first client still has the
// URL (and also the dummy URL)
ASSERT_EQ(2U, GetTypedUrlsFromClient(0).size());
EXPECT_TRUE(CheckSyncHasMetadataForURLID(0, url_id_on_first_client));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddThenExpireThenAddAgain) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
base::Time now = base::Time::Now();
// Populate one client with a URL, should sync to the other.
GURL url("http://www.add-one-history.google.com/");
base::Time insertion_time = now - base::TimeDelta::FromDays(1);
AddUrlToHistoryWithTimestamp(0, url, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED, insertion_time);
std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(url, urls[0].url());
history::URLID url_id_on_first_client = urls[0].id();
// Wait for sync to finish.
ASSERT_TRUE(TypedURLChecker(1, url.spec()).Wait());
// Second client should have the url.
urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(1U, urls.size());
EXPECT_TRUE(CheckSyncHasURLMetadata(0, url));
// Expire the url on the first client.
ExpireHistoryBefore(0, insertion_time + base::TimeDelta::FromSeconds(1));
// The data and the metadata should be gone on the first client.
ASSERT_EQ(0U, GetTypedUrlsFromClient(0).size());
EXPECT_FALSE(CheckSyncHasMetadataForURLID(0, url_id_on_first_client));
// Let sync finish.
// Add a dummy url and sync it.
AddUrlToHistory(0, GURL(kDummyUrl));
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_TRUE(TypedURLChecker(1, kDummyUrl).Wait());
// The expiration should not get synced up, the second client still has the
// URL.
urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(2U, urls.size());
EXPECT_TRUE(CheckSyncHasURLMetadata(1, url));
// The first client can add the URL again (regression test for
// https://crbug.com/827111).
AddUrlToHistoryWithTransition(0, url, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED);
urls = GetTypedUrlsFromClient(0);
EXPECT_EQ(2U, urls.size());
EXPECT_TRUE(CheckSyncHasURLMetadata(0, url));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddThenExpireVisitByVisit) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
base::Time now = base::Time::Now();
// Populate one client with a URL (with three visits), should sync to the
// other. First non-typed, then typed, then non-typed again.
GURL url("http://www.add-one-history.google.com/");
base::Time insertion_time = now - base::TimeDelta::FromDays(6);
base::Time second_typed_visit_time = now - base::TimeDelta::FromDays(5);
base::Time third_link_visit_time = now - base::TimeDelta::FromDays(4);
base::Time dummy_visit_1 = now - base::TimeDelta::FromDays(3);
base::Time dummy_visit_2 = now - base::TimeDelta::FromDays(2);
base::Time dummy_visit_3 = now - base::TimeDelta::FromDays(1);
AddUrlToHistoryWithTimestamp(0, url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED, insertion_time);
AddUrlToHistoryWithTimestamp(0, url, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED,
second_typed_visit_time);
AddUrlToHistoryWithTimestamp(0, url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED, third_link_visit_time);
std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(url, urls[0].url());
history::URLID url_id_on_first_client = urls[0].id();
// Wait for sync to finish.
ASSERT_TRUE(TypedURLChecker(1, url.spec()).Wait());
// Second client should have the url.
ASSERT_EQ(1U, GetTypedUrlsFromClient(1).size());
EXPECT_TRUE(CheckSyncHasURLMetadata(1, url));
// Expire the first (non-typed) visit on the first client and assert both data
// and metadata are intact.
ExpireHistoryBefore(0, insertion_time + base::TimeDelta::FromSeconds(1));
ASSERT_EQ(1U, GetTypedUrlsFromClient(0).size());
EXPECT_TRUE(CheckSyncHasMetadataForURLID(0, url_id_on_first_client));
// Force a sync cycle (add a dummy typed url and sync it) and check the second
// client still has the original URL (plus the dummy one).
AddUrlToHistoryWithTimestamp(0, GURL(kDummyUrl), ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED, dummy_visit_1);
ASSERT_EQ(2U, GetTypedUrlsFromClient(0).size());
ASSERT_TRUE(TypedURLChecker(1, kDummyUrl).Wait());
ASSERT_EQ(2U, GetTypedUrlsFromClient(1).size());
EXPECT_TRUE(CheckSyncHasURLMetadata(1, url));
// Expire the second (typed) visit on the first client and assert both data
// and metadata for the URL are gone.
ExpireHistoryBefore(
0, second_typed_visit_time + base::TimeDelta::FromSeconds(1));
std::vector<history::URLRow> pruned_urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, pruned_urls.size());
ASSERT_EQ(GURL(kDummyUrl), pruned_urls[0].url());
EXPECT_FALSE(CheckSyncHasMetadataForURLID(0, url_id_on_first_client));
// Force a sync cycle (add another visit to the dummy url and sync it).
AddUrlToHistoryWithTimestamp(0, GURL(kDummyUrl), ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED, dummy_visit_2);
ASSERT_TRUE(TypedURLChecker(1, kDummyUrl).Wait());
// The expiration should not get synced up, the second client still has the
// URL (and also the dummy one).
ASSERT_EQ(2U, GetTypedUrlsFromClient(1).size());
EXPECT_TRUE(CheckSyncHasURLMetadata(1, url));
// Now expire also the last non-typed visit (make sure it has no impact).
ExpireHistoryBefore(0,
third_link_visit_time + base::TimeDelta::FromSeconds(1));
ASSERT_EQ(1U, GetTypedUrlsFromClient(0).size());
EXPECT_FALSE(CheckSyncHasMetadataForURLID(0, url_id_on_first_client));
// Force a sync cycle (add another visit to the dummy url and sync it) and
// check the second client still has the same state.
AddUrlToHistoryWithTimestamp(0, GURL(kDummyUrl), ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED, dummy_visit_3);
ASSERT_TRUE(TypedURLChecker(1, kDummyUrl).Wait());
ASSERT_EQ(2U, GetTypedUrlsFromClient(1).size());
EXPECT_TRUE(CheckSyncHasURLMetadata(1, url));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, E2E_ENABLED(AddThenDelete)) {
// Use a randomized URL to prevent test collisions.
const base::string16 kHistoryUrl = ASCIIToUTF16(base::StringPrintf(
"http://www.add-history.google.com/%s", base::GenerateGUID().c_str()));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
size_t initial_count = GetTypedUrlsFromClient(0).size();
// Populate one client with a URL, wait for it to sync to the other.
GURL new_url(kHistoryUrl);
AddUrlToHistory(0, new_url);
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Assert that the second client has the correct new URL.
history::URLRows urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(initial_count + 1, urls.size());
ASSERT_EQ(new_url, urls.back().url());
// Delete from first client, and wait for them to sync.
DeleteUrlFromHistory(0, new_url);
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Assert that it's deleted from the second client.
ASSERT_EQ(initial_count, GetTypedUrlsFromClient(1).size());
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
AddMultipleVisitsThenDeleteAllTypedVisits) {
const base::string16 kHistoryUrl(ASCIIToUTF16("http://history1.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
base::Time now = base::Time::Now();
base::Time insertion_time = now - base::TimeDelta::FromDays(2);
base::Time visit_time = now - base::TimeDelta::FromDays(1);
// Populate one client with a URL with multiple visits, wait for it to sync to
// the other.
GURL new_url(kHistoryUrl);
AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED, insertion_time);
AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED, visit_time);
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Assert that the second client has the correct new URL.
history::URLRows urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(1u, urls.size());
ASSERT_EQ(new_url, urls[0].url());
// Delete the only typed visit from the first client, and wait for them to
// sync.
ExpireHistoryBetween(0, insertion_time - base::TimeDelta::FromSeconds(1),
insertion_time + base::TimeDelta::FromSeconds(1));
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Assert that it's deleted from the second client.
ASSERT_EQ(0u, GetTypedUrlsFromClient(1).size());
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
E2E_ENABLED(DisableEnableSync)) {
const base::string16 kUrl1(ASCIIToUTF16("http://history1.google.com/"));
const base::string16 kUrl2(ASCIIToUTF16("http://history2.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Disable history sync for one client, leave it active for the other.
GetClient(0)->DisableSyncForType(syncer::UserSelectableType::kHistory);
// Add one URL to non-syncing client, add a different URL to the other,
// wait for sync cycle to complete. No data should be exchanged.
GURL url1(kUrl1);
GURL url2(kUrl2);
AddUrlToHistory(0, url1);
AddUrlToHistory(1, url2);
ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(1)).Wait());
// Make sure that no data was exchanged.
history::URLRows post_sync_urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, post_sync_urls.size());
ASSERT_EQ(url1, post_sync_urls[0].url());
post_sync_urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(1U, post_sync_urls.size());
ASSERT_EQ(url2, post_sync_urls[0].url());
// Enable history sync, make both URLs are synced to each client.
GetClient(0)->EnableSyncForType(syncer::UserSelectableType::kHistory);
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddOneDeleteOther) {
const base::string16 kHistoryUrl(
ASCIIToUTF16("http://www.add-one-delete-history.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Populate one client with a URL, should sync to the other.
GURL new_url(kHistoryUrl);
AddUrlToHistory(0, new_url);
history::URLRows urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(new_url, urls[0].url());
// Both clients should have this URL.
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Now, delete the URL from the second client.
DeleteUrlFromHistory(1, new_url);
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
// Both clients should have this URL removed.
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddOneDeleteOtherAddAgain) {
const base::string16 kHistoryUrl(
ASCIIToUTF16("http://www.add-delete-add-history.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Populate one client with a URL, should sync to the other.
GURL new_url(kHistoryUrl);
AddUrlToHistory(0, new_url);
history::URLRows urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(new_url, urls[0].url());
// Both clients should have this URL.
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Now, delete the URL from the second client.
DeleteUrlFromHistory(1, new_url);
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
// Both clients should have this URL removed.
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
// Add it to the first client again, should succeed (tests that the deletion
// properly disassociates that URL).
AddUrlToHistory(0, new_url);
// Both clients should have this URL added again.
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
MergeTypedWithNonTypedDuringAssociation) {
ASSERT_TRUE(SetupClients());
GURL new_url("http://history.com");
base::Time timestamp = base::Time::Now();
// Put a non-typed URL in both clients with an identical timestamp.
// Then add a typed URL to the second client - this test makes sure that
// we properly merge both sets of visits together to end up with the same
// set of visits on both ends.
AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED, timestamp);
AddUrlToHistoryWithTimestamp(1, new_url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED, timestamp);
AddUrlToHistoryWithTimestamp(1, new_url, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED,
timestamp + base::TimeDelta::FromSeconds(1));
// Now start up sync - URLs should get merged. Fully sync client 1 first,
// before syncing client 0, so we have both of client 1's URLs in the sync DB
// at the time that client 0 does model association.
ASSERT_TRUE(GetClient(1)->SetupSync()) << "SetupSync() failed";
ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(1)).Wait());
ASSERT_TRUE(GetClient(0)->SetupSync()) << "SetupSync() failed";
ASSERT_TRUE(TypedURLChecker(1, new_url.spec()).Wait());
ASSERT_TRUE(CheckClientsEqual());
// At this point, we should have no duplicates (total visit count should be
// 2). We only need to check client 0 since we already verified that both
// clients are identical above.
history::URLRows urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(new_url, urls[0].url());
ASSERT_TRUE(CheckNoDuplicateVisits());
ASSERT_EQ(2, GetVisitCountForFirstURL(0));
}
// Tests transitioning a URL from non-typed to typed when both clients
// have already seen that URL (so a merge is required).
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
MergeTypedWithNonTypedDuringChangeProcessing) {
ASSERT_TRUE(SetupClients());
GURL new_url("http://history.com");
base::Time timestamp = base::Time::Now();
// Setup both clients with the identical typed URL visit. This means we can't
// use the verifier in this test, because this will show up as two distinct
// visits in the verifier.
AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED, timestamp);
AddUrlToHistoryWithTimestamp(1, new_url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED, timestamp);
// Now start up sync. Neither URL should get synced as they do not look like
// typed URLs.
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(CheckClientsEqual());
history::URLRows urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(0U, urls.size());
// Now, add a typed visit to the first client.
AddUrlToHistoryWithTimestamp(0, new_url, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED,
timestamp + base::TimeDelta::FromSeconds(1));
ASSERT_TRUE(TypedURLChecker(1, new_url.spec()).Wait());
ASSERT_TRUE(CheckClientsEqual());
ASSERT_TRUE(CheckNoDuplicateVisits());
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(2, GetVisitCountForFirstURL(0));
ASSERT_EQ(2, GetVisitCountForFirstURL(1));
}
// Tests transitioning a URL from non-typed to typed when one of the clients
// has never seen that URL before (so no merge is necessary).
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, UpdateToNonTypedURL) {
const base::string16 kHistoryUrl(
ASCIIToUTF16("http://www.add-delete-add-history.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Populate one client with a non-typed URL, should not be synced.
GURL new_url(kHistoryUrl);
AddUrlToHistoryWithTransition(0, new_url, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED);
history::URLRows urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(0U, urls.size());
// Both clients should have 0 typed URLs.
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(0U, urls.size());
// Now, add a typed visit to this URL.
AddUrlToHistory(0, new_url);
// Let sync finish.
ASSERT_TRUE(TypedURLChecker(1, new_url.spec()).Wait());
// Both clients should have this URL as typed and have two visits synced up.
ASSERT_TRUE(CheckClientsEqual());
urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(new_url, urls[0].url());
ASSERT_EQ(2, GetVisitCountForFirstURL(0));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
E2E_ENABLED(DontSyncUpdatedNonTypedURLs)) {
// Checks if a non-typed URL that has been updated (modified) doesn't get
// synced. This is a regression test after fixing a bug where adding a
// non-typed URL was guarded against but later modifying it was not. Since
// "update" is "update or create if missing", non-typed URLs were being
// created.
const GURL kNonTypedURL("http://link.google.com/");
const GURL kTypedURL("http://typed.google.com/");
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
AddUrlToHistoryWithTransition(0, kNonTypedURL, ui::PAGE_TRANSITION_LINK,
history::SOURCE_BROWSED);
AddUrlToHistoryWithTransition(0, kTypedURL, ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED);
// Modify the non-typed URL. It should not get synced.
typed_urls_helper::SetPageTitle(0, kNonTypedURL, "Welcome to Non-Typed URL");
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
history::VisitVector visits;
// First client has both visits.
visits = typed_urls_helper::GetVisitsForURLFromClient(0, kNonTypedURL);
ASSERT_EQ(1U, visits.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
ui::PAGE_TRANSITION_LINK));
visits = typed_urls_helper::GetVisitsForURLFromClient(0, kTypedURL);
ASSERT_EQ(1U, visits.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
ui::PAGE_TRANSITION_TYPED));
// Second client has only the typed visit.
visits = typed_urls_helper::GetVisitsForURLFromClient(1, kNonTypedURL);
ASSERT_EQ(0U, visits.size());
visits = typed_urls_helper::GetVisitsForURLFromClient(1, kTypedURL);
ASSERT_EQ(1U, visits.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
ui::PAGE_TRANSITION_TYPED));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
E2E_ENABLED(SyncTypedRedirects)) {
const base::string16 kHistoryUrl(ASCIIToUTF16("http://typed.google.com/"));
const base::string16 kRedirectedHistoryUrl(
ASCIIToUTF16("http://www.typed.google.com/"));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Simulate a typed address that gets redirected by the server to a different
// address.
GURL initial_url(kHistoryUrl);
const ui::PageTransition initial_transition = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_CHAIN_START);
AddUrlToHistoryWithTransition(0, initial_url, initial_transition,
history::SOURCE_BROWSED);
GURL redirected_url(kRedirectedHistoryUrl);
const ui::PageTransition redirected_transition = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_CHAIN_END |
ui::PAGE_TRANSITION_SERVER_REDIRECT);
// This address will have a typed_count == 0 because it's a redirection.
// It should still be synced.
AddUrlToHistoryWithTransition(0, redirected_url, redirected_transition,
history::SOURCE_BROWSED);
// Both clients should have both URLs.
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
history::VisitVector visits =
typed_urls_helper::GetVisitsForURLFromClient(0, initial_url);
ASSERT_EQ(1U, visits.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
ui::PAGE_TRANSITION_TYPED));
visits = typed_urls_helper::GetVisitsForURLFromClient(0, redirected_url);
ASSERT_EQ(1U, visits.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
ui::PAGE_TRANSITION_TYPED));
visits = typed_urls_helper::GetVisitsForURLFromClient(1, initial_url);
ASSERT_EQ(1U, visits.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
ui::PAGE_TRANSITION_TYPED));
visits = typed_urls_helper::GetVisitsForURLFromClient(1, redirected_url);
ASSERT_EQ(1U, visits.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
ui::PAGE_TRANSITION_TYPED));
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
SkipImportedVisits) {
GURL imported_url("http://imported_url.com");
GURL browsed_url("http://browsed_url.com");
GURL browsed_and_imported_url("http://browsed_and_imported_url.com");
ASSERT_TRUE(SetupClients());
// Create 3 items in our first client - 1 imported, one browsed, one with
// both imported and browsed entries.
AddUrlToHistoryWithTransition(0, imported_url,
ui::PAGE_TRANSITION_TYPED,
history::SOURCE_FIREFOX_IMPORTED);
AddUrlToHistoryWithTransition(0, browsed_url,
ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED);
AddUrlToHistoryWithTransition(0, browsed_and_imported_url,
ui::PAGE_TRANSITION_TYPED,
history::SOURCE_FIREFOX_IMPORTED);
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(TypedURLChecker(1, browsed_url.spec()).Wait());
history::URLRows urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(browsed_url, urls[0].url());
// Now browse to 3rd URL - this should cause it to be synced, even though it
// was initially imported.
AddUrlToHistoryWithTransition(0, browsed_and_imported_url,
ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED);
ASSERT_TRUE(TypedURLChecker(1, browsed_and_imported_url.spec()).Wait());
urls = GetTypedUrlsFromClient(1);
ASSERT_EQ(2U, urls.size());
// Make sure the imported URL didn't make it over.
for (size_t i = 0; i < urls.size(); ++i) {
ASSERT_NE(imported_url, urls[i].url());
}
}
IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, BookmarksWithTypedVisit) {
GURL bookmark_url("http://www.bookmark.google.com/");
GURL bookmark_icon_url("http://www.bookmark.google.com/favicon.ico");
ASSERT_TRUE(SetupClients());
// Create a bookmark.
const BookmarkNode* node = bookmarks_helper::AddURL(
0, bookmarks_helper::IndexedURLTitle(0), bookmark_url);
bookmarks_helper::SetFavicon(0, node, bookmark_icon_url,
bookmarks_helper::CreateFavicon(SK_ColorWHITE),
bookmarks_helper::FROM_UI);
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// A row in the DB for client 1 should have been created as a result of the
// sync.
history::URLRow row;
ASSERT_TRUE(GetUrlFromClient(1, bookmark_url, &row));
// Now, add a typed visit for client 0 to the bookmark URL and sync it over
// - this should not cause a crash.
AddUrlToHistory(0, bookmark_url);
ASSERT_TRUE(ProfilesHaveSameTypedURLsChecker().Wait());
history::URLRows urls = GetTypedUrlsFromClient(0);
ASSERT_EQ(1U, urls.size());
ASSERT_EQ(bookmark_url, urls[0].url());
ASSERT_EQ(1, GetVisitCountForFirstURL(0));
}