Chromium Code Reviews| Index: components/sync/engine_impl/loopback_server/loopback_server.cc |
| diff --git a/components/sync/test/fake_server/fake_server.cc b/components/sync/engine_impl/loopback_server/loopback_server.cc |
| similarity index 50% |
| copy from components/sync/test/fake_server/fake_server.cc |
| copy to components/sync/engine_impl/loopback_server/loopback_server.cc |
| index a24a22095eaf10432d0ddea1be71cfa0b78a77b8..c7bbe56cb74a93607075aa57e86b2d184afd5747 100644 |
| --- a/components/sync/test/fake_server/fake_server.cc |
| +++ b/components/sync/engine_impl/loopback_server/loopback_server.cc |
| @@ -1,53 +1,58 @@ |
| -// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Copyright 2016 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 "components/sync/test/fake_server/fake_server.h" |
| +#include "components/sync/engine_impl/loopback_server/loopback_server.h" |
| + |
| +#include <stdint.h> |
| #include <algorithm> |
| #include <limits> |
| +#include <memory> |
| #include <set> |
| +#include <string> |
| #include <utility> |
| +#include <vector> |
| +#include "base/files/file_util.h" |
| #include "base/guid.h" |
| #include "base/logging.h" |
| +#include "base/rand_util.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/synchronization/lock.h" |
| -#include "components/sync/test/fake_server/bookmark_entity.h" |
| -#include "components/sync/test/fake_server/permanent_entity.h" |
| -#include "components/sync/test/fake_server/tombstone_entity.h" |
| -#include "components/sync/test/fake_server/unique_client_entity.h" |
| +#include "components/sync/base/model_type.h" |
| +#include "components/sync/engine_impl/loopback_server/persistent_bookmark_entity.h" |
| +#include "components/sync/engine_impl/loopback_server/persistent_permanent_entity.h" |
| +#include "components/sync/engine_impl/loopback_server/persistent_tombstone_entity.h" |
| +#include "components/sync/engine_impl/loopback_server/persistent_unique_client_entity.h" |
| #include "net/base/net_errors.h" |
| #include "net/http/http_status_code.h" |
| using std::string; |
| using std::vector; |
| + |
| using syncer::GetModelType; |
| using syncer::GetModelTypeFromSpecifics; |
| using syncer::ModelType; |
| using syncer::ModelTypeSet; |
| -namespace fake_server { |
| +namespace syncer { |
| -class FakeServerEntity; |
| +class LoopbackServerEntity; |
| namespace { |
| -// The default keystore key. |
| -static const char kDefaultKeystoreKey[] = "1111111111111111"; |
| +static const int kCurrentLoopbackServerProtoVersion = 1; |
| +static const int kKeystoreKeyLenght = 16; |
| -// Properties of the bookmark bar permanent folder. |
| +// Properties of the bookmark bar permanent folders. |
| static const char kBookmarkBarFolderServerTag[] = "bookmark_bar"; |
| static const char kBookmarkBarFolderName[] = "Bookmark Bar"; |
| - |
| -// Properties of the other bookmarks permanent folder. |
| static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks"; |
| static const char kOtherBookmarksFolderName[] = "Other Bookmarks"; |
| - |
| -// Properties of the synced bookmarks permanent folder. |
| static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks"; |
| static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks"; |
| @@ -83,7 +88,7 @@ class UpdateSieve { |
| // Determines whether the server should send an |entity| to the client as |
| // part of a GetUpdatesResponse. |
| - bool ClientWantsItem(const FakeServerEntity& entity) const { |
| + bool ClientWantsItem(const LoopbackServerEntity& entity) const { |
| int64_t version = entity.GetVersion(); |
| if (version <= min_version_) { |
| return false; |
| @@ -92,7 +97,7 @@ class UpdateSieve { |
| } |
| ModelTypeToVersionMap::const_iterator it = |
| - request_from_version_.find(entity.model_type()); |
| + request_from_version_.find(entity.GetModelType()); |
| return it == request_from_version_.end() ? false : it->second < version; |
| } |
| @@ -134,7 +139,6 @@ std::unique_ptr<UpdateSieve> UpdateSieve::Create( |
| bool parsed = base::StringToInt64(marker.token(), &version); |
| CHECK(parsed) << "Unable to parse progress marker token."; |
| } |
| - |
| ModelType model_type = |
| syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()); |
| request_from_version[model_type] = version; |
| @@ -147,40 +151,37 @@ std::unique_ptr<UpdateSieve> UpdateSieve::Create( |
| new UpdateSieve(request_from_version, min_version)); |
| } |
| -// Returns whether |entity| is deleted or permanent. |
| -bool IsDeletedOrPermanent(const FakeServerEntity& entity) { |
| - return entity.IsDeleted() || entity.IsPermanent(); |
| -} |
| - |
| } // namespace |
| -FakeServer::FakeServer() |
| - : version_(0), |
| - store_birthday_(0), |
| - authenticated_(true), |
| - error_type_(sync_pb::SyncEnums::SUCCESS), |
| - alternate_triggered_errors_(false), |
| - request_counter_(0), |
| - network_enabled_(true), |
| - weak_ptr_factory_(this) { |
| +LoopbackServer::LoopbackServer(const base::FilePath& persistent_file) |
| + : version_(0), store_birthday_(0), persistent_file_(persistent_file) { |
| Init(); |
| } |
| -FakeServer::~FakeServer() {} |
| +LoopbackServer::~LoopbackServer() {} |
| -void FakeServer::Init() { |
| - keystore_keys_.push_back(kDefaultKeystoreKey); |
| +void LoopbackServer::Init() { |
| + if (LoadStateFromFile(persistent_file_)) |
| + return; |
| + |
| + keystore_keys_.push_back(GenerateNewKeystoreKey()); |
| const bool create_result = CreateDefaultPermanentItems(); |
| DCHECK(create_result) << "Permanent items were not created successfully."; |
| } |
| -bool FakeServer::CreatePermanentBookmarkFolder(const std::string& server_tag, |
| - const std::string& name) { |
| +std::string LoopbackServer::GenerateNewKeystoreKey() const { |
| + // TODO(pastarmovj): Check if true random bytes is ok or alpha-nums is needed? |
| + return base::RandBytesAsString(kKeystoreKeyLenght); |
| +} |
| + |
| +bool LoopbackServer::CreatePermanentBookmarkFolder( |
| + const std::string& server_tag, |
| + const std::string& name) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - std::unique_ptr<FakeServerEntity> entity = |
| - PermanentEntity::Create(syncer::BOOKMARKS, server_tag, name, |
| - ModelTypeToRootTag(syncer::BOOKMARKS)); |
| + std::unique_ptr<LoopbackServerEntity> entity = |
| + PersistentPermanentEntity::Create(syncer::BOOKMARKS, server_tag, name, |
| + ModelTypeToRootTag(syncer::BOOKMARKS)); |
| if (!entity) |
| return false; |
| @@ -188,7 +189,7 @@ bool FakeServer::CreatePermanentBookmarkFolder(const std::string& server_tag, |
| return true; |
| } |
| -bool FakeServer::CreateDefaultPermanentItems() { |
| +bool LoopbackServer::CreateDefaultPermanentItems() { |
| // Permanent folders are always required for Bookmarks (hierarchical |
| // structure) and Nigori (data stored in permanent root folder). |
| ModelTypeSet permanent_folder_types = |
| @@ -198,8 +199,8 @@ bool FakeServer::CreateDefaultPermanentItems() { |
| it.Inc()) { |
| ModelType model_type = it.Get(); |
| - std::unique_ptr<FakeServerEntity> top_level_entity = |
| - PermanentEntity::CreateTopLevel(model_type); |
| + std::unique_ptr<LoopbackServerEntity> top_level_entity = |
| + PersistentPermanentEntity::CreateTopLevel(model_type); |
| if (!top_level_entity) { |
| return false; |
| } |
| @@ -218,37 +219,21 @@ bool FakeServer::CreateDefaultPermanentItems() { |
| return true; |
| } |
| -void FakeServer::UpdateEntityVersion(FakeServerEntity* entity) { |
| +void LoopbackServer::UpdateEntityVersion(LoopbackServerEntity* entity) { |
| entity->SetVersion(++version_); |
| } |
| -void FakeServer::SaveEntity(std::unique_ptr<FakeServerEntity> entity) { |
| +void LoopbackServer::SaveEntity(std::unique_ptr<LoopbackServerEntity> entity) { |
| UpdateEntityVersion(entity.get()); |
| - entities_[entity->id()] = std::move(entity); |
| + entities_[entity->GetId()] = std::move(entity); |
| } |
| -void FakeServer::HandleCommand(const string& request, |
| - const base::Closure& completion_closure, |
| - int* error_code, |
| - int* response_code, |
| - std::string* response) { |
| +void LoopbackServer::HandleCommand( |
| + const string& request, |
| + HttpResponse::ServerConnectionCode* server_status, |
| + int64_t* response_code, |
| + std::string* response) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - if (!network_enabled_) { |
| - *error_code = net::ERR_FAILED; |
| - *response_code = net::ERR_FAILED; |
| - *response = string(); |
| - completion_closure.Run(); |
| - return; |
| - } |
| - request_counter_++; |
| - |
| - if (!authenticated_) { |
| - *error_code = 0; |
| - *response_code = net::HTTP_UNAUTHORIZED; |
| - *response = string(); |
| - completion_closure.Run(); |
| - return; |
| - } |
| sync_pb::ClientToServerMessage message; |
| bool parsed = message.ParseFromString(request); |
| @@ -259,23 +244,14 @@ void FakeServer::HandleCommand(const string& request, |
| if (message.has_store_birthday() && |
| message.store_birthday() != GetStoreBirthday()) { |
| response_proto.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY); |
| - } else if (error_type_ != sync_pb::SyncEnums::SUCCESS && |
| - ShouldSendTriggeredError()) { |
| - response_proto.set_error_code(error_type_); |
| - } else if (triggered_actionable_error_.get() && ShouldSendTriggeredError()) { |
| - sync_pb::ClientToServerResponse_Error* error = |
| - response_proto.mutable_error(); |
| - error->CopyFrom(*(triggered_actionable_error_.get())); |
| } else { |
| bool success = false; |
| switch (message.message_contents()) { |
| case sync_pb::ClientToServerMessage::GET_UPDATES: |
| - last_getupdates_message_ = message; |
| success = HandleGetUpdatesRequest(message.get_updates(), |
| response_proto.mutable_get_updates()); |
| break; |
| case sync_pb::ClientToServerMessage::COMMIT: |
| - last_commit_message_ = message; |
| success = HandleCommitRequest(message.commit(), |
| message.invalidator_client_id(), |
| response_proto.mutable_commit()); |
| @@ -286,20 +262,16 @@ void FakeServer::HandleCommand(const string& request, |
| success = true; |
| break; |
| default: |
| - *error_code = net::ERR_NOT_IMPLEMENTED; |
| - *response_code = 0; |
| + *server_status = HttpResponse::SYNC_SERVER_ERROR; |
| + *response_code = net::ERR_NOT_IMPLEMENTED; |
| *response = string(); |
| - completion_closure.Run(); |
| return; |
| } |
| if (!success) { |
| - // TODO(pvalenzuela): Add logging here so that tests have more info about |
| - // the failure. |
| - *error_code = net::ERR_FAILED; |
| - *response_code = 0; |
| + *server_status = HttpResponse::SYNC_SERVER_ERROR; |
| + *response_code = net::ERR_FAILED; |
| *response = string(); |
| - completion_closure.Run(); |
| return; |
| } |
| @@ -308,30 +280,15 @@ void FakeServer::HandleCommand(const string& request, |
| response_proto.set_store_birthday(GetStoreBirthday()); |
| - *error_code = 0; |
| + *server_status = HttpResponse::SERVER_CONNECTION_OK; |
| *response_code = net::HTTP_OK; |
| *response = response_proto.SerializeAsString(); |
| - completion_closure.Run(); |
| -} |
| - |
| -bool FakeServer::GetLastCommitMessage(sync_pb::ClientToServerMessage* message) { |
| - if (!last_commit_message_.has_commit()) |
| - return false; |
| - |
| - message->CopyFrom(last_commit_message_); |
| - return true; |
| -} |
| -bool FakeServer::GetLastGetUpdatesMessage( |
| - sync_pb::ClientToServerMessage* message) { |
| - if (!last_getupdates_message_.has_get_updates()) |
| - return false; |
| - |
| - message->CopyFrom(last_getupdates_message_); |
| - return true; |
| + // TODO(pastarmovj): This should be done asynchronously. |
| + SaveStateToFile(persistent_file_); |
| } |
| -bool FakeServer::HandleGetUpdatesRequest( |
| +bool LoopbackServer::HandleGetUpdatesRequest( |
| const sync_pb::GetUpdatesMessage& get_updates, |
| sync_pb::GetUpdatesResponse* response) { |
| // TODO(pvalenzuela): Implement batching instead of sending all information |
| @@ -352,7 +309,7 @@ bool FakeServer::HandleGetUpdatesRequest( |
| int64_t max_response_version = 0; |
| for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| ++it) { |
| - const FakeServerEntity& entity = *it->second; |
| + const LoopbackServerEntity& entity = *it->second; |
| if (sieve->ClientWantsItem(entity)) { |
| sync_pb::SyncEntity* response_entity = response->add_entries(); |
| entity.SerializeAsProto(response_entity); |
| @@ -360,7 +317,7 @@ bool FakeServer::HandleGetUpdatesRequest( |
| max_response_version = |
| std::max(max_response_version, response_entity->version()); |
| - if (entity.model_type() == syncer::NIGORI) { |
| + if (entity.GetModelType() == syncer::NIGORI) { |
| send_encryption_keys_based_on_nigori = |
| response_entity->specifics().nigori().passphrase_type() == |
| sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; |
| @@ -380,7 +337,7 @@ bool FakeServer::HandleGetUpdatesRequest( |
| return true; |
| } |
| -string FakeServer::CommitEntity( |
| +string LoopbackServer::CommitEntity( |
| const sync_pb::SyncEntity& client_entity, |
| sync_pb::CommitResponse_EntryResponse* entry_response, |
| const string& client_guid, |
| @@ -389,51 +346,52 @@ string FakeServer::CommitEntity( |
| return string(); |
| } |
| - std::unique_ptr<FakeServerEntity> entity; |
| + std::unique_ptr<LoopbackServerEntity> entity; |
| if (client_entity.deleted()) { |
| - entity = TombstoneEntity::Create(client_entity.id_string(), |
| - client_entity.client_defined_unique_tag()); |
| + entity = PersistentTombstoneEntity::Create(client_entity); |
| DeleteChildren(client_entity.id_string()); |
| } else if (GetModelType(client_entity) == 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 = PermanentEntity::CreateUpdatedNigoriEntity(client_entity, |
| - *iter->second); |
| + entity = PersistentPermanentEntity::CreateUpdatedNigoriEntity( |
| + client_entity, *iter->second); |
| } else if (client_entity.has_client_defined_unique_tag()) { |
| - entity = UniqueClientEntity::Create(client_entity); |
| + entity = PersistentUniqueClientEntity::Create(client_entity); |
| } else { |
| // TODO(pvalenzuela): Validate entity's parent ID. |
| EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); |
| if (iter != entities_.end()) { |
| - entity = BookmarkEntity::CreateUpdatedVersion(client_entity, |
| - *iter->second, parent_id); |
| + entity = PersistentBookmarkEntity::CreateUpdatedVersion( |
| + client_entity, *iter->second, parent_id); |
| } else { |
| - entity = BookmarkEntity::CreateNew(client_entity, parent_id, client_guid); |
| + entity = PersistentBookmarkEntity::CreateNew(client_entity, parent_id, |
| + client_guid); |
| } |
| } |
| if (!entity) { |
| - // TODO(pvalenzuela): Add logging so that it is easier to determine why |
| - // creation failed. |
| + LOG(ERROR) << "No server entity was created for client entity with type: " |
| + << GetModelType(client_entity) |
| + << " and ID: " << client_entity.id_string() << "."; |
| return string(); |
| } |
| - const std::string id = entity->id(); |
| + const std::string id = entity->GetId(); |
| SaveEntity(std::move(entity)); |
| BuildEntryResponseForSuccessfulCommit(id, entry_response); |
| return id; |
| } |
| -void FakeServer::BuildEntryResponseForSuccessfulCommit( |
| +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 FakeServerEntity& entity = *iter->second; |
| + const LoopbackServerEntity& entity = *iter->second; |
| entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS); |
| - entry_response->set_id_string(entity.id()); |
| + entry_response->set_id_string(entity.GetId()); |
| if (entity.IsDeleted()) { |
| entry_response->set_version(entity.GetVersion() + 1); |
| @@ -443,7 +401,8 @@ void FakeServer::BuildEntryResponseForSuccessfulCommit( |
| } |
| } |
| -bool FakeServer::IsChild(const string& id, const string& potential_parent_id) { |
| +bool LoopbackServer::IsChild(const string& id, |
| + const string& potential_parent_id) { |
| EntityMap::const_iterator iter = entities_.find(id); |
| if (iter == entities_.end()) { |
| // We've hit an ID (probably the imaginary root entity) that isn't stored |
| @@ -451,7 +410,7 @@ bool FakeServer::IsChild(const string& id, const string& potential_parent_id) { |
| return false; |
| } |
| - const FakeServerEntity& entity = *iter->second; |
| + const LoopbackServerEntity& entity = *iter->second; |
| if (entity.GetParentId() == potential_parent_id) |
| return true; |
| @@ -459,24 +418,26 @@ bool FakeServer::IsChild(const string& id, const string& potential_parent_id) { |
| return IsChild(entity.GetParentId(), potential_parent_id); |
| } |
| -void FakeServer::DeleteChildren(const string& id) { |
| - std::vector<std::unique_ptr<FakeServerEntity>> tombstones; |
| +void LoopbackServer::DeleteChildren(const string& id) { |
| + std::vector<sync_pb::SyncEntity> tombstones; |
| // Find all the children of id. |
| - for (const auto& entity : entities_) { |
| + for (auto& entity : entities_) { |
| if (IsChild(entity.first, id)) { |
| - tombstones.push_back(TombstoneEntity::Create( |
| - entity.first, entity.second->client_defined_unique_tag())); |
| + sync_pb::SyncEntity proto; |
| + entity.second->SerializeAsProto(&proto); |
| + tombstones.emplace_back(proto); |
| } |
| } |
| for (auto& tombstone : tombstones) { |
| - SaveEntity(std::move(tombstone)); |
| + SaveEntity(PersistentTombstoneEntity::Create(tombstone)); |
| } |
| } |
| -bool FakeServer::HandleCommitRequest(const sync_pb::CommitMessage& commit, |
| - const std::string& invalidator_client_id, |
| - sync_pb::CommitResponse* response) { |
| +bool LoopbackServer::HandleCommitRequest( |
| + const sync_pb::CommitMessage& commit, |
| + const std::string& invalidator_client_id, |
| + sync_pb::CommitResponse* response) { |
| std::map<string, string> client_to_server_ids; |
| string guid = commit.cache_guid(); |
| ModelTypeSet committed_model_types; |
| @@ -506,109 +467,13 @@ bool FakeServer::HandleCommitRequest(const sync_pb::CommitMessage& commit, |
| EntityMap::const_iterator iter = entities_.find(entity_id); |
| CHECK(iter != entities_.end()); |
| - committed_model_types.Put(iter->second->model_type()); |
| - } |
| - |
| - FOR_EACH_OBSERVER(Observer, observers_, |
| - OnCommit(invalidator_client_id, committed_model_types)); |
| - return true; |
| -} |
| - |
| -std::unique_ptr<base::DictionaryValue> |
| -FakeServer::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()), new base::ListValue()); |
| - } |
| - |
| - for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| - ++it) { |
| - const FakeServerEntity& entity = *it->second; |
| - if (IsDeletedOrPermanent(entity)) { |
| - // 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.model_type()), |
| - &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; |
| -} |
| - |
| -std::vector<sync_pb::SyncEntity> FakeServer::GetSyncEntitiesByModelType( |
| - ModelType model_type) { |
| - std::vector<sync_pb::SyncEntity> sync_entities; |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| - ++it) { |
| - const FakeServerEntity& entity = *it->second; |
| - if (!IsDeletedOrPermanent(entity) && entity.model_type() == model_type) { |
| - sync_pb::SyncEntity sync_entity; |
| - entity.SerializeAsProto(&sync_entity); |
| - sync_entities.push_back(sync_entity); |
| - } |
| - } |
| - return sync_entities; |
| -} |
| - |
| -void FakeServer::InjectEntity(std::unique_ptr<FakeServerEntity> entity) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - SaveEntity(std::move(entity)); |
| -} |
| - |
| -bool FakeServer::ModifyEntitySpecifics( |
| - const std::string& id, |
| - const sync_pb::EntitySpecifics& updated_specifics) { |
| - EntityMap::const_iterator iter = entities_.find(id); |
| - if (iter == entities_.end() || |
| - iter->second->model_type() != |
| - GetModelTypeFromSpecifics(updated_specifics)) { |
| - return false; |
| - } |
| - |
| - FakeServerEntity* entity = iter->second.get(); |
| - entity->SetSpecifics(updated_specifics); |
| - UpdateEntityVersion(entity); |
| - return true; |
| -} |
| - |
| -bool FakeServer::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->model_type() != syncer::BOOKMARKS || |
| - GetModelTypeFromSpecifics(updated_specifics) != syncer::BOOKMARKS) { |
| - return false; |
| + committed_model_types.Put(iter->second->GetModelType()); |
| } |
| - BookmarkEntity* entity = static_cast<BookmarkEntity*>(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 FakeServer::ClearServerData() { |
| +void LoopbackServer::ClearServerData() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| entities_.clear(); |
| keystore_keys_.clear(); |
| @@ -616,113 +481,111 @@ void FakeServer::ClearServerData() { |
| Init(); |
| } |
| -void FakeServer::SetAuthenticated() { |
| +std::string LoopbackServer::GetStoreBirthday() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - authenticated_ = true; |
| + return base::Int64ToString(store_birthday_); |
| } |
| -void FakeServer::SetUnauthenticated() { |
| +void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - authenticated_ = false; |
| -} |
| -bool FakeServer::TriggerError(const sync_pb::SyncEnums::ErrorType& error_type) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - if (triggered_actionable_error_.get()) { |
| - DVLOG(1) << "Only one type of error can be triggered at any given time."; |
| - return false; |
| - } |
| - |
| - error_type_ = error_type; |
| - return true; |
| -} |
| - |
| -bool FakeServer::TriggerActionableError( |
| - const sync_pb::SyncEnums::ErrorType& error_type, |
| - const string& description, |
| - const string& url, |
| - const sync_pb::SyncEnums::Action& action) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - if (error_type_ != sync_pb::SyncEnums::SUCCESS) { |
| - DVLOG(1) << "Only one type of error can be triggered at any given time."; |
| - return false; |
| + proto->set_version(kCurrentLoopbackServerProtoVersion); |
| + proto->set_store_birthday(store_birthday_); |
| + proto->set_last_version_assigned(version_); |
| + for (const auto& key : keystore_keys_) |
| + proto->add_keystore_keys(key); |
| + for (const auto& entity : entities_) { |
| + auto* new_entity = proto->mutable_entities()->Add(); |
| + if (entity.second->IsDeleted()) |
|
pavely
2016/10/06 23:48:45
This "if" statement is essentially a switch on the
pastarmovj
2016/10/13 14:13:39
Done.
|
| + new_entity->set_type(sync_pb::LoopbackServerEntity_Type_TOMBSTONE); |
| + else if (entity.second->IsPermanent()) |
| + new_entity->set_type(sync_pb::LoopbackServerEntity_Type_PERMANENT); |
| + else if (entity.second->RequiresParentId()) |
| + new_entity->set_type(sync_pb::LoopbackServerEntity_Type_BOOKMARK); |
| + else |
| + new_entity->set_type(sync_pb::LoopbackServerEntity_Type_UNIQUE); |
| + new_entity->set_model_type((int64_t)(entity.second->GetModelType())); |
| + entity.second->SerializeAsProto(new_entity->mutable_entity()); |
| } |
| - |
| - sync_pb::ClientToServerResponse_Error* error = |
| - new sync_pb::ClientToServerResponse_Error(); |
| - error->set_error_type(error_type); |
| - error->set_error_description(description); |
| - error->set_url(url); |
| - error->set_action(action); |
| - triggered_actionable_error_.reset(error); |
| - return true; |
| } |
| -bool FakeServer::EnableAlternatingTriggeredErrors() { |
| +bool LoopbackServer::DeSerializeState( |
| + const sync_pb::LoopbackServerProto& proto) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - if (error_type_ == sync_pb::SyncEnums::SUCCESS && |
| - !triggered_actionable_error_.get()) { |
| - DVLOG(1) << "No triggered error set. Alternating can't be enabled."; |
| - return false; |
| + CHECK_EQ(proto.version(), kCurrentLoopbackServerProtoVersion); |
| + |
| + store_birthday_ = proto.store_birthday(); |
| + version_ = proto.last_version_assigned(); |
| + for (int i = 0; i < proto.keystore_keys_size(); ++i) |
| + keystore_keys_.push_back(proto.keystore_keys(i)); |
| + for (int i = 0; i < proto.entities_size(); ++i) { |
| + const auto& entity = proto.entities(i); |
| + switch (entity.type()) { |
|
pavely
2016/10/06 23:48:45
I would refactor this switch into a factory functi
pastarmovj
2016/10/13 14:13:39
Done.
|
| + case sync_pb::LoopbackServerEntity_Type_TOMBSTONE: |
| + entities_[entity.entity().id_string()] = |
| + PersistentTombstoneEntity::Create(entity.entity()); |
| + break; |
| + case sync_pb::LoopbackServerEntity_Type_PERMANENT: { |
| + std::unique_ptr<PersistentPermanentEntity> new_entity( |
| + new PersistentPermanentEntity( |
| + entity.entity().id_string(), entity.entity().version(), |
| + syncer::GetModelType(entity.entity()), entity.entity().name(), |
| + entity.entity().parent_id_string(), |
| + entity.entity().server_defined_unique_tag(), |
| + entity.entity().specifics())); |
| + entities_[entity.entity().id_string()] = std::move(new_entity); |
| + break; |
| + } |
| + case sync_pb::LoopbackServerEntity_Type_BOOKMARK: |
| + entities_[entity.entity().id_string()] = |
| + PersistentBookmarkEntity::CreateFromEntity(entity.entity()); |
| + break; |
| + case sync_pb::LoopbackServerEntity_Type_UNIQUE: |
| + entities_[entity.entity().id_string()] = |
| + PersistentUniqueClientEntity::Create(entity.entity()); |
| + break; |
| + default: |
| + CHECK(false) << "Unknown type encountered"; |
| + } |
| } |
| - alternate_triggered_errors_ = true; |
| - // Reset the counter so that the the first request yields a triggered error. |
| - request_counter_ = 0; |
| return true; |
| } |
| -bool FakeServer::ShouldSendTriggeredError() const { |
| - if (!alternate_triggered_errors_) |
| - return true; |
| - |
| - // Check that the counter is odd so that we trigger an error on the first |
| - // request after alternating is enabled. |
| - return request_counter_ % 2 != 0; |
| -} |
| - |
| -void FakeServer::AddObserver(Observer* observer) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - observers_.AddObserver(observer); |
| -} |
| - |
| -void FakeServer::RemoveObserver(Observer* observer) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - observers_.RemoveObserver(observer); |
| -} |
| +// Saves all entities and server state to a protobuf file in |filename|. |
| +bool LoopbackServer::SaveStateToFile(const base::FilePath& filename) const { |
| + sync_pb::LoopbackServerProto proto; |
| + SerializeState(&proto); |
| -void FakeServer::EnableNetwork() { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - network_enabled_ = true; |
| -} |
| - |
| -void FakeServer::DisableNetwork() { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - network_enabled_ = false; |
| + std::string serialized = proto.SerializeAsString(); |
| + int result = base::WriteFile(filename, serialized.data(), serialized.size()); |
| + return result == static_cast<int>(serialized.size()); |
| } |
| -std::string FakeServer::GetBookmarkBarFolderId() const { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| - ++it) { |
| - FakeServerEntity* entity = it->second.get(); |
| - if (entity->GetName() == kBookmarkBarFolderName && entity->IsFolder() && |
| - entity->model_type() == syncer::BOOKMARKS) { |
| - return entity->id(); |
| +// Loads all entities and server state from a protobuf file in |filename|. |
| +bool LoopbackServer::LoadStateFromFile(const base::FilePath& filename) { |
| + if (base::PathExists(filename)) { |
| + std::string serialized; |
| + if (base::ReadFileToString(filename, &serialized)) { |
| + sync_pb::LoopbackServerProto proto; |
| + if (serialized.length() > 0 && proto.ParseFromString(serialized)) { |
| + DeSerializeState(proto); |
| + return true; |
| + } else { |
| + LOG(ERROR) << "Loopback sync can not parse the persistent state file."; |
| + return false; |
| + } |
| + } else { |
| + // TODO(pastarmovj): Try to understand what is the issue e.g. file already |
| + // open, no access rights etc. and decide if better course of action is |
| + // available instead of giving up and wiping the global state on the next |
| + // write. |
| + LOG(ERROR) << "Loopback sync can not read the persistent state file."; |
| + return false; |
| } |
| } |
| - NOTREACHED() << "Bookmark Bar entity not found."; |
| - return ""; |
| -} |
| - |
| -base::WeakPtr<FakeServer> FakeServer::AsWeakPtr() { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - return weak_ptr_factory_.GetWeakPtr(); |
| -} |
| - |
| -std::string FakeServer::GetStoreBirthday() const { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - return base::Int64ToString(store_birthday_); |
| + LOG(WARNING) << "Loopback sync persistent state file does not exist."; |
| + return false; |
| } |
| -} // namespace fake_server |
| +} // namespace syncer |