| Index: chrome/browser/history/typed_url_syncable_service_unittest.cc
|
| diff --git a/chrome/browser/history/typed_url_syncable_service_unittest.cc b/chrome/browser/history/typed_url_syncable_service_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2c6c2e4eb02ab8d38c179c8a3f03edb27d4a33d8
|
| --- /dev/null
|
| +++ b/chrome/browser/history/typed_url_syncable_service_unittest.cc
|
| @@ -0,0 +1,657 @@
|
| +// Copyright (c) 2013 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 "chrome/browser/history/typed_url_syncable_service.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "chrome/browser/history/history_backend.h"
|
| +#include "chrome/browser/history/history_types.h"
|
| +#include "content/public/browser/notification_types.h"
|
| +#include "sync/api/sync_error.h"
|
| +#include "sync/api/sync_error_factory_mock.h"
|
| +#include "sync/protocol/sync.pb.h"
|
| +#include "sync/protocol/typed_url_specifics.pb.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using history::HistoryBackend;
|
| +using history::URLID;
|
| +using history::URLRow;
|
| +using history::URLRows;
|
| +using history::VisitRow;
|
| +using history::VisitVector;
|
| +
|
| +namespace {
|
| +
|
| +// Constants used to limit size of visits processed.
|
| +static const int kMaxTypedUrlVisits = 100;
|
| +static const int kMaxVisitsToFetch = 1000;
|
| +
|
| +// Visits with this timestamp are treated as expired.
|
| +static const int EXPIRED_VISIT = -1;
|
| +
|
| +// TestChangeProcessor --------------------------------------------------------
|
| +
|
| +class TestChangeProcessor : public syncer::SyncChangeProcessor {
|
| + public:
|
| + TestChangeProcessor() : change_output_(NULL) {}
|
| +
|
| + // syncer::SyncChangeProcessor implementation.
|
| + virtual syncer::SyncError ProcessSyncChanges(
|
| + const tracked_objects::Location& from_here,
|
| + const syncer::SyncChangeList& change_list) OVERRIDE {
|
| + change_output_->insert(change_output_->end(), change_list.begin(),
|
| + change_list.end());
|
| + return syncer::SyncError();
|
| + }
|
| +
|
| + // Set pointer location to write SyncChanges to in ProcessSyncChanges.
|
| + void SetChangeOutput(syncer::SyncChangeList *change_output) {
|
| + change_output_ = change_output;
|
| + }
|
| +
|
| + private:
|
| + syncer::SyncChangeList *change_output_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
|
| +};
|
| +
|
| +// TestHistoryBackend ----------------------------------------------------------
|
| +
|
| +class TestHistoryBackend : public HistoryBackend {
|
| + public:
|
| + TestHistoryBackend() : HistoryBackend(base::FilePath(), 0, NULL, NULL) {}
|
| +
|
| + // HistoryBackend test implementation.
|
| + virtual bool IsExpiredVisitTime(const base::Time& time) OVERRIDE {
|
| + return time.ToInternalValue() == EXPIRED_VISIT;
|
| + }
|
| +
|
| + virtual bool GetMostRecentVisitsForURL(
|
| + URLID id,
|
| + int max_visits,
|
| + VisitVector* visits) OVERRIDE {
|
| + if (local_db_visits_[id].empty())
|
| + return false;
|
| +
|
| + visits->insert(visits->end(),
|
| + local_db_visits_[id].begin(),
|
| + local_db_visits_[id].end());
|
| + return true;
|
| + }
|
| +
|
| + // Helpers.
|
| + void SetVisitsForUrl(URLID id, VisitVector* visits) {
|
| + if (!local_db_visits_[id].empty()) {
|
| + local_db_visits_[id].clear();
|
| + }
|
| +
|
| + local_db_visits_[id].insert(local_db_visits_[id].end(),
|
| + visits->begin(),
|
| + visits->end());
|
| + }
|
| +
|
| + void DeleteVisitsForUrl(const URLID& id) {
|
| + local_db_visits_.erase(id);
|
| + }
|
| +
|
| + private:
|
| + virtual ~TestHistoryBackend() {}
|
| +
|
| + // Mock of visit table in local db.
|
| + std::map<URLID, VisitVector> local_db_visits_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +namespace history {
|
| +
|
| +// TypedUrlSyncableServiceTest -------------------------------------------------
|
| +
|
| +class TypedUrlSyncableServiceTest : public testing::Test {
|
| + public:
|
| + // Create a new row object and add a typed visit to the |visits| vector.
|
| + // Note that the real history db returns visits in reverse chronological
|
| + // order, so |visits| is treated this way. If the newest (first) visit
|
| + // in visits does not match |last_visit|, then a typed visit for this
|
| + // time is prepended to the front (or if |last_visit| is too old, it is
|
| + // set equal to the time of the newest visit).
|
| + static URLRow MakeTypedUrlRow(const char* url,
|
| + const char* title,
|
| + int typed_count,
|
| + int64 last_visit,
|
| + bool hidden,
|
| + VisitVector* visits);
|
| +
|
| + static void AddNewestVisit(URLRow* url,
|
| + VisitVector* visits,
|
| + content::PageTransition transition,
|
| + int64 visit_time);
|
| +
|
| + static void AddOldestVisit(URLRow* url,
|
| + VisitVector* visits,
|
| + content::PageTransition transition,
|
| + int64 visit_time);
|
| +
|
| + static bool URLsEqual(URLRow& row,
|
| + sync_pb::TypedUrlSpecifics& specifics) {
|
| + return ((row.url().spec().compare(specifics.url()) == 0) &&
|
| + (UTF16ToUTF8(row.title()).compare(specifics.title()) == 0) &&
|
| + (row.hidden() == specifics.hidden()));
|
| + }
|
| +
|
| + bool InitiateServerState(
|
| + unsigned int num_typed_urls,
|
| + unsigned int num_reload_urls,
|
| + URLRows* rows,
|
| + std::vector<VisitVector>* visit_vectors,
|
| + const std::vector<const char*>& urls,
|
| + syncer::SyncChangeList* change_list);
|
| +
|
| + protected:
|
| + TypedUrlSyncableServiceTest() {}
|
| +
|
| + virtual ~TypedUrlSyncableServiceTest() {}
|
| +
|
| + virtual void SetUp() OVERRIDE {
|
| + fake_history_backend_ = new TestHistoryBackend();
|
| + typed_url_sync_service_.reset(new TypedUrlSyncableService(
|
| + fake_history_backend_));
|
| + fake_change_processor_.reset(new TestChangeProcessor);
|
| + }
|
| +
|
| + scoped_refptr<HistoryBackend> fake_history_backend_;
|
| + scoped_ptr<TypedUrlSyncableService> typed_url_sync_service_;
|
| + scoped_ptr<syncer::SyncChangeProcessor> fake_change_processor_;
|
| +};
|
| +
|
| +URLRow TypedUrlSyncableServiceTest::MakeTypedUrlRow(
|
| + const char* url,
|
| + const char* title,
|
| + int typed_count,
|
| + int64 last_visit,
|
| + bool hidden,
|
| + VisitVector* visits) {
|
| + DCHECK(visits->empty());
|
| +
|
| + // Give each URL a unique ID, to mimic the behavior of the real database.
|
| + static int unique_url_id = 0;
|
| + GURL gurl(url);
|
| + URLRow history_url(gurl, ++unique_url_id);
|
| + history_url.set_title(UTF8ToUTF16(title));
|
| + history_url.set_typed_count(typed_count);
|
| + history_url.set_hidden(hidden);
|
| +
|
| + base::Time last_visit_time = base::Time::FromInternalValue(last_visit);
|
| + history_url.set_last_visit(last_visit_time);
|
| +
|
| + VisitVector::iterator first = visits->begin();
|
| + if (typed_count > 0) {
|
| + // Add a typed visit for time |last_visit|.
|
| + visits->insert(first,
|
| + VisitRow(history_url.id(), last_visit_time, 0,
|
| + content::PAGE_TRANSITION_TYPED, 0));
|
| + } else {
|
| + // Add a non-typed visit for time |last_visit|.
|
| + visits->insert(first,
|
| + VisitRow(history_url.id(), last_visit_time, 0,
|
| + content::PAGE_TRANSITION_RELOAD, 0));
|
| + }
|
| +
|
| + history_url.set_visit_count(visits->size());
|
| + return history_url;
|
| +}
|
| +
|
| +void TypedUrlSyncableServiceTest::AddNewestVisit(
|
| + URLRow* url,
|
| + VisitVector* visits,
|
| + content::PageTransition transition,
|
| + int64 visit_time) {
|
| + base::Time time = base::Time::FromInternalValue(visit_time);
|
| + visits->insert(visits->begin(),
|
| + VisitRow(url->id(), time, 0, transition, 0));
|
| +
|
| + if (transition == content::PAGE_TRANSITION_TYPED) {
|
| + url->set_typed_count(url->typed_count() + 1);
|
| + }
|
| +
|
| + url->set_last_visit(time);
|
| + url->set_visit_count(visits->size());
|
| +}
|
| +
|
| +void TypedUrlSyncableServiceTest::AddOldestVisit(
|
| + URLRow* url,
|
| + VisitVector* visits,
|
| + content::PageTransition transition,
|
| + int64 visit_time) {
|
| + base::Time time = base::Time::FromInternalValue(visit_time);
|
| + visits->push_back(VisitRow(url->id(), time, 0, transition, 0));
|
| +
|
| + if (transition == content::PAGE_TRANSITION_TYPED) {
|
| + url->set_typed_count(url->typed_count() + 1);
|
| + }
|
| +
|
| + url->set_visit_count(visits->size());
|
| +}
|
| +
|
| +bool TypedUrlSyncableServiceTest::InitiateServerState(
|
| + unsigned int num_typed_urls,
|
| + unsigned int num_reload_urls,
|
| + URLRows* rows,
|
| + std::vector<VisitVector>* visit_vectors,
|
| + const std::vector<const char*>& urls,
|
| + syncer::SyncChangeList* change_list) {
|
| + unsigned int total_urls = num_typed_urls + num_reload_urls;
|
| + DCHECK(urls.size() >= total_urls);
|
| + if (!typed_url_sync_service_.get())
|
| + return false;
|
| +
|
| + static_cast<TestChangeProcessor*>(fake_change_processor_.get())->
|
| + SetChangeOutput(change_list);
|
| +
|
| + // Set change processor.
|
| + syncer::SyncMergeResult result =
|
| + typed_url_sync_service_->MergeDataAndStartSyncing(
|
| + syncer::TYPED_URLS,
|
| + syncer::SyncDataList(),
|
| + fake_change_processor_.Pass(),
|
| + scoped_ptr<syncer::SyncErrorFactory>(
|
| + new syncer::SyncErrorFactoryMock()));
|
| + EXPECT_FALSE(result.error().IsSet()) << result.error().message();
|
| +
|
| + if (total_urls) {
|
| + // Create new URL rows, populate the mock backend with its visits, and
|
| + // send to the sync service.
|
| + URLRows changed_urls;
|
| +
|
| + for (unsigned int i = 0; i < total_urls; ++i) {
|
| + int typed = i < num_typed_urls ? 1 : 0;
|
| + VisitVector visits;
|
| + visit_vectors->push_back(visits);
|
| + rows->push_back(MakeTypedUrlRow(
|
| + urls[i], "pie", typed, i + 3, false, &visit_vectors->back()));
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + SetVisitsForUrl(rows->back().id(), &visit_vectors->back());
|
| + changed_urls.push_back(rows->back());
|
| + }
|
| +
|
| + typed_url_sync_service_->OnUrlsModified(&changed_urls);
|
| + }
|
| + // Check that communication with sync was successful.
|
| + if (num_typed_urls != change_list->size())
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, AddLocalTypedUrlAndSync) {
|
| + // Create a local typed URL (simulate a typed visit) that is not already
|
| + // in sync. Check that sync is sent an ADD change for the existing URL.
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(1, 0, &url_rows, &visit_vectors, urls, &change_list));
|
| +
|
| + URLRow url_row = url_rows.front();
|
| + VisitVector visits = visit_vectors.front();
|
| +
|
| + // Check change processor.
|
| + ASSERT_EQ(1u, change_list.size());
|
| + ASSERT_TRUE(change_list[0].IsValid());
|
| + EXPECT_EQ(syncer::TYPED_URLS, change_list[0].sync_data().GetDataType());
|
| + EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change_list[0].change_type());
|
| +
|
| + // Get typed url specifics.
|
| + sync_pb::TypedUrlSpecifics url_specifics =
|
| + change_list[0].sync_data().GetSpecifics().typed_url();
|
| +
|
| + EXPECT_TRUE(URLsEqual(url_row, url_specifics));
|
| + ASSERT_EQ(1, url_specifics.visits_size());
|
| + ASSERT_EQ(static_cast<const int>(visits.size()), url_specifics.visits_size());
|
| + EXPECT_EQ(visits[0].visit_time.ToInternalValue(), url_specifics.visits(0));
|
| + EXPECT_EQ(static_cast<const int>(visits[0].transition),
|
| + url_specifics.visit_transitions(0));
|
| +
|
| + // Check that in-memory representation of sync state is accurate.
|
| + std::set<GURL> sync_state;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state);
|
| + EXPECT_FALSE(sync_state.empty());
|
| + EXPECT_EQ(1u, sync_state.size());
|
| + EXPECT_NE(sync_state.end(), sync_state.find(url_row.url()));
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, UpdateLocalTypedUrlAndSync) {
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(1, 0, &url_rows, &visit_vectors, urls, &change_list));
|
| + change_list.clear();
|
| +
|
| + // Update the URL row, adding another typed visit to the visit vector.
|
| + URLRow url_row = url_rows.front();
|
| + VisitVector visits = visit_vectors.front();
|
| +
|
| + URLRows changed_urls;
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_TYPED, 7);
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + SetVisitsForUrl(url_row.id(), &visits);
|
| + changed_urls.push_back(url_row);
|
| +
|
| + // Notify typed url sync service of the update.
|
| + typed_url_sync_service_->OnUrlsModified(&changed_urls);
|
| +
|
| + ASSERT_EQ(1u, change_list.size());
|
| + ASSERT_TRUE(change_list[0].IsValid());
|
| + EXPECT_EQ(syncer::TYPED_URLS, change_list[0].sync_data().GetDataType());
|
| + EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change_list[0].change_type());
|
| +
|
| + sync_pb::TypedUrlSpecifics url_specifics =
|
| + change_list[0].sync_data().GetSpecifics().typed_url();
|
| +
|
| + EXPECT_TRUE(URLsEqual(url_row, url_specifics));
|
| + ASSERT_EQ(2, url_specifics.visits_size());
|
| + ASSERT_EQ(static_cast<const int>(visits.size()), url_specifics.visits_size());
|
| +
|
| + // Check that each visit has been translated/communicated correctly.
|
| + // Note that the specifics record visits in chronological order, and the
|
| + // visits from the db are in reverse chronological order.
|
| + EXPECT_EQ(visits[0].visit_time.ToInternalValue(), url_specifics.visits(1));
|
| + EXPECT_EQ(static_cast<const int>(visits[0].transition),
|
| + url_specifics.visit_transitions(1));
|
| + EXPECT_EQ(visits[1].visit_time.ToInternalValue(), url_specifics.visits(0));
|
| + EXPECT_EQ(static_cast<const int>(visits[1].transition),
|
| + url_specifics.visit_transitions(0));
|
| +
|
| + // Check that in-memory representation of sync state is accurate.
|
| + std::set<GURL> sync_state;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state);
|
| + EXPECT_FALSE(sync_state.empty());
|
| + EXPECT_EQ(1u, sync_state.size());
|
| + EXPECT_NE(sync_state.end(), sync_state.find(url_row.url()));
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, LinkVisitLocalTypedUrlAndSync) {
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(1, 0, &url_rows, &visit_vectors, urls, &change_list));
|
| + change_list.clear();
|
| +
|
| + URLRow url_row = url_rows.front();
|
| + VisitVector visits = visit_vectors.front();
|
| +
|
| + // Update the URL row, adding a non-typed visit to the visit vector.
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_LINK, 6);
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + SetVisitsForUrl(url_row.id(), &visits);
|
| +
|
| + content::PageTransition transition = content::PAGE_TRANSITION_LINK;
|
| + // Notify typed url sync service of non-typed visit, expect no change.
|
| + typed_url_sync_service_->OnUrlVisited(transition, &url_row);
|
| + ASSERT_EQ(0u, change_list.size());
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, TypedVisitLocalTypedUrlAndSync) {
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(1, 0, &url_rows, &visit_vectors, urls, &change_list));
|
| + change_list.clear();
|
| +
|
| + URLRow url_row = url_rows.front();
|
| + VisitVector visits = visit_vectors.front();
|
| +
|
| + // Update the URL row, adding another typed visit to the visit vector.
|
| + AddOldestVisit(&url_row, &visits, content::PAGE_TRANSITION_LINK, 1);
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_LINK, 6);
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_TYPED, 7);
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + SetVisitsForUrl(url_row.id(), &visits);
|
| +
|
| + // Notify typed url sync service of typed visit.
|
| + content::PageTransition transition = content::PAGE_TRANSITION_TYPED;
|
| + typed_url_sync_service_->OnUrlVisited(transition, &url_row);
|
| +
|
| + ASSERT_EQ(1u, change_list.size());
|
| + ASSERT_TRUE(change_list[0].IsValid());
|
| + EXPECT_EQ(syncer::TYPED_URLS, change_list[0].sync_data().GetDataType());
|
| + EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change_list[0].change_type());
|
| +
|
| + sync_pb::TypedUrlSpecifics url_specifics =
|
| + change_list[0].sync_data().GetSpecifics().typed_url();
|
| +
|
| + EXPECT_TRUE(URLsEqual(url_row, url_specifics));
|
| + ASSERT_EQ(4u, visits.size());
|
| + EXPECT_EQ(static_cast<const int>(visits.size()), url_specifics.visits_size());
|
| +
|
| + // Check that each visit has been translated/communicated correctly.
|
| + // Note that the specifics record visits in chronological order, and the
|
| + // visits from the db are in reverse chronological order.
|
| + int r = url_specifics.visits_size() - 1;
|
| + for (int i = 0; i < url_specifics.visits_size(); ++i, --r) {
|
| + EXPECT_EQ(visits[i].visit_time.ToInternalValue(), url_specifics.visits(r));
|
| + EXPECT_EQ(static_cast<const int>(visits[i].transition),
|
| + url_specifics.visit_transitions(r));
|
| + }
|
| +
|
| + // Check that in-memory representation of sync state is accurate.
|
| + std::set<GURL> sync_state;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state);
|
| + EXPECT_FALSE(sync_state.empty());
|
| + EXPECT_EQ(1u, sync_state.size());
|
| + EXPECT_NE(sync_state.end(), sync_state.find(url_row.url()));
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, DeleteLocalTypedUrlAndSync) {
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| + urls.push_back("http://cake.com/");
|
| + urls.push_back("http://google.com/");
|
| + urls.push_back("http://foo.com/");
|
| + urls.push_back("http://bar.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(4, 1, &url_rows, &visit_vectors, urls, &change_list));
|
| + change_list.clear();
|
| +
|
| + // Check that in-memory representation of sync state is accurate.
|
| + std::set<GURL> sync_state;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state);
|
| + EXPECT_FALSE(sync_state.empty());
|
| + EXPECT_EQ(4u, sync_state.size());
|
| +
|
| + // Simulate visit expiry of typed visit, no syncing is done
|
| + // This is to test that sync relies on the in-memory cache to know
|
| + // which urls were typed and synced, and should be deleted.
|
| + url_rows[0].set_typed_count(0);
|
| + VisitVector visits;
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + SetVisitsForUrl(url_rows[0].id(), &visits);
|
| +
|
| + // Delete some urls from backend and create deleted row vector.
|
| + URLRows rows;
|
| + for (size_t i = 0; i < 3u; ++i) {
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + DeleteVisitsForUrl(url_rows[i].id());
|
| + rows.push_back(url_rows[i]);
|
| + }
|
| +
|
| + // Notify typed url sync service.
|
| + typed_url_sync_service_->OnUrlsDeleted(false, false, &rows);
|
| +
|
| + ASSERT_EQ(3u, change_list.size());
|
| + for (size_t i = 0; i < change_list.size(); ++i) {
|
| + ASSERT_TRUE(change_list[i].IsValid());
|
| + ASSERT_EQ(syncer::TYPED_URLS, change_list[i].sync_data().GetDataType());
|
| + EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, change_list[i].change_type());
|
| + sync_pb::TypedUrlSpecifics url_specifics =
|
| + change_list[i].sync_data().GetSpecifics().typed_url();
|
| + EXPECT_EQ(url_rows[i].url().spec(), url_specifics.url());
|
| + }
|
| +
|
| + // Check that in-memory representation of sync state is accurate.
|
| + std::set<GURL> sync_state_deleted;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state_deleted);
|
| + ASSERT_EQ(1u, sync_state_deleted.size());
|
| + EXPECT_NE(sync_state_deleted.end(),
|
| + sync_state_deleted.find(url_rows[3].url()));
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, DeleteAllLocalTypedUrlAndSync) {
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| + urls.push_back("http://cake.com/");
|
| + urls.push_back("http://google.com/");
|
| + urls.push_back("http://foo.com/");
|
| + urls.push_back("http://bar.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(4, 1, &url_rows, &visit_vectors, urls, &change_list));
|
| + change_list.clear();
|
| +
|
| + // Check that in-memory representation of sync state is accurate.
|
| + std::set<GURL> sync_state;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state);
|
| + EXPECT_EQ(4u, sync_state.size());
|
| +
|
| + // Delete urls from backend.
|
| + for (size_t i = 0; i < 4u; ++ i) {
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + DeleteVisitsForUrl(url_rows[i].id());
|
| + }
|
| + // Delete urls with |all_history| flag set.
|
| + bool all_history = true;
|
| +
|
| + // Notify typed url sync service.
|
| + typed_url_sync_service_->OnUrlsDeleted(all_history, false, NULL);
|
| +
|
| + ASSERT_EQ(4u, change_list.size());
|
| + for (size_t i = 0; i < change_list.size(); ++i) {
|
| + ASSERT_TRUE(change_list[i].IsValid());
|
| + ASSERT_EQ(syncer::TYPED_URLS, change_list[i].sync_data().GetDataType());
|
| + EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, change_list[i].change_type());
|
| + }
|
| + // Check that in-memory representation of sync state is accurate.
|
| + std::set<GURL> sync_state_deleted;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state_deleted);
|
| + EXPECT_TRUE(sync_state_deleted.empty());
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, MaxVisitLocalTypedUrlAndSync) {
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(0, 1, &url_rows, &visit_vectors, urls, &change_list));
|
| +
|
| + URLRow url_row = url_rows.front();
|
| + VisitVector visits;
|
| +
|
| + // Add |kMaxTypedUrlVisits| + 10 visits to the url. The 10 oldest
|
| + // non-typed visits are expected to be skipped.
|
| + int i = 1;
|
| + for (; i <= kMaxTypedUrlVisits - 20; ++i)
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_TYPED, i);
|
| + for (; i <= kMaxTypedUrlVisits; ++i)
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_LINK, i);
|
| + for (; i <= kMaxTypedUrlVisits + 10; ++i)
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_TYPED, i);
|
| +
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + SetVisitsForUrl(url_row.id(), &visits);
|
| +
|
| + // Notify typed url sync service of typed visit.
|
| + content::PageTransition transition = content::PAGE_TRANSITION_TYPED;
|
| + typed_url_sync_service_->OnUrlVisited(transition, &url_row);
|
| +
|
| + ASSERT_EQ(1u, change_list.size());
|
| + ASSERT_TRUE(change_list[0].IsValid());
|
| + sync_pb::TypedUrlSpecifics url_specifics =
|
| + change_list[0].sync_data().GetSpecifics().typed_url();
|
| + ASSERT_EQ(kMaxTypedUrlVisits, url_specifics.visits_size());
|
| +
|
| + // Check that each visit has been translated/communicated correctly.
|
| + // Note that the specifics record visits in chronological order, and the
|
| + // visits from the db are in reverse chronological order.
|
| + int num_typed_visits_synced = 0;
|
| + int num_other_visits_synced = 0;
|
| + int r = url_specifics.visits_size() - 1;
|
| + for (int i = 0; i < url_specifics.visits_size(); ++i, --r) {
|
| + if (url_specifics.visit_transitions(i) == content::PAGE_TRANSITION_TYPED) {
|
| + ++num_typed_visits_synced;
|
| + } else {
|
| + ++num_other_visits_synced;
|
| + }
|
| + }
|
| + EXPECT_EQ(kMaxTypedUrlVisits - 10, num_typed_visits_synced);
|
| + EXPECT_EQ(10, num_other_visits_synced);
|
| +}
|
| +
|
| +TEST_F(TypedUrlSyncableServiceTest, ThrottleVisitLocalTypedUrlSync) {
|
| + syncer::SyncChangeList change_list;
|
| +
|
| + URLRows url_rows;
|
| + std::vector<VisitVector> visit_vectors;
|
| + std::vector<const char*> urls;
|
| + urls.push_back("http://pie.com/");
|
| +
|
| + ASSERT_TRUE(
|
| + InitiateServerState(0, 1, &url_rows, &visit_vectors, urls, &change_list));
|
| +
|
| + URLRow url_row = url_rows.front();
|
| + VisitVector visits;
|
| +
|
| + // Add enough visits to the url so that typed count is above the throttle
|
| + // limit, and not right on the interval that gets synced.
|
| + for (int i = 1; i < 42; ++i)
|
| + AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_TYPED, i);
|
| +
|
| + static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
|
| + SetVisitsForUrl(url_row.id(), &visits);
|
| +
|
| + // Notify typed url sync service of typed visit.
|
| + content::PageTransition transition = content::PAGE_TRANSITION_TYPED;
|
| + typed_url_sync_service_->OnUrlVisited(transition, &url_row);
|
| +
|
| + // Should throttle, so sync and local cache should not update.
|
| + ASSERT_EQ(0u, change_list.size());
|
| + std::set<GURL> sync_state;
|
| + typed_url_sync_service_.get()->GetSyncedUrls(&sync_state);
|
| + EXPECT_TRUE(sync_state.empty());
|
| +}
|
| +
|
| +} // namespace history
|
|
|