summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-30 17:33:18 +0000
committerzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-30 17:33:18 +0000
commit7e6851a56fbeef097a06e58e0aa22ed78fb3b0eb (patch)
tree706a132fa94804b3d8df4d51a8b7af8ae4c3743e
parent1cd5881de55d7b557e7e308b9b2e7a2442c86a6e (diff)
downloadchromium_src-7e6851a56fbeef097a06e58e0aa22ed78fb3b0eb.zip
chromium_src-7e6851a56fbeef097a06e58e0aa22ed78fb3b0eb.tar.gz
chromium_src-7e6851a56fbeef097a06e58e0aa22ed78fb3b0eb.tar.bz2
Update typed_url sync to support visits.
BUG=none TEST=none Review URL: http://codereview.chromium.org/1775004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46085 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/history/history_backend.cc55
-rw-r--r--chrome/browser/history/history_backend.h9
-rw-r--r--chrome/browser/sync/glue/typed_url_change_processor.cc151
-rw-r--r--chrome/browser/sync/glue/typed_url_change_processor.h7
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator.cc209
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator.h21
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator_unittest.cc161
-rw-r--r--chrome/browser/sync/profile_sync_service_typed_url_unittest.cc109
-rw-r--r--chrome/browser/sync/protocol/typed_url_specifics.proto7
9 files changed, 602 insertions, 127 deletions
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 58fa489..4be006a 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -855,12 +855,65 @@ bool HistoryBackend::GetAllTypedURLs(std::vector<history::URLRow>* urls) {
return false;
}
-bool HistoryBackend::UpdateURL(const URLID id, const history::URLRow& url) {
+bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
+ if (db_.get())
+ return db_->GetVisitsForURL(id, visits);
+ return false;
+}
+
+bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
if (db_.get())
return db_->UpdateURLRow(id, url);
return false;
}
+bool HistoryBackend::AddVisits(const GURL& url,
+ const std::vector<base::Time>& visits) {
+ if (db_.get()) {
+ for (std::vector<base::Time>::const_iterator visit = visits.begin();
+ visit != visits.end(); ++visit) {
+ if (!AddPageVisit(url, *visit, 0, 0).first) {
+ return false;
+ }
+ }
+ ScheduleCommit();
+ return true;
+ }
+ return false;
+}
+
+bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
+ if (db_.get()) {
+ std::map<URLID, int> url_visits_removed;
+ for (VisitVector::const_iterator visit = visits.begin();
+ visit != visits.end(); ++visit) {
+ db_->DeleteVisit(*visit);
+ std::map<URLID, int>::iterator visit_count =
+ url_visits_removed.find(visit->url_id);
+ if (visit_count == url_visits_removed.end()) {
+ url_visits_removed[visit->url_id] = 1;
+ } else {
+ ++visit_count->second;
+ }
+ }
+ for (std::map<URLID, int>::iterator count = url_visits_removed.begin();
+ count != url_visits_removed.end(); ++count) {
+ history::URLRow url_row;
+ if (!db_->GetURLRow(count->first, &url_row)) {
+ return false;
+ }
+ DCHECK(count->second <= url_row.visit_count());
+ url_row.set_visit_count(url_row.visit_count() - count->second);
+ if (!db_->UpdateURLRow(url_row.id(), url_row)) {
+ return false;
+ }
+ }
+ ScheduleCommit();
+ return true;
+ }
+ return false;
+}
+
bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
if (db_.get())
return db_->GetRowForURL(url, url_row) != 0;
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index 7d230c6..7289b5a 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -240,7 +240,14 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
virtual bool GetAllTypedURLs(std::vector<history::URLRow>* urls);
- virtual bool UpdateURL(const URLID id, const history::URLRow& url);
+ virtual bool GetVisitsForURL(URLID id, VisitVector* visits);
+
+ virtual bool UpdateURL(URLID id, const history::URLRow& url);
+
+ virtual bool AddVisits(const GURL& url,
+ const std::vector<base::Time>& visits);
+
+ virtual bool RemoveVisits(const VisitVector& visits);
virtual bool GetURL(const GURL& url, history::URLRow* url_row);
diff --git a/chrome/browser/sync/glue/typed_url_change_processor.cc b/chrome/browser/sync/glue/typed_url_change_processor.cc
index 864721b..e659f23 100644
--- a/chrome/browser/sync/glue/typed_url_change_processor.cc
+++ b/chrome/browser/sync/glue/typed_url_change_processor.cc
@@ -50,20 +50,34 @@ void TypedUrlChangeProcessor::Observe(NotificationType type,
LOG(INFO) << "Observed typed_url change.";
DCHECK(running());
DCHECK(NotificationType::HISTORY_TYPED_URLS_MODIFIED == type ||
- NotificationType::HISTORY_URLS_DELETED == type);
+ NotificationType::HISTORY_URLS_DELETED == type ||
+ NotificationType::HISTORY_URL_VISITED == type);
if (type == NotificationType::HISTORY_TYPED_URLS_MODIFIED) {
HandleURLsModified(Details<history::URLsModifiedDetails>(details).ptr());
} else if (type == NotificationType::HISTORY_URLS_DELETED) {
HandleURLsDeleted(Details<history::URLsDeletedDetails>(details).ptr());
+ } else if (type == NotificationType::HISTORY_URL_VISITED) {
+ HandleURLsVisited(Details<history::URLVisitedDetails>(details).ptr());
}
}
void TypedUrlChangeProcessor::HandleURLsModified(
history::URLsModifiedDetails* details) {
- sync_api::WriteTransaction trans(share_handle());
+ // Get all the visits.
+ std::map<history::URLID, history::VisitVector> visit_vectors;
+ for (std::vector<history::URLRow>::iterator url =
+ details->changed_urls.begin(); url != details->changed_urls.end();
+ ++url) {
+ if (!history_backend_->GetVisitsForURL(url->id(),
+ &(visit_vectors[url->id()]))) {
+ error_handler()->OnUnrecoverableError();
+ LOG(ERROR) << "Could not get the url's visits.";
+ return;
+ }
+ DCHECK(!visit_vectors[url->id()].empty());
+ }
- // TODO(sync): Get visits without holding the write transaction.
- // See issue 34206
+ sync_api::WriteTransaction trans(share_handle());
sync_api::ReadNode typed_url_root(&trans);
if (!typed_url_root.InitByTagLookup(kTypedUrlTag)) {
@@ -78,9 +92,20 @@ void TypedUrlChangeProcessor::HandleURLsModified(
++url) {
std::string tag = url->url().spec();
+ history::VisitVector& visits = visit_vectors[url->id()];
+
+ DCHECK(!visits.empty());
+
+ DCHECK(static_cast<size_t>(url->visit_count()) == visits.size());
+ if (static_cast<size_t>(url->visit_count()) != visits.size()) {
+ error_handler()->OnUnrecoverableError();
+ LOG(ERROR) << "Visit count does not match.";
+ return;
+ }
+
sync_api::WriteNode update_node(&trans);
if (update_node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) {
- model_associator_->WriteToSyncNode(*url, &update_node);
+ model_associator_->WriteToSyncNode(*url, visits, &update_node);
} else {
sync_api::WriteNode create_node(&trans);
if (!create_node.InitUniqueByCreation(syncable::TYPED_URLS,
@@ -91,7 +116,7 @@ void TypedUrlChangeProcessor::HandleURLsModified(
}
create_node.SetTitle(UTF8ToWide(tag));
- model_associator_->WriteToSyncNode(*url, &create_node);
+ model_associator_->WriteToSyncNode(*url, visits, &create_node);
model_associator_->Associate(&tag, create_node.GetId());
}
@@ -112,13 +137,8 @@ void TypedUrlChangeProcessor::HandleURLsDeleted(
url != details->urls.end(); ++url) {
sync_api::WriteNode sync_node(&trans);
int64 sync_id =
- model_associator_->GetSyncIdFromChromeId(url->spec());
- if (sync_api::kInvalidId == sync_id) {
- LOG(ERROR) << "Unexpected notification for: " <<
- url->spec();
- error_handler()->OnUnrecoverableError();
- return;
- } else {
+ model_associator_->GetSyncIdFromChromeId(url->spec());
+ if (sync_api::kInvalidId != sync_id) {
if (!sync_node.InitByIdLookup(sync_id)) {
LOG(ERROR) << "Typed url node lookup failed.";
error_handler()->OnUnrecoverableError();
@@ -131,6 +151,34 @@ void TypedUrlChangeProcessor::HandleURLsDeleted(
}
}
+void TypedUrlChangeProcessor::HandleURLsVisited(
+ history::URLVisitedDetails* details) {
+ if (!details->row.typed_count()) {
+ // We only care about typed urls.
+ return;
+ }
+ history::VisitVector visits;
+ if (!history_backend_->GetVisitsForURL(details->row.id(), &visits) ||
+ visits.empty()) {
+ error_handler()->OnUnrecoverableError();
+ LOG(ERROR) << "Could not get the url's visits.";
+ return;
+ }
+
+ DCHECK(static_cast<size_t>(details->row.visit_count()) == visits.size());
+
+ sync_api::WriteTransaction trans(share_handle());
+ std::string tag = details->row.url().spec();
+ sync_api::WriteNode update_node(&trans);
+ if (!update_node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) {
+ // If we don't know about it yet, it will be added later.
+ return;
+ }
+ sync_pb::TypedUrlSpecifics typed_url(update_node.GetTypedUrlSpecifics());
+ typed_url.add_visit(visits.back().visit_time.ToInternalValue());
+ update_node.SetTypedUrlSpecifics(typed_url);
+}
+
void TypedUrlChangeProcessor::ApplyChangesFromSyncModel(
const sync_api::BaseTransaction* trans,
const sync_api::SyncManager::ChangeRecord* changes,
@@ -149,6 +197,8 @@ void TypedUrlChangeProcessor::ApplyChangesFromSyncModel(
TypedUrlModelAssociator::TypedUrlTitleVector titles;
TypedUrlModelAssociator::TypedUrlVector new_urls;
+ TypedUrlModelAssociator::TypedUrlVisitVector new_visits;
+ history::VisitVector deleted_visits;
TypedUrlModelAssociator::TypedUrlUpdateVector updated_urls;
for (int i = 0; i < change_count; ++i) {
@@ -166,33 +216,62 @@ void TypedUrlChangeProcessor::ApplyChangesFromSyncModel(
const sync_pb::TypedUrlSpecifics& typed_url(
sync_node.GetTypedUrlSpecifics());
+ GURL url(typed_url.url());
+
if (sync_api::SyncManager::ChangeRecord::ACTION_ADD == changes[i].action) {
- history::URLRow new_url(GURL(typed_url.url()));
+ DCHECK(typed_url.visit_size());
+ if (!typed_url.visit_size()) {
+ continue;
+ }
+
+ history::URLRow new_url(url);
new_url.set_title(UTF8ToWide(typed_url.title()));
- new_url.set_visit_count(typed_url.visit_count());
+
+ // When we add a new url, the last visit is always added, thus we set
+ // the initial visit count to one. This value will be automatically
+ // incremented as visits are added.
+ new_url.set_visit_count(1);
new_url.set_typed_count(typed_url.typed_count());
- new_url.set_last_visit(
- base::Time::FromInternalValue(typed_url.last_visit()));
new_url.set_hidden(typed_url.hidden());
+ new_url.set_last_visit(base::Time::FromInternalValue(
+ typed_url.visit(typed_url.visit_size() - 1)));
+
new_urls.push_back(new_url);
+
+ // The latest visit gets added automatically, so skip it.
+ std::vector<base::Time> added_visits;
+ for (int c = 0; c < typed_url.visit_size() - 1; ++c) {
+ DCHECK(typed_url.visit(c) < typed_url.visit(c + 1));
+ added_visits.push_back(
+ base::Time::FromInternalValue(typed_url.visit(c)));
+ }
+
+ new_visits.push_back(
+ std::pair<GURL, std::vector<base::Time> >(url, added_visits));
} else if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
changes[i].action) {
- history_backend_->DeleteURL(GURL(typed_url.url()));
+ history_backend_->DeleteURL(url);
} else {
history::URLRow old_url;
- if (!history_backend_->GetURL(GURL(typed_url.url()), &old_url)) {
+ if (!history_backend_->GetURL(url, &old_url)) {
LOG(ERROR) << "TypedUrl db lookup failed.";
error_handler()->OnUnrecoverableError();
return;
}
- history::URLRow new_url(GURL(typed_url.url()));
+ history::VisitVector visits;
+ if (!history_backend_->GetVisitsForURL(old_url.id(), &visits)) {
+ LOG(ERROR) << "Could not get the url's visits.";
+ error_handler()->OnUnrecoverableError();
+ return;
+ }
+
+ history::URLRow new_url(url);
new_url.set_title(UTF8ToWide(typed_url.title()));
- new_url.set_visit_count(typed_url.visit_count());
+ new_url.set_visit_count(old_url.visit_count());
new_url.set_typed_count(typed_url.typed_count());
- new_url.set_last_visit(
- base::Time::FromInternalValue(typed_url.last_visit()));
+ new_url.set_last_visit(old_url.last_visit());
new_url.set_hidden(typed_url.hidden());
updated_urls.push_back(
@@ -202,9 +281,28 @@ void TypedUrlChangeProcessor::ApplyChangesFromSyncModel(
titles.push_back(std::pair<GURL, std::wstring>(new_url.url(),
new_url.title()));
}
+
+ std::vector<base::Time> added_visits;
+ history::VisitVector removed_visits;
+ TypedUrlModelAssociator::DiffVisits(visits, typed_url,
+ &added_visits, &removed_visits);
+ if (added_visits.size()) {
+ new_visits.push_back(
+ std::pair<GURL, std::vector<base::Time> >(url, added_visits));
+ }
+ if (removed_visits.size()) {
+ deleted_visits.insert(deleted_visits.end(), removed_visits.begin(),
+ removed_visits.end());
+ }
}
}
- model_associator_->WriteToHistoryBackend(&titles, &new_urls, &updated_urls);
+ if (!model_associator_->WriteToHistoryBackend(&titles, &new_urls,
+ &updated_urls,
+ &new_visits, &deleted_visits)) {
+ LOG(ERROR) << "Could not write to the history backend.";
+ error_handler()->OnUnrecoverableError();
+ return;
+ }
StartObserving();
}
@@ -227,6 +325,8 @@ void TypedUrlChangeProcessor::StartObserving() {
NotificationService::AllSources());
notification_registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
NotificationService::AllSources());
+ notification_registrar_.Add(this, NotificationType::HISTORY_URL_VISITED,
+ NotificationService::AllSources());
}
void TypedUrlChangeProcessor::StopObserving() {
@@ -237,6 +337,9 @@ void TypedUrlChangeProcessor::StopObserving() {
notification_registrar_.Remove(this,
NotificationType::HISTORY_URLS_DELETED,
NotificationService::AllSources());
+ notification_registrar_.Remove(this,
+ NotificationType::HISTORY_URL_VISITED,
+ NotificationService::AllSources());
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/typed_url_change_processor.h b/chrome/browser/sync/glue/typed_url_change_processor.h
index 920c62e..7fb9eb6 100644
--- a/chrome/browser/sync/glue/typed_url_change_processor.h
+++ b/chrome/browser/sync/glue/typed_url_change_processor.h
@@ -24,6 +24,7 @@ namespace history {
class HistoryBackend;
struct URLsDeletedDetails;
struct URLsModifiedDetails;
+struct URLVisitedDetails;
class URLRow;
};
@@ -60,16 +61,12 @@ class TypedUrlChangeProcessor : public ChangeProcessor,
virtual void StopImpl();
private:
- bool WriteTypedUrl(sync_api::WriteNode* node,
- const string16& name,
- const string16& value,
- std::vector<base::Time>& timestamps);
-
void StartObserving();
void StopObserving();
void HandleURLsModified(history::URLsModifiedDetails* details);
void HandleURLsDeleted(history::URLsDeletedDetails* details);
+ void HandleURLsVisited(history::URLVisitedDetails* details);
// The two models should be associated according to this ModelAssociator.
TypedUrlModelAssociator* model_associator_;
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.cc b/chrome/browser/sync/glue/typed_url_model_associator.cc
index 458ad79..b5f60f1 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator.cc
+++ b/chrome/browser/sync/glue/typed_url_model_associator.cc
@@ -42,8 +42,21 @@ bool TypedUrlModelAssociator::AssociateModels() {
return false;
}
+ // Get all the visits.
+ std::map<history::URLID, history::VisitVector> visit_vectors;
+ for (std::vector<history::URLRow>::iterator ix = typed_urls.begin();
+ ix != typed_urls.end(); ++ix) {
+ if (!history_backend_->GetVisitsForURL(ix->id(),
+ &(visit_vectors[ix->id()]))) {
+ LOG(ERROR) << "Could not get the url's visits.";
+ return false;
+ }
+ DCHECK(!visit_vectors[ix->id()].empty());
+ }
+
TypedUrlTitleVector titles;
TypedUrlVector new_urls;
+ TypedUrlVisitVector new_visits;
TypedUrlUpdateVector updated_urls;
{
@@ -61,6 +74,13 @@ bool TypedUrlModelAssociator::AssociateModels() {
ix != typed_urls.end(); ++ix) {
std::string tag = ix->url().spec();
+ history::VisitVector& visits = visit_vectors[ix->id()];
+ DCHECK(visits.size() == static_cast<size_t>(ix->visit_count()));
+ if (visits.size() != static_cast<size_t>(ix->visit_count())) {
+ LOG(ERROR) << "Visit count does not match.";
+ return false;
+ }
+
sync_api::ReadNode node(&trans);
if (node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) {
const sync_pb::TypedUrlSpecifics& typed_url(
@@ -69,14 +89,16 @@ bool TypedUrlModelAssociator::AssociateModels() {
history::URLRow new_url(ix->url());
- int difference = MergeUrls(typed_url, *ix, &new_url);
+ std::vector<base::Time> added_visits;
+ int difference = MergeUrls(typed_url, *ix, &visits, &new_url,
+ &added_visits);
if (difference & DIFF_NODE_CHANGED) {
sync_api::WriteNode write_node(&trans);
if (!write_node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) {
LOG(ERROR) << "Failed to edit typed_url sync node.";
return false;
}
- WriteToSyncNode(new_url, &write_node);
+ WriteToSyncNode(new_url, visits, &write_node);
}
if (difference & DIFF_TITLE_CHANGED) {
titles.push_back(std::pair<GURL, std::wstring>(new_url.url(),
@@ -86,6 +108,11 @@ bool TypedUrlModelAssociator::AssociateModels() {
updated_urls.push_back(
std::pair<history::URLID, history::URLRow>(ix->id(), new_url));
}
+ if (difference & DIFF_VISITS_ADDED) {
+ new_visits.push_back(
+ std::pair<GURL, std::vector<base::Time> >(ix->url(),
+ added_visits));
+ }
Associate(&tag, node.GetId());
} else {
@@ -97,7 +124,7 @@ bool TypedUrlModelAssociator::AssociateModels() {
}
node.SetTitle(UTF8ToWide(tag));
- WriteToSyncNode(*ix, &node);
+ WriteToSyncNode(*ix, visits, &node);
Associate(&tag, node.GetId());
}
@@ -116,15 +143,31 @@ bool TypedUrlModelAssociator::AssociateModels() {
sync_child_node.GetTypedUrlSpecifics());
if (current_urls.find(typed_url.url()) == current_urls.end()) {
+ new_visits.push_back(
+ std::pair<GURL, std::vector<base::Time> >(
+ GURL(typed_url.url()),
+ std::vector<base::Time>()));
+ std::vector<base::Time>& visits = new_visits.back().second;
history::URLRow new_url(GURL(typed_url.url()));
new_url.set_title(UTF8ToWide(typed_url.title()));
- new_url.set_visit_count(typed_url.visit_count());
+
+ // When we add a new url, the last visit is always added, thus we set
+ // the initial visit count to one. This value will be automatically
+ // incremented as visits are added.
+ new_url.set_visit_count(1);
new_url.set_typed_count(typed_url.typed_count());
- new_url.set_last_visit(
- base::Time::FromInternalValue(typed_url.last_visit()));
new_url.set_hidden(typed_url.hidden());
+ // The latest visit gets added automatically, so skip it.
+ for (int c = 0; c < typed_url.visit_size() - 1; ++c) {
+ DCHECK(typed_url.visit(c) < typed_url.visit(c + 1));
+ visits.push_back(base::Time::FromInternalValue(typed_url.visit(c)));
+ }
+
+ new_url.set_last_visit(base::Time::FromInternalValue(
+ typed_url.visit(typed_url.visit_size() - 1)));
+
Associate(&typed_url.url(), sync_child_node.GetId());
new_urls.push_back(new_url);
}
@@ -138,9 +181,8 @@ bool TypedUrlModelAssociator::AssociateModels() {
// this is the only thread that writes to the database. We also don't have
// to worry about the sync model getting out of sync, because changes are
// propogated to the ChangeProcessor on this thread.
- WriteToHistoryBackend(&titles, &new_urls, &updated_urls);
-
- return true;
+ return WriteToHistoryBackend(&titles, &new_urls, &updated_urls,
+ &new_visits, NULL);
}
bool TypedUrlModelAssociator::DeleteAllNodes(
@@ -235,10 +277,12 @@ bool TypedUrlModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
return true;
}
-void TypedUrlModelAssociator::WriteToHistoryBackend(
+bool TypedUrlModelAssociator::WriteToHistoryBackend(
const TypedUrlTitleVector* titles,
const TypedUrlVector* new_urls,
- const TypedUrlUpdateVector* updated_urls) {
+ const TypedUrlUpdateVector* updated_urls,
+ const TypedUrlVisitVector* new_visits,
+ const history::VisitVector* deleted_visits) {
if (titles) {
for (TypedUrlTitleVector::const_iterator title = titles->begin();
title != titles->end(); ++title) {
@@ -251,24 +295,49 @@ void TypedUrlModelAssociator::WriteToHistoryBackend(
if (updated_urls) {
for (TypedUrlUpdateVector::const_iterator url = updated_urls->begin();
url != updated_urls->end(); ++url) {
- history_backend_->UpdateURL(url->first, url->second);
+ if (!history_backend_->UpdateURL(url->first, url->second)) {
+ LOG(ERROR) << "Could not update page: " << url->second.url().spec();
+ return false;
+ }
+ }
+ }
+ if (new_visits) {
+ for (TypedUrlVisitVector::const_iterator visits = new_visits->begin();
+ visits != new_visits->end(); ++visits) {
+ if (!history_backend_->AddVisits(visits->first, visits->second)) {
+ LOG(ERROR) << "Could not add visits.";
+ return false;
+ }
+ }
+ }
+ if (deleted_visits) {
+ if (!history_backend_->RemoveVisits(*deleted_visits)) {
+ LOG(ERROR) << "Could not remove visits.";
+ return false;
}
}
+ return true;
}
// static
int TypedUrlModelAssociator::MergeUrls(
const sync_pb::TypedUrlSpecifics& typed_url,
const history::URLRow& url,
- history::URLRow* new_url) {
+ history::VisitVector* visits,
+ history::URLRow* new_url,
+ std::vector<base::Time>* new_visits) {
DCHECK(new_url);
DCHECK(!typed_url.url().compare(url.url().spec()));
DCHECK(!typed_url.url().compare(new_url->url().spec()));
+ DCHECK(visits->size());
+
+ new_url->set_visit_count(visits->size());
// Convert these values only once.
std::wstring typed_title(UTF8ToWide(typed_url.title()));
base::Time typed_visit =
- base::Time::FromInternalValue(typed_url.last_visit());
+ base::Time::FromInternalValue(
+ typed_url.visit(typed_url.visit_size() - 1));
// This is a bitfield represting what we'll need to update with the output
// value.
@@ -276,12 +345,10 @@ int TypedUrlModelAssociator::MergeUrls(
// Check if the non-incremented values changed.
if ((typed_title.compare(url.title()) != 0) ||
- (typed_visit != url.last_visit()) ||
(typed_url.hidden() != url.hidden())) {
// Use the values from the most recent visit.
if (typed_visit >= url.last_visit()) {
new_url->set_title(typed_title);
- new_url->set_last_visit(typed_visit);
new_url->set_hidden(typed_url.hidden());
different |= DIFF_ROW_CHANGED;
@@ -291,55 +358,129 @@ int TypedUrlModelAssociator::MergeUrls(
}
} else {
new_url->set_title(url.title());
- new_url->set_last_visit(url.last_visit());
new_url->set_hidden(url.hidden());
different |= DIFF_NODE_CHANGED;
}
} else {
// No difference.
new_url->set_title(url.title());
- new_url->set_last_visit(url.last_visit());
new_url->set_hidden(url.hidden());
}
- // For visit count, we just select the maximum value.
- if (typed_url.visit_count() > url.visit_count()) {
- new_url->set_visit_count(typed_url.visit_count());
- different |= DIFF_ROW_CHANGED;
- } else if (typed_url.visit_count() < url.visit_count()) {
- new_url->set_visit_count(url.visit_count());
- different |= DIFF_NODE_CHANGED;
- } else {
- new_url->set_visit_count(typed_url.visit_count());
- }
-
// For typed count, we just select the maximum value.
if (typed_url.typed_count() > url.typed_count()) {
new_url->set_typed_count(typed_url.typed_count());
different |= DIFF_ROW_CHANGED;
} else if (typed_url.typed_count() < url.typed_count()) {
- new_url->set_typed_count(url.visit_count());
+ new_url->set_typed_count(url.typed_count());
different |= DIFF_NODE_CHANGED;
} else {
// No difference.
new_url->set_typed_count(typed_url.typed_count());
}
+ size_t left_visit_count = typed_url.visit_size();
+ size_t right_visit_count = visits->size();
+ size_t left = 0;
+ size_t right = 0;
+ while (left < left_visit_count && right < right_visit_count) {
+ base::Time left_time = base::Time::FromInternalValue(typed_url.visit(left));
+ if (left_time < (*visits)[right].visit_time) {
+ different |= DIFF_VISITS_ADDED;
+ new_visits->push_back(left_time);
+ // This visit is added to visits below.
+ ++left;
+ } else if (left_time > (*visits)[right].visit_time) {
+ different |= DIFF_NODE_CHANGED;
+ ++right;
+ } else {
+ ++left;
+ ++right;
+ }
+ }
+
+ for ( ; left < left_visit_count; ++left) {
+ different |= DIFF_VISITS_ADDED;
+ base::Time left_time = base::Time::FromInternalValue(typed_url.visit(left));
+ new_visits->push_back(left_time);
+ // This visit is added to visits below.
+ }
+ if (different & DIFF_VISITS_ADDED) {
+ history::VisitVector::iterator visit_ix = visits->begin();
+ for (std::vector<base::Time>::iterator new_visit = new_visits->begin();
+ new_visit != new_visits->end(); ++new_visit) {
+ while (visit_ix != visits->end() && *new_visit > visit_ix->visit_time) {
+ ++visit_ix;
+ }
+ visit_ix = visits->insert(visit_ix,
+ history::VisitRow(url.id(), *new_visit,
+ 0, 0, 0));
+ ++visit_ix;
+ }
+ }
+
+ new_url->set_last_visit(visits->back().visit_time);
+
+ DCHECK(static_cast<size_t>(new_url->visit_count()) ==
+ (visits->size() - new_visits->size()));
+
return different;
}
// static
-void TypedUrlModelAssociator::WriteToSyncNode(const history::URLRow& url,
- sync_api::WriteNode* node) {
+void TypedUrlModelAssociator::WriteToSyncNode(
+ const history::URLRow& url,
+ const history::VisitVector& visits,
+ sync_api::WriteNode* node) {
+ DCHECK(!url.last_visit().is_null());
+ DCHECK(!visits.empty());
+ DCHECK(url.last_visit() == visits.back().visit_time);
+
sync_pb::TypedUrlSpecifics typed_url;
typed_url.set_url(url.url().spec());
typed_url.set_title(WideToUTF8(url.title()));
- typed_url.set_visit_count(url.visit_count());
typed_url.set_typed_count(url.typed_count());
- typed_url.set_last_visit(url.last_visit().ToInternalValue());
typed_url.set_hidden(url.hidden());
+ for (history::VisitVector::const_iterator visit = visits.begin();
+ visit != visits.end(); ++visit) {
+ typed_url.add_visit(visit->visit_time.ToInternalValue());
+ }
+
node->SetTypedUrlSpecifics(typed_url);
}
+// static
+void TypedUrlModelAssociator::DiffVisits(
+ const history::VisitVector& old_visits,
+ const sync_pb::TypedUrlSpecifics& new_url,
+ std::vector<base::Time>* new_visits,
+ history::VisitVector* removed_visits) {
+ size_t left_visit_count = old_visits.size();
+ size_t right_visit_count = new_url.visit_size();
+ size_t left = 0;
+ size_t right = 0;
+ while (left < left_visit_count && right < right_visit_count) {
+ base::Time right_time = base::Time::FromInternalValue(new_url.visit(right));
+ if (old_visits[left].visit_time < right_time) {
+ removed_visits->push_back(old_visits[left]);
+ ++left;
+ } else if (old_visits[left].visit_time > right_time) {
+ new_visits->push_back(right_time);
+ ++right;
+ } else {
+ ++left;
+ ++right;
+ }
+ }
+
+ for ( ; left < left_visit_count; ++left) {
+ removed_visits->push_back(old_visits[left]);
+ }
+
+ for ( ; right < right_visit_count; ++right) {
+ new_visits->push_back(base::Time::FromInternalValue(new_url.visit(right)));
+ }
+}
+
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.h b/chrome/browser/sync/glue/typed_url_model_associator.h
index 82f4fa6..5aea994 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator.h
+++ b/chrome/browser/sync/glue/typed_url_model_associator.h
@@ -50,7 +50,9 @@ class TypedUrlModelAssociator
typedef std::vector<std::pair<GURL, std::wstring> > TypedUrlTitleVector;
typedef std::vector<history::URLRow> TypedUrlVector;
typedef std::vector<std::pair<history::URLID, history::URLRow> >
- TypedUrlUpdateVector;
+ TypedUrlUpdateVector;
+ typedef std::vector<std::pair<GURL, std::vector<base::Time> > >
+ TypedUrlVisitVector;
static syncable::ModelType model_type() { return syncable::TYPED_URLS; }
TypedUrlModelAssociator(ProfileSyncService* sync_service,
@@ -106,23 +108,34 @@ class TypedUrlModelAssociator
// |sync_id| with that node's id.
virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id);
- void WriteToHistoryBackend(const TypedUrlTitleVector* titles,
+ bool WriteToHistoryBackend(const TypedUrlTitleVector* titles,
const TypedUrlVector* new_urls,
- const TypedUrlUpdateVector* updated_urls);
+ const TypedUrlUpdateVector* updated_urls,
+ const TypedUrlVisitVector* new_visits,
+ const history::VisitVector* deleted_visits);
enum {
DIFF_NONE = 0x0000,
DIFF_NODE_CHANGED = 0x0001,
DIFF_TITLE_CHANGED = 0x0002,
DIFF_ROW_CHANGED = 0x0004,
+ DIFF_VISITS_ADDED = 0x0008,
};
static int MergeUrls(const sync_pb::TypedUrlSpecifics& typed_url,
const history::URLRow& url,
- history::URLRow* new_url);
+ history::VisitVector* visits,
+ history::URLRow* new_url,
+ std::vector<base::Time>* new_visits);
static void WriteToSyncNode(const history::URLRow& url,
+ const history::VisitVector& visits,
sync_api::WriteNode* node);
+ static void DiffVisits(const history::VisitVector& old_visits,
+ const sync_pb::TypedUrlSpecifics& new_url,
+ std::vector<base::Time>* new_visits,
+ history::VisitVector* removed_visits);
+
protected:
// Returns sync service instance.
ProfileSyncService* sync_service() { return sync_service_; }
diff --git a/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc b/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc
index 397e4e2..238b575 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc
+++ b/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/basictypes.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/history/history_types.h"
@@ -16,34 +17,34 @@ class TypedUrlModelAssociatorTest : public testing::Test {
public:
static history::URLRow MakeTypedUrlRow(const char* url,
const char* title,
- int visit_count,
int typed_count,
int64 last_visit,
- bool hidden) {
+ bool hidden,
+ history::VisitVector* visits) {
GURL gurl(url);
history::URLRow history_url(gurl);
history_url.set_title(UTF8ToWide(title));
- history_url.set_visit_count(visit_count);
history_url.set_typed_count(typed_count);
history_url.set_last_visit(
base::Time::FromInternalValue(last_visit));
history_url.set_hidden(hidden);
+ visits->push_back(history::VisitRow(
+ history_url.id(), history_url.last_visit(), 0, 0, 0));
+ history_url.set_visit_count(visits->size());
return history_url;
}
static sync_pb::TypedUrlSpecifics MakeTypedUrlSpecifics(const char* url,
const char* title,
- int visit_count,
int typed_count,
int64 last_visit,
bool hidden) {
sync_pb::TypedUrlSpecifics typed_url;
typed_url.set_url(url);
typed_url.set_title(title);
- typed_url.set_visit_count(visit_count);
typed_url.set_typed_count(typed_count);
- typed_url.set_last_visit(last_visit);
typed_url.set_hidden(hidden);
+ typed_url.add_visit(last_visit);
return typed_url;
}
@@ -52,69 +53,173 @@ class TypedUrlModelAssociatorTest : public testing::Test {
(lhs.title().compare(rhs.title()) == 0) &&
(lhs.visit_count() == rhs.visit_count()) &&
(lhs.typed_count() == rhs.typed_count()) &&
- (lhs.last_visit() == rhs.last_visit()) &&
(lhs.hidden() == rhs.hidden());
}
};
TEST_F(TypedUrlModelAssociatorTest, MergeUrls) {
+ history::VisitVector visits1;
history::URLRow row1(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 2, 3, false));
+ 2, 3, false, &visits1));
sync_pb::TypedUrlSpecifics specs1(MakeTypedUrlSpecifics("http://pie.com/",
"pie",
- 1, 2, 3, false));
+ 2, 3, false));
history::URLRow new_row1(GURL("http://pie.com/"));
+ std::vector<base::Time> new_visits1;
EXPECT_EQ(TypedUrlModelAssociator::DIFF_NONE,
- TypedUrlModelAssociator::MergeUrls(specs1, row1, &new_row1));
+ TypedUrlModelAssociator::MergeUrls(specs1, row1, &visits1,
+ &new_row1, &new_visits1));
+ history::VisitVector visits2;
history::URLRow row2(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 2, 3, false));
+ 2, 3, false, &visits2));
sync_pb::TypedUrlSpecifics specs2(MakeTypedUrlSpecifics("http://pie.com/",
"pie",
- 1, 2, 4, true));
+ 2, 3, true));
+ history::VisitVector expected_visits2;
history::URLRow expected2(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 2, 4, true));
+ 2, 3, true, &expected_visits2));
history::URLRow new_row2(GURL("http://pie.com/"));
+ std::vector<base::Time> new_visits2;
EXPECT_EQ(TypedUrlModelAssociator::DIFF_ROW_CHANGED,
- TypedUrlModelAssociator::MergeUrls(specs2, row2, &new_row2));
+ TypedUrlModelAssociator::MergeUrls(specs2, row2, &visits2,
+ &new_row2, &new_visits2));
EXPECT_TRUE(URLsEqual(new_row2, expected2));
+ history::VisitVector visits3;
history::URLRow row3(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 2, 3, false));
+ 2, 3, false, &visits3));
sync_pb::TypedUrlSpecifics specs3(MakeTypedUrlSpecifics("http://pie.com/",
"pie2",
- 1, 2, 4, true));
+ 2, 3, true));
+ history::VisitVector expected_visits3;
history::URLRow expected3(MakeTypedUrlRow("http://pie.com/", "pie2",
- 1, 2, 4, true));
+ 2, 3, true, &expected_visits3));
history::URLRow new_row3(GURL("http://pie.com/"));
+ std::vector<base::Time> new_visits3;
EXPECT_EQ(TypedUrlModelAssociator::DIFF_ROW_CHANGED |
TypedUrlModelAssociator::DIFF_TITLE_CHANGED,
- TypedUrlModelAssociator::MergeUrls(specs3, row3, &new_row3));
+ TypedUrlModelAssociator::MergeUrls(specs3, row3, &visits3,
+ &new_row3, &new_visits3));
EXPECT_TRUE(URLsEqual(new_row3, expected3));
+ history::VisitVector visits4;
history::URLRow row4(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 2, 4, false));
+ 2, 4, false, &visits4));
sync_pb::TypedUrlSpecifics specs4(MakeTypedUrlSpecifics("http://pie.com/",
"pie2",
- 1, 2, 3, true));
+ 2, 3, true));
+ history::VisitVector expected_visits4;
history::URLRow expected4(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 2, 4, false));
+ 2, 3, false, &expected_visits4));
history::URLRow new_row4(GURL("http://pie.com/"));
- EXPECT_EQ(TypedUrlModelAssociator::DIFF_NODE_CHANGED,
- TypedUrlModelAssociator::MergeUrls(specs4, row4, &new_row4));
+ std::vector<base::Time> new_visits4;
+ EXPECT_EQ(TypedUrlModelAssociator::DIFF_NODE_CHANGED |
+ TypedUrlModelAssociator::DIFF_VISITS_ADDED,
+ TypedUrlModelAssociator::MergeUrls(specs4, row4, &visits4,
+ &new_row4, &new_visits4));
EXPECT_TRUE(URLsEqual(new_row4, expected4));
+ history::VisitVector visits5;
history::URLRow row5(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 1, 3, false));
+ 1, 4, false, &visits5));
sync_pb::TypedUrlSpecifics specs5(MakeTypedUrlSpecifics("http://pie.com/",
"pie",
- 1, 2, 3, false));
+ 2, 3, false));
+ history::VisitVector expected_visits5;
history::URLRow expected5(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 2, 3, false));
+ 2, 3, false, &expected_visits5));
history::URLRow new_row5(GURL("http://pie.com/"));
+ std::vector<base::Time> new_visits5;
EXPECT_EQ(TypedUrlModelAssociator::DIFF_ROW_CHANGED |
- TypedUrlModelAssociator::DIFF_NODE_CHANGED,
- TypedUrlModelAssociator::MergeUrls(specs5, row5, &new_row5));
+ TypedUrlModelAssociator::DIFF_VISITS_ADDED,
+ TypedUrlModelAssociator::MergeUrls(specs5, row5, &visits5,
+ &new_row5, &new_visits5));
EXPECT_TRUE(URLsEqual(new_row5, expected5));
}
+
+TEST_F(TypedUrlModelAssociatorTest, DiffVisitsSame) {
+ history::VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64 visits[] = { 1024, 2065, 65534, 1237684 };
+
+ for (size_t c = 0; c < arraysize(visits); ++c) {
+ old_visits.push_back(history::VisitRow(
+ 0, base::Time::FromInternalValue(visits[c]), 0, 0, 0));
+ new_url.add_visit(visits[c]);
+ }
+
+ std::vector<base::Time> new_visits;
+ history::VisitVector removed_visits;
+
+ TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
+ &new_visits, &removed_visits);
+ EXPECT_TRUE(new_visits.empty());
+ EXPECT_TRUE(removed_visits.empty());
+}
+
+TEST_F(TypedUrlModelAssociatorTest, DiffVisitsRemove) {
+ history::VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64 visits_left[] = { 1, 1024, 1500, 2065, 6000,
+ 65534, 1237684, 2237684 };
+ const int64 visits_right[] = { 1024, 2065, 65534, 1237684 };
+
+ const int64 visits_removed[] = { 1, 1500, 6000, 2237684 };
+
+ for (size_t c = 0; c < arraysize(visits_left); ++c) {
+ old_visits.push_back(history::VisitRow(
+ 0, base::Time::FromInternalValue(visits_left[c]), 0, 0, 0));
+ }
+
+ for (size_t c = 0; c < arraysize(visits_right); ++c) {
+ new_url.add_visit(visits_right[c]);
+ }
+
+ std::vector<base::Time> new_visits;
+ history::VisitVector removed_visits;
+
+ TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
+ &new_visits, &removed_visits);
+ EXPECT_TRUE(new_visits.empty());
+ ASSERT_TRUE(removed_visits.size() == arraysize(visits_removed));
+ for (size_t c = 0; c < arraysize(visits_removed); ++c) {
+ EXPECT_EQ(removed_visits[c].visit_time.ToInternalValue(),
+ visits_removed[c]);
+ }
+}
+
+TEST_F(TypedUrlModelAssociatorTest, DiffVisitsAdd) {
+ history::VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64 visits_left[] = { 1024, 2065, 65534, 1237684 };
+ const int64 visits_right[] = { 1, 1024, 1500, 2065, 6000,
+ 65534, 1237684, 2237684 };
+
+ const int64 visits_added[] = { 1, 1500, 6000, 2237684 };
+
+ for (size_t c = 0; c < arraysize(visits_left); ++c) {
+ old_visits.push_back(history::VisitRow(
+ 0, base::Time::FromInternalValue(visits_left[c]), 0, 0, 0));
+ }
+
+ for (size_t c = 0; c < arraysize(visits_right); ++c) {
+ new_url.add_visit(visits_right[c]);
+ }
+
+ std::vector<base::Time> new_visits;
+ history::VisitVector removed_visits;
+
+ TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
+ &new_visits, &removed_visits);
+ EXPECT_TRUE(removed_visits.empty());
+ ASSERT_TRUE(new_visits.size() == arraysize(visits_added));
+ for (size_t c = 0; c < arraysize(visits_added); ++c) {
+ EXPECT_EQ(new_visits[c].ToInternalValue(),
+ visits_added[c]);
+ }
+}
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index e784b49..13995db 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -74,9 +74,14 @@ class HistoryBackendMock : public HistoryBackend {
public:
HistoryBackendMock() : HistoryBackend(FilePath(), NULL, NULL) {}
MOCK_METHOD1(GetAllTypedURLs, bool(std::vector<history::URLRow>* entries));
- MOCK_METHOD2(UpdateURL, bool(history::URLID id, history::URLRow& url));
- MOCK_METHOD2(SetPageTitle, void(const GURL& url, const std::wstring& title));
+ MOCK_METHOD2(GetVisitsForURL, bool(history::URLID id,
+ history::VisitVector* visits));
+ MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
+ MOCK_METHOD2(AddVisits, bool(const GURL& url,
+ const std::vector<base::Time>& visits));
+ MOCK_METHOD1(RemoveVisits, bool(const history::VisitVector& visits));
MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
+ MOCK_METHOD2(SetPageTitle, void(const GURL& url, const std::wstring& title));
MOCK_METHOD1(DeleteURL, void(const GURL& url));
};
@@ -204,7 +209,8 @@ class ProfileSyncServiceTypedUrlTest : public testing::Test {
node.Put(SPECIFICS, specifics);
}
- void AddTypedUrlSyncNode(const history::URLRow& url) {
+ void AddTypedUrlSyncNode(const history::URLRow& url,
+ const history::VisitVector& visits) {
sync_api::WriteTransaction trans(
service_->backend()->GetUserShareHandle());
sync_api::ReadNode typed_url_root(&trans);
@@ -215,7 +221,7 @@ class ProfileSyncServiceTypedUrlTest : public testing::Test {
ASSERT_TRUE(node.InitUniqueByCreation(syncable::TYPED_URLS,
typed_url_root,
tag));
- TypedUrlModelAssociator::WriteToSyncNode(url, &node);
+ TypedUrlModelAssociator::WriteToSyncNode(url, visits, &node);
}
void GetTypedUrlsFromSyncDB(std::vector<history::URLRow>* urls) {
@@ -235,10 +241,11 @@ class ProfileSyncServiceTypedUrlTest : public testing::Test {
history::URLRow new_url(GURL(typed_url.url()));
new_url.set_title(UTF8ToWide(typed_url.title()));
- new_url.set_visit_count(typed_url.visit_count());
new_url.set_typed_count(typed_url.typed_count());
- new_url.set_last_visit(
- base::Time::FromInternalValue(typed_url.last_visit()));
+ DCHECK(typed_url.visit_size());
+ new_url.set_visit_count(typed_url.visit_size());
+ new_url.set_last_visit(base::Time::FromInternalValue(
+ typed_url.visit(typed_url.visit_size() - 1)));
new_url.set_hidden(typed_url.hidden());
urls->push_back(new_url);
@@ -264,18 +271,20 @@ class ProfileSyncServiceTypedUrlTest : public testing::Test {
static history::URLRow MakeTypedUrlEntry(const char* url,
const char* title,
- int visit_count,
int typed_count,
int64 last_visit,
- bool hidden) {
+ bool hidden,
+ history::VisitVector* visits) {
GURL gurl(url);
URLRow history_url(gurl);
history_url.set_title(UTF8ToWide(title));
- history_url.set_visit_count(visit_count);
history_url.set_typed_count(typed_count);
history_url.set_last_visit(
base::Time::FromInternalValue(last_visit));
history_url.set_hidden(hidden);
+ visits->push_back(history::VisitRow(
+ history_url.id(), history_url.last_visit(), 0, 0, 0));
+ history_url.set_visit_count(visits->size());
return history_url;
}
@@ -322,7 +331,10 @@ class AddTypedUrlEntriesTask : public Task {
virtual void Run() {
test_->CreateTypedUrlRoot();
for (size_t i = 0; i < entries_.size(); ++i) {
- test_->AddTypedUrlSyncNode(entries_[i]);
+ history::VisitVector visits;
+ visits.push_back(history::VisitRow(
+ entries_[i].id(), entries_[i].last_visit(), 0, 0, 0));
+ test_->AddTypedUrlSyncNode(entries_[i], visits);
}
}
@@ -344,10 +356,14 @@ TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
std::vector<history::URLRow> entries;
+ history::VisitVector visits;
entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
- 1, 2, 15, false));
+ 2, 15, false, &visits));
+
EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
+ WillRepeatedly(DoAll(SetArgumentPointee<1>(visits), Return(true)));
SetIdleChangeProcessorExpectations();
CreateTypedUrlRootTask task(this);
StartSyncService(&task);
@@ -358,15 +374,21 @@ TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
}
TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
+ history::VisitVector native_visits;
+ history::VisitVector sync_visits;
history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
- 1, 2, 15, false));
+ 2, 15, false, &native_visits));
history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
- 2, 3, 16, false));
+ 3, 16, false, &sync_visits));
std::vector<history::URLRow> native_entries;
native_entries.push_back(native_entry);
EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
+ WillRepeatedly(DoAll(SetArgumentPointee<1>(native_visits), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), AddVisits(_, _)).
+ WillRepeatedly(Return(true));
std::vector<history::URLRow> sync_entries;
sync_entries.push_back(sync_entry);
@@ -391,17 +413,27 @@ TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
}
TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
+ history::VisitVector native_visits;
history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
- 1, 2, 15, false));
+ 2, 15, false, &native_visits));
+ history::VisitVector sync_visits;
history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name",
- 2, 1, 17, false));
+ 1, 17, false, &sync_visits));
+ history::VisitVector merged_visits;
+ merged_visits.push_back(history::VisitRow(
+ sync_entry.id(), base::Time::FromInternalValue(15), 0, 0, 0));
+
history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name",
- 2, 1, 17, false));
+ 2, 17, false, &merged_visits));
std::vector<history::URLRow> native_entries;
native_entries.push_back(native_entry);
EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
+ WillRepeatedly(DoAll(SetArgumentPointee<1>(native_visits), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), AddVisits(_, _)).
+ WillRepeatedly(Return(true));
std::vector<history::URLRow> sync_entries;
sync_entries.push_back(sync_entry);
@@ -420,15 +452,19 @@ TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
}
TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
+ history::VisitVector added_visits;
+ history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
+ 2, 15, false, &added_visits));
+
EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
WillOnce(Return(true));
+ EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
+ WillOnce(DoAll(SetArgumentPointee<1>(added_visits), Return(true)));
+
SetIdleChangeProcessorExpectations();
CreateTypedUrlRootTask task(this);
StartSyncService(&task);
- history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
- 1, 2, 15, false));
-
history::URLsModifiedDetails details;
details.changed_urls.push_back(added_entry);
scoped_refptr<ThreadNotifier> notifier = new ThreadNotifier(&history_thread_);
@@ -442,18 +478,25 @@ TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
}
TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
+ history::VisitVector original_visits;
history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 1, 2, 15, false));
+ 2, 15, false,
+ &original_visits));
std::vector<history::URLRow> original_entries;
original_entries.push_back(original_entry);
EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
+ WillRepeatedly(DoAll(SetArgumentPointee<1>(original_visits),
+ Return(true)));
CreateTypedUrlRootTask task(this);
StartSyncService(&task);
+ history::VisitVector updated_visits;
history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 3, 7, 19, false));
+ 7, 15, false,
+ &updated_visits));
history::URLsModifiedDetails details;
details.changed_urls.push_back(updated_entry);
@@ -468,17 +511,24 @@ TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
}
TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
+ history::VisitVector original_visits1;
history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
- 1, 2, 15, false));
+ 2, 15, false,
+ &original_visits1));
+ history::VisitVector original_visits2;
history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
"entry2",
- 2, 3, 17, false));
+ 3, 15, false,
+ &original_visits2));
std::vector<history::URLRow> original_entries;
original_entries.push_back(original_entry1);
original_entries.push_back(original_entry2);
EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
+ WillRepeatedly(DoAll(SetArgumentPointee<1>(original_visits1),
+ Return(true)));
CreateTypedUrlRootTask task(this);
StartSyncService(&task);
@@ -496,17 +546,24 @@ TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
}
TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) {
+ history::VisitVector original_visits1;
history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
- 1, 2, 15, false));
+ 2, 15, false,
+ &original_visits1));
+ history::VisitVector original_visits2;
history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
"entry2",
- 2, 3, 17, false));
+ 3, 15, false,
+ &original_visits2));
std::vector<history::URLRow> original_entries;
original_entries.push_back(original_entry1);
original_entries.push_back(original_entry2);
EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
+ WillRepeatedly(DoAll(SetArgumentPointee<1>(original_visits1),
+ Return(true)));
CreateTypedUrlRootTask task(this);
StartSyncService(&task);
diff --git a/chrome/browser/sync/protocol/typed_url_specifics.proto b/chrome/browser/sync/protocol/typed_url_specifics.proto
index a6bd309..f9112b6 100644
--- a/chrome/browser/sync/protocol/typed_url_specifics.proto
+++ b/chrome/browser/sync/protocol/typed_url_specifics.proto
@@ -16,10 +16,9 @@ import "sync.proto";
message TypedUrlSpecifics {
optional string url = 1;
optional string title = 2;
- optional int32 visit_count = 3;
- optional int32 typed_count = 4;
- optional int64 last_visit = 5;
- optional bool hidden = 6;
+ optional int32 typed_count = 3;
+ optional bool hidden = 4;
+ repeated int64 visit = 5;
}
extend EntitySpecifics {