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