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 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 59 MockConnectionManager::~MockConnectionManager() { 60 EXPECT_TRUE(update_queue_.empty()) << "Unfetched updates."; 61 } 62 63 void MockConnectionManager::SetCommitTimeRename(string prepend) { 64 commit_time_rename_prepended_string_ = prepend; 65 } 66 67 void MockConnectionManager::SetMidCommitCallback( 68 const base::Closure& callback) { 69 mid_commit_callback_ = callback; 70 } 71 72 void MockConnectionManager::SetMidCommitObserver( 73 MockConnectionManager::MidCommitObserver* observer) { 74 mid_commit_observer_ = observer; 75 } 76 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 174 sync_pb::GetUpdatesResponse* MockConnectionManager::GetUpdateResponse() { 175 if (update_queue_.empty()) { 176 NextUpdateBatch(); 177 } 178 return &update_queue_.back(); 179 } 180 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 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 217 void MockConnectionManager::SetGUClientCommand( 218 sync_pb::ClientCommand* command) { 219 gu_client_command_.reset(command); 220 } 221 222 void MockConnectionManager::SetCommitClientCommand( 223 sync_pb::ClientCommand* command) { 224 commit_client_command_.reset(command); 225 } 226 227 void MockConnectionManager::SetTransientErrorId(syncable::Id id) { 228 transient_error_ids_.push_back(id); 229 } 230 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 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 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 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 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 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 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 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 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 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 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 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 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 454 void MockConnectionManager::SetLastUpdateServerTag(const string& tag) { 455 GetMutableLastUpdate()->set_server_defined_unique_tag(tag); 456 } 457 458 void MockConnectionManager::SetLastUpdateClientTag(const string& tag) { 459 GetMutableLastUpdate()->set_client_defined_unique_tag(tag); 460 } 461 462 void MockConnectionManager::SetLastUpdatePosition(int64 server_position) { 463 GetMutableLastUpdate()->set_position_in_parent(server_position); 464 } 465 466 void MockConnectionManager::SetNewTimestamp(int ts) { 467 next_token_ = base::StringPrintf("mock connection ts = %d", ts); 468 ApplyToken(); 469 } 470 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 481 void MockConnectionManager::SetChangesRemaining(int64 timestamp) { 482 GetUpdateResponse()->set_changes_remaining(timestamp); 483 } 484 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 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 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 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 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 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 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 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 662 void MockConnectionManager::NextUpdateBatch() { 663 update_queue_.push_back(sync_pb::GetUpdatesResponse::default_instance()); 664 SetChangesRemaining(0); 665 ApplyToken(); 666 } 667 668 const CommitMessage& MockConnectionManager::last_sent_commit() const { 669 EXPECT_TRUE(!commit_messages_.empty()); 670 return *commit_messages_.back(); 671 } 672 673 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& 679 MockConnectionManager::last_request() const { 680 EXPECT_TRUE(!requests_.empty()); 681 return requests_.back(); 682 } 683 684 const std::vector<sync_pb::ClientToServerMessage>& 685 MockConnectionManager::requests() const { 686 return requests_; 687 } 688 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* 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 716 void MockConnectionManager::SetServerReachable() { 717 server_reachable_ = true; 718 } 719 720 void MockConnectionManager::SetServerNotReachable() { 721 server_reachable_ = false; 722 } 723 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 732 void MockConnectionManager::SetServerStatus( 733 HttpResponse::ServerConnectionCode server_status) { 734 server_status_ = server_status; 735 } 736 737 } // namespace syncer 738