Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(626)

Side by Side Diff: sync/test/fake_server/fake_server.cc

Issue 115243007: Basic implementation of the Sync C++ fake server (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: move files Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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.
4
5 #include "sync/test/fake_server/fake_server.h"
6
7 #include <limits>
8 #include <string>
9 #include <vector>
10
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 "sync/internal_api/public/base/model_type.h"
16 #include "sync/protocol/sync.pb.h"
17
18 using std::string;
19
20 // The parent tag for childen of the root node.
21 static const std::string kRootParentTag = "0";
22
23 namespace syncer {
24 namespace {
25
26 // A filter used during GetUpdates calls to determine what information to
27 // send back to the client. There is a 1:1 correspondence between any given
28 // GetUpdates call and an UpdateSieve instance.
29 class UpdateSieve {
30 public:
31 // Factory method for creating an UpdateSieve.
32 static scoped_ptr<UpdateSieve> Create(
rlarocque 2014/01/14 01:53:38 nit that I should have caught earlier: You should
pval...(no longer on Chromium) 2014/01/14 02:14:45 Thanks. Done.
33 const sync_pb::GetUpdatesMessage& get_updates_message) {
34 DCHECK_GT(get_updates_message.from_progress_marker_size(), 0);
35
36 ModelTypeToVersionMap request_from_version;
37 int64 min_version = std::numeric_limits<int64>::max();
38 for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) {
39 sync_pb::DataTypeProgressMarker marker =
40 get_updates_message.from_progress_marker(i);
41
42 int64 version;
43 if (!marker.has_token() || marker.token().empty()) {
44 // Initialize the version on the first request for this type.
45 version = 0;
46 } else {
47 DCHECK(base::StringToInt64(marker.token(), &version));
48 }
49
50 ModelType model_type = GetModelTypeFromSpecificsFieldNumber(
51 marker.data_type_id());
52 request_from_version[model_type] = version;
53
54 if (version < min_version)
55 min_version = version;
56 }
57
58 return scoped_ptr<UpdateSieve>(
59 new UpdateSieve(request_from_version, min_version));
60 }
61
62 ~UpdateSieve() { }
63
64 // Sets the progress markers in |get_updates_response| given the progress
65 // markers from the original GetUpdatesMessage and |new_version| (the latest
66 // version in the entries sent back).
67 void UpdateProgressMarkers(
68 int64 new_version,
69 sync_pb::GetUpdatesResponse* get_updates_response) const {
70 ModelTypeToVersionMap::const_iterator it;
71 for (it = request_from_version_.begin(); it != request_from_version_.end();
72 ++it) {
73 sync_pb::DataTypeProgressMarker* new_marker =
74 get_updates_response->add_new_progress_marker();
75 new_marker->set_data_type_id(
76 GetSpecificsFieldNumberFromModelType(it->first));
77
78 int64 version = std::max(new_version, it->second);
79 new_marker->set_token(base::Int64ToString(version));
80 }
81 }
82
83 // Determines whether the server should send |entity| to the client based
84 // on its type and version.
85 bool ClientWantsItem(const sync_pb::SyncEntity& entity) const {
86 ModelTypeToVersionMap::const_iterator it =
87 request_from_version_.find(GetModelType(entity));
88
89 return it == request_from_version_.end() ?
90 false : it->second < entity.version();
91 }
92
93 // Returns the mininum version seen across all types.
94 int64 GetMinVersion() const {
95 return min_version_;
96 }
97
98 // Returns the data type IDs of types being synced for the first time.
99 std::vector<ModelType> GetFirstTimeTypes() const {
100 std::vector<ModelType> types;
101
102 ModelTypeToVersionMap::const_iterator it;
103 for (it = request_from_version_.begin(); it != request_from_version_.end();
104 ++it) {
105 if (it->second == 0)
106 types.push_back(it->first);
107 }
108
109 return types;
110 }
111
112 private:
113 typedef std::map<ModelType, int64> ModelTypeToVersionMap;
114
115 // Creates an UpdateSieve.
116 UpdateSieve(const ModelTypeToVersionMap request_from_version,
117 const int64 min_version)
118 : request_from_version_(request_from_version),
119 min_version_(min_version) { }
120
121 // Maps data type IDs to the latest version seen for that type.
122 const ModelTypeToVersionMap request_from_version_;
123
124 // The minimum version seen among all data types.
125 const int min_version_;
126 };
127
128 } // namespace
129
130 FakeServer::FakeServer() : version_(0), birthday_("1234567890") {
131 keystore_keys_.push_back("1111111111111111");
132 }
133
134 FakeServer::~FakeServer() { }
135
136 void FakeServer::CreateDefaultPermanentItems(
137 const std::vector<ModelType>& first_time_types) {
138 for (std::vector<ModelType>::const_iterator it = first_time_types.begin();
139 it != first_time_types.end(); ++it) {
140 if (!ModelTypeSet::All().Has(*it)) {
141 NOTREACHED() << "An unexpected ModelType was encountered.";
142 }
143
144 ModelType model_type = *it;
145 CreateSyncEntity(model_type,
146 ModelTypeToRootTag(model_type),
147 ModelTypeToString(model_type),
148 kRootParentTag);
149
150 if (model_type == BOOKMARKS) {
151 CreateSyncEntity(BOOKMARKS,
152 "bookmark_bar",
153 "Bookmark Bar",
154 ModelTypeToRootTag(BOOKMARKS));
155 CreateSyncEntity(BOOKMARKS,
156 "other_bookmarks",
157 "Other Bookmarks",
158 ModelTypeToRootTag(BOOKMARKS));
159 }
160 }
161
162
163 // TODO(pvalenzuela): Create the mobile bookmarks folder when the fake server
164 // is used by mobile tests.
165 }
166
167 void FakeServer::CreateSyncEntity(ModelType model_type,
168 const std::string& id,
169 const std::string& name,
170 const std::string& parent_tag) {
171 DCHECK(!id.empty());
172 DCHECK(!name.empty());
173 DCHECK(!parent_tag.empty());
174
175 sync_pb::SyncEntity entity;
176 entity.set_id_string(id);
177 entity.set_non_unique_name(name);
178 entity.set_name(name);
179 entity.set_server_defined_unique_tag(id);
180 entity.set_folder(true);
181 entity.set_deleted(false);
182
183 entity.set_parent_id_string(parent_tag);
184
185 if (parent_tag != kRootParentTag && model_type == BOOKMARKS) {
186 // Use a dummy value here.
187 entity.set_position_in_parent(1337);
188 }
189
190 sync_pb::EntitySpecifics* specifics = entity.mutable_specifics();
191 AddDefaultFieldValue(model_type, specifics);
192
193 SaveEntity(entity);
194 }
195
196 void FakeServer::SaveEntity(sync_pb::SyncEntity entity) {
197 version_++;
198 entity.set_version(version_);
199 entity.set_sync_timestamp(version_);
200
201 sync_pb::SyncEntity original_entity = entities_[entity.id_string()];
202 entity.set_originator_cache_guid(original_entity.originator_cache_guid());
203 entity.set_originator_client_item_id(
204 original_entity.originator_client_item_id());
205
206 entities_[entity.id_string()] = entity;
207 }
208
209 int FakeServer::HandleCommand(string request,
210 int* response_code,
211 string* response) {
212 sync_pb::ClientToServerMessage message;
213 DCHECK(message.ParseFromString(request));
214
215 sync_pb::ClientToServerResponse response_proto;
216 switch (message.message_contents()) {
217 case sync_pb::ClientToServerMessage::GET_UPDATES:
218 response_proto = HandleGetUpdatesRequest(message);
219 break;
220 case sync_pb::ClientToServerMessage::COMMIT:
221 response_proto = HandleCommitRequest(message);
222 break;
223 default:
224 // Any nonzero int will indicate a failure here. This one happens to
225 // be net::ERR_NOT_IMPLEMENTED.
226 return -11;
227 }
228
229 *response_code = 200;
230 *response = response_proto.SerializeAsString();
231 return 0;
232 }
233
234 bool SyncEntityVersionComparator(const sync_pb::SyncEntity& first,
235 const sync_pb::SyncEntity& second) {
236 return first.version() < second.version();
237 }
238
239 sync_pb::ClientToServerResponse FakeServer::HandleGetUpdatesRequest(
240 const sync_pb::ClientToServerMessage& message) {
241 sync_pb::ClientToServerResponse response;
242 response.set_error_code(sync_pb::SyncEnums::SUCCESS);
243 response.set_store_birthday(birthday_);
244
245 sync_pb::GetUpdatesResponse* get_updates_response =
246 response.mutable_get_updates();
247 // TODO(pvalenzuela): Implement batching instead of sending all information
248 // at once.
249 get_updates_response->set_changes_remaining(0);
250
251 scoped_ptr<UpdateSieve> sieve = UpdateSieve::Create(message.get_updates());
252 CreateDefaultPermanentItems(sieve->GetFirstTimeTypes());
253
254 int64 min_version = sieve->GetMinVersion();
255
256 bool send_encryption_keys_based_on_nigori = false;
257 int64 max_response_version = 0;
258 for (EntityMap::iterator it = entities_.begin(); it != entities_.end();
259 ++it) {
260 sync_pb::SyncEntity entity = it->second;
261 if (entity.version() > min_version && sieve->ClientWantsItem(entity)) {
262 sync_pb::SyncEntity* response_entity =
263 get_updates_response->add_entries();
264 response_entity->CopyFrom(entity);
265 max_response_version = std::max(max_response_version,
266 response_entity->version());
267
268 if (response_entity->name() == ModelTypeToString(NIGORI)) {
269 send_encryption_keys_based_on_nigori =
270 response_entity->specifics().nigori().passphrase_type() ==
271 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE;
272 }
273 }
274 }
275
276 if (send_encryption_keys_based_on_nigori ||
277 message.get_updates().need_encryption_key()) {
278 for (std::vector<std::string>::iterator it = keystore_keys_.begin();
279 it != keystore_keys_.end(); ++it) {
280 get_updates_response->add_encryption_keys(*it);
281 }
282 }
283
284 sieve->UpdateProgressMarkers(max_response_version, get_updates_response);
285
286 return response;
287 }
288
289 sync_pb::SyncEntity FakeServer::CommitEntity(sync_pb::SyncEntity entity,
290 string guid) {
291 // TODO(pvalenzuela): Implement this. Right now this method cheats and
292 // doesn't actually commit.
293 return entity;
294 }
295
296 sync_pb::ClientToServerResponse FakeServer::HandleCommitRequest(
297 const sync_pb::ClientToServerMessage& message) {
298 sync_pb::ClientToServerResponse response;
299 response.set_error_code(sync_pb::SyncEnums::SUCCESS);
300 response.set_store_birthday(birthday_);
301
302 sync_pb::CommitMessage commit = message.commit();
303 string guid = commit.cache_guid();
304
305 sync_pb::CommitResponse* commit_response = response.mutable_commit();
306
307 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it;
308 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) {
309 sync_pb::CommitResponse_EntryResponse* entry_response =
310 commit_response->add_entryresponse();
311
312 sync_pb::SyncEntity server_entity = CommitEntity(*it, guid);
313
314 entry_response->set_id_string(server_entity.id_string());
315 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS);
316 entry_response->set_version(it->version() + 1);
317 }
318
319 return response;
320 }
321
322 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/test/fake_server/fake_server.h ('k') | sync/test/fake_server/fake_server_http_post_provider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698