Fix import error in mac_platform_backend.py
[chromium-blink-merge.git] / sync / test / fake_server / fake_server.cc
blob4c1ea65b0d605de48f120bd0a345a2196b0fce32
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
3 // found in the LICENSE file.
5 #include "sync/test/fake_server/fake_server.h"
7 #include <limits>
8 #include <string>
9 #include <vector>
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "net/base/net_errors.h"
16 #include "net/http/http_status_code.h"
17 #include "sync/internal_api/public/base/model_type.h"
18 #include "sync/protocol/sync.pb.h"
20 using std::string;
22 // The parent tag for childen of the root node.
23 static const char kRootParentTag[] = "0";
25 // The default birthday value.
26 static const char kDefaultBirthday[] = "1234567890";
28 // The default keystore key.
29 static const char kDefaultKeystoreKey[] = "1111111111111111";
31 // A dummy value to use for the position_in_parent field of SyncEntity.
32 static const int64 kDummyBookmarkPositionInParent = 1337;
34 namespace syncer {
35 namespace {
37 // A filter used during GetUpdates calls to determine what information to
38 // send back to the client. There is a 1:1 correspondence between any given
39 // GetUpdates call and an UpdateSieve instance.
40 class UpdateSieve {
41 public:
42 ~UpdateSieve() { }
44 // Factory method for creating an UpdateSieve.
45 static scoped_ptr<UpdateSieve> Create(
46 const sync_pb::GetUpdatesMessage& get_updates_message);
48 // Sets the progress markers in |get_updates_response| given the progress
49 // markers from the original GetUpdatesMessage and |new_version| (the latest
50 // version in the entries sent back).
51 void UpdateProgressMarkers(
52 int64 new_version,
53 sync_pb::GetUpdatesResponse* get_updates_response) const {
54 ModelTypeToVersionMap::const_iterator it;
55 for (it = request_from_version_.begin(); it != request_from_version_.end();
56 ++it) {
57 sync_pb::DataTypeProgressMarker* new_marker =
58 get_updates_response->add_new_progress_marker();
59 new_marker->set_data_type_id(
60 GetSpecificsFieldNumberFromModelType(it->first));
62 int64 version = std::max(new_version, it->second);
63 new_marker->set_token(base::Int64ToString(version));
67 // Determines whether the server should send |entity| to the client based
68 // on its type and version.
69 bool ClientWantsItem(const sync_pb::SyncEntity& entity) const {
70 ModelTypeToVersionMap::const_iterator it =
71 request_from_version_.find(GetModelType(entity));
73 return it == request_from_version_.end() ?
74 false : it->second < entity.version();
77 // Returns the mininum version seen across all types.
78 int64 GetMinVersion() const {
79 return min_version_;
82 // Returns the data type IDs of types being synced for the first time.
83 std::vector<ModelType> GetFirstTimeTypes() const {
84 std::vector<ModelType> types;
86 ModelTypeToVersionMap::const_iterator it;
87 for (it = request_from_version_.begin(); it != request_from_version_.end();
88 ++it) {
89 if (it->second == 0)
90 types.push_back(it->first);
93 return types;
96 private:
97 typedef std::map<ModelType, int64> ModelTypeToVersionMap;
99 // Creates an UpdateSieve.
100 UpdateSieve(const ModelTypeToVersionMap request_from_version,
101 const int64 min_version)
102 : request_from_version_(request_from_version),
103 min_version_(min_version) { }
105 // Maps data type IDs to the latest version seen for that type.
106 const ModelTypeToVersionMap request_from_version_;
108 // The minimum version seen among all data types.
109 const int min_version_;
112 scoped_ptr<UpdateSieve> UpdateSieve::Create(
113 const sync_pb::GetUpdatesMessage& get_updates_message) {
114 DCHECK_GT(get_updates_message.from_progress_marker_size(), 0);
116 UpdateSieve::ModelTypeToVersionMap request_from_version;
117 int64 min_version = std::numeric_limits<int64>::max();
118 for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) {
119 sync_pb::DataTypeProgressMarker marker =
120 get_updates_message.from_progress_marker(i);
122 int64 version = 0;
123 // Let the version remain zero if there is no token or an empty token (the
124 // first request for this type).
125 if (marker.has_token() && !marker.token().empty()) {
126 bool parsed = base::StringToInt64(marker.token(), &version);
127 DCHECK(parsed);
130 ModelType model_type = GetModelTypeFromSpecificsFieldNumber(
131 marker.data_type_id());
132 request_from_version[model_type] = version;
134 if (version < min_version)
135 min_version = version;
138 return scoped_ptr<UpdateSieve>(
139 new UpdateSieve(request_from_version, min_version));
142 } // namespace
144 FakeServer::FakeServer() : version_(0), birthday_(kDefaultBirthday) {
145 keystore_keys_.push_back(kDefaultKeystoreKey);
148 FakeServer::~FakeServer() { }
150 void FakeServer::CreateDefaultPermanentItems(
151 const std::vector<ModelType>& first_time_types) {
152 for (std::vector<ModelType>::const_iterator it = first_time_types.begin();
153 it != first_time_types.end(); ++it) {
154 if (!ModelTypeSet::All().Has(*it)) {
155 NOTREACHED() << "An unexpected ModelType was encountered.";
158 ModelType model_type = *it;
159 CreateSyncEntity(model_type,
160 ModelTypeToRootTag(model_type),
161 ModelTypeToString(model_type),
162 kRootParentTag);
164 if (model_type == BOOKMARKS) {
165 CreateSyncEntity(BOOKMARKS,
166 "bookmark_bar",
167 "Bookmark Bar",
168 ModelTypeToRootTag(BOOKMARKS));
169 CreateSyncEntity(BOOKMARKS,
170 "other_bookmarks",
171 "Other Bookmarks",
172 ModelTypeToRootTag(BOOKMARKS));
177 // TODO(pvalenzuela): Create the mobile bookmarks folder when the fake server
178 // is used by mobile tests.
181 void FakeServer::CreateSyncEntity(ModelType model_type,
182 const std::string& id,
183 const std::string& name,
184 const std::string& parent_tag) {
185 DCHECK(!id.empty());
186 DCHECK(!name.empty());
187 DCHECK(!parent_tag.empty());
189 sync_pb::SyncEntity entity;
190 entity.set_id_string(id);
191 entity.set_non_unique_name(name);
192 entity.set_name(name);
193 entity.set_server_defined_unique_tag(id);
194 entity.set_folder(true);
195 entity.set_deleted(false);
197 entity.set_parent_id_string(parent_tag);
199 if (parent_tag != kRootParentTag && model_type == BOOKMARKS) {
200 // Use a dummy value here.
201 entity.set_position_in_parent(kDummyBookmarkPositionInParent);
204 sync_pb::EntitySpecifics* specifics = entity.mutable_specifics();
205 AddDefaultFieldValue(model_type, specifics);
207 SaveEntity(&entity);
210 void FakeServer::SaveEntity(sync_pb::SyncEntity* entity) {
211 version_++;
212 entity->set_version(version_);
213 entity->set_sync_timestamp(version_);
215 sync_pb::SyncEntity original_entity = entities_[entity->id_string()];
216 entity->set_originator_cache_guid(original_entity.originator_cache_guid());
217 entity->set_originator_client_item_id(
218 original_entity.originator_client_item_id());
220 entities_[entity->id_string()] = *entity;
223 int FakeServer::HandleCommand(const string& request,
224 int* response_code,
225 string* response) {
226 sync_pb::ClientToServerMessage message;
227 bool parsed = message.ParseFromString(request);
228 DCHECK(parsed);
230 sync_pb::ClientToServerResponse response_proto;
231 switch (message.message_contents()) {
232 case sync_pb::ClientToServerMessage::GET_UPDATES:
233 response_proto = HandleGetUpdatesRequest(message);
234 break;
235 case sync_pb::ClientToServerMessage::COMMIT:
236 response_proto = HandleCommitRequest(message);
237 break;
238 default:
239 return net::ERR_NOT_IMPLEMENTED;
242 *response_code = net::HTTP_OK;
243 *response = response_proto.SerializeAsString();
244 return 0;
247 bool SyncEntityVersionComparator(const sync_pb::SyncEntity& first,
248 const sync_pb::SyncEntity& second) {
249 return first.version() < second.version();
252 sync_pb::ClientToServerResponse FakeServer::HandleGetUpdatesRequest(
253 const sync_pb::ClientToServerMessage& message) {
254 sync_pb::ClientToServerResponse response;
255 response.set_error_code(sync_pb::SyncEnums::SUCCESS);
256 response.set_store_birthday(birthday_);
258 sync_pb::GetUpdatesResponse* get_updates_response =
259 response.mutable_get_updates();
260 // TODO(pvalenzuela): Implement batching instead of sending all information
261 // at once.
262 get_updates_response->set_changes_remaining(0);
264 scoped_ptr<UpdateSieve> sieve = UpdateSieve::Create(message.get_updates());
265 CreateDefaultPermanentItems(sieve->GetFirstTimeTypes());
267 int64 min_version = sieve->GetMinVersion();
269 bool send_encryption_keys_based_on_nigori = false;
270 int64 max_response_version = 0;
271 for (EntityMap::iterator it = entities_.begin(); it != entities_.end();
272 ++it) {
273 sync_pb::SyncEntity entity = it->second;
274 if (entity.version() > min_version && sieve->ClientWantsItem(entity)) {
275 sync_pb::SyncEntity* response_entity =
276 get_updates_response->add_entries();
277 response_entity->CopyFrom(entity);
278 max_response_version = std::max(max_response_version,
279 response_entity->version());
281 if (response_entity->name() == ModelTypeToString(NIGORI)) {
282 send_encryption_keys_based_on_nigori =
283 response_entity->specifics().nigori().passphrase_type() ==
284 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE;
289 if (send_encryption_keys_based_on_nigori ||
290 message.get_updates().need_encryption_key()) {
291 for (std::vector<std::string>::iterator it = keystore_keys_.begin();
292 it != keystore_keys_.end(); ++it) {
293 get_updates_response->add_encryption_keys(*it);
297 sieve->UpdateProgressMarkers(max_response_version, get_updates_response);
299 return response;
302 sync_pb::SyncEntity FakeServer::CommitEntity(const sync_pb::SyncEntity& entity,
303 string guid) {
304 // TODO(pvalenzuela): Implement this. Right now this method cheats and
305 // doesn't actually commit.
306 return entity;
309 sync_pb::ClientToServerResponse FakeServer::HandleCommitRequest(
310 const sync_pb::ClientToServerMessage& message) {
311 sync_pb::ClientToServerResponse response;
312 response.set_error_code(sync_pb::SyncEnums::SUCCESS);
313 response.set_store_birthday(birthday_);
315 sync_pb::CommitMessage commit = message.commit();
316 string guid = commit.cache_guid();
318 sync_pb::CommitResponse* commit_response = response.mutable_commit();
320 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it;
321 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) {
322 sync_pb::CommitResponse_EntryResponse* entry_response =
323 commit_response->add_entryresponse();
325 sync_pb::SyncEntity server_entity = CommitEntity(*it, guid);
327 entry_response->set_id_string(server_entity.id_string());
328 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS);
329 entry_response->set_version(it->version() + 1);
332 return response;
335 } // namespace syncer