| 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 |