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

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

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 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
« no previous file with comments | « sync/test/fake_server/fake_server.h ('k') | sync/test/fake_server/fake_server_entity.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "sync/test/fake_server/fake_server.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <limits>
11 #include <memory>
12 #include <set>
13 #include <string>
14 #include <utility>
15 #include <vector>
16
17 #include "base/guid.h"
18 #include "base/logging.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/synchronization/lock.h"
24 #include "net/base/net_errors.h"
25 #include "net/http/http_status_code.h"
26 #include "sync/internal_api/public/base/model_type.h"
27 #include "sync/protocol/sync.pb.h"
28 #include "sync/test/fake_server/bookmark_entity.h"
29 #include "sync/test/fake_server/permanent_entity.h"
30 #include "sync/test/fake_server/tombstone_entity.h"
31 #include "sync/test/fake_server/unique_client_entity.h"
32
33 using std::string;
34 using std::vector;
35
36 using syncer::GetModelType;
37 using syncer::GetModelTypeFromSpecifics;
38 using syncer::ModelType;
39 using syncer::ModelTypeSet;
40
41 namespace fake_server {
42
43 class FakeServerEntity;
44
45 namespace {
46
47 // The default keystore key.
48 static const char kDefaultKeystoreKey[] = "1111111111111111";
49
50 // Properties of the bookmark bar permanent folder.
51 static const char kBookmarkBarFolderServerTag[] = "bookmark_bar";
52 static const char kBookmarkBarFolderName[] = "Bookmark Bar";
53
54 // Properties of the other bookmarks permanent folder.
55 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks";
56 static const char kOtherBookmarksFolderName[] = "Other Bookmarks";
57
58 // Properties of the synced bookmarks permanent folder.
59 static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks";
60 static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks";
61
62 // 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
64 // GetUpdates call and an UpdateSieve instance.
65 class UpdateSieve {
66 public:
67 ~UpdateSieve() { }
68
69 // Factory method for creating an UpdateSieve.
70 static std::unique_ptr<UpdateSieve> Create(
71 const sync_pb::GetUpdatesMessage& get_updates_message);
72
73 // Sets the progress markers in |get_updates_response| given the progress
74 // markers from the original GetUpdatesMessage and |new_version| (the latest
75 // version in the entries sent back).
76 void UpdateProgressMarkers(
77 int64_t new_version,
78 sync_pb::GetUpdatesResponse* get_updates_response) const {
79 ModelTypeToVersionMap::const_iterator it;
80 for (it = request_from_version_.begin(); it != request_from_version_.end();
81 ++it) {
82 sync_pb::DataTypeProgressMarker* new_marker =
83 get_updates_response->add_new_progress_marker();
84 new_marker->set_data_type_id(
85 GetSpecificsFieldNumberFromModelType(it->first));
86
87 int64_t version = std::max(new_version, it->second);
88 new_marker->set_token(base::Int64ToString(version));
89 }
90 }
91
92 // Determines whether the server should send an |entity| to the client as
93 // part of a GetUpdatesResponse.
94 bool ClientWantsItem(const FakeServerEntity& entity) const {
95 int64_t version = entity.GetVersion();
96 if (version <= min_version_) {
97 return false;
98 } else if (entity.IsDeleted()) {
99 return true;
100 }
101
102 ModelTypeToVersionMap::const_iterator it =
103 request_from_version_.find(entity.GetModelType());
104
105 return it == request_from_version_.end() ? false : it->second < version;
106 }
107
108 // Returns the minimum version seen across all types.
109 int64_t GetMinVersion() const { return min_version_; }
110
111 private:
112 typedef std::map<ModelType, int64_t> ModelTypeToVersionMap;
113
114 // Creates an UpdateSieve.
115 UpdateSieve(const ModelTypeToVersionMap request_from_version,
116 const int64_t min_version)
117 : request_from_version_(request_from_version),
118 min_version_(min_version) {}
119
120 // Maps data type IDs to the latest version seen for that type.
121 const ModelTypeToVersionMap request_from_version_;
122
123 // The minimum version seen among all data types.
124 const int min_version_;
125 };
126
127 std::unique_ptr<UpdateSieve> UpdateSieve::Create(
128 const sync_pb::GetUpdatesMessage& get_updates_message) {
129 CHECK_GT(get_updates_message.from_progress_marker_size(), 0)
130 << "A GetUpdates request must have at least one progress marker.";
131
132 UpdateSieve::ModelTypeToVersionMap request_from_version;
133 int64_t min_version = std::numeric_limits<int64_t>::max();
134 for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) {
135 sync_pb::DataTypeProgressMarker marker =
136 get_updates_message.from_progress_marker(i);
137
138 int64_t version = 0;
139 // Let the version remain zero if there is no token or an empty token (the
140 // first request for this type).
141 if (marker.has_token() && !marker.token().empty()) {
142 bool parsed = base::StringToInt64(marker.token(), &version);
143 CHECK(parsed) << "Unable to parse progress marker token.";
144 }
145
146 ModelType model_type = syncer::GetModelTypeFromSpecificsFieldNumber(
147 marker.data_type_id());
148 request_from_version[model_type] = version;
149
150 if (version < min_version)
151 min_version = version;
152 }
153
154 return std::unique_ptr<UpdateSieve>(
155 new UpdateSieve(request_from_version, min_version));
156 }
157
158 // Returns whether |entity| is deleted or permanent.
159 bool IsDeletedOrPermanent(const FakeServerEntity& entity) {
160 return entity.IsDeleted() || entity.IsPermanent();
161 }
162
163 } // namespace
164
165 FakeServer::FakeServer() : version_(0),
166 store_birthday_(0),
167 authenticated_(true),
168 error_type_(sync_pb::SyncEnums::SUCCESS),
169 alternate_triggered_errors_(false),
170 request_counter_(0),
171 network_enabled_(true),
172 weak_ptr_factory_(this) {
173 Init();
174 }
175
176 FakeServer::~FakeServer() {}
177
178 void FakeServer::Init() {
179 keystore_keys_.push_back(kDefaultKeystoreKey);
180
181 const bool create_result = CreateDefaultPermanentItems();
182 DCHECK(create_result) << "Permanent items were not created successfully.";
183 }
184
185 bool FakeServer::CreatePermanentBookmarkFolder(const std::string& server_tag,
186 const std::string& name) {
187 DCHECK(thread_checker_.CalledOnValidThread());
188 std::unique_ptr<FakeServerEntity> entity =
189 PermanentEntity::Create(syncer::BOOKMARKS, server_tag, name,
190 ModelTypeToRootTag(syncer::BOOKMARKS));
191 if (!entity)
192 return false;
193
194 SaveEntity(std::move(entity));
195 return true;
196 }
197
198 bool FakeServer::CreateDefaultPermanentItems() {
199 // Permanent folders are always required for Bookmarks (hierarchical
200 // structure) and Nigori (data stored in permanent root folder).
201 ModelTypeSet permanent_folder_types =
202 ModelTypeSet(syncer::BOOKMARKS, syncer::NIGORI);
203
204 for (ModelTypeSet::Iterator it = permanent_folder_types.First(); it.Good();
205 it.Inc()) {
206 ModelType model_type = it.Get();
207
208 std::unique_ptr<FakeServerEntity> top_level_entity =
209 PermanentEntity::CreateTopLevel(model_type);
210 if (!top_level_entity) {
211 return false;
212 }
213 SaveEntity(std::move(top_level_entity));
214
215 if (model_type == syncer::BOOKMARKS) {
216 if (!CreatePermanentBookmarkFolder(kBookmarkBarFolderServerTag,
217 kBookmarkBarFolderName))
218 return false;
219 if (!CreatePermanentBookmarkFolder(kOtherBookmarksFolderServerTag,
220 kOtherBookmarksFolderName))
221 return false;
222 }
223 }
224
225 return true;
226 }
227
228 void FakeServer::UpdateEntityVersion(FakeServerEntity* entity) {
229 entity->SetVersion(++version_);
230 }
231
232 void FakeServer::SaveEntity(std::unique_ptr<FakeServerEntity> entity) {
233 UpdateEntityVersion(entity.get());
234 entities_[entity->GetId()] = std::move(entity);
235 }
236
237 void FakeServer::HandleCommand(const string& request,
238 const base::Closure& completion_closure,
239 int* error_code,
240 int* response_code,
241 std::string* response) {
242 DCHECK(thread_checker_.CalledOnValidThread());
243 if (!network_enabled_) {
244 *error_code = net::ERR_FAILED;
245 *response_code = net::ERR_FAILED;
246 *response = string();
247 completion_closure.Run();
248 return;
249 }
250 request_counter_++;
251
252 if (!authenticated_) {
253 *error_code = 0;
254 *response_code = net::HTTP_UNAUTHORIZED;
255 *response = string();
256 completion_closure.Run();
257 return;
258 }
259
260 sync_pb::ClientToServerMessage message;
261 bool parsed = message.ParseFromString(request);
262 CHECK(parsed) << "Unable to parse the ClientToServerMessage.";
263
264 sync_pb::ClientToServerResponse response_proto;
265
266 if (message.has_store_birthday() &&
267 message.store_birthday() != GetStoreBirthday()) {
268 response_proto.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY);
269 } else if (error_type_ != sync_pb::SyncEnums::SUCCESS &&
270 ShouldSendTriggeredError()) {
271 response_proto.set_error_code(error_type_);
272 } else if (triggered_actionable_error_.get() && ShouldSendTriggeredError()) {
273 sync_pb::ClientToServerResponse_Error* error =
274 response_proto.mutable_error();
275 error->CopyFrom(*(triggered_actionable_error_.get()));
276 } else {
277 bool success = false;
278 switch (message.message_contents()) {
279 case sync_pb::ClientToServerMessage::GET_UPDATES:
280 last_getupdates_message_ = message;
281 success = HandleGetUpdatesRequest(message.get_updates(),
282 response_proto.mutable_get_updates());
283 break;
284 case sync_pb::ClientToServerMessage::COMMIT:
285 last_commit_message_ = message;
286 success = HandleCommitRequest(message.commit(),
287 message.invalidator_client_id(),
288 response_proto.mutable_commit());
289 break;
290 case sync_pb::ClientToServerMessage::CLEAR_SERVER_DATA:
291 ClearServerData();
292 response_proto.mutable_clear_server_data();
293 success = true;
294 break;
295 default:
296 *error_code = net::ERR_NOT_IMPLEMENTED;
297 *response_code = 0;
298 *response = string();
299 completion_closure.Run();
300 return;
301 }
302
303 if (!success) {
304 // TODO(pvalenzuela): Add logging here so that tests have more info about
305 // the failure.
306 *error_code = net::ERR_FAILED;
307 *response_code = 0;
308 *response = string();
309 completion_closure.Run();
310 return;
311 }
312
313 response_proto.set_error_code(sync_pb::SyncEnums::SUCCESS);
314 }
315
316 response_proto.set_store_birthday(GetStoreBirthday());
317
318 *error_code = 0;
319 *response_code = net::HTTP_OK;
320 *response = response_proto.SerializeAsString();
321 completion_closure.Run();
322 }
323
324 bool FakeServer::GetLastCommitMessage(
325 sync_pb::ClientToServerMessage* message) {
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,
344 sync_pb::GetUpdatesResponse* response) {
345 // TODO(pvalenzuela): Implement batching instead of sending all information
346 // at once.
347 response->set_changes_remaining(0);
348
349 std::unique_ptr<UpdateSieve> sieve = UpdateSieve::Create(get_updates);
350
351 // This folder is called "Synced Bookmarks" by sync and is renamed
352 // "Mobile Bookmarks" by the mobile client UIs.
353 if (get_updates.create_mobile_bookmarks_folder() &&
354 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag,
355 kSyncedBookmarksFolderName)) {
356 return false;
357 }
358
359 bool send_encryption_keys_based_on_nigori = false;
360 int64_t max_response_version = 0;
361 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
362 ++it) {
363 const FakeServerEntity& entity = *it->second;
364 if (sieve->ClientWantsItem(entity)) {
365 sync_pb::SyncEntity* response_entity = response->add_entries();
366 entity.SerializeAsProto(response_entity);
367
368 max_response_version = std::max(max_response_version,
369 response_entity->version());
370
371 if (entity.GetModelType() == syncer::NIGORI) {
372 send_encryption_keys_based_on_nigori =
373 response_entity->specifics().nigori().passphrase_type() ==
374 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE;
375 }
376 }
377 }
378
379 if (send_encryption_keys_based_on_nigori ||
380 get_updates.need_encryption_key()) {
381 for (vector<string>::iterator it = keystore_keys_.begin();
382 it != keystore_keys_.end(); ++it) {
383 response->add_encryption_keys(*it);
384 }
385 }
386
387 sieve->UpdateProgressMarkers(max_response_version, response);
388 return true;
389 }
390
391 string FakeServer::CommitEntity(
392 const sync_pb::SyncEntity& client_entity,
393 sync_pb::CommitResponse_EntryResponse* entry_response,
394 const string& client_guid,
395 const string& parent_id) {
396 if (client_entity.version() == 0 && client_entity.deleted()) {
397 return string();
398 }
399
400 std::unique_ptr<FakeServerEntity> entity;
401 if (client_entity.deleted()) {
402 entity = TombstoneEntity::Create(client_entity.id_string());
403 DeleteChildren(client_entity.id_string());
404 } else if (GetModelType(client_entity) == syncer::NIGORI) {
405 // NIGORI is the only permanent item type that should be updated by the
406 // client.
407 EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
408 CHECK(iter != entities_.end());
409 entity = PermanentEntity::CreateUpdatedNigoriEntity(client_entity,
410 *iter->second);
411 } else if (client_entity.has_client_defined_unique_tag()) {
412 entity = UniqueClientEntity::Create(client_entity);
413 } else {
414 // TODO(pvalenzuela): Validate entity's parent ID.
415 EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
416 if (iter != entities_.end()) {
417 entity = BookmarkEntity::CreateUpdatedVersion(client_entity,
418 *iter->second, parent_id);
419 } else {
420 entity = BookmarkEntity::CreateNew(client_entity, parent_id, client_guid);
421 }
422 }
423
424 if (!entity) {
425 // TODO(pvalenzuela): Add logging so that it is easier to determine why
426 // creation failed.
427 return string();
428 }
429
430 const std::string id = entity->GetId();
431 SaveEntity(std::move(entity));
432 BuildEntryResponseForSuccessfulCommit(id, entry_response);
433 return id;
434 }
435
436 void FakeServer::BuildEntryResponseForSuccessfulCommit(
437 const std::string& entity_id,
438 sync_pb::CommitResponse_EntryResponse* entry_response) {
439 EntityMap::const_iterator iter = entities_.find(entity_id);
440 CHECK(iter != entities_.end());
441 const FakeServerEntity& entity = *iter->second;
442 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS);
443 entry_response->set_id_string(entity.GetId());
444
445 if (entity.IsDeleted()) {
446 entry_response->set_version(entity.GetVersion() + 1);
447 } else {
448 entry_response->set_version(entity.GetVersion());
449 entry_response->set_name(entity.GetName());
450 }
451 }
452
453 bool FakeServer::IsChild(const string& id, const string& potential_parent_id) {
454 EntityMap::const_iterator iter = entities_.find(id);
455 if (iter == entities_.end()) {
456 // We've hit an ID (probably the imaginary root entity) that isn't stored
457 // by the server, so it can't be a child.
458 return false;
459 }
460
461 const FakeServerEntity& entity = *iter->second;
462 if (entity.GetParentId() == potential_parent_id)
463 return true;
464
465 // Recursively look up the tree.
466 return IsChild(entity.GetParentId(), potential_parent_id);
467 }
468
469 void FakeServer::DeleteChildren(const string& id) {
470 std::set<string> tombstones_ids;
471 // Find all the children of id.
472 for (auto& entity : entities_) {
473 if (IsChild(entity.first, id)) {
474 tombstones_ids.insert(entity.first);
475 }
476 }
477
478 for (auto& tombstone_id : tombstones_ids) {
479 SaveEntity(TombstoneEntity::Create(tombstone_id));
480 }
481 }
482
483 bool FakeServer::HandleCommitRequest(const sync_pb::CommitMessage& commit,
484 const std::string& invalidator_client_id,
485 sync_pb::CommitResponse* response) {
486 std::map<string, string> client_to_server_ids;
487 string guid = commit.cache_guid();
488 ModelTypeSet committed_model_types;
489
490 // TODO(pvalenzuela): Add validation of CommitMessage.entries.
491 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it;
492 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) {
493 sync_pb::CommitResponse_EntryResponse* entry_response =
494 response->add_entryresponse();
495
496 sync_pb::SyncEntity client_entity = *it;
497 string parent_id = client_entity.parent_id_string();
498 if (client_to_server_ids.find(parent_id) !=
499 client_to_server_ids.end()) {
500 parent_id = client_to_server_ids[parent_id];
501 }
502
503 const string entity_id =
504 CommitEntity(client_entity, entry_response, guid, parent_id);
505 if (entity_id.empty()) {
506 return false;
507 }
508
509 // Record the ID if it was renamed.
510 if (entity_id != client_entity.id_string()) {
511 client_to_server_ids[client_entity.id_string()] = entity_id;
512 }
513
514 EntityMap::const_iterator iter = entities_.find(entity_id);
515 CHECK(iter != entities_.end());
516 committed_model_types.Put(iter->second->GetModelType());
517 }
518
519 FOR_EACH_OBSERVER(Observer, observers_,
520 OnCommit(invalidator_client_id, committed_model_types));
521 return true;
522 }
523
524 std::unique_ptr<base::DictionaryValue>
525 FakeServer::GetEntitiesAsDictionaryValue() {
526 DCHECK(thread_checker_.CalledOnValidThread());
527 std::unique_ptr<base::DictionaryValue> dictionary(
528 new base::DictionaryValue());
529
530 // Initialize an empty ListValue for all ModelTypes.
531 ModelTypeSet all_types = ModelTypeSet::All();
532 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
533 dictionary->Set(ModelTypeToString(it.Get()), new base::ListValue());
534 }
535
536 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
537 ++it) {
538 const FakeServerEntity& entity = *it->second;
539 if (IsDeletedOrPermanent(entity)) {
540 // Tombstones are ignored as they don't represent current data. Folders
541 // are also ignored as current verification infrastructure does not
542 // consider them.
543 continue;
544 }
545 base::ListValue* list_value;
546 if (!dictionary->GetList(ModelTypeToString(entity.GetModelType()),
547 &list_value)) {
548 return std::unique_ptr<base::DictionaryValue>();
549 }
550 // TODO(pvalenzuela): Store more data for each entity so additional
551 // verification can be performed. One example of additional verification
552 // is checking the correctness of the bookmark hierarchy.
553 list_value->AppendString(entity.GetName());
554 }
555
556 return dictionary;
557 }
558
559 std::vector<sync_pb::SyncEntity> FakeServer::GetSyncEntitiesByModelType(
560 ModelType model_type) {
561 std::vector<sync_pb::SyncEntity> sync_entities;
562 DCHECK(thread_checker_.CalledOnValidThread());
563 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
564 ++it) {
565 const FakeServerEntity& entity = *it->second;
566 if (!IsDeletedOrPermanent(entity) && entity.GetModelType() == model_type) {
567 sync_pb::SyncEntity sync_entity;
568 entity.SerializeAsProto(&sync_entity);
569 sync_entities.push_back(sync_entity);
570 }
571 }
572 return sync_entities;
573 }
574
575 void FakeServer::InjectEntity(std::unique_ptr<FakeServerEntity> entity) {
576 DCHECK(thread_checker_.CalledOnValidThread());
577 SaveEntity(std::move(entity));
578 }
579
580 bool FakeServer::ModifyEntitySpecifics(
581 const std::string& id,
582 const sync_pb::EntitySpecifics& updated_specifics) {
583 EntityMap::const_iterator iter = entities_.find(id);
584 if (iter == entities_.end() ||
585 iter->second->GetModelType() !=
586 GetModelTypeFromSpecifics(updated_specifics)) {
587 return false;
588 }
589
590 FakeServerEntity* entity = iter->second.get();
591 entity->SetSpecifics(updated_specifics);
592 UpdateEntityVersion(entity);
593 return true;
594 }
595
596 bool FakeServer::ModifyBookmarkEntity(
597 const std::string& id,
598 const std::string& parent_id,
599 const sync_pb::EntitySpecifics& updated_specifics) {
600 EntityMap::const_iterator iter = entities_.find(id);
601 if (iter == entities_.end() ||
602 iter->second->GetModelType() != syncer::BOOKMARKS ||
603 GetModelTypeFromSpecifics(updated_specifics) != syncer::BOOKMARKS) {
604 return false;
605 }
606
607 BookmarkEntity* entity = static_cast<BookmarkEntity*>(iter->second.get());
608
609 entity->SetParentId(parent_id);
610 entity->SetSpecifics(updated_specifics);
611 if (updated_specifics.has_bookmark()) {
612 entity->SetName(updated_specifics.bookmark().title());
613 }
614 UpdateEntityVersion(entity);
615 return true;
616 }
617
618 void FakeServer::ClearServerData() {
619 DCHECK(thread_checker_.CalledOnValidThread());
620 entities_.clear();
621 keystore_keys_.clear();
622 ++store_birthday_;
623 Init();
624 }
625
626 void FakeServer::SetAuthenticated() {
627 DCHECK(thread_checker_.CalledOnValidThread());
628 authenticated_ = true;
629 }
630
631 void FakeServer::SetUnauthenticated() {
632 DCHECK(thread_checker_.CalledOnValidThread());
633 authenticated_ = false;
634 }
635
636 bool FakeServer::TriggerError(const sync_pb::SyncEnums::ErrorType& error_type) {
637 DCHECK(thread_checker_.CalledOnValidThread());
638 if (triggered_actionable_error_.get()) {
639 DVLOG(1) << "Only one type of error can be triggered at any given time.";
640 return false;
641 }
642
643 error_type_ = error_type;
644 return true;
645 }
646
647 bool FakeServer::TriggerActionableError(
648 const sync_pb::SyncEnums::ErrorType& error_type,
649 const string& description,
650 const string& url,
651 const sync_pb::SyncEnums::Action& action) {
652 DCHECK(thread_checker_.CalledOnValidThread());
653 if (error_type_ != sync_pb::SyncEnums::SUCCESS) {
654 DVLOG(1) << "Only one type of error can be triggered at any given time.";
655 return false;
656 }
657
658 sync_pb::ClientToServerResponse_Error* error =
659 new sync_pb::ClientToServerResponse_Error();
660 error->set_error_type(error_type);
661 error->set_error_description(description);
662 error->set_url(url);
663 error->set_action(action);
664 triggered_actionable_error_.reset(error);
665 return true;
666 }
667
668 bool FakeServer::EnableAlternatingTriggeredErrors() {
669 DCHECK(thread_checker_.CalledOnValidThread());
670 if (error_type_ == sync_pb::SyncEnums::SUCCESS &&
671 !triggered_actionable_error_.get()) {
672 DVLOG(1) << "No triggered error set. Alternating can't be enabled.";
673 return false;
674 }
675
676 alternate_triggered_errors_ = true;
677 // Reset the counter so that the the first request yields a triggered error.
678 request_counter_ = 0;
679 return true;
680 }
681
682 bool FakeServer::ShouldSendTriggeredError() const {
683 if (!alternate_triggered_errors_)
684 return true;
685
686 // Check that the counter is odd so that we trigger an error on the first
687 // request after alternating is enabled.
688 return request_counter_ % 2 != 0;
689 }
690
691 void FakeServer::AddObserver(Observer* observer) {
692 DCHECK(thread_checker_.CalledOnValidThread());
693 observers_.AddObserver(observer);
694 }
695
696 void FakeServer::RemoveObserver(Observer* observer) {
697 DCHECK(thread_checker_.CalledOnValidThread());
698 observers_.RemoveObserver(observer);
699 }
700
701 void FakeServer::EnableNetwork() {
702 DCHECK(thread_checker_.CalledOnValidThread());
703 network_enabled_ = true;
704 }
705
706 void FakeServer::DisableNetwork() {
707 DCHECK(thread_checker_.CalledOnValidThread());
708 network_enabled_ = false;
709 }
710
711 std::string FakeServer::GetBookmarkBarFolderId() const {
712 DCHECK(thread_checker_.CalledOnValidThread());
713 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
714 ++it) {
715 FakeServerEntity* entity = it->second.get();
716 if (entity->GetName() == kBookmarkBarFolderName &&
717 entity->IsFolder() &&
718 entity->GetModelType() == syncer::BOOKMARKS) {
719 return entity->GetId();
720 }
721 }
722 NOTREACHED() << "Bookmark Bar entity not found.";
723 return "";
724 }
725
726 base::WeakPtr<FakeServer> FakeServer::AsWeakPtr() {
727 DCHECK(thread_checker_.CalledOnValidThread());
728 return weak_ptr_factory_.GetWeakPtr();
729 }
730
731 std::string FakeServer::GetStoreBirthday() const {
732 DCHECK(thread_checker_.CalledOnValidThread());
733 return base::Int64ToString(store_birthday_);
734 }
735
736 } // namespace fake_server
OLDNEW
« no previous file with comments | « sync/test/fake_server/fake_server.h ('k') | sync/test/fake_server/fake_server_entity.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698