Index: components/sync/engine_impl/loopback_server/loopback_server.cc |
diff --git a/components/sync/engine_impl/loopback_server/loopback_server.cc b/components/sync/engine_impl/loopback_server/loopback_server.cc |
index 61094cf4d0e3abd31723bf837d91d0c23a5c022a..2a4be37139362b4fb4831a4ebcaacb84f49501b0 100644 |
--- a/components/sync/engine_impl/loopback_server/loopback_server.cc |
+++ b/components/sync/engine_impl/loopback_server/loopback_server.cc |
@@ -134,7 +134,10 @@ class UpdateSieve { |
} // namespace |
LoopbackServer::LoopbackServer(const base::FilePath& persistent_file) |
- : version_(0), store_birthday_(0), persistent_file_(persistent_file) { |
+ : version_(0), |
+ store_birthday_(0), |
+ persistent_file_(persistent_file), |
+ observer_for_tests_(NULL) { |
Init(); |
} |
@@ -160,8 +163,9 @@ bool LoopbackServer::CreatePermanentBookmarkFolder( |
const std::string& name) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
std::unique_ptr<LoopbackServerEntity> entity = |
- PersistentPermanentEntity::Create(syncer::BOOKMARKS, server_tag, name, |
- ModelTypeToRootTag(syncer::BOOKMARKS)); |
+ PersistentPermanentEntity::CreateNew( |
+ syncer::BOOKMARKS, server_tag, name, |
+ ModelTypeToRootTag(syncer::BOOKMARKS)); |
if (!entity) |
return false; |
@@ -323,19 +327,18 @@ string LoopbackServer::CommitEntity( |
} |
std::unique_ptr<LoopbackServerEntity> entity; |
+ syncer::ModelType type = GetModelType(client_entity); |
if (client_entity.deleted()) { |
- entity = PersistentTombstoneEntity::Create(client_entity); |
+ entity = PersistentTombstoneEntity::CreateFromEntity(client_entity); |
DeleteChildren(client_entity.id_string()); |
- } else if (GetModelType(client_entity) == syncer::NIGORI) { |
+ } else if (type == syncer::NIGORI) { |
// NIGORI is the only permanent item type that should be updated by the |
// client. |
EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); |
CHECK(iter != entities_.end()); |
entity = PersistentPermanentEntity::CreateUpdatedNigoriEntity( |
client_entity, *iter->second); |
- } else if (client_entity.has_client_defined_unique_tag()) { |
- entity = PersistentUniqueClientEntity::Create(client_entity); |
- } else { |
+ } else if (type == syncer::BOOKMARKS) { |
// TODO(pvalenzuela): Validate entity's parent ID. |
EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); |
if (iter != entities_.end()) { |
@@ -345,13 +348,8 @@ string LoopbackServer::CommitEntity( |
entity = PersistentBookmarkEntity::CreateNew(client_entity, parent_id, |
client_guid); |
} |
- } |
- |
- if (!entity) { |
- LOG(ERROR) << "No server entity was created for client entity with type: " |
- << GetModelType(client_entity) |
- << " and ID: " << client_entity.id_string() << "."; |
- return string(); |
+ } else { |
+ entity = PersistentUniqueClientEntity::CreateFromEntity(client_entity); |
} |
const std::string id = entity->GetId(); |
@@ -360,13 +358,20 @@ string LoopbackServer::CommitEntity( |
return id; |
} |
+void LoopbackServer::OverrideResponseType( |
+ ResponseTypeProvider response_type_override) { |
+ response_type_override_ = std::move(response_type_override); |
+} |
+ |
void LoopbackServer::BuildEntryResponseForSuccessfulCommit( |
const std::string& entity_id, |
sync_pb::CommitResponse_EntryResponse* entry_response) { |
EntityMap::const_iterator iter = entities_.find(entity_id); |
CHECK(iter != entities_.end()); |
const LoopbackServerEntity& entity = *iter->second; |
- entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS); |
+ entry_response->set_response_type(response_type_override_ |
+ ? response_type_override_.Run(entity) |
+ : sync_pb::CommitResponse::SUCCESS); |
entry_response->set_id_string(entity.GetId()); |
if (entity.IsDeleted()) { |
@@ -406,7 +411,7 @@ void LoopbackServer::DeleteChildren(const string& id) { |
} |
for (auto& tombstone : tombstones) { |
- SaveEntity(PersistentTombstoneEntity::Create(tombstone)); |
+ SaveEntity(PersistentTombstoneEntity::CreateFromEntity(tombstone)); |
} |
} |
@@ -446,6 +451,9 @@ bool LoopbackServer::HandleCommitRequest( |
committed_model_types.Put(iter->second->GetModelType()); |
} |
+ if (observer_for_tests_) |
+ observer_for_tests_->OnCommit(invalidator_client_id, committed_model_types); |
+ |
return true; |
} |
@@ -454,6 +462,7 @@ void LoopbackServer::ClearServerData() { |
entities_.clear(); |
keystore_keys_.clear(); |
++store_birthday_; |
+ base::DeleteFile(persistent_file_, false); |
Init(); |
} |
@@ -462,6 +471,98 @@ std::string LoopbackServer::GetStoreBirthday() const { |
return base::Int64ToString(store_birthday_); |
} |
+std::vector<sync_pb::SyncEntity> LoopbackServer::GetSyncEntitiesByModelType( |
+ ModelType model_type) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ std::vector<sync_pb::SyncEntity> sync_entities; |
+ for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
+ ++it) { |
+ const LoopbackServerEntity& entity = *it->second; |
+ if (!(entity.IsDeleted() || entity.IsPermanent()) && |
+ entity.GetModelType() == model_type) { |
+ sync_pb::SyncEntity sync_entity; |
+ entity.SerializeAsProto(&sync_entity); |
+ sync_entities.push_back(sync_entity); |
+ } |
+ } |
+ return sync_entities; |
+} |
+ |
+std::unique_ptr<base::DictionaryValue> |
+LoopbackServer::GetEntitiesAsDictionaryValue() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ std::unique_ptr<base::DictionaryValue> dictionary( |
+ new base::DictionaryValue()); |
+ |
+ // Initialize an empty ListValue for all ModelTypes. |
+ ModelTypeSet all_types = ModelTypeSet::All(); |
+ for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) { |
+ dictionary->Set(ModelTypeToString(it.Get()), |
+ base::MakeUnique<base::ListValue>()); |
+ } |
+ |
+ for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
+ ++it) { |
+ const LoopbackServerEntity& entity = *it->second; |
+ if (entity.IsDeleted() || entity.IsPermanent()) { |
+ // Tombstones are ignored as they don't represent current data. Folders |
+ // are also ignored as current verification infrastructure does not |
+ // consider them. |
+ continue; |
+ } |
+ base::ListValue* list_value; |
+ if (!dictionary->GetList(ModelTypeToString(entity.GetModelType()), |
+ &list_value)) { |
+ return std::unique_ptr<base::DictionaryValue>(); |
+ } |
+ // TODO(pvalenzuela): Store more data for each entity so additional |
+ // verification can be performed. One example of additional verification |
+ // is checking the correctness of the bookmark hierarchy. |
+ list_value->AppendString(entity.GetName()); |
+ } |
+ |
+ return dictionary; |
+} |
+ |
+bool LoopbackServer::ModifyEntitySpecifics( |
+ const std::string& id, |
+ const sync_pb::EntitySpecifics& updated_specifics) { |
+ EntityMap::const_iterator iter = entities_.find(id); |
+ if (iter == entities_.end() || |
+ iter->second->GetModelType() != |
+ GetModelTypeFromSpecifics(updated_specifics)) { |
+ return false; |
+ } |
+ |
+ LoopbackServerEntity* entity = iter->second.get(); |
+ entity->SetSpecifics(updated_specifics); |
+ UpdateEntityVersion(entity); |
+ return true; |
+} |
+ |
+bool LoopbackServer::ModifyBookmarkEntity( |
+ const std::string& id, |
+ const std::string& parent_id, |
+ const sync_pb::EntitySpecifics& updated_specifics) { |
+ EntityMap::const_iterator iter = entities_.find(id); |
+ if (iter == entities_.end() || |
+ iter->second->GetModelType() != syncer::BOOKMARKS || |
+ GetModelTypeFromSpecifics(updated_specifics) != syncer::BOOKMARKS) { |
+ return false; |
+ } |
+ |
+ PersistentBookmarkEntity* entity = |
+ static_cast<PersistentBookmarkEntity*>(iter->second.get()); |
+ |
+ entity->SetParentId(parent_id); |
+ entity->SetSpecifics(updated_specifics); |
+ if (updated_specifics.has_bookmark()) { |
+ entity->SetName(updated_specifics.bookmark().title()); |
+ } |
+ UpdateEntityVersion(entity); |
+ return true; |
+} |
+ |
void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { |
DCHECK(thread_checker_.CalledOnValidThread()); |