Update V8 to version 4.7.56.
[chromium-blink-merge.git] / sync / test / fake_server / fake_server.cc
blob9a464578c3ca33d15bab81c8c819fd5aa89e775b
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sync/test/fake_server/fake_server.h"
7 #include <algorithm>
8 #include <limits>
9 #include <string>
10 #include <vector>
12 #include "base/basictypes.h"
13 #include "base/guid.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/synchronization/lock.h"
21 #include "net/base/net_errors.h"
22 #include "net/http/http_status_code.h"
23 #include "sync/internal_api/public/base/model_type.h"
24 #include "sync/protocol/sync.pb.h"
25 #include "sync/test/fake_server/bookmark_entity.h"
26 #include "sync/test/fake_server/permanent_entity.h"
27 #include "sync/test/fake_server/tombstone_entity.h"
28 #include "sync/test/fake_server/unique_client_entity.h"
30 using std::string;
31 using std::vector;
33 using syncer::GetModelType;
34 using syncer::GetModelTypeFromSpecifics;
35 using syncer::ModelType;
36 using syncer::ModelTypeSet;
38 namespace fake_server {
40 class FakeServerEntity;
42 namespace {
44 // The default keystore key.
45 static const char kDefaultKeystoreKey[] = "1111111111111111";
47 // Properties of the bookmark bar permanent folder.
48 static const char kBookmarkBarFolderServerTag[] = "bookmark_bar";
49 static const char kBookmarkBarFolderName[] = "Bookmark Bar";
51 // Properties of the other bookmarks permanent folder.
52 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks";
53 static const char kOtherBookmarksFolderName[] = "Other Bookmarks";
55 // Properties of the synced bookmarks permanent folder.
56 static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks";
57 static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks";
59 // A filter used during GetUpdates calls to determine what information to
60 // send back to the client. There is a 1:1 correspondence between any given
61 // GetUpdates call and an UpdateSieve instance.
62 class UpdateSieve {
63 public:
64 ~UpdateSieve() { }
66 // Factory method for creating an UpdateSieve.
67 static scoped_ptr<UpdateSieve> Create(
68 const sync_pb::GetUpdatesMessage& get_updates_message);
70 // Sets the progress markers in |get_updates_response| given the progress
71 // markers from the original GetUpdatesMessage and |new_version| (the latest
72 // version in the entries sent back).
73 void UpdateProgressMarkers(
74 int64 new_version,
75 sync_pb::GetUpdatesResponse* get_updates_response) const {
76 ModelTypeToVersionMap::const_iterator it;
77 for (it = request_from_version_.begin(); it != request_from_version_.end();
78 ++it) {
79 sync_pb::DataTypeProgressMarker* new_marker =
80 get_updates_response->add_new_progress_marker();
81 new_marker->set_data_type_id(
82 GetSpecificsFieldNumberFromModelType(it->first));
84 int64 version = std::max(new_version, it->second);
85 new_marker->set_token(base::Int64ToString(version));
89 // Determines whether the server should send an |entity| to the client as
90 // part of a GetUpdatesResponse.
91 bool ClientWantsItem(const FakeServerEntity& entity) const {
92 int64 version = entity.GetVersion();
93 if (version <= min_version_) {
94 return false;
95 } else if (entity.IsDeleted()) {
96 return true;
99 ModelTypeToVersionMap::const_iterator it =
100 request_from_version_.find(entity.GetModelType());
102 return it == request_from_version_.end() ? false : it->second < version;
105 // Returns the minimum version seen across all types.
106 int64 GetMinVersion() const {
107 return min_version_;
110 private:
111 typedef std::map<ModelType, int64> ModelTypeToVersionMap;
113 // Creates an UpdateSieve.
114 UpdateSieve(const ModelTypeToVersionMap request_from_version,
115 const int64 min_version)
116 : request_from_version_(request_from_version),
117 min_version_(min_version) { }
119 // Maps data type IDs to the latest version seen for that type.
120 const ModelTypeToVersionMap request_from_version_;
122 // The minimum version seen among all data types.
123 const int min_version_;
126 scoped_ptr<UpdateSieve> UpdateSieve::Create(
127 const sync_pb::GetUpdatesMessage& get_updates_message) {
128 CHECK_GT(get_updates_message.from_progress_marker_size(), 0)
129 << "A GetUpdates request must have at least one progress marker.";
131 UpdateSieve::ModelTypeToVersionMap request_from_version;
132 int64 min_version = std::numeric_limits<int64>::max();
133 for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) {
134 sync_pb::DataTypeProgressMarker marker =
135 get_updates_message.from_progress_marker(i);
137 int64 version = 0;
138 // Let the version remain zero if there is no token or an empty token (the
139 // first request for this type).
140 if (marker.has_token() && !marker.token().empty()) {
141 bool parsed = base::StringToInt64(marker.token(), &version);
142 CHECK(parsed) << "Unable to parse progress marker token.";
145 ModelType model_type = syncer::GetModelTypeFromSpecificsFieldNumber(
146 marker.data_type_id());
147 request_from_version[model_type] = version;
149 if (version < min_version)
150 min_version = version;
153 return scoped_ptr<UpdateSieve>(
154 new UpdateSieve(request_from_version, min_version));
157 // Returns whether |entity| is deleted or permanent.
158 bool IsDeletedOrPermanent(const FakeServerEntity& entity) {
159 return entity.IsDeleted() || entity.IsPermanent();
162 } // namespace
164 FakeServer::FakeServer() : version_(0),
165 store_birthday_(0),
166 authenticated_(true),
167 error_type_(sync_pb::SyncEnums::SUCCESS),
168 alternate_triggered_errors_(false),
169 request_counter_(0),
170 network_enabled_(true),
171 weak_ptr_factory_(this) {
172 keystore_keys_.push_back(kDefaultKeystoreKey);
174 const bool create_result = CreateDefaultPermanentItems();
175 DCHECK(create_result) << "Permanent items were not created successfully.";
178 FakeServer::~FakeServer() {}
180 bool FakeServer::CreatePermanentBookmarkFolder(const std::string& server_tag,
181 const std::string& name) {
182 DCHECK(thread_checker_.CalledOnValidThread());
183 scoped_ptr<FakeServerEntity> entity =
184 PermanentEntity::Create(syncer::BOOKMARKS, server_tag, name,
185 ModelTypeToRootTag(syncer::BOOKMARKS));
186 if (!entity)
187 return false;
189 SaveEntity(entity.Pass());
190 return true;
193 bool FakeServer::CreateDefaultPermanentItems() {
194 ModelTypeSet all_types = syncer::ProtocolTypes();
195 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
196 ModelType model_type = it.Get();
197 scoped_ptr<FakeServerEntity> top_level_entity =
198 PermanentEntity::CreateTopLevel(model_type);
199 if (!top_level_entity) {
200 return false;
202 SaveEntity(top_level_entity.Pass());
204 if (model_type == syncer::BOOKMARKS) {
205 if (!CreatePermanentBookmarkFolder(kBookmarkBarFolderServerTag,
206 kBookmarkBarFolderName))
207 return false;
208 if (!CreatePermanentBookmarkFolder(kOtherBookmarksFolderServerTag,
209 kOtherBookmarksFolderName))
210 return false;
214 return true;
217 void FakeServer::UpdateEntityVersion(FakeServerEntity* entity) {
218 entity->SetVersion(++version_);
221 void FakeServer::SaveEntity(scoped_ptr<FakeServerEntity> entity) {
222 UpdateEntityVersion(entity.get());
223 const string id = entity->GetId();
224 entities_.set(id, entity.Pass());
227 void FakeServer::HandleCommand(const string& request,
228 const base::Closure& completion_closure,
229 int* error_code,
230 int* response_code,
231 std::string* response) {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 if (!network_enabled_) {
234 *error_code = net::ERR_FAILED;
235 *response_code = net::ERR_FAILED;
236 *response = string();
237 completion_closure.Run();
238 return;
240 request_counter_++;
242 if (!authenticated_) {
243 *error_code = 0;
244 *response_code = net::HTTP_UNAUTHORIZED;
245 *response = string();
246 completion_closure.Run();
247 return;
250 sync_pb::ClientToServerMessage message;
251 bool parsed = message.ParseFromString(request);
252 CHECK(parsed) << "Unable to parse the ClientToServerMessage.";
254 sync_pb::ClientToServerResponse response_proto;
256 if (message.has_store_birthday() &&
257 message.store_birthday() != GetStoreBirthday()) {
258 response_proto.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY);
259 } else if (error_type_ != sync_pb::SyncEnums::SUCCESS &&
260 ShouldSendTriggeredError()) {
261 response_proto.set_error_code(error_type_);
262 } else if (triggered_actionable_error_.get() && ShouldSendTriggeredError()) {
263 sync_pb::ClientToServerResponse_Error* error =
264 response_proto.mutable_error();
265 error->CopyFrom(*(triggered_actionable_error_.get()));
266 } else {
267 bool success = false;
268 switch (message.message_contents()) {
269 case sync_pb::ClientToServerMessage::GET_UPDATES:
270 success = HandleGetUpdatesRequest(message.get_updates(),
271 response_proto.mutable_get_updates());
272 break;
273 case sync_pb::ClientToServerMessage::COMMIT:
274 success = HandleCommitRequest(message.commit(),
275 message.invalidator_client_id(),
276 response_proto.mutable_commit());
277 break;
278 case sync_pb::ClientToServerMessage::CLEAR_SERVER_DATA:
279 ClearServerData();
280 response_proto.mutable_clear_server_data();
281 success = true;
282 break;
283 default:
284 *error_code = net::ERR_NOT_IMPLEMENTED;
285 *response_code = 0;
286 *response = string();
287 completion_closure.Run();
288 return;
291 if (!success) {
292 // TODO(pvalenzuela): Add logging here so that tests have more info about
293 // the failure.
294 *error_code = net::ERR_FAILED;
295 *response_code = 0;
296 *response = string();
297 completion_closure.Run();
298 return;
301 response_proto.set_error_code(sync_pb::SyncEnums::SUCCESS);
304 response_proto.set_store_birthday(GetStoreBirthday());
306 *error_code = 0;
307 *response_code = net::HTTP_OK;
308 *response = response_proto.SerializeAsString();
309 completion_closure.Run();
312 bool FakeServer::HandleGetUpdatesRequest(
313 const sync_pb::GetUpdatesMessage& get_updates,
314 sync_pb::GetUpdatesResponse* response) {
315 // TODO(pvalenzuela): Implement batching instead of sending all information
316 // at once.
317 response->set_changes_remaining(0);
319 scoped_ptr<UpdateSieve> sieve = UpdateSieve::Create(get_updates);
321 // This folder is called "Synced Bookmarks" by sync and is renamed
322 // "Mobile Bookmarks" by the mobile client UIs.
323 if (get_updates.create_mobile_bookmarks_folder() &&
324 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag,
325 kSyncedBookmarksFolderName)) {
326 return false;
329 bool send_encryption_keys_based_on_nigori = false;
330 int64 max_response_version = 0;
331 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
332 ++it) {
333 const FakeServerEntity& entity = *it->second;
334 if (sieve->ClientWantsItem(entity)) {
335 sync_pb::SyncEntity* response_entity = response->add_entries();
336 entity.SerializeAsProto(response_entity);
337 max_response_version = std::max(max_response_version,
338 response_entity->version());
340 if (entity.GetModelType() == syncer::NIGORI) {
341 send_encryption_keys_based_on_nigori =
342 response_entity->specifics().nigori().passphrase_type() ==
343 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE;
348 if (send_encryption_keys_based_on_nigori ||
349 get_updates.need_encryption_key()) {
350 for (vector<string>::iterator it = keystore_keys_.begin();
351 it != keystore_keys_.end(); ++it) {
352 response->add_encryption_keys(*it);
356 sieve->UpdateProgressMarkers(max_response_version, response);
357 return true;
360 string FakeServer::CommitEntity(
361 const sync_pb::SyncEntity& client_entity,
362 sync_pb::CommitResponse_EntryResponse* entry_response,
363 const string& client_guid,
364 const string& parent_id) {
365 if (client_entity.version() == 0 && client_entity.deleted()) {
366 return string();
369 scoped_ptr<FakeServerEntity> entity;
370 if (client_entity.deleted()) {
371 entity = TombstoneEntity::Create(client_entity.id_string());
372 DeleteChildren(client_entity.id_string());
373 } else if (GetModelType(client_entity) == syncer::NIGORI) {
374 // NIGORI is the only permanent item type that should be updated by the
375 // client.
376 EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
377 CHECK(iter != entities_.end());
378 entity = PermanentEntity::CreateUpdatedNigoriEntity(client_entity,
379 *iter->second);
380 } else if (client_entity.has_client_defined_unique_tag()) {
381 entity = UniqueClientEntity::Create(client_entity);
382 } else {
383 // TODO(pvalenzuela): Validate entity's parent ID.
384 EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
385 if (iter != entities_.end()) {
386 entity = BookmarkEntity::CreateUpdatedVersion(client_entity,
387 *iter->second, parent_id);
388 } else {
389 entity = BookmarkEntity::CreateNew(client_entity, parent_id, client_guid);
393 if (!entity) {
394 // TODO(pvalenzuela): Add logging so that it is easier to determine why
395 // creation failed.
396 return string();
399 const std::string id = entity->GetId();
400 SaveEntity(entity.Pass());
401 BuildEntryResponseForSuccessfulCommit(id, entry_response);
402 return id;
405 void FakeServer::BuildEntryResponseForSuccessfulCommit(
406 const std::string& entity_id,
407 sync_pb::CommitResponse_EntryResponse* entry_response) {
408 EntityMap::const_iterator iter = entities_.find(entity_id);
409 CHECK(iter != entities_.end());
410 const FakeServerEntity& entity = *iter->second;
411 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS);
412 entry_response->set_id_string(entity.GetId());
414 if (entity.IsDeleted()) {
415 entry_response->set_version(entity.GetVersion() + 1);
416 } else {
417 entry_response->set_version(entity.GetVersion());
418 entry_response->set_name(entity.GetName());
422 bool FakeServer::IsChild(const string& id, const string& potential_parent_id) {
423 EntityMap::const_iterator iter = entities_.find(id);
424 if (iter == entities_.end()) {
425 // We've hit an ID (probably the imaginary root entity) that isn't stored
426 // by the server, so it can't be a child.
427 return false;
430 const FakeServerEntity& entity = *iter->second;
431 if (entity.GetParentId() == potential_parent_id)
432 return true;
434 // Recursively look up the tree.
435 return IsChild(entity.GetParentId(), potential_parent_id);
438 void FakeServer::DeleteChildren(const string& id) {
439 std::set<string> tombstones_ids;
440 // Find all the children of id.
441 for (auto& entity : entities_) {
442 if (IsChild(entity.first, id)) {
443 tombstones_ids.insert(entity.first);
447 for (auto& tombstone_id : tombstones_ids) {
448 SaveEntity(TombstoneEntity::Create(tombstone_id));
452 bool FakeServer::HandleCommitRequest(const sync_pb::CommitMessage& commit,
453 const std::string& invalidator_client_id,
454 sync_pb::CommitResponse* response) {
455 std::map<string, string> client_to_server_ids;
456 string guid = commit.cache_guid();
457 ModelTypeSet committed_model_types;
459 // TODO(pvalenzuela): Add validation of CommitMessage.entries.
460 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it;
461 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) {
462 sync_pb::CommitResponse_EntryResponse* entry_response =
463 response->add_entryresponse();
465 sync_pb::SyncEntity client_entity = *it;
466 string parent_id = client_entity.parent_id_string();
467 if (client_to_server_ids.find(parent_id) !=
468 client_to_server_ids.end()) {
469 parent_id = client_to_server_ids[parent_id];
472 const string entity_id =
473 CommitEntity(client_entity, entry_response, guid, parent_id);
474 if (entity_id.empty()) {
475 return false;
478 // Record the ID if it was renamed.
479 if (entity_id != client_entity.id_string()) {
480 client_to_server_ids[client_entity.id_string()] = entity_id;
483 EntityMap::const_iterator iter = entities_.find(entity_id);
484 CHECK(iter != entities_.end());
485 committed_model_types.Put(iter->second->GetModelType());
488 FOR_EACH_OBSERVER(Observer, observers_,
489 OnCommit(invalidator_client_id, committed_model_types));
490 return true;
493 scoped_ptr<base::DictionaryValue> FakeServer::GetEntitiesAsDictionaryValue() {
494 DCHECK(thread_checker_.CalledOnValidThread());
495 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
497 // Initialize an empty ListValue for all ModelTypes.
498 ModelTypeSet all_types = ModelTypeSet::All();
499 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
500 dictionary->Set(ModelTypeToString(it.Get()), new base::ListValue());
503 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
504 ++it) {
505 const FakeServerEntity& entity = *it->second;
506 if (IsDeletedOrPermanent(entity)) {
507 // Tombstones are ignored as they don't represent current data. Folders
508 // are also ignored as current verification infrastructure does not
509 // consider them.
510 continue;
512 base::ListValue* list_value;
513 if (!dictionary->GetList(ModelTypeToString(entity.GetModelType()),
514 &list_value)) {
515 return scoped_ptr<base::DictionaryValue>();
517 // TODO(pvalenzuela): Store more data for each entity so additional
518 // verification can be performed. One example of additional verification
519 // is checking the correctness of the bookmark hierarchy.
520 list_value->Append(new base::StringValue(entity.GetName()));
523 return dictionary.Pass();
526 std::vector<sync_pb::SyncEntity> FakeServer::GetSyncEntitiesByModelType(
527 ModelType model_type) {
528 std::vector<sync_pb::SyncEntity> sync_entities;
529 DCHECK(thread_checker_.CalledOnValidThread());
530 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
531 ++it) {
532 const FakeServerEntity& entity = *it->second;
533 if (!IsDeletedOrPermanent(entity) && entity.GetModelType() == model_type) {
534 sync_pb::SyncEntity sync_entity;
535 entity.SerializeAsProto(&sync_entity);
536 sync_entities.push_back(sync_entity);
539 return sync_entities;
542 void FakeServer::InjectEntity(scoped_ptr<FakeServerEntity> entity) {
543 DCHECK(thread_checker_.CalledOnValidThread());
544 SaveEntity(entity.Pass());
547 bool FakeServer::ModifyEntitySpecifics(
548 const std::string& id,
549 const sync_pb::EntitySpecifics& updated_specifics) {
550 EntityMap::const_iterator iter = entities_.find(id);
551 if (iter == entities_.end() ||
552 iter->second->GetModelType() !=
553 GetModelTypeFromSpecifics(updated_specifics)) {
554 return false;
557 scoped_ptr<FakeServerEntity> entity = entities_.take_and_erase(iter);
558 entity->SetSpecifics(updated_specifics);
559 UpdateEntityVersion(entity.get());
560 entities_.insert(id, entity.Pass());
561 return true;
564 bool FakeServer::ModifyBookmarkEntity(
565 const std::string& id,
566 const std::string& parent_id,
567 const sync_pb::EntitySpecifics& updated_specifics) {
568 EntityMap::const_iterator iter = entities_.find(id);
569 if (iter == entities_.end() ||
570 iter->second->GetModelType() != syncer::BOOKMARKS ||
571 GetModelTypeFromSpecifics(updated_specifics) != syncer::BOOKMARKS) {
572 return false;
575 scoped_ptr<BookmarkEntity> entity(
576 static_cast<BookmarkEntity*>(entities_.take_and_erase(iter).release()));
578 entity->SetParentId(parent_id);
579 entity->SetSpecifics(updated_specifics);
580 if (updated_specifics.has_bookmark()) {
581 entity->SetName(updated_specifics.bookmark().title());
583 UpdateEntityVersion(entity.get());
584 entities_.insert(id, entity.Pass());
585 return true;
588 void FakeServer::ClearServerData() {
589 DCHECK(thread_checker_.CalledOnValidThread());
590 entities_.clear();
591 keystore_keys_.clear();
592 ++store_birthday_;
595 void FakeServer::SetAuthenticated() {
596 DCHECK(thread_checker_.CalledOnValidThread());
597 authenticated_ = true;
600 void FakeServer::SetUnauthenticated() {
601 DCHECK(thread_checker_.CalledOnValidThread());
602 authenticated_ = false;
605 bool FakeServer::TriggerError(const sync_pb::SyncEnums::ErrorType& error_type) {
606 DCHECK(thread_checker_.CalledOnValidThread());
607 if (triggered_actionable_error_.get()) {
608 DVLOG(1) << "Only one type of error can be triggered at any given time.";
609 return false;
612 error_type_ = error_type;
613 return true;
616 bool FakeServer::TriggerActionableError(
617 const sync_pb::SyncEnums::ErrorType& error_type,
618 const string& description,
619 const string& url,
620 const sync_pb::SyncEnums::Action& action) {
621 DCHECK(thread_checker_.CalledOnValidThread());
622 if (error_type_ != sync_pb::SyncEnums::SUCCESS) {
623 DVLOG(1) << "Only one type of error can be triggered at any given time.";
624 return false;
627 sync_pb::ClientToServerResponse_Error* error =
628 new sync_pb::ClientToServerResponse_Error();
629 error->set_error_type(error_type);
630 error->set_error_description(description);
631 error->set_url(url);
632 error->set_action(action);
633 triggered_actionable_error_.reset(error);
634 return true;
637 bool FakeServer::EnableAlternatingTriggeredErrors() {
638 DCHECK(thread_checker_.CalledOnValidThread());
639 if (error_type_ == sync_pb::SyncEnums::SUCCESS &&
640 !triggered_actionable_error_.get()) {
641 DVLOG(1) << "No triggered error set. Alternating can't be enabled.";
642 return false;
645 alternate_triggered_errors_ = true;
646 // Reset the counter so that the the first request yields a triggered error.
647 request_counter_ = 0;
648 return true;
651 bool FakeServer::ShouldSendTriggeredError() const {
652 if (!alternate_triggered_errors_)
653 return true;
655 // Check that the counter is odd so that we trigger an error on the first
656 // request after alternating is enabled.
657 return request_counter_ % 2 != 0;
660 void FakeServer::AddObserver(Observer* observer) {
661 DCHECK(thread_checker_.CalledOnValidThread());
662 observers_.AddObserver(observer);
665 void FakeServer::RemoveObserver(Observer* observer) {
666 DCHECK(thread_checker_.CalledOnValidThread());
667 observers_.RemoveObserver(observer);
670 void FakeServer::EnableNetwork() {
671 DCHECK(thread_checker_.CalledOnValidThread());
672 network_enabled_ = true;
675 void FakeServer::DisableNetwork() {
676 DCHECK(thread_checker_.CalledOnValidThread());
677 network_enabled_ = false;
680 std::string FakeServer::GetBookmarkBarFolderId() const {
681 DCHECK(thread_checker_.CalledOnValidThread());
682 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
683 ++it) {
684 FakeServerEntity* entity = it->second;
685 if (entity->GetName() == kBookmarkBarFolderName &&
686 entity->IsFolder() &&
687 entity->GetModelType() == syncer::BOOKMARKS) {
688 return entity->GetId();
691 NOTREACHED() << "Bookmark Bar entity not found.";
692 return "";
695 base::WeakPtr<FakeServer> FakeServer::AsWeakPtr() {
696 DCHECK(thread_checker_.CalledOnValidThread());
697 return weak_ptr_factory_.GetWeakPtr();
700 std::string FakeServer::GetStoreBirthday() const {
701 DCHECK(thread_checker_.CalledOnValidThread());
702 return base::Int64ToString(store_birthday_);
705 } // namespace fake_server