Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4579)

Unified Diff: chrome/browser/history/typed_url_syncable_service_unittest.cc

Issue 12703036: [Sync] Add interface and backend impl for typed URL syncable service (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..53d9208626eda600405eca0193b6f09e68a07097
--- /dev/null
+++ b/chrome/browser/history/typed_url_syncable_service_unittest.cc
@@ -0,0 +1,673 @@
+// 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::URLsDeletedDetails;
+using history::URLsModifiedDetails;
+using history::URLVisitedDetails;
+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
+
+// TestHistoryBackend ----------------------------------------------------------
+
+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() {
Andrew T Wilson (Slow) 2013/04/09 12:48:30 add 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
+ // fill the URL details to send to the sync service
Andrew T Wilson (Slow) 2013/04/09 12:48:30 nit: sentence punctuation for all comments.
+ scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
+
+ 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());
+ details->changed_urls.push_back(rows->back());
+ }
+
+ typed_url_sync_service_->OnUrlsModified(details.get());
+ }
+ // 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();
+
+ scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
+ AddNewestVisit(&url_row, &visits, content::PAGE_TRANSITION_TYPED, 7);
+ static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
+ SetVisitsForUrl(url_row.id(), &visits);
+ details->changed_urls.push_back(url_row);
+
+ // Notify typed url sync service of the update
+ typed_url_sync_service_->OnUrlsModified(details.get());
+ ASSERT_TRUE(details.get());
+
+ 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);
+
+ scoped_ptr<URLVisitedDetails> visit_details(new URLVisitedDetails);
+ visit_details->row = url_row;
+ visit_details->transition = content::PAGE_TRANSITION_LINK;
+ // Notify typed url sync service of non-typed visit, expect no change
+ typed_url_sync_service_->OnUrlVisited(visit_details.get());
+ 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);
+
+ scoped_ptr<URLVisitedDetails> visit_details(new URLVisitedDetails);
+ visit_details->row = url_row;
+
+ // Notify typed url sync service of typed visit
+ visit_details->transition = content::PAGE_TRANSITION_TYPED;
+ typed_url_sync_service_->OnUrlVisited(visit_details.get());
+
+ 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 delete details
+ scoped_ptr<URLsDeletedDetails> delete_details(new URLsDeletedDetails);
+ for (size_t i = 0; i < 3u; ++i) {
+ static_cast<TestHistoryBackend*>(fake_history_backend_.get())->
+ DeleteVisitsForUrl(url_rows[i].id());
+ delete_details->rows.push_back(url_rows[i]);
+ }
+
+ // Notify typed url sync service
+ typed_url_sync_service_->OnUrlsDeleted(delete_details.get());
+ ASSERT_TRUE(delete_details.get());
+ delete_details.reset();
+
+ 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());
+ }
+ // Create delete details with |all_history| flag set
+ scoped_ptr<URLsDeletedDetails> delete_details(new URLsDeletedDetails);
+ delete_details->all_history = true;
+
+ // Notify typed url sync service
+ typed_url_sync_service_->OnUrlsDeleted(delete_details.get());
+ ASSERT_TRUE(delete_details.get());
+ delete_details.reset();
+
+ 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);
+
+ scoped_ptr<URLVisitedDetails> visit_details(new URLVisitedDetails);
+ visit_details->row = url_row;
+
+ // Notify typed url sync service of typed visit
+ visit_details->transition = content::PAGE_TRANSITION_TYPED;
+ typed_url_sync_service_->OnUrlVisited(visit_details.get());
+
+ 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);
+
+ scoped_ptr<URLVisitedDetails> visit_details(new URLVisitedDetails);
+ visit_details->row = url_row;
+
+ // Notify typed url sync service of typed visit
+ visit_details->transition = content::PAGE_TRANSITION_TYPED;
+ typed_url_sync_service_->OnUrlVisited(visit_details.get());
+
+ // 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());
+}

Powered by Google App Engine
This is Rietveld 408576698