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

Side by Side Diff: sync/internal_api/test/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: Created 7 years 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/internal_api/public/test/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/strings/string_number_conversions.h"
14 #include "sync/internal_api/public/base/model_type.h"
15 #include "sync/protocol/sync.pb.h"
16
17 using std::string;
18
19 // The PermanentItemSpec parent_tag for a root node.
20 static const std::string kRootParentTag = "0";
rlarocque 2013/12/18 20:22:01 I'm not 100% sure about this, but I think this lin
pval...(no longer on Chromium) 2014/01/03 23:25:31 I'm fine with leaving it here if there are no awfu
rlarocque 2014/01/04 00:06:24 The namespace doesn't matter too much. Because it
21
22 namespace syncer {
23
24 FakeServer::UpdateSieve::UpdateSieve(
25 const sync_pb::GetUpdatesMessage& get_updates_message)
26 : get_updates_message_(get_updates_message) {
27 DCHECK_GT(get_updates_message.from_progress_marker_size(), 0);
28
29 int64 min_version = std::numeric_limits<int64>::max();
30 for (int i = 0; i < get_updates_message_.from_progress_marker_size(); i++) {
31 sync_pb::DataTypeProgressMarker marker =
32 get_updates_message_.from_progress_marker(i);
33
34 int64 version;
35 if (!base::StringToInt64(marker.token(), &version)) {
36 version = 0;
37 }
38
39 state_[marker.data_type_id()] = version;
40
41 if (version < min_version)
42 min_version = version;
43 }
44
45 min_version_ = min_version;
46 state_[ModelTypeFromInt(TOP_LEVEL_FOLDER)] = min_version_;
rlarocque 2013/12/18 20:22:01 This looks sketchy to me. TOP_LEVEL_FOLDER is eno
pval...(no longer on Chromium) 2014/01/03 23:25:31 I've removed handling of TOP_LEVEL_FOLDER since it
47 }
48
49 FakeServer::UpdateSieve::~UpdateSieve() { }
50
51 void FakeServer::UpdateSieve::UpdateProgressMarkers(
52 int64 new_version,
53 sync_pb::GetUpdatesResponse* get_updates_response) {
54 for (TypeIdToVersionMap::iterator it = state_.begin(); it != state_.end();
55 ++it) {
56 if (it->first == TOP_LEVEL_FOLDER)
57 continue;
58
59 sync_pb::DataTypeProgressMarker* new_marker =
60 get_updates_response->add_new_progress_marker();
61 new_marker->set_data_type_id(it->first);
62
63 int64 version = new_version > state_[new_marker->data_type_id()] ?
64 new_version : state_[new_marker->data_type_id()];
65 new_marker->set_token(base::Int64ToString(version));
66 }
67 }
68
69 bool FakeServer::UpdateSieve::ClientWantsItem(
70 const sync_pb::SyncEntity& entity) {
71 ModelType model_type = GetModelType(entity);
72 int data_type_id = GetSpecificsFieldNumberFromModelType(model_type);
73 return state_[data_type_id] < entity.version();
74 }
75
76 int64 FakeServer::UpdateSieve::GetMinVersion() {
77 return min_version_;
78 }
79
80 std::vector<int> FakeServer::UpdateSieve::GetFirstTimeTypes() {
81 std::vector<int> types;
82
83 for (TypeIdToVersionMap::iterator it = state_.begin(); it != state_.end();
84 ++it) {
85 if (state_[it->first] == 0)
rlarocque 2013/12/18 20:22:01 Could TOP_LEVEL_FOLDER wind up in this list of typ
pval...(no longer on Chromium) 2014/01/03 23:25:31 Not anymore (see comment above about removing it e
86 types.push_back(it->first);
87 }
88
89 return types;
90 }
91
92 FakeServer::FakeServer() : initialized_(false), version_(0) { }
93
94 FakeServer::~FakeServer() { }
95
96 bool FakeServer::Init() {
97 // Use dummy values for these fields.
98 keystore_keys_.push_back("1111111111111111");
99 birthday_ = "1234567890";
100
101 initialized_ = PopulatePermanentItemSpecs();
102 return initialized_;
103 }
104
105 bool FakeServer::PopulatePermanentItemSpecs() {
106 ModelTypeSet protocol_types = ProtocolTypes();
107 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good();
108 it.Inc()) {
109 ModelType model_type = it.Get();
110
111 PermanentItemSpec spec;
112 spec.tag = ModelTypeToRootTag(model_type);
113 spec.name = ModelTypeToString(model_type);
114 spec.parent_tag = kRootParentTag;
rlarocque 2013/12/18 20:22:01 It seems you're using tags as IDs? The root node'
pval...(no longer on Chromium) 2014/01/03 23:25:31 Is it only "r" on the client side? It appears tha
rlarocque 2014/01/04 00:06:24 Looks like you're right. The server refers to is
115 spec.sync_type = model_type;
116 spec.create_by_default = true;
117 permanent_item_specs_.push_back(spec);
118 }
119
120 PermanentItemSpec bookmark_bar_spec;
121 bookmark_bar_spec.tag = "bookmark_bar";
122 bookmark_bar_spec.name = "Bookmark Bar";
123 bookmark_bar_spec.parent_tag = "google_chrome_bookmarks";
124 bookmark_bar_spec.sync_type = BOOKMARKS;
125 bookmark_bar_spec.create_by_default = true;
126 permanent_item_specs_.push_back(bookmark_bar_spec);
127
128 PermanentItemSpec other_bookmarks_spec;
129 other_bookmarks_spec.tag = "other_bookmarks";
130 other_bookmarks_spec.name = "Other Bookmarks";
131 other_bookmarks_spec.parent_tag = "google_chrome_bookmarks";
132 other_bookmarks_spec.sync_type = BOOKMARKS;
133 other_bookmarks_spec.create_by_default = true;
134 permanent_item_specs_.push_back(other_bookmarks_spec);
135
rlarocque 2013/12/18 20:22:01 In certain situations, you should create the mobil
albertb 2013/12/18 20:45:30 Specifically, the situation when you need to creat
pval...(no longer on Chromium) 2014/01/03 23:25:31 Thanks; I added a TODO for this.
136 return true;
137 }
138
139 void FakeServer::CreateDefaultPermanentItems(
140 const std::vector<int>& first_time_type_ids) {
141 for (size_t i = 0; i < permanent_item_specs_.size(); i++) {
rlarocque 2013/12/18 20:22:01 Why is the creation of permanent items a two-step
pval...(no longer on Chromium) 2014/01/03 23:25:31 This was a result of following the Python server's
142 PermanentItemSpec spec = permanent_item_specs_[i];
143
144 int spec_id = GetSpecificsFieldNumberFromModelType(spec.sync_type);
145 bool first_time = std::find(first_time_type_ids.begin(),
146 first_time_type_ids.end(), spec_id) != first_time_type_ids.end();
147
148 if (first_time && spec.create_by_default) {
149 CreatePermanentItem(spec);
150 }
151 }
152 }
153
154 void FakeServer::CreatePermanentItem(const PermanentItemSpec& spec) {
155 sync_pb::SyncEntity entity;
156 entity.set_id_string(spec.tag);
157 entity.set_non_unique_name(spec.name);
158 entity.set_name(spec.name);
159 entity.set_server_defined_unique_tag(spec.tag);
160 entity.set_folder(true);
161 entity.set_deleted(false);
162
163 if (spec.parent_tag == kRootParentTag) {
164 entity.set_parent_id_string(kRootParentTag);
165 } else {
166 for (size_t i = 0; i < permanent_item_specs_.size(); i++) {
rlarocque 2013/12/18 20:22:01 nit: You should prefer to use STL iterators rather
pval...(no longer on Chromium) 2014/01/03 23:25:31 Done.
167 if (spec.parent_tag == permanent_item_specs_[i].tag) {
168 entity.set_parent_id_string(permanent_item_specs_[i].tag);
rlarocque 2013/12/18 20:22:01 This looks like it's redundant. Can't you just ca
pval...(no longer on Chromium) 2014/01/03 23:25:31 Yes. I've made this change in the new version.
169 // Use a dummy value here.
170 entity.set_position_in_parent(1337);
rlarocque 2013/12/18 20:22:01 I think this should be unset on all items that are
pval...(no longer on Chromium) 2014/01/03 23:25:31 Done.
171 }
172 }
173
174 if (entity.parent_id_string().empty()) {
175 NOTREACHED() << "The permanent item's parent node was not found.";
176 }
177 }
178
179 sync_pb::EntitySpecifics* specifics = entity.mutable_specifics();
180 AddDefaultFieldValue(spec.sync_type, specifics);
181
182 SaveEntity(entity);
183 }
184
185 void FakeServer::SaveEntity(sync_pb::SyncEntity entity) {
186 version_++;
187 entity.set_version(version_);
188 entity.set_sync_timestamp(version_);
189
190 sync_pb::SyncEntity original_entity = entities_[entity.id_string()];
191 entity.set_originator_cache_guid(original_entity.originator_cache_guid());
albertb 2013/12/18 20:45:30 The client should be setting originator_cache_guid
rlarocque 2013/12/18 21:26:49 Are you sure? I'm pretty sure we're not setting i
albertb 2013/12/18 21:47:30 Ah, I was slightly confused. Looking at the code:
pval...(no longer on Chromium) 2014/01/03 23:25:31 Thanks for the explanation. I will follow this co
albertb 2014/01/06 17:25:16 That does look correct. The server should preserve
192 entity.set_originator_client_item_id(
albertb 2013/12/18 20:45:30 Same comment about originator_client_item_id.
193 original_entity.originator_client_item_id());
194
195 entities_[entity.id_string()] = entity;
196 }
197
198 string FakeServer::HandleCommand(string request, int* error_code,
199 int* response_code) {
200 DCHECK(initialized_);
201 sync_pb::ClientToServerMessage message;
202 DCHECK(message.ParseFromString(request));
203
204 switch (message.message_contents()) {
205 case sync_pb::ClientToServerMessage::GET_UPDATES:
206 *error_code = 0;
207 *response_code = 200;
208 return HandleGetUpdatesRequest(message).SerializeAsString();
209 case sync_pb::ClientToServerMessage::COMMIT:
210 *error_code = 0;
211 *response_code = 200;
212 return HandleCommitRequest(message).SerializeAsString();
213 default:
214 *error_code = -1;
215 *response_code = 400;
216 return "";
217 }
218 }
219
220 bool SyncEntityVersionComparator(const sync_pb::SyncEntity& first,
221 const sync_pb::SyncEntity& second) {
222 return first.version() < second.version();
223 }
224
225 sync_pb::ClientToServerResponse FakeServer::HandleGetUpdatesRequest(
226 const sync_pb::ClientToServerMessage& message) {
227 sync_pb::ClientToServerResponse response;
228 response.set_error_code(sync_pb::SyncEnums::SUCCESS);
229 response.set_store_birthday(birthday_);
230
231 sync_pb::GetUpdatesResponse* get_updates_response =
232 response.mutable_get_updates();
233 get_updates_response->set_changes_remaining(0);
albertb 2013/12/18 20:45:30 Will all SyncEntities always fit in a single respo
pval...(no longer on Chromium) 2014/01/03 23:25:31 I've added a TODO for this.
234
235 UpdateSieve sieve(message.get_updates());
236 CreateDefaultPermanentItems(sieve.GetFirstTimeTypes());
237
238 int64 min_version = sieve.GetMinVersion();
239
240 // use std::transform instead?
241 std::vector<sync_pb::SyncEntity> filtered_entities;
242 for (EntityMap::iterator it = entities_.begin(); it != entities_.end();
243 ++it) {
244 sync_pb::SyncEntity entity = it->second;
245 if (entity.version() > min_version) {
246 filtered_entities.push_back(entity);
247 }
248 }
249
250 std::sort(filtered_entities.begin(), filtered_entities.end(),
251 SyncEntityVersionComparator);
252
253 bool sending_nigori = false;
254 for (size_t i = 0; i < filtered_entities.size(); i++) {
255 if (sieve.ClientWantsItem(filtered_entities[i])) {
256 sync_pb::SyncEntity* entity = get_updates_response->add_entries();
257 entity->CopyFrom(filtered_entities[i]);
258
259 if (entity->name() == "Nigori")
260 sending_nigori = true;
261 }
262 }
263
264 if (sending_nigori || message.get_updates().need_encryption_key()) {
albertb 2013/12/18 20:45:30 Note that sending_nigori does not necessarily impl
pval...(no longer on Chromium) 2014/01/03 23:25:31 Thanks, I added some logic here for this.
265 for (size_t i = 0; i < keystore_keys_.size(); i++) {
266 get_updates_response->add_encryption_keys(keystore_keys_[i]);
267 }
268 }
269
270 int new_version = filtered_entities.empty() ?
271 0 : filtered_entities.back().version();
272
273 sieve.UpdateProgressMarkers(new_version, get_updates_response);
274
275 return response;
276 }
277
278 sync_pb::SyncEntity FakeServer::CommitEntity(sync_pb::SyncEntity entity,
279 string guid) {
280 // TODO(pvalenzuela): Implement this. Right now this method cheats and
281 // doesn't actually commit.
282 return entity;
283 }
284
285 sync_pb::ClientToServerResponse FakeServer::HandleCommitRequest(
286 const sync_pb::ClientToServerMessage& message) {
287 sync_pb::ClientToServerResponse response;
288 response.set_error_code(sync_pb::SyncEnums::SUCCESS);
289 response.set_store_birthday(birthday_);
290
291 sync_pb::CommitMessage commit = message.commit();
292 string guid = commit.cache_guid();
293
294 sync_pb::CommitResponse* commit_response = response.mutable_commit();
295
296 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it;
297 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) {
298 sync_pb::CommitResponse_EntryResponse* entry_response =
299 commit_response->add_entryresponse();
300
301 sync_pb::SyncEntity server_entity = CommitEntity(*it, guid);
302
303 entry_response->set_id_string(server_entity.id_string());
304 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS);
305 entry_response->set_version(it->version() + 1);
306 }
307
308 return response;
309 }
310
311 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698