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

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

Issue 2969643002: Reland - Replace FakeServer's implementation with LoopbackServer invocations. (Closed)
Patch Set: Rebased on master. Created 3 years, 5 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/test/fake_server/fake_server.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <set> 9 #include <set>
10 #include <utility> 10 #include <utility>
11 11
12 #include "base/guid.h" 12 #include "base/guid.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
19 #include "base/synchronization/lock.h" 19 #include "base/synchronization/lock.h"
20 #include "components/sync/test/fake_server/bookmark_entity.h" 20 #include "base/threading/thread_restrictions.h"
21 #include "components/sync/test/fake_server/permanent_entity.h" 21 #include "components/sync/engine_impl/net/server_connection_manager.h"
22 #include "components/sync/test/fake_server/tombstone_entity.h"
23 #include "components/sync/test/fake_server/unique_client_entity.h"
24 #include "net/base/net_errors.h" 22 #include "net/base/net_errors.h"
25 #include "net/http/http_status_code.h" 23 #include "net/http/http_status_code.h"
26 24
27 using std::string; 25 using std::string;
28 using std::vector; 26 using std::vector;
29 using syncer::GetModelType; 27 using syncer::GetModelType;
30 using syncer::GetModelTypeFromSpecifics; 28 using syncer::GetModelTypeFromSpecifics;
29 using syncer::LoopbackServer;
30 using syncer::LoopbackServerEntity;
31 using syncer::ModelType; 31 using syncer::ModelType;
32 using syncer::ModelTypeSet; 32 using syncer::ModelTypeSet;
33 33
34 namespace fake_server { 34 namespace fake_server {
35 35
36 class FakeServerEntity;
37
38 namespace {
39
40 // The default keystore key.
41 static const char kDefaultKeystoreKey[] = "1111111111111111";
42
43 // Properties of the bookmark bar permanent folder.
44 static const char kBookmarkBarFolderServerTag[] = "bookmark_bar";
45 static const char kBookmarkBarFolderName[] = "Bookmark Bar";
46
47 // Properties of the other bookmarks permanent folder.
48 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks";
49 static const char kOtherBookmarksFolderName[] = "Other Bookmarks";
50
51 // Properties of the synced bookmarks permanent folder.
52 static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks";
53 static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks";
54
55 // A filter used during GetUpdates calls to determine what information to
56 // send back to the client; filtering out old entities and tracking versions to
57 // use in response progress markers. Note that only the GetUpdatesMessage's
58 // from_progress_marker is used to determine this; legacy fields are ignored.
59 class UpdateSieve {
60 public:
61 explicit UpdateSieve(const sync_pb::GetUpdatesMessage& message)
62 : UpdateSieve(MessageToVersionMap(message)) {}
63 ~UpdateSieve() {}
64
65 // Sets the progress markers in |get_updates_response| based on the highest
66 // version between request progress markers and response entities.
67 void SetProgressMarkers(
68 sync_pb::GetUpdatesResponse* get_updates_response) const {
69 for (const auto& kv : response_version_map_) {
70 sync_pb::DataTypeProgressMarker* new_marker =
71 get_updates_response->add_new_progress_marker();
72 new_marker->set_data_type_id(
73 GetSpecificsFieldNumberFromModelType(kv.first));
74 new_marker->set_token(base::Int64ToString(kv.second));
75 }
76 }
77
78 // Determines whether the server should send an |entity| to the client as
79 // part of a GetUpdatesResponse. Update internal tracking of max versions as a
80 // side effect which will later be used to set response progress markers.
81 bool ClientWantsItem(const FakeServerEntity& entity) {
82 int64_t version = entity.GetVersion();
83 ModelType type = entity.model_type();
84 response_version_map_[type] =
85 std::max(response_version_map_[type], version);
86 auto it = request_version_map_.find(type);
87 return it == request_version_map_.end() ? false : it->second < version;
88 }
89
90 private:
91 using ModelTypeToVersionMap = std::map<ModelType, int64_t>;
92
93 static UpdateSieve::ModelTypeToVersionMap MessageToVersionMap(
94 const sync_pb::GetUpdatesMessage& get_updates_message) {
95 CHECK_GT(get_updates_message.from_progress_marker_size(), 0)
96 << "A GetUpdates request must have at least one progress marker.";
97 ModelTypeToVersionMap request_version_map;
98
99 for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) {
100 sync_pb::DataTypeProgressMarker marker =
101 get_updates_message.from_progress_marker(i);
102
103 int64_t version = 0;
104 // Let the version remain zero if there is no token or an empty token (the
105 // first request for this type).
106 if (marker.has_token() && !marker.token().empty()) {
107 bool parsed = base::StringToInt64(marker.token(), &version);
108 CHECK(parsed) << "Unable to parse progress marker token.";
109 }
110
111 ModelType model_type =
112 syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id());
113 DCHECK(request_version_map.find(model_type) == request_version_map.end());
114 request_version_map[model_type] = version;
115 }
116 return request_version_map;
117 }
118
119 explicit UpdateSieve(const ModelTypeToVersionMap request_version_map)
120 : request_version_map_(request_version_map),
121 response_version_map_(request_version_map) {}
122
123 // The largest versions the client has seen before this request, and is used
124 // to filter entities to send back to clients. The values in this map are not
125 // updated after being initially set. The presence of a type in this map is a
126 // proxy for the desire to receive results about this type.
127 const ModelTypeToVersionMap request_version_map_;
128
129 // The largest versions seen between client and server, ultimately used to
130 // send progress markers back to the client.
131 ModelTypeToVersionMap response_version_map_;
132 };
133
134 // Returns whether |entity| is deleted or permanent.
135 bool IsDeletedOrPermanent(const FakeServerEntity& entity) {
136 return entity.IsDeleted() || entity.IsPermanent();
137 }
138
139 } // namespace
140
141 FakeServer::FakeServer() 36 FakeServer::FakeServer()
142 : version_(0), 37 : authenticated_(true),
143 store_birthday_(0),
144 authenticated_(true),
145 error_type_(sync_pb::SyncEnums::SUCCESS), 38 error_type_(sync_pb::SyncEnums::SUCCESS),
146 alternate_triggered_errors_(false), 39 alternate_triggered_errors_(false),
147 request_counter_(0), 40 request_counter_(0),
148 network_enabled_(true), 41 network_enabled_(true),
149 weak_ptr_factory_(this) { 42 weak_ptr_factory_(this) {
150 Init(); 43 base::ThreadRestrictions::SetIOAllowed(true);
44 loopback_server_storage_ = base::MakeUnique<base::ScopedTempDir>();
45 if (!loopback_server_storage_->CreateUniqueTempDir()) {
46 NOTREACHED() << "Creating temp dir failed.";
47 }
48 loopback_server_ = base::MakeUnique<syncer::LoopbackServer>(
49 loopback_server_storage_->GetPath().AppendASCII("profile.pb"));
50 loopback_server_->set_observer_for_tests(this);
151 } 51 }
152 52
153 FakeServer::~FakeServer() {} 53 FakeServer::~FakeServer() {}
154 54
155 void FakeServer::Init() {
156 keystore_keys_.push_back(kDefaultKeystoreKey);
157
158 const bool create_result = CreateDefaultPermanentItems();
159 DCHECK(create_result) << "Permanent items were not created successfully.";
160 }
161
162 bool FakeServer::CreatePermanentBookmarkFolder(const std::string& server_tag,
163 const std::string& name) {
164 DCHECK(thread_checker_.CalledOnValidThread());
165 std::unique_ptr<FakeServerEntity> entity =
166 PermanentEntity::Create(syncer::BOOKMARKS, server_tag, name,
167 ModelTypeToRootTag(syncer::BOOKMARKS));
168 if (!entity)
169 return false;
170
171 SaveEntity(std::move(entity));
172 return true;
173 }
174
175 bool FakeServer::CreateDefaultPermanentItems() {
176 // Permanent folders are always required for Bookmarks (hierarchical
177 // structure) and Nigori (data stored in permanent root folder).
178 ModelTypeSet permanent_folder_types =
179 ModelTypeSet(syncer::BOOKMARKS, syncer::NIGORI);
180
181 for (ModelTypeSet::Iterator it = permanent_folder_types.First(); it.Good();
182 it.Inc()) {
183 ModelType model_type = it.Get();
184
185 std::unique_ptr<FakeServerEntity> top_level_entity =
186 PermanentEntity::CreateTopLevel(model_type);
187 if (!top_level_entity) {
188 return false;
189 }
190 SaveEntity(std::move(top_level_entity));
191
192 if (model_type == syncer::BOOKMARKS) {
193 if (!CreatePermanentBookmarkFolder(kBookmarkBarFolderServerTag,
194 kBookmarkBarFolderName))
195 return false;
196 if (!CreatePermanentBookmarkFolder(kOtherBookmarksFolderServerTag,
197 kOtherBookmarksFolderName))
198 return false;
199 }
200 }
201
202 return true;
203 }
204
205 void FakeServer::UpdateEntityVersion(FakeServerEntity* entity) {
206 entity->SetVersion(++version_);
207 }
208
209 void FakeServer::SaveEntity(std::unique_ptr<FakeServerEntity> entity) {
210 UpdateEntityVersion(entity.get());
211 entities_[entity->id()] = std::move(entity);
212 }
213
214 void FakeServer::HandleCommand(const string& request, 55 void FakeServer::HandleCommand(const string& request,
215 const base::Closure& completion_closure, 56 const base::Closure& completion_closure,
216 int* error_code, 57 int* error_code,
217 int* response_code, 58 int* response_code,
218 std::string* response) { 59 std::string* response) {
219 DCHECK(thread_checker_.CalledOnValidThread()); 60 DCHECK(thread_checker_.CalledOnValidThread());
61
220 if (!network_enabled_) { 62 if (!network_enabled_) {
221 *error_code = net::ERR_FAILED; 63 *error_code = net::ERR_FAILED;
222 *response_code = net::ERR_FAILED; 64 *response_code = net::ERR_FAILED;
223 *response = string(); 65 *response = string();
224 completion_closure.Run(); 66 completion_closure.Run();
225 return; 67 return;
226 } 68 }
227 request_counter_++; 69 request_counter_++;
228 70
229 if (!authenticated_) { 71 if (!authenticated_) {
230 *error_code = 0; 72 *error_code = 0;
231 *response_code = net::HTTP_UNAUTHORIZED; 73 *response_code = net::HTTP_UNAUTHORIZED;
232 *response = string(); 74 *response = string();
233 completion_closure.Run(); 75 completion_closure.Run();
234 return; 76 return;
235 } 77 }
236 78
237 sync_pb::ClientToServerMessage message;
238 bool parsed = message.ParseFromString(request);
239 CHECK(parsed) << "Unable to parse the ClientToServerMessage.";
240
241 sync_pb::ClientToServerResponse response_proto; 79 sync_pb::ClientToServerResponse response_proto;
242 80 *response_code = 200;
243 if (message.has_store_birthday() && 81 *error_code = 0;
244 message.store_birthday() != GetStoreBirthday()) { 82 if (error_type_ != sync_pb::SyncEnums::SUCCESS &&
245 response_proto.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY); 83 ShouldSendTriggeredError()) {
246 } else if (error_type_ != sync_pb::SyncEnums::SUCCESS &&
247 ShouldSendTriggeredError()) {
248 response_proto.set_error_code(error_type_); 84 response_proto.set_error_code(error_type_);
249 } else if (triggered_actionable_error_.get() && ShouldSendTriggeredError()) { 85 } else if (triggered_actionable_error_.get() && ShouldSendTriggeredError()) {
250 sync_pb::ClientToServerResponse_Error* error = 86 sync_pb::ClientToServerResponse_Error* error =
251 response_proto.mutable_error(); 87 response_proto.mutable_error();
252 error->CopyFrom(*(triggered_actionable_error_.get())); 88 error->CopyFrom(*(triggered_actionable_error_.get()));
253 } else { 89 } else {
254 bool success = false; 90 sync_pb::ClientToServerMessage message;
91 bool parsed = message.ParseFromString(request);
92 CHECK(parsed) << "Unable to parse the ClientToServerMessage.";
255 switch (message.message_contents()) { 93 switch (message.message_contents()) {
256 case sync_pb::ClientToServerMessage::GET_UPDATES: 94 case sync_pb::ClientToServerMessage::GET_UPDATES:
257 last_getupdates_message_ = message; 95 last_getupdates_message_ = message;
258 success = HandleGetUpdatesRequest(message.get_updates(),
259 response_proto.mutable_get_updates());
260 break; 96 break;
261 case sync_pb::ClientToServerMessage::COMMIT: 97 case sync_pb::ClientToServerMessage::COMMIT:
262 last_commit_message_ = message; 98 last_commit_message_ = message;
263 success = HandleCommitRequest(message.commit(),
264 message.invalidator_client_id(),
265 response_proto.mutable_commit());
266 break;
267 case sync_pb::ClientToServerMessage::CLEAR_SERVER_DATA:
268 ClearServerData();
269 response_proto.mutable_clear_server_data();
270 success = true;
271 break; 99 break;
272 default: 100 default:
273 *error_code = net::ERR_NOT_IMPLEMENTED; 101 break;
274 *response_code = 0; 102 // Don't care.
275 *response = string();
276 completion_closure.Run();
277 return;
278 } 103 }
279 104
280 if (!success) { 105 int64_t response_code_large;
281 // TODO(pvalenzuela): Add logging here so that tests have more info about 106 syncer::HttpResponse::ServerConnectionCode server_status;
282 // the failure. 107 base::ThreadRestrictions::SetIOAllowed(true);
283 *error_code = net::ERR_FAILED; 108 loopback_server_->HandleCommand(request, &server_status,
284 *response_code = 0; 109 &response_code_large, response);
285 *response = string(); 110 *response_code = static_cast<int>(response_code_large);
286 completion_closure.Run(); 111 completion_closure.Run();
287 return; 112 return;
288 }
289
290 response_proto.set_error_code(sync_pb::SyncEnums::SUCCESS);
291 } 113 }
292 114
293 response_proto.set_store_birthday(GetStoreBirthday()); 115 response_proto.set_store_birthday(loopback_server_->GetStoreBirthday());
294
295 *error_code = 0;
296 *response_code = net::HTTP_OK;
297 *response = response_proto.SerializeAsString(); 116 *response = response_proto.SerializeAsString();
298 completion_closure.Run(); 117 completion_closure.Run();
299 } 118 }
300 119
301 bool FakeServer::GetLastCommitMessage(sync_pb::ClientToServerMessage* message) { 120 bool FakeServer::GetLastCommitMessage(sync_pb::ClientToServerMessage* message) {
302 if (!last_commit_message_.has_commit()) 121 if (!last_commit_message_.has_commit())
303 return false; 122 return false;
304 123
305 message->CopyFrom(last_commit_message_); 124 message->CopyFrom(last_commit_message_);
306 return true; 125 return true;
307 } 126 }
308 127
309 bool FakeServer::GetLastGetUpdatesMessage( 128 bool FakeServer::GetLastGetUpdatesMessage(
310 sync_pb::ClientToServerMessage* message) { 129 sync_pb::ClientToServerMessage* message) {
311 if (!last_getupdates_message_.has_get_updates()) 130 if (!last_getupdates_message_.has_get_updates())
312 return false; 131 return false;
313 132
314 message->CopyFrom(last_getupdates_message_); 133 message->CopyFrom(last_getupdates_message_);
315 return true; 134 return true;
316 } 135 }
317 136
318 bool FakeServer::HandleGetUpdatesRequest(
319 const sync_pb::GetUpdatesMessage& get_updates,
320 sync_pb::GetUpdatesResponse* response) {
321 // TODO(pvalenzuela): Implement batching instead of sending all information
322 // at once.
323 response->set_changes_remaining(0);
324
325 auto sieve = base::MakeUnique<UpdateSieve>(get_updates);
326
327 // This folder is called "Synced Bookmarks" by sync and is renamed
328 // "Mobile Bookmarks" by the mobile client UIs.
329 if (get_updates.create_mobile_bookmarks_folder() &&
330 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag,
331 kSyncedBookmarksFolderName)) {
332 return false;
333 }
334
335 bool send_encryption_keys_based_on_nigori = false;
336 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
337 ++it) {
338 const FakeServerEntity& entity = *it->second;
339 if (sieve->ClientWantsItem(entity)) {
340 sync_pb::SyncEntity* response_entity = response->add_entries();
341 entity.SerializeAsProto(response_entity);
342
343 if (entity.model_type() == syncer::NIGORI) {
344 send_encryption_keys_based_on_nigori =
345 response_entity->specifics().nigori().passphrase_type() ==
346 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE;
347 }
348 }
349 }
350
351 if (send_encryption_keys_based_on_nigori ||
352 get_updates.need_encryption_key()) {
353 for (vector<string>::iterator it = keystore_keys_.begin();
354 it != keystore_keys_.end(); ++it) {
355 response->add_encryption_keys(*it);
356 }
357 }
358
359 sieve->SetProgressMarkers(response);
360 return true;
361 }
362
363 string FakeServer::CommitEntity(
364 const sync_pb::SyncEntity& client_entity,
365 sync_pb::CommitResponse_EntryResponse* entry_response,
366 const string& client_guid,
367 const string& parent_id) {
368 if (client_entity.version() == 0 && client_entity.deleted()) {
369 return string();
370 }
371
372 std::unique_ptr<FakeServerEntity> entity;
373 syncer::ModelType type = GetModelType(client_entity);
374 if (client_entity.deleted()) {
375 entity = TombstoneEntity::Create(client_entity.id_string(),
376 client_entity.client_defined_unique_tag());
377 DeleteChildren(client_entity.id_string());
378 } else if (type == syncer::NIGORI) {
379 // NIGORI is the only permanent item type that should be updated by the
380 // client.
381 EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
382 CHECK(iter != entities_.end());
383 entity = PermanentEntity::CreateUpdatedNigoriEntity(client_entity,
384 *iter->second);
385 } else if (type == syncer::BOOKMARKS) {
386 // TODO(pvalenzuela): Validate entity's parent ID.
387 EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
388 if (iter != entities_.end()) {
389 entity = BookmarkEntity::CreateUpdatedVersion(client_entity,
390 *iter->second, parent_id);
391 } else {
392 entity = BookmarkEntity::CreateNew(client_entity, parent_id, client_guid);
393 }
394 } else {
395 entity = UniqueClientEntity::Create(client_entity);
396 }
397
398 const std::string id = entity->id();
399 SaveEntity(std::move(entity));
400 BuildEntryResponseForSuccessfulCommit(id, entry_response);
401 return id;
402 }
403
404 void FakeServer::OverrideResponseType( 137 void FakeServer::OverrideResponseType(
405 ResponseTypeProvider response_type_override) { 138 LoopbackServer::ResponseTypeProvider response_type_override) {
406 response_type_override_ = std::move(response_type_override); 139 loopback_server_->OverrideResponseType(std::move(response_type_override));
407 }
408
409 void FakeServer::BuildEntryResponseForSuccessfulCommit(
410 const std::string& entity_id,
411 sync_pb::CommitResponse_EntryResponse* entry_response) {
412 EntityMap::const_iterator iter = entities_.find(entity_id);
413 CHECK(iter != entities_.end());
414 const FakeServerEntity& entity = *iter->second;
415 entry_response->set_response_type(response_type_override_
416 ? response_type_override_.Run(entity)
417 : sync_pb::CommitResponse::SUCCESS);
418 entry_response->set_id_string(entity.id());
419
420 if (entity.IsDeleted()) {
421 entry_response->set_version(entity.GetVersion() + 1);
422 } else {
423 entry_response->set_version(entity.GetVersion());
424 entry_response->set_name(entity.GetName());
425 }
426 }
427
428 bool FakeServer::IsChild(const string& id, const string& potential_parent_id) {
429 EntityMap::const_iterator iter = entities_.find(id);
430 if (iter == entities_.end()) {
431 // We've hit an ID (probably the imaginary root entity) that isn't stored
432 // by the server, so it can't be a child.
433 return false;
434 }
435
436 const FakeServerEntity& entity = *iter->second;
437 if (entity.GetParentId() == potential_parent_id)
438 return true;
439
440 // Recursively look up the tree.
441 return IsChild(entity.GetParentId(), potential_parent_id);
442 }
443
444 void FakeServer::DeleteChildren(const string& id) {
445 std::vector<std::unique_ptr<FakeServerEntity>> tombstones;
446 // Find all the children of id.
447 for (const auto& entity : entities_) {
448 if (IsChild(entity.first, id)) {
449 tombstones.push_back(TombstoneEntity::Create(
450 entity.first, entity.second->client_defined_unique_tag()));
451 }
452 }
453
454 for (auto& tombstone : tombstones) {
455 SaveEntity(std::move(tombstone));
456 }
457 }
458
459 bool FakeServer::HandleCommitRequest(const sync_pb::CommitMessage& commit,
460 const std::string& invalidator_client_id,
461 sync_pb::CommitResponse* response) {
462 std::map<string, string> client_to_server_ids;
463 string guid = commit.cache_guid();
464 ModelTypeSet committed_model_types;
465
466 // TODO(pvalenzuela): Add validation of CommitMessage.entries.
467 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it;
468 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) {
469 sync_pb::CommitResponse_EntryResponse* entry_response =
470 response->add_entryresponse();
471
472 sync_pb::SyncEntity client_entity = *it;
473 string parent_id = client_entity.parent_id_string();
474 if (client_to_server_ids.find(parent_id) != client_to_server_ids.end()) {
475 parent_id = client_to_server_ids[parent_id];
476 }
477
478 const string entity_id =
479 CommitEntity(client_entity, entry_response, guid, parent_id);
480 if (entity_id.empty()) {
481 return false;
482 }
483
484 // Record the ID if it was renamed.
485 if (entity_id != client_entity.id_string()) {
486 client_to_server_ids[client_entity.id_string()] = entity_id;
487 }
488
489 EntityMap::const_iterator iter = entities_.find(entity_id);
490 CHECK(iter != entities_.end());
491 committed_model_types.Put(iter->second->model_type());
492 }
493
494 for (auto& observer : observers_)
495 observer.OnCommit(invalidator_client_id, committed_model_types);
496
497 return true;
498 } 140 }
499 141
500 std::unique_ptr<base::DictionaryValue> 142 std::unique_ptr<base::DictionaryValue>
501 FakeServer::GetEntitiesAsDictionaryValue() { 143 FakeServer::GetEntitiesAsDictionaryValue() {
502 DCHECK(thread_checker_.CalledOnValidThread()); 144 DCHECK(thread_checker_.CalledOnValidThread());
503 std::unique_ptr<base::DictionaryValue> dictionary( 145 return loopback_server_->GetEntitiesAsDictionaryValue();
504 new base::DictionaryValue());
505
506 // Initialize an empty ListValue for all ModelTypes.
507 ModelTypeSet all_types = ModelTypeSet::All();
508 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
509 dictionary->Set(ModelTypeToString(it.Get()),
510 base::MakeUnique<base::ListValue>());
511 }
512
513 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
514 ++it) {
515 const FakeServerEntity& entity = *it->second;
516 if (IsDeletedOrPermanent(entity)) {
517 // Tombstones are ignored as they don't represent current data. Folders
518 // are also ignored as current verification infrastructure does not
519 // consider them.
520 continue;
521 }
522 base::ListValue* list_value;
523 if (!dictionary->GetList(ModelTypeToString(entity.model_type()),
524 &list_value)) {
525 return std::unique_ptr<base::DictionaryValue>();
526 }
527 // TODO(pvalenzuela): Store more data for each entity so additional
528 // verification can be performed. One example of additional verification
529 // is checking the correctness of the bookmark hierarchy.
530 list_value->AppendString(entity.GetName());
531 }
532
533 return dictionary;
534 } 146 }
535 147
536 std::vector<sync_pb::SyncEntity> FakeServer::GetSyncEntitiesByModelType( 148 std::vector<sync_pb::SyncEntity> FakeServer::GetSyncEntitiesByModelType(
537 ModelType model_type) { 149 ModelType model_type) {
538 std::vector<sync_pb::SyncEntity> sync_entities;
539 DCHECK(thread_checker_.CalledOnValidThread()); 150 DCHECK(thread_checker_.CalledOnValidThread());
540 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); 151 return loopback_server_->GetSyncEntitiesByModelType(model_type);
541 ++it) {
542 const FakeServerEntity& entity = *it->second;
543 if (!IsDeletedOrPermanent(entity) && entity.model_type() == model_type) {
544 sync_pb::SyncEntity sync_entity;
545 entity.SerializeAsProto(&sync_entity);
546 sync_entities.push_back(sync_entity);
547 }
548 }
549 return sync_entities;
550 } 152 }
551 153
552 void FakeServer::InjectEntity(std::unique_ptr<FakeServerEntity> entity) { 154 void FakeServer::InjectEntity(std::unique_ptr<LoopbackServerEntity> entity) {
553 DCHECK(thread_checker_.CalledOnValidThread()); 155 DCHECK(thread_checker_.CalledOnValidThread());
554 SaveEntity(std::move(entity)); 156 loopback_server_->SaveEntity(std::move(entity));
555 } 157 }
556 158
557 bool FakeServer::ModifyEntitySpecifics( 159 bool FakeServer::ModifyEntitySpecifics(
558 const std::string& id, 160 const std::string& id,
559 const sync_pb::EntitySpecifics& updated_specifics) { 161 const sync_pb::EntitySpecifics& updated_specifics) {
560 EntityMap::const_iterator iter = entities_.find(id); 162 return loopback_server_->ModifyEntitySpecifics(id, updated_specifics);
561 if (iter == entities_.end() ||
562 iter->second->model_type() !=
563 GetModelTypeFromSpecifics(updated_specifics)) {
564 return false;
565 }
566
567 FakeServerEntity* entity = iter->second.get();
568 entity->SetSpecifics(updated_specifics);
569 UpdateEntityVersion(entity);
570 return true;
571 } 163 }
572 164
573 bool FakeServer::ModifyBookmarkEntity( 165 bool FakeServer::ModifyBookmarkEntity(
574 const std::string& id, 166 const std::string& id,
575 const std::string& parent_id, 167 const std::string& parent_id,
576 const sync_pb::EntitySpecifics& updated_specifics) { 168 const sync_pb::EntitySpecifics& updated_specifics) {
577 EntityMap::const_iterator iter = entities_.find(id); 169 return loopback_server_->ModifyBookmarkEntity(id, parent_id,
578 if (iter == entities_.end() || 170 updated_specifics);
579 iter->second->model_type() != syncer::BOOKMARKS ||
580 GetModelTypeFromSpecifics(updated_specifics) != syncer::BOOKMARKS) {
581 return false;
582 }
583
584 BookmarkEntity* entity = static_cast<BookmarkEntity*>(iter->second.get());
585
586 entity->SetParentId(parent_id);
587 entity->SetSpecifics(updated_specifics);
588 if (updated_specifics.has_bookmark()) {
589 entity->SetName(updated_specifics.bookmark().title());
590 }
591 UpdateEntityVersion(entity);
592 return true;
593 } 171 }
594 172
595 void FakeServer::ClearServerData() { 173 void FakeServer::ClearServerData() {
596 DCHECK(thread_checker_.CalledOnValidThread()); 174 DCHECK(thread_checker_.CalledOnValidThread());
597 entities_.clear(); 175 loopback_server_->ClearServerData();
598 keystore_keys_.clear();
599 ++store_birthday_;
600 Init();
601 } 176 }
602 177
603 void FakeServer::SetAuthenticated() { 178 void FakeServer::SetAuthenticated() {
604 DCHECK(thread_checker_.CalledOnValidThread()); 179 DCHECK(thread_checker_.CalledOnValidThread());
605 authenticated_ = true; 180 authenticated_ = true;
606 } 181 }
607 182
608 void FakeServer::SetUnauthenticated() { 183 void FakeServer::SetUnauthenticated() {
609 DCHECK(thread_checker_.CalledOnValidThread()); 184 DCHECK(thread_checker_.CalledOnValidThread());
610 authenticated_ = false; 185 authenticated_ = false;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 void FakeServer::AddObserver(Observer* observer) { 243 void FakeServer::AddObserver(Observer* observer) {
669 DCHECK(thread_checker_.CalledOnValidThread()); 244 DCHECK(thread_checker_.CalledOnValidThread());
670 observers_.AddObserver(observer); 245 observers_.AddObserver(observer);
671 } 246 }
672 247
673 void FakeServer::RemoveObserver(Observer* observer) { 248 void FakeServer::RemoveObserver(Observer* observer) {
674 DCHECK(thread_checker_.CalledOnValidThread()); 249 DCHECK(thread_checker_.CalledOnValidThread());
675 observers_.RemoveObserver(observer); 250 observers_.RemoveObserver(observer);
676 } 251 }
677 252
253 void FakeServer::OnCommit(const std::string& committer_id,
254 syncer::ModelTypeSet committed_model_types) {
255 for (auto& observer : observers_)
256 observer.OnCommit(committer_id, committed_model_types);
257 }
258
678 void FakeServer::EnableNetwork() { 259 void FakeServer::EnableNetwork() {
679 DCHECK(thread_checker_.CalledOnValidThread()); 260 DCHECK(thread_checker_.CalledOnValidThread());
680 network_enabled_ = true; 261 network_enabled_ = true;
681 } 262 }
682 263
683 void FakeServer::DisableNetwork() { 264 void FakeServer::DisableNetwork() {
684 DCHECK(thread_checker_.CalledOnValidThread()); 265 DCHECK(thread_checker_.CalledOnValidThread());
685 network_enabled_ = false; 266 network_enabled_ = false;
686 } 267 }
687 268
688 std::string FakeServer::GetBookmarkBarFolderId() const {
689 DCHECK(thread_checker_.CalledOnValidThread());
690 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
691 ++it) {
692 FakeServerEntity* entity = it->second.get();
693 if (entity->GetName() == kBookmarkBarFolderName && entity->IsFolder() &&
694 entity->model_type() == syncer::BOOKMARKS) {
695 return entity->id();
696 }
697 }
698 NOTREACHED() << "Bookmark Bar entity not found.";
699 return "";
700 }
701
702 base::WeakPtr<FakeServer> FakeServer::AsWeakPtr() { 269 base::WeakPtr<FakeServer> FakeServer::AsWeakPtr() {
703 DCHECK(thread_checker_.CalledOnValidThread()); 270 DCHECK(thread_checker_.CalledOnValidThread());
704 return weak_ptr_factory_.GetWeakPtr(); 271 return weak_ptr_factory_.GetWeakPtr();
705 } 272 }
706 273
707 std::string FakeServer::GetStoreBirthday() const {
708 DCHECK(thread_checker_.CalledOnValidThread());
709 return base::Int64ToString(store_birthday_);
710 }
711
712 } // namespace fake_server 274 } // namespace fake_server
OLDNEW
« no previous file with comments | « components/sync/test/fake_server/fake_server.h ('k') | components/sync/test/fake_server/fake_server_entity.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698