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

Side by Side Diff: components/sync/engine_impl/net/loopback_server/loopback_server.cc

Issue 2106743002: WIP: Local sync only... (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix after rebase. Created 4 years, 2 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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698