1 // Copyright 2012 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 // Mock ServerConnectionManager class for use in client regression tests.
6
7 #include "sync/test/engine/mock_connection_manager.h"
8
9 #include <map>
10
11 #include "base/location.h"
12 #include "base/strings/stringprintf.h"
13 #include "sync/engine/syncer_proto_util.h"
14 #include "sync/protocol/bookmark_specifics.pb.h"
15 #include "sync/syncable/directory.h"
16 #include "sync/syncable/syncable_write_transaction.h"
17 #include "sync/test/engine/test_id_factory.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using std::find;
21 using std::map;
22 using std::string;
23 using sync_pb::ClientToServerMessage;
24 using sync_pb::CommitMessage;
25 using sync_pb::CommitResponse;
26 using sync_pb::GetUpdatesMessage;
27 using sync_pb::SyncEnums;
28
29 namespace syncer {
30
31 using syncable::WriteTransaction;
32
33 static char kValidAuthToken[] = "AuthToken";
34 static char kCacheGuid[] = "kqyg7097kro6GSUod+GSg==";
35
MockConnectionManager(syncable::Directory * directory,CancelationSignal * signal)36 MockConnectionManager::MockConnectionManager(syncable::Directory* directory,
37 CancelationSignal* signal)
38 : ServerConnectionManager("unused", 0, false, signal),
39 server_reachable_(true),
40 conflict_all_commits_(false),
41 conflict_n_commits_(0),
42 next_new_id_(10000),
43 store_birthday_("Store BDay!"),
44 store_birthday_sent_(false),
45 client_stuck_(false),
46 countdown_to_postbuffer_fail_(0),
47 directory_(directory),
48 mid_commit_observer_(NULL),
49 throttling_(false),
50 fail_with_auth_invalid_(false),
51 fail_non_periodic_get_updates_(false),
52 next_position_in_parent_(2),
53 use_legacy_bookmarks_protocol_(false),
54 num_get_updates_requests_(0) {
55 SetNewTimestamp(0);
56 SetAuthToken(kValidAuthToken);
57 }
58
~MockConnectionManager()59 MockConnectionManager::~MockConnectionManager() {
60 EXPECT_TRUE(update_queue_.empty()) << "Unfetched updates.";
61 }
62
SetCommitTimeRename(string prepend)63 void MockConnectionManager::SetCommitTimeRename(string prepend) {
64 commit_time_rename_prepended_string_ = prepend;
65 }
66
SetMidCommitCallback(const base::Closure & callback)67 void MockConnectionManager::SetMidCommitCallback(
68 const base::Closure& callback) {
69 mid_commit_callback_ = callback;
70 }
71
SetMidCommitObserver(MockConnectionManager::MidCommitObserver * observer)72 void MockConnectionManager::SetMidCommitObserver(
73 MockConnectionManager::MidCommitObserver* observer) {
74 mid_commit_observer_ = observer;
75 }
76
PostBufferToPath(PostBufferParams * params,const string & path,const string & auth_token,ScopedServerStatusWatcher * watcher)77 bool MockConnectionManager::PostBufferToPath(PostBufferParams* params,
78 const string& path,
79 const string& auth_token,
80 ScopedServerStatusWatcher* watcher) {
81 ClientToServerMessage post;
82 CHECK(post.ParseFromString(params->buffer_in));
83 CHECK(post.has_protocol_version());
84 CHECK(post.has_api_key());
85 CHECK(post.has_bag_of_chips());
86
87 requests_.push_back(post);
88 client_stuck_ = post.sync_problem_detected();
89 sync_pb::ClientToServerResponse response;
90 response.Clear();
91
92 if (directory_) {
93 // If the Directory's locked when we do this, it's a problem as in normal
94 // use this function could take a while to return because it accesses the
95 // network. As we can't test this we do the next best thing and hang here
96 // when there's an issue.
97 CHECK(directory_->good());
98 WriteTransaction wt(FROM_HERE, syncable::UNITTEST, directory_);
99 }
100
101 if (auth_token.empty()) {
102 params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
103 return false;
104 }
105
106 if (auth_token != kValidAuthToken) {
107 // Simulate server-side auth failure.
108 params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
109 InvalidateAndClearAuthToken();
110 }
111
112 if (--countdown_to_postbuffer_fail_ == 0) {
113 // Fail as countdown hits zero.
114 params->response.server_status = HttpResponse::SYNC_SERVER_ERROR;
115 return false;
116 }
117
118 if (!server_reachable_) {
119 params->response.server_status = HttpResponse::CONNECTION_UNAVAILABLE;
120 return false;
121 }
122
123 // Default to an ok connection.
124 params->response.server_status = HttpResponse::SERVER_CONNECTION_OK;
125 response.set_error_code(SyncEnums::SUCCESS);
126 const string current_store_birthday = store_birthday();
127 response.set_store_birthday(current_store_birthday);
128 if (post.has_store_birthday() && post.store_birthday() !=
129 current_store_birthday) {
130 response.set_error_code(SyncEnums::NOT_MY_BIRTHDAY);
131 response.set_error_message("Merry Unbirthday!");
132 response.SerializeToString(¶ms->buffer_out);
133 store_birthday_sent_ = true;
134 return true;
135 }
136 bool result = true;
137 EXPECT_TRUE(!store_birthday_sent_ || post.has_store_birthday() ||
138 post.message_contents() == ClientToServerMessage::AUTHENTICATE);
139 store_birthday_sent_ = true;
140
141 if (post.message_contents() == ClientToServerMessage::COMMIT) {
142 ProcessCommit(&post, &response);
143 } else if (post.message_contents() == ClientToServerMessage::GET_UPDATES) {
144 ProcessGetUpdates(&post, &response);
145 } else {
146 EXPECT_TRUE(false) << "Unknown/unsupported ClientToServerMessage";
147 return false;
148 }
149
150 {
151 base::AutoLock lock(response_code_override_lock_);
152 if (throttling_) {
153 response.set_error_code(SyncEnums::THROTTLED);
154 throttling_ = false;
155 }
156
157 if (fail_with_auth_invalid_)
158 response.set_error_code(SyncEnums::AUTH_INVALID);
159 }
160
161 response.SerializeToString(¶ms->buffer_out);
162 if (post.message_contents() == ClientToServerMessage::COMMIT &&
163 !mid_commit_callback_.is_null()) {
164 mid_commit_callback_.Run();
165 mid_commit_callback_.Reset();
166 }
167 if (mid_commit_observer_) {
168 mid_commit_observer_->Observe();
169 }
170
171 return result;
172 }
173
GetUpdateResponse()174 sync_pb::GetUpdatesResponse* MockConnectionManager::GetUpdateResponse() {
175 if (update_queue_.empty()) {
176 NextUpdateBatch();
177 }
178 return &update_queue_.back();
179 }
180
AddDefaultBookmarkData(sync_pb::SyncEntity * entity,bool is_folder)181 void MockConnectionManager::AddDefaultBookmarkData(sync_pb::SyncEntity* entity,
182 bool is_folder) {
183 if (use_legacy_bookmarks_protocol_) {
184 sync_pb::SyncEntity_BookmarkData* data = entity->mutable_bookmarkdata();
185 data->set_bookmark_folder(is_folder);
186
187 if (!is_folder) {
188 data->set_bookmark_url("http://google.com");
189 }
190 } else {
191 entity->set_folder(is_folder);
192 entity->mutable_specifics()->mutable_bookmark();
193 if (!is_folder) {
194 entity->mutable_specifics()->mutable_bookmark()->
195 set_url("http://google.com");
196 }
197 }
198 }
199
AddUpdateDirectory(int id,int parent_id,string name,int64 version,int64 sync_ts,std::string originator_cache_guid,std::string originator_client_item_id)200 sync_pb::SyncEntity* MockConnectionManager::AddUpdateDirectory(
201 int id,
202 int parent_id,
203 string name,
204 int64 version,
205 int64 sync_ts,
206 std::string originator_cache_guid,
207 std::string originator_client_item_id) {
208 return AddUpdateDirectory(TestIdFactory::FromNumber(id),
209 TestIdFactory::FromNumber(parent_id),
210 name,
211 version,
212 sync_ts,
213 originator_cache_guid,
214 originator_client_item_id);
215 }
216
SetGUClientCommand(sync_pb::ClientCommand * command)217 void MockConnectionManager::SetGUClientCommand(
218 sync_pb::ClientCommand* command) {
219 gu_client_command_.reset(command);
220 }
221
SetCommitClientCommand(sync_pb::ClientCommand * command)222 void MockConnectionManager::SetCommitClientCommand(
223 sync_pb::ClientCommand* command) {
224 commit_client_command_.reset(command);
225 }
226
SetTransientErrorId(syncable::Id id)227 void MockConnectionManager::SetTransientErrorId(syncable::Id id) {
228 transient_error_ids_.push_back(id);
229 }
230
AddUpdateBookmark(int id,int parent_id,string name,int64 version,int64 sync_ts,string originator_client_item_id,string originator_cache_guid)231 sync_pb::SyncEntity* MockConnectionManager::AddUpdateBookmark(
232 int id, int parent_id,
233 string name, int64 version,
234 int64 sync_ts,
235 string originator_client_item_id,
236 string originator_cache_guid) {
237 return AddUpdateBookmark(TestIdFactory::FromNumber(id),
238 TestIdFactory::FromNumber(parent_id),
239 name,
240 version,
241 sync_ts,
242 originator_client_item_id,
243 originator_cache_guid);
244 }
245
AddUpdateSpecifics(int id,int parent_id,string name,int64 version,int64 sync_ts,bool is_dir,int64 position,const sync_pb::EntitySpecifics & specifics)246 sync_pb::SyncEntity* MockConnectionManager::AddUpdateSpecifics(
247 int id,
248 int parent_id,
249 string name,
250 int64 version,
251 int64 sync_ts,
252 bool is_dir,
253 int64 position,
254 const sync_pb::EntitySpecifics& specifics) {
255 sync_pb::SyncEntity* ent = AddUpdateMeta(
256 TestIdFactory::FromNumber(id).GetServerId(),
257 TestIdFactory::FromNumber(parent_id).GetServerId(),
258 name, version, sync_ts);
259 ent->set_position_in_parent(position);
260 ent->mutable_specifics()->CopyFrom(specifics);
261 ent->set_folder(is_dir);
262 return ent;
263 }
264
AddUpdateSpecifics(int id,int parent_id,string name,int64 version,int64 sync_ts,bool is_dir,int64 position,const sync_pb::EntitySpecifics & specifics,string originator_cache_guid,string originator_client_item_id)265 sync_pb::SyncEntity* MockConnectionManager::AddUpdateSpecifics(
266 int id,
267 int parent_id,
268 string name,
269 int64 version,
270 int64 sync_ts,
271 bool is_dir,
272 int64 position,
273 const sync_pb::EntitySpecifics& specifics,
274 string originator_cache_guid,
275 string originator_client_item_id) {
276 sync_pb::SyncEntity* ent = AddUpdateSpecifics(
277 id, parent_id, name, version, sync_ts, is_dir, position, specifics);
278 ent->set_originator_cache_guid(originator_cache_guid);
279 ent->set_originator_client_item_id(originator_client_item_id);
280 return ent;
281 }
282
SetNigori(int id,int64 version,int64 sync_ts,const sync_pb::EntitySpecifics & specifics)283 sync_pb::SyncEntity* MockConnectionManager::SetNigori(
284 int id,
285 int64 version,
286 int64 sync_ts,
287 const sync_pb::EntitySpecifics& specifics) {
288 sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
289 ent->set_id_string(TestIdFactory::FromNumber(id).GetServerId());
290 ent->set_parent_id_string(TestIdFactory::FromNumber(0).GetServerId());
291 ent->set_server_defined_unique_tag(ModelTypeToRootTag(NIGORI));
292 ent->set_name("Nigori");
293 ent->set_non_unique_name("Nigori");
294 ent->set_version(version);
295 ent->set_sync_timestamp(sync_ts);
296 ent->set_mtime(sync_ts);
297 ent->set_ctime(1);
298 ent->set_position_in_parent(0);
299 ent->set_folder(false);
300 ent->mutable_specifics()->CopyFrom(specifics);
301 return ent;
302 }
303
AddUpdatePref(string id,string parent_id,string client_tag,int64 version,int64 sync_ts)304 sync_pb::SyncEntity* MockConnectionManager::AddUpdatePref(string id,
305 string parent_id,
306 string client_tag,
307 int64 version,
308 int64 sync_ts) {
309 sync_pb::SyncEntity* ent =
310 AddUpdateMeta(id, parent_id, " ", version, sync_ts);
311
312 ent->set_client_defined_unique_tag(client_tag);
313
314 sync_pb::EntitySpecifics specifics;
315 AddDefaultFieldValue(PREFERENCES, &specifics);
316 ent->mutable_specifics()->CopyFrom(specifics);
317
318 return ent;
319 }
320
AddUpdateFull(string id,string parent_id,string name,int64 version,int64 sync_ts,bool is_dir)321 sync_pb::SyncEntity* MockConnectionManager::AddUpdateFull(
322 string id, string parent_id,
323 string name, int64 version,
324 int64 sync_ts, bool is_dir) {
325 sync_pb::SyncEntity* ent =
326 AddUpdateMeta(id, parent_id, name, version, sync_ts);
327 AddDefaultBookmarkData(ent, is_dir);
328 return ent;
329 }
330
AddUpdateMeta(string id,string parent_id,string name,int64 version,int64 sync_ts)331 sync_pb::SyncEntity* MockConnectionManager::AddUpdateMeta(
332 string id, string parent_id,
333 string name, int64 version,
334 int64 sync_ts) {
335 sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
336 ent->set_id_string(id);
337 ent->set_parent_id_string(parent_id);
338 ent->set_non_unique_name(name);
339 ent->set_name(name);
340 ent->set_version(version);
341 ent->set_sync_timestamp(sync_ts);
342 ent->set_mtime(sync_ts);
343 ent->set_ctime(1);
344 ent->set_position_in_parent(GeneratePositionInParent());
345
346 // This isn't perfect, but it works well enough. This is an update, which
347 // means the ID is a server ID, which means it never changes. By making
348 // kCacheGuid also never change, we guarantee that the same item always has
349 // the same originator_cache_guid and originator_client_item_id.
350 //
351 // Unfortunately, neither this class nor the tests that use it explicitly
352 // track sync entitites, so supporting proper cache guids and client item IDs
353 // would require major refactoring. The ID used here ought to be the "c-"
354 // style ID that was sent up on the commit.
355 ent->set_originator_cache_guid(kCacheGuid);
356 ent->set_originator_client_item_id(id);
357
358 return ent;
359 }
360
AddUpdateDirectory(string id,string parent_id,string name,int64 version,int64 sync_ts,std::string originator_cache_guid,std::string originator_client_item_id)361 sync_pb::SyncEntity* MockConnectionManager::AddUpdateDirectory(
362 string id,
363 string parent_id,
364 string name,
365 int64 version,
366 int64 sync_ts,
367 std::string originator_cache_guid,
368 std::string originator_client_item_id) {
369 sync_pb::SyncEntity* ret =
370 AddUpdateFull(id, parent_id, name, version, sync_ts, true);
371 ret->set_originator_cache_guid(originator_cache_guid);
372 ret->set_originator_client_item_id(originator_client_item_id);
373 return ret;
374 }
375
AddUpdateBookmark(string id,string parent_id,string name,int64 version,int64 sync_ts,string originator_cache_guid,string originator_client_item_id)376 sync_pb::SyncEntity* MockConnectionManager::AddUpdateBookmark(
377 string id,
378 string parent_id,
379 string name, int64 version,
380 int64 sync_ts,
381 string originator_cache_guid,
382 string originator_client_item_id) {
383 sync_pb::SyncEntity* ret =
384 AddUpdateFull(id, parent_id, name, version, sync_ts, false);
385 ret->set_originator_cache_guid(originator_cache_guid);
386 ret->set_originator_client_item_id(originator_client_item_id);
387 return ret;
388 }
389
AddUpdateFromLastCommit()390 sync_pb::SyncEntity* MockConnectionManager::AddUpdateFromLastCommit() {
391 EXPECT_EQ(1, last_sent_commit().entries_size());
392 EXPECT_EQ(1, last_commit_response().entryresponse_size());
393 EXPECT_EQ(CommitResponse::SUCCESS,
394 last_commit_response().entryresponse(0).response_type());
395
396 if (last_sent_commit().entries(0).deleted()) {
397 AddUpdateTombstone(syncable::Id::CreateFromServerId(
398 last_sent_commit().entries(0).id_string()));
399 } else {
400 sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
401 ent->CopyFrom(last_sent_commit().entries(0));
402 ent->clear_insert_after_item_id();
403 ent->clear_old_parent_id();
404 ent->set_position_in_parent(
405 last_commit_response().entryresponse(0).position_in_parent());
406 ent->set_version(
407 last_commit_response().entryresponse(0).version());
408 ent->set_id_string(
409 last_commit_response().entryresponse(0).id_string());
410
411 // This is the same hack as in AddUpdateMeta. See the comment in that
412 // function for more information.
413 ent->set_originator_cache_guid(kCacheGuid);
414 ent->set_originator_client_item_id(
415 last_commit_response().entryresponse(0).id_string());
416
417 if (last_sent_commit().entries(0).has_unique_position()) {
418 ent->mutable_unique_position()->CopyFrom(
419 last_sent_commit().entries(0).unique_position());
420 }
421
422 // Tests don't currently care about the following:
423 // parent_id_string, name, non_unique_name.
424 }
425 return GetMutableLastUpdate();
426 }
427
AddUpdateTombstone(const syncable::Id & id)428 void MockConnectionManager::AddUpdateTombstone(const syncable::Id& id) {
429 // Tombstones have only the ID set and dummy values for the required fields.
430 sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
431 ent->set_id_string(id.GetServerId());
432 ent->set_version(0);
433 ent->set_name("");
434 ent->set_deleted(true);
435
436 // Make sure we can still extract the ModelType from this tombstone.
437 ent->mutable_specifics()->mutable_bookmark();
438 }
439
SetLastUpdateDeleted()440 void MockConnectionManager::SetLastUpdateDeleted() {
441 // Tombstones have only the ID set. Wipe anything else.
442 string id_string = GetMutableLastUpdate()->id_string();
443 GetUpdateResponse()->mutable_entries()->RemoveLast();
444 AddUpdateTombstone(syncable::Id::CreateFromServerId(id_string));
445 }
446
SetLastUpdateOriginatorFields(const string & client_id,const string & entry_id)447 void MockConnectionManager::SetLastUpdateOriginatorFields(
448 const string& client_id,
449 const string& entry_id) {
450 GetMutableLastUpdate()->set_originator_cache_guid(client_id);
451 GetMutableLastUpdate()->set_originator_client_item_id(entry_id);
452 }
453
SetLastUpdateServerTag(const string & tag)454 void MockConnectionManager::SetLastUpdateServerTag(const string& tag) {
455 GetMutableLastUpdate()->set_server_defined_unique_tag(tag);
456 }
457
SetLastUpdateClientTag(const string & tag)458 void MockConnectionManager::SetLastUpdateClientTag(const string& tag) {
459 GetMutableLastUpdate()->set_client_defined_unique_tag(tag);
460 }
461
SetLastUpdatePosition(int64 server_position)462 void MockConnectionManager::SetLastUpdatePosition(int64 server_position) {
463 GetMutableLastUpdate()->set_position_in_parent(server_position);
464 }
465
SetNewTimestamp(int ts)466 void MockConnectionManager::SetNewTimestamp(int ts) {
467 next_token_ = base::StringPrintf("mock connection ts = %d", ts);
468 ApplyToken();
469 }
470
ApplyToken()471 void MockConnectionManager::ApplyToken() {
472 if (!update_queue_.empty()) {
473 GetUpdateResponse()->clear_new_progress_marker();
474 sync_pb::DataTypeProgressMarker* new_marker =
475 GetUpdateResponse()->add_new_progress_marker();
476 new_marker->set_data_type_id(-1); // Invalid -- clients shouldn't see.
477 new_marker->set_token(next_token_);
478 }
479 }
480
SetChangesRemaining(int64 timestamp)481 void MockConnectionManager::SetChangesRemaining(int64 timestamp) {
482 GetUpdateResponse()->set_changes_remaining(timestamp);
483 }
484
ProcessGetUpdates(sync_pb::ClientToServerMessage * csm,sync_pb::ClientToServerResponse * response)485 void MockConnectionManager::ProcessGetUpdates(
486 sync_pb::ClientToServerMessage* csm,
487 sync_pb::ClientToServerResponse* response) {
488 CHECK(csm->has_get_updates());
489 ASSERT_EQ(csm->message_contents(), ClientToServerMessage::GET_UPDATES);
490 const GetUpdatesMessage& gu = csm->get_updates();
491 num_get_updates_requests_++;
492 EXPECT_FALSE(gu.has_from_timestamp());
493 EXPECT_FALSE(gu.has_requested_types());
494
495 if (fail_non_periodic_get_updates_) {
496 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC,
497 gu.caller_info().source());
498 }
499
500 // Verify that the items we're about to send back to the client are of
501 // the types requested by the client. If this fails, it probably indicates
502 // a test bug.
503 EXPECT_TRUE(gu.fetch_folders());
504 EXPECT_FALSE(gu.has_requested_types());
505 if (update_queue_.empty()) {
506 GetUpdateResponse();
507 }
508 sync_pb::GetUpdatesResponse* updates = &update_queue_.front();
509 for (int i = 0; i < updates->entries_size(); ++i) {
510 if (!updates->entries(i).deleted()) {
511 ModelType entry_type = GetModelType(updates->entries(i));
512 EXPECT_TRUE(
513 IsModelTypePresentInSpecifics(gu.from_progress_marker(), entry_type))
514 << "Syncer did not request updates being provided by the test.";
515 }
516 }
517
518 response->mutable_get_updates()->CopyFrom(*updates);
519
520 // Set appropriate progress markers, overriding the value squirreled
521 // away by ApplyToken().
522 std::string token = response->get_updates().new_progress_marker(0).token();
523 response->mutable_get_updates()->clear_new_progress_marker();
524 for (int i = 0; i < gu.from_progress_marker_size(); ++i) {
525 sync_pb::DataTypeProgressMarker* new_marker =
526 response->mutable_get_updates()->add_new_progress_marker();
527 new_marker->set_data_type_id(gu.from_progress_marker(i).data_type_id());
528 new_marker->set_token(token);
529 }
530
531 // Fill the keystore key if requested.
532 if (gu.need_encryption_key())
533 response->mutable_get_updates()->add_encryption_keys(keystore_key_);
534
535 update_queue_.pop_front();
536
537 if (gu_client_command_) {
538 response->mutable_client_command()->CopyFrom(*gu_client_command_.get());
539 }
540 }
541
SetKeystoreKey(const std::string & key)542 void MockConnectionManager::SetKeystoreKey(const std::string& key) {
543 // Note: this is not a thread-safe set, ok for now. NOT ok if tests
544 // run the syncer on the background thread while this method is called.
545 keystore_key_ = key;
546 }
547
ShouldConflictThisCommit()548 bool MockConnectionManager::ShouldConflictThisCommit() {
549 bool conflict = false;
550 if (conflict_all_commits_) {
551 conflict = true;
552 } else if (conflict_n_commits_ > 0) {
553 conflict = true;
554 --conflict_n_commits_;
555 }
556 return conflict;
557 }
558
ShouldTransientErrorThisId(syncable::Id id)559 bool MockConnectionManager::ShouldTransientErrorThisId(syncable::Id id) {
560 return find(transient_error_ids_.begin(), transient_error_ids_.end(), id)
561 != transient_error_ids_.end();
562 }
563
ProcessCommit(sync_pb::ClientToServerMessage * csm,sync_pb::ClientToServerResponse * response_buffer)564 void MockConnectionManager::ProcessCommit(
565 sync_pb::ClientToServerMessage* csm,
566 sync_pb::ClientToServerResponse* response_buffer) {
567 CHECK(csm->has_commit());
568 ASSERT_EQ(csm->message_contents(), ClientToServerMessage::COMMIT);
569 map <string, string> changed_ids;
570 const CommitMessage& commit_message = csm->commit();
571 CommitResponse* commit_response = response_buffer->mutable_commit();
572 commit_messages_.push_back(new CommitMessage);
573 commit_messages_.back()->CopyFrom(commit_message);
574 map<string, sync_pb::CommitResponse_EntryResponse*> response_map;
575 for (int i = 0; i < commit_message.entries_size() ; i++) {
576 const sync_pb::SyncEntity& entry = commit_message.entries(i);
577 CHECK(entry.has_id_string());
578 string id_string = entry.id_string();
579 ASSERT_LT(entry.name().length(), 256ul) << " name probably too long. True "
580 "server name checking not implemented";
581 syncable::Id id;
582 if (entry.version() == 0) {
583 // Relies on our new item string id format. (string representation of a
584 // negative number).
585 id = syncable::Id::CreateFromClientString(id_string);
586 } else {
587 id = syncable::Id::CreateFromServerId(id_string);
588 }
589 committed_ids_.push_back(id);
590
591 if (response_map.end() == response_map.find(id_string))
592 response_map[id_string] = commit_response->add_entryresponse();
593 sync_pb::CommitResponse_EntryResponse* er = response_map[id_string];
594 if (ShouldConflictThisCommit()) {
595 er->set_response_type(CommitResponse::CONFLICT);
596 continue;
597 }
598 if (ShouldTransientErrorThisId(id)) {
599 er->set_response_type(CommitResponse::TRANSIENT_ERROR);
600 continue;
601 }
602 er->set_response_type(CommitResponse::SUCCESS);
603 er->set_version(entry.version() + 1);
604 if (!commit_time_rename_prepended_string_.empty()) {
605 // Commit time rename sent down from the server.
606 er->set_name(commit_time_rename_prepended_string_ + entry.name());
607 }
608 string parent_id_string = entry.parent_id_string();
609 // Remap id's we've already assigned.
610 if (changed_ids.end() != changed_ids.find(parent_id_string)) {
611 parent_id_string = changed_ids[parent_id_string];
612 er->set_parent_id_string(parent_id_string);
613 }
614 if (entry.has_version() && 0 != entry.version()) {
615 er->set_id_string(id_string); // Allows verification.
616 } else {
617 string new_id = base::StringPrintf("mock_server:%d", next_new_id_++);
618 changed_ids[id_string] = new_id;
619 er->set_id_string(new_id);
620 }
621 }
622 commit_responses_.push_back(new CommitResponse(*commit_response));
623
624 if (commit_client_command_) {
625 response_buffer->mutable_client_command()->CopyFrom(
626 *commit_client_command_.get());
627 }
628 }
629
AddUpdateDirectory(syncable::Id id,syncable::Id parent_id,string name,int64 version,int64 sync_ts,string originator_cache_guid,string originator_client_item_id)630 sync_pb::SyncEntity* MockConnectionManager::AddUpdateDirectory(
631 syncable::Id id,
632 syncable::Id parent_id,
633 string name,
634 int64 version,
635 int64 sync_ts,
636 string originator_cache_guid,
637 string originator_client_item_id) {
638 return AddUpdateDirectory(id.GetServerId(), parent_id.GetServerId(),
639 name, version, sync_ts, originator_cache_guid,
640 originator_client_item_id);
641 }
642
AddUpdateBookmark(syncable::Id id,syncable::Id parent_id,string name,int64 version,int64 sync_ts,string originator_cache_guid,string originator_client_item_id)643 sync_pb::SyncEntity* MockConnectionManager::AddUpdateBookmark(
644 syncable::Id id,
645 syncable::Id parent_id,
646 string name,
647 int64 version,
648 int64 sync_ts,
649 string originator_cache_guid,
650 string originator_client_item_id) {
651 return AddUpdateBookmark(id.GetServerId(), parent_id.GetServerId(),
652 name, version, sync_ts, originator_cache_guid,
653 originator_client_item_id);
654 }
655
GetMutableLastUpdate()656 sync_pb::SyncEntity* MockConnectionManager::GetMutableLastUpdate() {
657 sync_pb::GetUpdatesResponse* updates = GetUpdateResponse();
658 EXPECT_GT(updates->entries_size(), 0);
659 return updates->mutable_entries()->Mutable(updates->entries_size() - 1);
660 }
661
NextUpdateBatch()662 void MockConnectionManager::NextUpdateBatch() {
663 update_queue_.push_back(sync_pb::GetUpdatesResponse::default_instance());
664 SetChangesRemaining(0);
665 ApplyToken();
666 }
667
last_sent_commit() const668 const CommitMessage& MockConnectionManager::last_sent_commit() const {
669 EXPECT_TRUE(!commit_messages_.empty());
670 return *commit_messages_.back();
671 }
672
last_commit_response() const673 const CommitResponse& MockConnectionManager::last_commit_response() const {
674 EXPECT_TRUE(!commit_responses_.empty());
675 return *commit_responses_.back();
676 }
677
678 const sync_pb::ClientToServerMessage&
last_request() const679 MockConnectionManager::last_request() const {
680 EXPECT_TRUE(!requests_.empty());
681 return requests_.back();
682 }
683
684 const std::vector<sync_pb::ClientToServerMessage>&
requests() const685 MockConnectionManager::requests() const {
686 return requests_;
687 }
688
IsModelTypePresentInSpecifics(const google::protobuf::RepeatedPtrField<sync_pb::DataTypeProgressMarker> & filter,ModelType value)689 bool MockConnectionManager::IsModelTypePresentInSpecifics(
690 const google::protobuf::RepeatedPtrField<
691 sync_pb::DataTypeProgressMarker>& filter,
692 ModelType value) {
693 int data_type_id = GetSpecificsFieldNumberFromModelType(value);
694 for (int i = 0; i < filter.size(); ++i) {
695 if (filter.Get(i).data_type_id() == data_type_id) {
696 return true;
697 }
698 }
699 return false;
700 }
701
702 sync_pb::DataTypeProgressMarker const*
GetProgressMarkerForType(const google::protobuf::RepeatedPtrField<sync_pb::DataTypeProgressMarker> & filter,ModelType value)703 MockConnectionManager::GetProgressMarkerForType(
704 const google::protobuf::RepeatedPtrField<
705 sync_pb::DataTypeProgressMarker>& filter,
706 ModelType value) {
707 int data_type_id = GetSpecificsFieldNumberFromModelType(value);
708 for (int i = 0; i < filter.size(); ++i) {
709 if (filter.Get(i).data_type_id() == data_type_id) {
710 return &(filter.Get(i));
711 }
712 }
713 return NULL;
714 }
715
SetServerReachable()716 void MockConnectionManager::SetServerReachable() {
717 server_reachable_ = true;
718 }
719
SetServerNotReachable()720 void MockConnectionManager::SetServerNotReachable() {
721 server_reachable_ = false;
722 }
723
UpdateConnectionStatus()724 void MockConnectionManager::UpdateConnectionStatus() {
725 if (!server_reachable_) {
726 server_status_ = HttpResponse::CONNECTION_UNAVAILABLE;
727 } else {
728 server_status_ = HttpResponse::SERVER_CONNECTION_OK;
729 }
730 }
731
SetServerStatus(HttpResponse::ServerConnectionCode server_status)732 void MockConnectionManager::SetServerStatus(
733 HttpResponse::ServerConnectionCode server_status) {
734 server_status_ = server_status;
735 }
736
737 } // namespace syncer
738