| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/sync/test/fake_server/fake_server.h" | 5 #include "components/sync/engine_impl/net/loopback_server/loopback_server.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <limits> | 10 #include <limits> |
| 11 #include <memory> | 11 #include <memory> |
| 12 #include <set> | 12 #include <set> |
| 13 #include <string> | 13 #include <string> |
| 14 #include <utility> | 14 #include <utility> |
| 15 #include <vector> | 15 #include <vector> |
| 16 | 16 |
| 17 #include "base/files/file_util.h" |
| 17 #include "base/guid.h" | 18 #include "base/guid.h" |
| 18 #include "base/logging.h" | 19 #include "base/logging.h" |
| 19 #include "base/stl_util.h" | 20 #include "base/stl_util.h" |
| 20 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
| 21 #include "base/strings/string_util.h" | 22 #include "base/strings/string_util.h" |
| 22 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
| 23 #include "base/synchronization/lock.h" | 24 #include "base/synchronization/lock.h" |
| 24 #include "components/sync/base/model_type.h" | |
| 25 #include "components/sync/protocol/sync.pb.h" | |
| 26 #include "components/sync/test/fake_server/bookmark_entity.h" | |
| 27 #include "components/sync/test/fake_server/permanent_entity.h" | |
| 28 #include "components/sync/test/fake_server/tombstone_entity.h" | |
| 29 #include "components/sync/test/fake_server/unique_client_entity.h" | |
| 30 #include "net/base/net_errors.h" | 25 #include "net/base/net_errors.h" |
| 31 #include "net/http/http_status_code.h" | 26 #include "net/http/http_status_code.h" |
| 27 #include "components/sync/base/model_type.h" |
| 28 #include "components/sync/engine_impl/net/loopback_server/bookmark_entity.h" |
| 29 #include "components/sync/engine_impl/net/loopback_server/permanent_entity.h" |
| 30 #include "components/sync/engine_impl/net/loopback_server/tombstone_entity.h" |
| 31 #include "components/sync/engine_impl/net/loopback_server/unique_client_entity.h
" |
| 32 | 32 |
| 33 using std::string; | 33 using std::string; |
| 34 using std::vector; | 34 using std::vector; |
| 35 | 35 |
| 36 using syncer::GetModelType; | 36 using syncer::GetModelType; |
| 37 using syncer::GetModelTypeFromSpecifics; | 37 using syncer::GetModelTypeFromSpecifics; |
| 38 using syncer::ModelType; | 38 using syncer::ModelType; |
| 39 using syncer::ModelTypeSet; | 39 using syncer::ModelTypeSet; |
| 40 | 40 |
| 41 namespace fake_server { | 41 namespace syncer { |
| 42 | 42 |
| 43 class FakeServerEntity; | 43 class LoopbackServerEntity; |
| 44 | 44 |
| 45 namespace { | 45 namespace { |
| 46 | 46 |
| 47 static const int kCurrentLoopbackServerProtoVersion = 1; |
| 48 |
| 47 // The default keystore key. | 49 // The default keystore key. |
| 48 static const char kDefaultKeystoreKey[] = "1111111111111111"; | 50 static const char kDefaultKeystoreKey[] = "1111111111111111"; |
| 49 | 51 |
| 50 // Properties of the bookmark bar permanent folder. | 52 // Properties of the bookmark bar permanent folder. |
| 51 static const char kBookmarkBarFolderServerTag[] = "bookmark_bar"; | 53 static const char kBookmarkBarFolderServerTag[] = "bookmark_bar"; |
| 52 static const char kBookmarkBarFolderName[] = "Bookmark Bar"; | 54 static const char kBookmarkBarFolderName[] = "Bookmark Bar"; |
| 53 | 55 |
| 54 // Properties of the other bookmarks permanent folder. | 56 // Properties of the other bookmarks permanent folder. |
| 55 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks"; | 57 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks"; |
| 56 static const char kOtherBookmarksFolderName[] = "Other Bookmarks"; | 58 static const char kOtherBookmarksFolderName[] = "Other Bookmarks"; |
| 57 | 59 |
| 58 // Properties of the synced bookmarks permanent folder. | 60 // Properties of the synced bookmarks permanent folder. |
| 59 static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks"; | 61 static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks"; |
| 60 static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks"; | 62 static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks"; |
| 61 | 63 |
| 64 // This is anyway for debug purposes. |
| 65 #define kSyncFileLocation FILE_PATH_LITERAL("C:\\src\\sync\\test.pb") |
| 66 |
| 62 // A filter used during GetUpdates calls to determine what information to | 67 // A filter used during GetUpdates calls to determine what information to |
| 63 // send back to the client. There is a 1:1 correspondence between any given | 68 // send back to the client. There is a 1:1 correspondence between any given |
| 64 // GetUpdates call and an UpdateSieve instance. | 69 // GetUpdates call and an UpdateSieve instance. |
| 65 class UpdateSieve { | 70 class UpdateSieve { |
| 66 public: | 71 public: |
| 67 ~UpdateSieve() {} | 72 ~UpdateSieve() { } |
| 68 | 73 |
| 69 // Factory method for creating an UpdateSieve. | 74 // Factory method for creating an UpdateSieve. |
| 70 static std::unique_ptr<UpdateSieve> Create( | 75 static std::unique_ptr<UpdateSieve> Create( |
| 71 const sync_pb::GetUpdatesMessage& get_updates_message); | 76 const sync_pb::GetUpdatesMessage& get_updates_message); |
| 72 | 77 |
| 73 // Sets the progress markers in |get_updates_response| given the progress | 78 // Sets the progress markers in |get_updates_response| given the progress |
| 74 // markers from the original GetUpdatesMessage and |new_version| (the latest | 79 // markers from the original GetUpdatesMessage and |new_version| (the latest |
| 75 // version in the entries sent back). | 80 // version in the entries sent back). |
| 76 void UpdateProgressMarkers( | 81 void UpdateProgressMarkers( |
| 77 int64_t new_version, | 82 int64_t new_version, |
| 78 sync_pb::GetUpdatesResponse* get_updates_response) const { | 83 sync_pb::GetUpdatesResponse* get_updates_response) const { |
| 79 ModelTypeToVersionMap::const_iterator it; | 84 ModelTypeToVersionMap::const_iterator it; |
| 80 for (it = request_from_version_.begin(); it != request_from_version_.end(); | 85 for (it = request_from_version_.begin(); it != request_from_version_.end(); |
| 81 ++it) { | 86 ++it) { |
| 82 sync_pb::DataTypeProgressMarker* new_marker = | 87 sync_pb::DataTypeProgressMarker* new_marker = |
| 83 get_updates_response->add_new_progress_marker(); | 88 get_updates_response->add_new_progress_marker(); |
| 84 new_marker->set_data_type_id( | 89 new_marker->set_data_type_id( |
| 85 GetSpecificsFieldNumberFromModelType(it->first)); | 90 GetSpecificsFieldNumberFromModelType(it->first)); |
| 86 | 91 |
| 87 int64_t version = std::max(new_version, it->second); | 92 int64_t version = std::max(new_version, it->second); |
| 88 new_marker->set_token(base::Int64ToString(version)); | 93 new_marker->set_token(base::Int64ToString(version)); |
| 89 } | 94 } |
| 90 } | 95 } |
| 91 | 96 |
| 92 // Determines whether the server should send an |entity| to the client as | 97 // Determines whether the server should send an |entity| to the client as |
| 93 // part of a GetUpdatesResponse. | 98 // part of a GetUpdatesResponse. |
| 94 bool ClientWantsItem(const FakeServerEntity& entity) const { | 99 bool ClientWantsItem(const LoopbackServerEntity& entity) const { |
| 95 int64_t version = entity.GetVersion(); | 100 int64_t version = entity.GetVersion(); |
| 96 if (version <= min_version_) { | 101 if (version <= min_version_) { |
| 97 return false; | 102 return false; |
| 98 } else if (entity.IsDeleted()) { | 103 } else if (entity.IsDeleted()) { |
| 99 return true; | 104 return true; |
| 100 } | 105 } |
| 101 | 106 |
| 102 ModelTypeToVersionMap::const_iterator it = | 107 ModelTypeToVersionMap::const_iterator it = |
| 103 request_from_version_.find(entity.model_type()); | 108 request_from_version_.find(entity.GetModelType()); |
| 104 | 109 |
| 105 return it == request_from_version_.end() ? false : it->second < version; | 110 return it == request_from_version_.end() ? false : it->second < version; |
| 106 } | 111 } |
| 107 | 112 |
| 108 // Returns the minimum version seen across all types. | 113 // Returns the minimum version seen across all types. |
| 109 int64_t GetMinVersion() const { return min_version_; } | 114 int64_t GetMinVersion() const { return min_version_; } |
| 110 | 115 |
| 111 private: | 116 private: |
| 112 typedef std::map<ModelType, int64_t> ModelTypeToVersionMap; | 117 typedef std::map<ModelType, int64_t> ModelTypeToVersionMap; |
| 113 | 118 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 136 get_updates_message.from_progress_marker(i); | 141 get_updates_message.from_progress_marker(i); |
| 137 | 142 |
| 138 int64_t version = 0; | 143 int64_t version = 0; |
| 139 // Let the version remain zero if there is no token or an empty token (the | 144 // Let the version remain zero if there is no token or an empty token (the |
| 140 // first request for this type). | 145 // first request for this type). |
| 141 if (marker.has_token() && !marker.token().empty()) { | 146 if (marker.has_token() && !marker.token().empty()) { |
| 142 bool parsed = base::StringToInt64(marker.token(), &version); | 147 bool parsed = base::StringToInt64(marker.token(), &version); |
| 143 CHECK(parsed) << "Unable to parse progress marker token."; | 148 CHECK(parsed) << "Unable to parse progress marker token."; |
| 144 } | 149 } |
| 145 | 150 |
| 146 ModelType model_type = | 151 ModelType model_type = syncer::GetModelTypeFromSpecificsFieldNumber( |
| 147 syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()); | 152 marker.data_type_id()); |
| 148 request_from_version[model_type] = version; | 153 request_from_version[model_type] = version; |
| 149 | 154 |
| 150 if (version < min_version) | 155 if (version < min_version) |
| 151 min_version = version; | 156 min_version = version; |
| 152 } | 157 } |
| 153 | 158 |
| 154 return std::unique_ptr<UpdateSieve>( | 159 return std::unique_ptr<UpdateSieve>( |
| 155 new UpdateSieve(request_from_version, min_version)); | 160 new UpdateSieve(request_from_version, min_version)); |
| 156 } | 161 } |
| 157 | 162 |
| 158 // Returns whether |entity| is deleted or permanent. | 163 // Returns whether |entity| is deleted or permanent. |
| 159 bool IsDeletedOrPermanent(const FakeServerEntity& entity) { | 164 bool IsDeletedOrPermanent(const LoopbackServerEntity& entity) { |
| 160 return entity.IsDeleted() || entity.IsPermanent(); | 165 return entity.IsDeleted() || entity.IsPermanent(); |
| 161 } | 166 } |
| 162 | 167 |
| 163 } // namespace | 168 } // namespace |
| 164 | 169 |
| 165 FakeServer::FakeServer() | 170 LoopbackServer::LoopbackServer() : version_(0), |
| 166 : version_(0), | 171 store_birthday_(0), |
| 167 store_birthday_(0), | 172 weak_ptr_factory_(this) { |
| 168 authenticated_(true), | |
| 169 error_type_(sync_pb::SyncEnums::SUCCESS), | |
| 170 alternate_triggered_errors_(false), | |
| 171 request_counter_(0), | |
| 172 network_enabled_(true), | |
| 173 weak_ptr_factory_(this) { | |
| 174 Init(); | 173 Init(); |
| 175 } | 174 } |
| 176 | 175 |
| 177 FakeServer::~FakeServer() {} | 176 LoopbackServer::~LoopbackServer() {} |
| 178 | 177 |
| 179 void FakeServer::Init() { | 178 void LoopbackServer::Init() { |
| 179 // TODO(pastarmovj): DEBUG ONLY! |
| 180 const base::FilePath proto_file(kSyncFileLocation); |
| 181 if (base::PathExists(proto_file)) { |
| 182 string serialized; |
| 183 if (base::ReadFileToString(proto_file, &serialized)) { |
| 184 sync_pb::LoopbackServerProto proto; |
| 185 if (proto.ParseFromString(serialized)) { |
| 186 DeSerializeState(proto); |
| 187 return; |
| 188 } else { |
| 189 LOG(ERROR) << "@@@@@ Can't parse sync loopback server PB file."; |
| 190 } |
| 191 } else { |
| 192 LOG(ERROR) << "@@@@@ Can't load sync loopback server PB file."; |
| 193 } |
| 194 } |
| 195 |
| 196 LOG(WARNING) << "@@@@@ No sync loopback server PB file."; |
| 180 keystore_keys_.push_back(kDefaultKeystoreKey); | 197 keystore_keys_.push_back(kDefaultKeystoreKey); |
| 181 | 198 |
| 182 const bool create_result = CreateDefaultPermanentItems(); | 199 const bool create_result = CreateDefaultPermanentItems(); |
| 183 DCHECK(create_result) << "Permanent items were not created successfully."; | 200 DCHECK(create_result) << "Permanent items were not created successfully."; |
| 184 } | 201 } |
| 185 | 202 |
| 186 bool FakeServer::CreatePermanentBookmarkFolder(const std::string& server_tag, | 203 bool LoopbackServer::CreatePermanentBookmarkFolder( |
| 187 const std::string& name) { | 204 const std::string& server_tag, const std::string& name) { |
| 188 DCHECK(thread_checker_.CalledOnValidThread()); | 205 DCHECK(thread_checker_.CalledOnValidThread()); |
| 189 std::unique_ptr<FakeServerEntity> entity = | 206 std::unique_ptr<LoopbackServerEntity> entity = |
| 190 PermanentEntity::Create(syncer::BOOKMARKS, server_tag, name, | 207 PermanentEntity::Create(syncer::BOOKMARKS, server_tag, name, |
| 191 ModelTypeToRootTag(syncer::BOOKMARKS)); | 208 ModelTypeToRootTag(syncer::BOOKMARKS)); |
| 192 if (!entity) | 209 if (!entity) |
| 193 return false; | 210 return false; |
| 194 | 211 |
| 195 SaveEntity(std::move(entity)); | 212 SaveEntity(std::move(entity)); |
| 196 return true; | 213 return true; |
| 197 } | 214 } |
| 198 | 215 |
| 199 bool FakeServer::CreateDefaultPermanentItems() { | 216 bool LoopbackServer::CreateDefaultPermanentItems() { |
| 200 // Permanent folders are always required for Bookmarks (hierarchical | 217 // Permanent folders are always required for Bookmarks (hierarchical |
| 201 // structure) and Nigori (data stored in permanent root folder). | 218 // structure) and Nigori (data stored in permanent root folder). |
| 202 ModelTypeSet permanent_folder_types = | 219 ModelTypeSet permanent_folder_types = |
| 203 ModelTypeSet(syncer::BOOKMARKS, syncer::NIGORI); | 220 ModelTypeSet(syncer::BOOKMARKS, syncer::NIGORI); |
| 204 | 221 |
| 205 for (ModelTypeSet::Iterator it = permanent_folder_types.First(); it.Good(); | 222 for (ModelTypeSet::Iterator it = permanent_folder_types.First(); it.Good(); |
| 206 it.Inc()) { | 223 it.Inc()) { |
| 207 ModelType model_type = it.Get(); | 224 ModelType model_type = it.Get(); |
| 208 | 225 |
| 209 std::unique_ptr<FakeServerEntity> top_level_entity = | 226 std::unique_ptr<LoopbackServerEntity> top_level_entity = |
| 210 PermanentEntity::CreateTopLevel(model_type); | 227 PermanentEntity::CreateTopLevel(model_type); |
| 211 if (!top_level_entity) { | 228 if (!top_level_entity) { |
| 212 return false; | 229 return false; |
| 213 } | 230 } |
| 214 SaveEntity(std::move(top_level_entity)); | 231 SaveEntity(std::move(top_level_entity)); |
| 215 | 232 |
| 216 if (model_type == syncer::BOOKMARKS) { | 233 if (model_type == syncer::BOOKMARKS) { |
| 217 if (!CreatePermanentBookmarkFolder(kBookmarkBarFolderServerTag, | 234 if (!CreatePermanentBookmarkFolder(kBookmarkBarFolderServerTag, |
| 218 kBookmarkBarFolderName)) | 235 kBookmarkBarFolderName)) |
| 219 return false; | 236 return false; |
| 220 if (!CreatePermanentBookmarkFolder(kOtherBookmarksFolderServerTag, | 237 if (!CreatePermanentBookmarkFolder(kOtherBookmarksFolderServerTag, |
| 221 kOtherBookmarksFolderName)) | 238 kOtherBookmarksFolderName)) |
| 222 return false; | 239 return false; |
| 223 } | 240 } |
| 224 } | 241 } |
| 225 | 242 |
| 226 return true; | 243 return true; |
| 227 } | 244 } |
| 228 | 245 |
| 229 void FakeServer::UpdateEntityVersion(FakeServerEntity* entity) { | 246 void LoopbackServer::UpdateEntityVersion(LoopbackServerEntity* entity) { |
| 230 entity->SetVersion(++version_); | 247 entity->SetVersion(++version_); |
| 231 } | 248 } |
| 232 | 249 |
| 233 void FakeServer::SaveEntity(std::unique_ptr<FakeServerEntity> entity) { | 250 void LoopbackServer::SaveEntity(std::unique_ptr<LoopbackServerEntity> entity) { |
| 234 UpdateEntityVersion(entity.get()); | 251 UpdateEntityVersion(entity.get()); |
| 235 entities_[entity->id()] = std::move(entity); | 252 entities_[entity->GetId()] = std::move(entity); |
| 236 } | 253 } |
| 237 | 254 |
| 238 void FakeServer::HandleCommand(const string& request, | 255 void LoopbackServer::HandleCommand( |
| 239 const base::Closure& completion_closure, | 256 const string& request, |
| 240 int* error_code, | 257 HttpResponse::ServerConnectionCode* server_status, |
| 241 int* response_code, | 258 int64_t* response_code, |
| 242 std::string* response) { | 259 std::string* response) { |
| 243 DCHECK(thread_checker_.CalledOnValidThread()); | 260 DCHECK(thread_checker_.CalledOnValidThread()); |
| 244 if (!network_enabled_) { | |
| 245 *error_code = net::ERR_FAILED; | |
| 246 *response_code = net::ERR_FAILED; | |
| 247 *response = string(); | |
| 248 completion_closure.Run(); | |
| 249 return; | |
| 250 } | |
| 251 request_counter_++; | |
| 252 | |
| 253 if (!authenticated_) { | |
| 254 *error_code = 0; | |
| 255 *response_code = net::HTTP_UNAUTHORIZED; | |
| 256 *response = string(); | |
| 257 completion_closure.Run(); | |
| 258 return; | |
| 259 } | |
| 260 | 261 |
| 261 sync_pb::ClientToServerMessage message; | 262 sync_pb::ClientToServerMessage message; |
| 262 bool parsed = message.ParseFromString(request); | 263 bool parsed = message.ParseFromString(request); |
| 263 CHECK(parsed) << "Unable to parse the ClientToServerMessage."; | 264 CHECK(parsed) << "Unable to parse the ClientToServerMessage."; |
| 264 | 265 |
| 265 sync_pb::ClientToServerResponse response_proto; | 266 sync_pb::ClientToServerResponse response_proto; |
| 266 | 267 |
| 267 if (message.has_store_birthday() && | 268 if (message.has_store_birthday() && |
| 268 message.store_birthday() != GetStoreBirthday()) { | 269 message.store_birthday() != GetStoreBirthday()) { |
| 269 response_proto.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY); | 270 response_proto.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY); |
| 270 } else if (error_type_ != sync_pb::SyncEnums::SUCCESS && | |
| 271 ShouldSendTriggeredError()) { | |
| 272 response_proto.set_error_code(error_type_); | |
| 273 } else if (triggered_actionable_error_.get() && ShouldSendTriggeredError()) { | |
| 274 sync_pb::ClientToServerResponse_Error* error = | |
| 275 response_proto.mutable_error(); | |
| 276 error->CopyFrom(*(triggered_actionable_error_.get())); | |
| 277 } else { | 271 } else { |
| 278 bool success = false; | 272 bool success = false; |
| 279 switch (message.message_contents()) { | 273 switch (message.message_contents()) { |
| 280 case sync_pb::ClientToServerMessage::GET_UPDATES: | 274 case sync_pb::ClientToServerMessage::GET_UPDATES: |
| 281 last_getupdates_message_ = message; | |
| 282 success = HandleGetUpdatesRequest(message.get_updates(), | 275 success = HandleGetUpdatesRequest(message.get_updates(), |
| 283 response_proto.mutable_get_updates()); | 276 response_proto.mutable_get_updates()); |
| 284 break; | 277 break; |
| 285 case sync_pb::ClientToServerMessage::COMMIT: | 278 case sync_pb::ClientToServerMessage::COMMIT: |
| 286 last_commit_message_ = message; | |
| 287 success = HandleCommitRequest(message.commit(), | 279 success = HandleCommitRequest(message.commit(), |
| 288 message.invalidator_client_id(), | 280 message.invalidator_client_id(), |
| 289 response_proto.mutable_commit()); | 281 response_proto.mutable_commit()); |
| 290 break; | 282 break; |
| 291 case sync_pb::ClientToServerMessage::CLEAR_SERVER_DATA: | 283 case sync_pb::ClientToServerMessage::CLEAR_SERVER_DATA: |
| 292 ClearServerData(); | 284 ClearServerData(); |
| 293 response_proto.mutable_clear_server_data(); | 285 response_proto.mutable_clear_server_data(); |
| 294 success = true; | 286 success = true; |
| 295 break; | 287 break; |
| 296 default: | 288 default: |
| 297 *error_code = net::ERR_NOT_IMPLEMENTED; | 289 *server_status = HttpResponse::SYNC_SERVER_ERROR; |
| 298 *response_code = 0; | 290 *response_code = net::ERR_NOT_IMPLEMENTED; |
| 299 *response = string(); | 291 *response = string(); |
| 300 completion_closure.Run(); | |
| 301 return; | 292 return; |
| 302 } | 293 } |
| 303 | 294 |
| 304 if (!success) { | 295 if (!success) { |
| 305 // TODO(pvalenzuela): Add logging here so that tests have more info about | 296 // TODO(pvalenzuela): Add logging here so that tests have more info about |
| 306 // the failure. | 297 // the failure. |
| 307 *error_code = net::ERR_FAILED; | 298 *server_status = HttpResponse::SYNC_SERVER_ERROR; |
| 308 *response_code = 0; | 299 *response_code = net::ERR_FAILED; |
| 309 *response = string(); | 300 *response = string(); |
| 310 completion_closure.Run(); | |
| 311 return; | 301 return; |
| 312 } | 302 } |
| 313 | 303 |
| 314 response_proto.set_error_code(sync_pb::SyncEnums::SUCCESS); | 304 response_proto.set_error_code(sync_pb::SyncEnums::SUCCESS); |
| 305 sync_pb::LoopbackServerProto proto; |
| 306 SerializeState(&proto); |
| 315 } | 307 } |
| 316 | 308 |
| 317 response_proto.set_store_birthday(GetStoreBirthday()); | 309 response_proto.set_store_birthday(GetStoreBirthday()); |
| 318 | 310 |
| 319 *error_code = 0; | 311 *server_status = HttpResponse::SERVER_CONNECTION_OK; |
| 320 *response_code = net::HTTP_OK; | 312 *response_code = net::HTTP_OK; |
| 321 *response = response_proto.SerializeAsString(); | 313 *response = response_proto.SerializeAsString(); |
| 322 completion_closure.Run(); | |
| 323 } | 314 } |
| 324 | 315 |
| 325 bool FakeServer::GetLastCommitMessage(sync_pb::ClientToServerMessage* message) { | 316 bool LoopbackServer::HandleGetUpdatesRequest( |
| 326 if (!last_commit_message_.has_commit()) | |
| 327 return false; | |
| 328 | |
| 329 message->CopyFrom(last_commit_message_); | |
| 330 return true; | |
| 331 } | |
| 332 | |
| 333 bool FakeServer::GetLastGetUpdatesMessage( | |
| 334 sync_pb::ClientToServerMessage* message) { | |
| 335 if (!last_getupdates_message_.has_get_updates()) | |
| 336 return false; | |
| 337 | |
| 338 message->CopyFrom(last_getupdates_message_); | |
| 339 return true; | |
| 340 } | |
| 341 | |
| 342 bool FakeServer::HandleGetUpdatesRequest( | |
| 343 const sync_pb::GetUpdatesMessage& get_updates, | 317 const sync_pb::GetUpdatesMessage& get_updates, |
| 344 sync_pb::GetUpdatesResponse* response) { | 318 sync_pb::GetUpdatesResponse* response) { |
| 345 // TODO(pvalenzuela): Implement batching instead of sending all information | 319 // TODO(pvalenzuela): Implement batching instead of sending all information |
| 346 // at once. | 320 // at once. |
| 347 response->set_changes_remaining(0); | 321 response->set_changes_remaining(0); |
| 348 | 322 |
| 323 |
| 349 std::unique_ptr<UpdateSieve> sieve = UpdateSieve::Create(get_updates); | 324 std::unique_ptr<UpdateSieve> sieve = UpdateSieve::Create(get_updates); |
| 350 | 325 |
| 351 // This folder is called "Synced Bookmarks" by sync and is renamed | 326 // This folder is called "Synced Bookmarks" by sync and is renamed |
| 352 // "Mobile Bookmarks" by the mobile client UIs. | 327 // "Mobile Bookmarks" by the mobile client UIs. |
| 353 if (get_updates.create_mobile_bookmarks_folder() && | 328 if (get_updates.create_mobile_bookmarks_folder() && |
| 354 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag, | 329 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag, |
| 355 kSyncedBookmarksFolderName)) { | 330 kSyncedBookmarksFolderName)) { |
| 356 return false; | 331 return false; |
| 357 } | 332 } |
| 358 | 333 |
| 359 bool send_encryption_keys_based_on_nigori = false; | 334 bool send_encryption_keys_based_on_nigori = false; |
| 360 int64_t max_response_version = 0; | 335 int64_t max_response_version = 0; |
| 361 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); | 336 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| 362 ++it) { | 337 ++it) { |
| 363 const FakeServerEntity& entity = *it->second; | 338 const LoopbackServerEntity& entity = *it->second; |
| 364 if (sieve->ClientWantsItem(entity)) { | 339 if (sieve->ClientWantsItem(entity)) { |
| 365 sync_pb::SyncEntity* response_entity = response->add_entries(); | 340 sync_pb::SyncEntity* response_entity = response->add_entries(); |
| 366 entity.SerializeAsProto(response_entity); | 341 entity.SerializeAsProto(response_entity); |
| 367 | 342 |
| 368 max_response_version = | 343 max_response_version = std::max(max_response_version, |
| 369 std::max(max_response_version, response_entity->version()); | 344 response_entity->version()); |
| 370 | 345 |
| 371 if (entity.model_type() == syncer::NIGORI) { | 346 if (entity.GetModelType() == syncer::NIGORI) { |
| 372 send_encryption_keys_based_on_nigori = | 347 send_encryption_keys_based_on_nigori = |
| 373 response_entity->specifics().nigori().passphrase_type() == | 348 response_entity->specifics().nigori().passphrase_type() == |
| 374 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; | 349 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; |
| 375 } | 350 } |
| 376 } | 351 } |
| 377 } | 352 } |
| 378 | 353 |
| 379 if (send_encryption_keys_based_on_nigori || | 354 if (send_encryption_keys_based_on_nigori || |
| 380 get_updates.need_encryption_key()) { | 355 get_updates.need_encryption_key()) { |
| 381 for (vector<string>::iterator it = keystore_keys_.begin(); | 356 for (vector<string>::iterator it = keystore_keys_.begin(); |
| 382 it != keystore_keys_.end(); ++it) { | 357 it != keystore_keys_.end(); ++it) { |
| 383 response->add_encryption_keys(*it); | 358 response->add_encryption_keys(*it); |
| 384 } | 359 } |
| 385 } | 360 } |
| 386 | 361 |
| 387 sieve->UpdateProgressMarkers(max_response_version, response); | 362 sieve->UpdateProgressMarkers(max_response_version, response); |
| 388 return true; | 363 return true; |
| 389 } | 364 } |
| 390 | 365 |
| 391 string FakeServer::CommitEntity( | 366 string LoopbackServer::CommitEntity( |
| 392 const sync_pb::SyncEntity& client_entity, | 367 const sync_pb::SyncEntity& client_entity, |
| 393 sync_pb::CommitResponse_EntryResponse* entry_response, | 368 sync_pb::CommitResponse_EntryResponse* entry_response, |
| 394 const string& client_guid, | 369 const string& client_guid, |
| 395 const string& parent_id) { | 370 const string& parent_id) { |
| 396 if (client_entity.version() == 0 && client_entity.deleted()) { | 371 if (client_entity.version() == 0 && client_entity.deleted()) { |
| 397 return string(); | 372 return string(); |
| 398 } | 373 } |
| 399 | 374 |
| 400 std::unique_ptr<FakeServerEntity> entity; | 375 std::unique_ptr<LoopbackServerEntity> entity; |
| 401 if (client_entity.deleted()) { | 376 if (client_entity.deleted()) { |
| 402 entity = TombstoneEntity::Create(client_entity.id_string(), | 377 entity = TombstoneEntity::Create(client_entity); |
| 403 client_entity.client_defined_unique_tag()); | |
| 404 DeleteChildren(client_entity.id_string()); | 378 DeleteChildren(client_entity.id_string()); |
| 405 } else if (GetModelType(client_entity) == syncer::NIGORI) { | 379 } else if (GetModelType(client_entity) == syncer::NIGORI) { |
| 406 // NIGORI is the only permanent item type that should be updated by the | 380 // NIGORI is the only permanent item type that should be updated by the |
| 407 // client. | 381 // client. |
| 408 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); | 382 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); |
| 409 CHECK(iter != entities_.end()); | 383 CHECK(iter != entities_.end()); |
| 410 entity = PermanentEntity::CreateUpdatedNigoriEntity(client_entity, | 384 entity = PermanentEntity::CreateUpdatedNigoriEntity(client_entity, |
| 411 *iter->second); | 385 *iter->second); |
| 412 } else if (client_entity.has_client_defined_unique_tag()) { | 386 } else if (client_entity.has_client_defined_unique_tag()) { |
| 413 entity = UniqueClientEntity::Create(client_entity); | 387 entity = UniqueClientEntity::Create(client_entity); |
| 414 } else { | 388 } else { |
| 415 // TODO(pvalenzuela): Validate entity's parent ID. | 389 // TODO(pvalenzuela): Validate entity's parent ID. |
| 416 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); | 390 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); |
| 417 if (iter != entities_.end()) { | 391 if (iter != entities_.end()) { |
| 418 entity = BookmarkEntity::CreateUpdatedVersion(client_entity, | 392 entity = BookmarkEntity::CreateUpdatedVersion(client_entity, |
| 419 *iter->second, parent_id); | 393 *iter->second, parent_id); |
| 420 } else { | 394 } else { |
| 421 entity = BookmarkEntity::CreateNew(client_entity, parent_id, client_guid); | 395 entity = BookmarkEntity::CreateNew(client_entity, parent_id, client_guid); |
| 422 } | 396 } |
| 423 } | 397 } |
| 424 | 398 |
| 425 if (!entity) { | 399 if (!entity) { |
| 426 // TODO(pvalenzuela): Add logging so that it is easier to determine why | 400 // TODO(pvalenzuela): Add logging so that it is easier to determine why |
| 427 // creation failed. | 401 // creation failed. |
| 428 return string(); | 402 return string(); |
| 429 } | 403 } |
| 430 | 404 |
| 431 const std::string id = entity->id(); | 405 const std::string id = entity->GetId(); |
| 432 SaveEntity(std::move(entity)); | 406 SaveEntity(std::move(entity)); |
| 433 BuildEntryResponseForSuccessfulCommit(id, entry_response); | 407 BuildEntryResponseForSuccessfulCommit(id, entry_response); |
| 434 return id; | 408 return id; |
| 435 } | 409 } |
| 436 | 410 |
| 437 void FakeServer::BuildEntryResponseForSuccessfulCommit( | 411 void LoopbackServer::BuildEntryResponseForSuccessfulCommit( |
| 438 const std::string& entity_id, | 412 const std::string& entity_id, |
| 439 sync_pb::CommitResponse_EntryResponse* entry_response) { | 413 sync_pb::CommitResponse_EntryResponse* entry_response) { |
| 440 EntityMap::const_iterator iter = entities_.find(entity_id); | 414 EntityMap::const_iterator iter = entities_.find(entity_id); |
| 441 CHECK(iter != entities_.end()); | 415 CHECK(iter != entities_.end()); |
| 442 const FakeServerEntity& entity = *iter->second; | 416 const LoopbackServerEntity& entity = *iter->second; |
| 443 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS); | 417 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS); |
| 444 entry_response->set_id_string(entity.id()); | 418 entry_response->set_id_string(entity.GetId()); |
| 445 | 419 |
| 446 if (entity.IsDeleted()) { | 420 if (entity.IsDeleted()) { |
| 447 entry_response->set_version(entity.GetVersion() + 1); | 421 entry_response->set_version(entity.GetVersion() + 1); |
| 448 } else { | 422 } else { |
| 449 entry_response->set_version(entity.GetVersion()); | 423 entry_response->set_version(entity.GetVersion()); |
| 450 entry_response->set_name(entity.GetName()); | 424 entry_response->set_name(entity.GetName()); |
| 451 } | 425 } |
| 452 } | 426 } |
| 453 | 427 |
| 454 bool FakeServer::IsChild(const string& id, const string& potential_parent_id) { | 428 bool LoopbackServer::IsChild(const string& id, |
| 429 const string& potential_parent_id) { |
| 455 EntityMap::const_iterator iter = entities_.find(id); | 430 EntityMap::const_iterator iter = entities_.find(id); |
| 456 if (iter == entities_.end()) { | 431 if (iter == entities_.end()) { |
| 457 // We've hit an ID (probably the imaginary root entity) that isn't stored | 432 // We've hit an ID (probably the imaginary root entity) that isn't stored |
| 458 // by the server, so it can't be a child. | 433 // by the server, so it can't be a child. |
| 459 return false; | 434 return false; |
| 460 } | 435 } |
| 461 | 436 |
| 462 const FakeServerEntity& entity = *iter->second; | 437 const LoopbackServerEntity& entity = *iter->second; |
| 463 if (entity.GetParentId() == potential_parent_id) | 438 if (entity.GetParentId() == potential_parent_id) |
| 464 return true; | 439 return true; |
| 465 | 440 |
| 466 // Recursively look up the tree. | 441 // Recursively look up the tree. |
| 467 return IsChild(entity.GetParentId(), potential_parent_id); | 442 return IsChild(entity.GetParentId(), potential_parent_id); |
| 468 } | 443 } |
| 469 | 444 |
| 470 void FakeServer::DeleteChildren(const string& id) { | 445 void LoopbackServer::DeleteChildren(const string& id) { |
| 471 std::vector<std::unique_ptr<FakeServerEntity>> tombstones; | 446 std::vector<sync_pb::SyncEntity> tombstones; |
| 472 // Find all the children of id. | 447 // Find all the children of id. |
| 473 for (const auto& entity : entities_) { | 448 for (auto& entity : entities_) { |
| 474 if (IsChild(entity.first, id)) { | 449 if (IsChild(entity.first, id)) { |
| 475 tombstones.push_back(TombstoneEntity::Create( | 450 sync_pb::SyncEntity proto; |
| 476 entity.first, entity.second->client_defined_unique_tag())); | 451 entity.second->SerializeAsProto(&proto); |
| 452 tombstones.emplace_back(proto); |
| 477 } | 453 } |
| 478 } | 454 } |
| 479 | 455 |
| 480 for (auto& tombstone : tombstones) { | 456 for (auto& tombstone : tombstones) { |
| 481 SaveEntity(std::move(tombstone)); | 457 SaveEntity(TombstoneEntity::Create(tombstone)); |
| 482 } | 458 } |
| 483 } | 459 } |
| 484 | 460 |
| 485 bool FakeServer::HandleCommitRequest(const sync_pb::CommitMessage& commit, | 461 bool LoopbackServer::HandleCommitRequest(const sync_pb::CommitMessage& commit, |
| 486 const std::string& invalidator_client_id, | 462 const std::string& invalidator_client_id, |
| 487 sync_pb::CommitResponse* response) { | 463 sync_pb::CommitResponse* response) { |
| 488 std::map<string, string> client_to_server_ids; | 464 std::map<string, string> client_to_server_ids; |
| 489 string guid = commit.cache_guid(); | 465 string guid = commit.cache_guid(); |
| 490 ModelTypeSet committed_model_types; | 466 ModelTypeSet committed_model_types; |
| 491 | 467 |
| 492 // TODO(pvalenzuela): Add validation of CommitMessage.entries. | 468 // TODO(pvalenzuela): Add validation of CommitMessage.entries. |
| 493 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it; | 469 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it; |
| 494 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) { | 470 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) { |
| 495 sync_pb::CommitResponse_EntryResponse* entry_response = | 471 sync_pb::CommitResponse_EntryResponse* entry_response = |
| 496 response->add_entryresponse(); | 472 response->add_entryresponse(); |
| 497 | 473 |
| 498 sync_pb::SyncEntity client_entity = *it; | 474 sync_pb::SyncEntity client_entity = *it; |
| 499 string parent_id = client_entity.parent_id_string(); | 475 string parent_id = client_entity.parent_id_string(); |
| 500 if (client_to_server_ids.find(parent_id) != client_to_server_ids.end()) { | 476 if (client_to_server_ids.find(parent_id) != |
| 477 client_to_server_ids.end()) { |
| 501 parent_id = client_to_server_ids[parent_id]; | 478 parent_id = client_to_server_ids[parent_id]; |
| 502 } | 479 } |
| 503 | 480 |
| 504 const string entity_id = | 481 const string entity_id = |
| 505 CommitEntity(client_entity, entry_response, guid, parent_id); | 482 CommitEntity(client_entity, entry_response, guid, parent_id); |
| 506 if (entity_id.empty()) { | 483 if (entity_id.empty()) { |
| 507 return false; | 484 return false; |
| 508 } | 485 } |
| 509 | 486 |
| 510 // Record the ID if it was renamed. | 487 // Record the ID if it was renamed. |
| 511 if (entity_id != client_entity.id_string()) { | 488 if (entity_id != client_entity.id_string()) { |
| 512 client_to_server_ids[client_entity.id_string()] = entity_id; | 489 client_to_server_ids[client_entity.id_string()] = entity_id; |
| 513 } | 490 } |
| 514 | 491 |
| 515 EntityMap::const_iterator iter = entities_.find(entity_id); | 492 EntityMap::const_iterator iter = entities_.find(entity_id); |
| 516 CHECK(iter != entities_.end()); | 493 CHECK(iter != entities_.end()); |
| 517 committed_model_types.Put(iter->second->model_type()); | 494 committed_model_types.Put(iter->second->GetModelType()); |
| 518 } | 495 } |
| 519 | 496 |
| 520 FOR_EACH_OBSERVER(Observer, observers_, | 497 FOR_EACH_OBSERVER(Observer, observers_, |
| 521 OnCommit(invalidator_client_id, committed_model_types)); | 498 OnCommit(invalidator_client_id, committed_model_types)); |
| 522 return true; | 499 return true; |
| 523 } | 500 } |
| 524 | 501 |
| 525 std::unique_ptr<base::DictionaryValue> | 502 std::vector<sync_pb::SyncEntity> LoopbackServer::GetSyncEntitiesByModelType( |
| 526 FakeServer::GetEntitiesAsDictionaryValue() { | |
| 527 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 528 std::unique_ptr<base::DictionaryValue> dictionary( | |
| 529 new base::DictionaryValue()); | |
| 530 | |
| 531 // Initialize an empty ListValue for all ModelTypes. | |
| 532 ModelTypeSet all_types = ModelTypeSet::All(); | |
| 533 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) { | |
| 534 dictionary->Set(ModelTypeToString(it.Get()), new base::ListValue()); | |
| 535 } | |
| 536 | |
| 537 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); | |
| 538 ++it) { | |
| 539 const FakeServerEntity& entity = *it->second; | |
| 540 if (IsDeletedOrPermanent(entity)) { | |
| 541 // Tombstones are ignored as they don't represent current data. Folders | |
| 542 // are also ignored as current verification infrastructure does not | |
| 543 // consider them. | |
| 544 continue; | |
| 545 } | |
| 546 base::ListValue* list_value; | |
| 547 if (!dictionary->GetList(ModelTypeToString(entity.model_type()), | |
| 548 &list_value)) { | |
| 549 return std::unique_ptr<base::DictionaryValue>(); | |
| 550 } | |
| 551 // TODO(pvalenzuela): Store more data for each entity so additional | |
| 552 // verification can be performed. One example of additional verification | |
| 553 // is checking the correctness of the bookmark hierarchy. | |
| 554 list_value->AppendString(entity.GetName()); | |
| 555 } | |
| 556 | |
| 557 return dictionary; | |
| 558 } | |
| 559 | |
| 560 std::vector<sync_pb::SyncEntity> FakeServer::GetSyncEntitiesByModelType( | |
| 561 ModelType model_type) { | 503 ModelType model_type) { |
| 562 std::vector<sync_pb::SyncEntity> sync_entities; | 504 std::vector<sync_pb::SyncEntity> sync_entities; |
| 563 DCHECK(thread_checker_.CalledOnValidThread()); | 505 DCHECK(thread_checker_.CalledOnValidThread()); |
| 564 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); | 506 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| 565 ++it) { | 507 ++it) { |
| 566 const FakeServerEntity& entity = *it->second; | 508 const LoopbackServerEntity& entity = *it->second; |
| 567 if (!IsDeletedOrPermanent(entity) && entity.model_type() == model_type) { | 509 if (!IsDeletedOrPermanent(entity) && entity.GetModelType() == model_type) { |
| 568 sync_pb::SyncEntity sync_entity; | 510 sync_pb::SyncEntity sync_entity; |
| 569 entity.SerializeAsProto(&sync_entity); | 511 entity.SerializeAsProto(&sync_entity); |
| 570 sync_entities.push_back(sync_entity); | 512 sync_entities.push_back(sync_entity); |
| 571 } | 513 } |
| 572 } | 514 } |
| 573 return sync_entities; | 515 return sync_entities; |
| 574 } | 516 } |
| 575 | 517 |
| 576 void FakeServer::InjectEntity(std::unique_ptr<FakeServerEntity> entity) { | 518 void LoopbackServer::ClearServerData() { |
| 577 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 578 SaveEntity(std::move(entity)); | |
| 579 } | |
| 580 | |
| 581 bool FakeServer::ModifyEntitySpecifics( | |
| 582 const std::string& id, | |
| 583 const sync_pb::EntitySpecifics& updated_specifics) { | |
| 584 EntityMap::const_iterator iter = entities_.find(id); | |
| 585 if (iter == entities_.end() || | |
| 586 iter->second->model_type() != | |
| 587 GetModelTypeFromSpecifics(updated_specifics)) { | |
| 588 return false; | |
| 589 } | |
| 590 | |
| 591 FakeServerEntity* entity = iter->second.get(); | |
| 592 entity->SetSpecifics(updated_specifics); | |
| 593 UpdateEntityVersion(entity); | |
| 594 return true; | |
| 595 } | |
| 596 | |
| 597 bool FakeServer::ModifyBookmarkEntity( | |
| 598 const std::string& id, | |
| 599 const std::string& parent_id, | |
| 600 const sync_pb::EntitySpecifics& updated_specifics) { | |
| 601 EntityMap::const_iterator iter = entities_.find(id); | |
| 602 if (iter == entities_.end() || | |
| 603 iter->second->model_type() != syncer::BOOKMARKS || | |
| 604 GetModelTypeFromSpecifics(updated_specifics) != syncer::BOOKMARKS) { | |
| 605 return false; | |
| 606 } | |
| 607 | |
| 608 BookmarkEntity* entity = static_cast<BookmarkEntity*>(iter->second.get()); | |
| 609 | |
| 610 entity->SetParentId(parent_id); | |
| 611 entity->SetSpecifics(updated_specifics); | |
| 612 if (updated_specifics.has_bookmark()) { | |
| 613 entity->SetName(updated_specifics.bookmark().title()); | |
| 614 } | |
| 615 UpdateEntityVersion(entity); | |
| 616 return true; | |
| 617 } | |
| 618 | |
| 619 void FakeServer::ClearServerData() { | |
| 620 DCHECK(thread_checker_.CalledOnValidThread()); | 519 DCHECK(thread_checker_.CalledOnValidThread()); |
| 621 entities_.clear(); | 520 entities_.clear(); |
| 622 keystore_keys_.clear(); | 521 keystore_keys_.clear(); |
| 623 ++store_birthday_; | 522 ++store_birthday_; |
| 624 Init(); | 523 Init(); |
| 625 } | 524 } |
| 626 | 525 |
| 627 void FakeServer::SetAuthenticated() { | 526 void LoopbackServer::AddObserver(Observer* observer) { |
| 628 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 629 authenticated_ = true; | |
| 630 } | |
| 631 | |
| 632 void FakeServer::SetUnauthenticated() { | |
| 633 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 634 authenticated_ = false; | |
| 635 } | |
| 636 | |
| 637 bool FakeServer::TriggerError(const sync_pb::SyncEnums::ErrorType& error_type) { | |
| 638 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 639 if (triggered_actionable_error_.get()) { | |
| 640 DVLOG(1) << "Only one type of error can be triggered at any given time."; | |
| 641 return false; | |
| 642 } | |
| 643 | |
| 644 error_type_ = error_type; | |
| 645 return true; | |
| 646 } | |
| 647 | |
| 648 bool FakeServer::TriggerActionableError( | |
| 649 const sync_pb::SyncEnums::ErrorType& error_type, | |
| 650 const string& description, | |
| 651 const string& url, | |
| 652 const sync_pb::SyncEnums::Action& action) { | |
| 653 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 654 if (error_type_ != sync_pb::SyncEnums::SUCCESS) { | |
| 655 DVLOG(1) << "Only one type of error can be triggered at any given time."; | |
| 656 return false; | |
| 657 } | |
| 658 | |
| 659 sync_pb::ClientToServerResponse_Error* error = | |
| 660 new sync_pb::ClientToServerResponse_Error(); | |
| 661 error->set_error_type(error_type); | |
| 662 error->set_error_description(description); | |
| 663 error->set_url(url); | |
| 664 error->set_action(action); | |
| 665 triggered_actionable_error_.reset(error); | |
| 666 return true; | |
| 667 } | |
| 668 | |
| 669 bool FakeServer::EnableAlternatingTriggeredErrors() { | |
| 670 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 671 if (error_type_ == sync_pb::SyncEnums::SUCCESS && | |
| 672 !triggered_actionable_error_.get()) { | |
| 673 DVLOG(1) << "No triggered error set. Alternating can't be enabled."; | |
| 674 return false; | |
| 675 } | |
| 676 | |
| 677 alternate_triggered_errors_ = true; | |
| 678 // Reset the counter so that the the first request yields a triggered error. | |
| 679 request_counter_ = 0; | |
| 680 return true; | |
| 681 } | |
| 682 | |
| 683 bool FakeServer::ShouldSendTriggeredError() const { | |
| 684 if (!alternate_triggered_errors_) | |
| 685 return true; | |
| 686 | |
| 687 // Check that the counter is odd so that we trigger an error on the first | |
| 688 // request after alternating is enabled. | |
| 689 return request_counter_ % 2 != 0; | |
| 690 } | |
| 691 | |
| 692 void FakeServer::AddObserver(Observer* observer) { | |
| 693 DCHECK(thread_checker_.CalledOnValidThread()); | 527 DCHECK(thread_checker_.CalledOnValidThread()); |
| 694 observers_.AddObserver(observer); | 528 observers_.AddObserver(observer); |
| 695 } | 529 } |
| 696 | 530 |
| 697 void FakeServer::RemoveObserver(Observer* observer) { | 531 void LoopbackServer::RemoveObserver(Observer* observer) { |
| 698 DCHECK(thread_checker_.CalledOnValidThread()); | 532 DCHECK(thread_checker_.CalledOnValidThread()); |
| 699 observers_.RemoveObserver(observer); | 533 observers_.RemoveObserver(observer); |
| 700 } | 534 } |
| 701 | 535 |
| 702 void FakeServer::EnableNetwork() { | 536 base::WeakPtr<LoopbackServer> LoopbackServer::AsWeakPtr() { |
| 703 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 704 network_enabled_ = true; | |
| 705 } | |
| 706 | |
| 707 void FakeServer::DisableNetwork() { | |
| 708 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 709 network_enabled_ = false; | |
| 710 } | |
| 711 | |
| 712 std::string FakeServer::GetBookmarkBarFolderId() const { | |
| 713 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 714 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); | |
| 715 ++it) { | |
| 716 FakeServerEntity* entity = it->second.get(); | |
| 717 if (entity->GetName() == kBookmarkBarFolderName && entity->IsFolder() && | |
| 718 entity->model_type() == syncer::BOOKMARKS) { | |
| 719 return entity->id(); | |
| 720 } | |
| 721 } | |
| 722 NOTREACHED() << "Bookmark Bar entity not found."; | |
| 723 return ""; | |
| 724 } | |
| 725 | |
| 726 base::WeakPtr<FakeServer> FakeServer::AsWeakPtr() { | |
| 727 DCHECK(thread_checker_.CalledOnValidThread()); | 537 DCHECK(thread_checker_.CalledOnValidThread()); |
| 728 return weak_ptr_factory_.GetWeakPtr(); | 538 return weak_ptr_factory_.GetWeakPtr(); |
| 729 } | 539 } |
| 730 | 540 |
| 731 std::string FakeServer::GetStoreBirthday() const { | 541 std::string LoopbackServer::GetStoreBirthday() const { |
| 732 DCHECK(thread_checker_.CalledOnValidThread()); | 542 DCHECK(thread_checker_.CalledOnValidThread()); |
| 733 return base::Int64ToString(store_birthday_); | 543 return base::Int64ToString(store_birthday_); |
| 734 } | 544 } |
| 735 | 545 |
| 736 } // namespace fake_server | 546 void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { |
| 547 proto->set_version(kCurrentLoopbackServerProtoVersion); |
| 548 proto->set_store_birthday(store_birthday_); |
| 549 proto->set_last_version_assigned(version_); |
| 550 for (const auto& key : keystore_keys_) |
| 551 proto->add_keystore_keys(key); |
| 552 for (const auto& entity : entities_) { |
| 553 auto* new_entity = proto->mutable_entities()->Add(); |
| 554 if (entity.second->IsDeleted()) |
| 555 new_entity->set_type(sync_pb::LoopbackServerEntity_Type_TOMBSTONE); |
| 556 else if (entity.second->IsPermanent()) |
| 557 new_entity->set_type(sync_pb::LoopbackServerEntity_Type_PERMANENT); |
| 558 else if (entity.second->RequiresParentId()) |
| 559 new_entity->set_type(sync_pb::LoopbackServerEntity_Type_BOOKMARK); |
| 560 else |
| 561 new_entity->set_type(sync_pb::LoopbackServerEntity_Type_UNIQUE); |
| 562 new_entity->set_model_type((int64_t)(entity.second->GetModelType())); |
| 563 entity.second->SerializeAsProto(new_entity->mutable_entity()); |
| 564 } |
| 565 |
| 566 // TODO(pastarmovj): DEBUG ONLY! |
| 567 string serialized = proto->SerializeAsString(); |
| 568 base::WriteFile(base::FilePath(kSyncFileLocation), |
| 569 serialized.data(), serialized.size()); |
| 570 } |
| 571 |
| 572 bool LoopbackServer::DeSerializeState( |
| 573 const sync_pb::LoopbackServerProto& proto) { |
| 574 CHECK_EQ(proto.version(), kCurrentLoopbackServerProtoVersion); |
| 575 store_birthday_ = proto.store_birthday(); |
| 576 version_ = proto.last_version_assigned(); |
| 577 for (int i = 0; i < proto.keystore_keys_size(); ++i) |
| 578 keystore_keys_.push_back(proto.keystore_keys(i)); |
| 579 for (int i = 0; i < proto.entities_size(); ++i) { |
| 580 const auto& entity = proto.entities(i); |
| 581 switch (entity.type()) { |
| 582 case sync_pb::LoopbackServerEntity_Type_TOMBSTONE: |
| 583 entities_[entity.entity().id_string()] = |
| 584 TombstoneEntity::Create(entity.entity()); |
| 585 break; |
| 586 case sync_pb::LoopbackServerEntity_Type_PERMANENT: { |
| 587 std::unique_ptr<PermanentEntity> new_entity(new PermanentEntity( |
| 588 entity.entity().id_string(), |
| 589 entity.entity().version(), |
| 590 syncer::GetModelType(entity.entity()), |
| 591 entity.entity().name(), |
| 592 entity.entity().parent_id_string(), |
| 593 entity.entity().server_defined_unique_tag(), |
| 594 entity.entity().specifics())); |
| 595 entities_[entity.entity().id_string()] = std::move(new_entity); |
| 596 break; |
| 597 } |
| 598 case sync_pb::LoopbackServerEntity_Type_BOOKMARK: |
| 599 entities_[entity.entity().id_string()] = |
| 600 BookmarkEntity::CreateFromEntity(entity.entity()); |
| 601 break; |
| 602 case sync_pb::LoopbackServerEntity_Type_UNIQUE: |
| 603 entities_[entity.entity().id_string()] = |
| 604 UniqueClientEntity::Create(entity.entity()); |
| 605 break; |
| 606 default: |
| 607 CHECK(false) << "Unknown type encountered"; |
| 608 } |
| 609 LOG(ERROR) << "@@@@@ " << entity.entity().version(); |
| 610 } |
| 611 |
| 612 return true; |
| 613 } |
| 614 |
| 615 |
| 616 } // namespace syncer |
| OLD | NEW |