root/sync/test/engine/mock_connection_manager.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. num_get_updates_requests_
  2. SetCommitTimeRename
  3. SetMidCommitCallback
  4. SetMidCommitObserver
  5. PostBufferToPath
  6. GetUpdateResponse
  7. AddDefaultBookmarkData
  8. AddUpdateDirectory
  9. SetGUClientCommand
  10. SetCommitClientCommand
  11. SetTransientErrorId
  12. AddUpdateBookmark
  13. AddUpdateSpecifics
  14. AddUpdateSpecifics
  15. SetNigori
  16. AddUpdatePref
  17. AddUpdateFull
  18. AddUpdateMeta
  19. AddUpdateDirectory
  20. AddUpdateBookmark
  21. AddUpdateFromLastCommit
  22. AddUpdateTombstone
  23. SetLastUpdateDeleted
  24. SetLastUpdateOriginatorFields
  25. SetLastUpdateServerTag
  26. SetLastUpdateClientTag
  27. SetLastUpdatePosition
  28. SetNewTimestamp
  29. ApplyToken
  30. SetChangesRemaining
  31. ProcessGetUpdates
  32. SetKeystoreKey
  33. ShouldConflictThisCommit
  34. ShouldTransientErrorThisId
  35. ProcessCommit
  36. AddUpdateDirectory
  37. AddUpdateBookmark
  38. GetMutableLastUpdate
  39. NextUpdateBatch
  40. last_sent_commit
  41. last_commit_response
  42. last_request
  43. requests
  44. IsModelTypePresentInSpecifics
  45. GetProgressMarkerForType
  46. SetServerReachable
  47. SetServerNotReachable
  48. UpdateConnectionStatus
  49. SetServerStatus

// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Mock ServerConnectionManager class for use in client regression tests.

#include "sync/test/engine/mock_connection_manager.h"

#include <map>

#include "base/location.h"
#include "base/strings/stringprintf.h"
#include "sync/engine/syncer_proto_util.h"
#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/syncable_write_transaction.h"
#include "sync/test/engine/test_id_factory.h"
#include "testing/gtest/include/gtest/gtest.h"

using std::find;
using std::map;
using std::string;
using sync_pb::ClientToServerMessage;
using sync_pb::CommitMessage;
using sync_pb::CommitResponse;
using sync_pb::GetUpdatesMessage;
using sync_pb::SyncEnums;

namespace syncer {

using syncable::WriteTransaction;

static char kValidAuthToken[] = "AuthToken";
static char kCacheGuid[] = "kqyg7097kro6GSUod+GSg==";

MockConnectionManager::MockConnectionManager(syncable::Directory* directory,
                                             CancelationSignal* signal)
    : ServerConnectionManager("unused", 0, false, signal),
      server_reachable_(true),
      conflict_all_commits_(false),
      conflict_n_commits_(0),
      next_new_id_(10000),
      store_birthday_("Store BDay!"),
      store_birthday_sent_(false),
      client_stuck_(false),
      countdown_to_postbuffer_fail_(0),
      directory_(directory),
      mid_commit_observer_(NULL),
      throttling_(false),
      fail_with_auth_invalid_(false),
      fail_non_periodic_get_updates_(false),
      next_position_in_parent_(2),
      use_legacy_bookmarks_protocol_(false),
      num_get_updates_requests_(0) {
  SetNewTimestamp(0);
  SetAuthToken(kValidAuthToken);
}

MockConnectionManager::~MockConnectionManager() {
  EXPECT_TRUE(update_queue_.empty()) << "Unfetched updates.";
}

void MockConnectionManager::SetCommitTimeRename(string prepend) {
  commit_time_rename_prepended_string_ = prepend;
}

void MockConnectionManager::SetMidCommitCallback(
    const base::Closure& callback) {
  mid_commit_callback_ = callback;
}

void MockConnectionManager::SetMidCommitObserver(
    MockConnectionManager::MidCommitObserver* observer) {
    mid_commit_observer_ = observer;
}

bool MockConnectionManager::PostBufferToPath(PostBufferParams* params,
    const string& path,
    const string& auth_token,
    ScopedServerStatusWatcher* watcher) {
  ClientToServerMessage post;
  CHECK(post.ParseFromString(params->buffer_in));
  CHECK(post.has_protocol_version());
  CHECK(post.has_api_key());
  CHECK(post.has_bag_of_chips());

  requests_.push_back(post);
  client_stuck_ = post.sync_problem_detected();
  sync_pb::ClientToServerResponse response;
  response.Clear();

  if (directory_) {
    // If the Directory's locked when we do this, it's a problem as in normal
    // use this function could take a while to return because it accesses the
    // network. As we can't test this we do the next best thing and hang here
    // when there's an issue.
    CHECK(directory_->good());
    WriteTransaction wt(FROM_HERE, syncable::UNITTEST, directory_);
  }

  if (auth_token.empty()) {
    params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
    return false;
  }

  if (auth_token != kValidAuthToken) {
    // Simulate server-side auth failure.
    params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
    InvalidateAndClearAuthToken();
  }

  if (--countdown_to_postbuffer_fail_ == 0) {
    // Fail as countdown hits zero.
    params->response.server_status = HttpResponse::SYNC_SERVER_ERROR;
    return false;
  }

  if (!server_reachable_) {
    params->response.server_status = HttpResponse::CONNECTION_UNAVAILABLE;
    return false;
  }

  // Default to an ok connection.
  params->response.server_status = HttpResponse::SERVER_CONNECTION_OK;
  response.set_error_code(SyncEnums::SUCCESS);
  const string current_store_birthday = store_birthday();
  response.set_store_birthday(current_store_birthday);
  if (post.has_store_birthday() && post.store_birthday() !=
      current_store_birthday) {
    response.set_error_code(SyncEnums::NOT_MY_BIRTHDAY);
    response.set_error_message("Merry Unbirthday!");
    response.SerializeToString(&params->buffer_out);
    store_birthday_sent_ = true;
    return true;
  }
  bool result = true;
  EXPECT_TRUE(!store_birthday_sent_ || post.has_store_birthday() ||
              post.message_contents() == ClientToServerMessage::AUTHENTICATE);
  store_birthday_sent_ = true;

  if (post.message_contents() == ClientToServerMessage::COMMIT) {
    ProcessCommit(&post, &response);
  } else if (post.message_contents() == ClientToServerMessage::GET_UPDATES) {
    ProcessGetUpdates(&post, &response);
  } else {
    EXPECT_TRUE(false) << "Unknown/unsupported ClientToServerMessage";
    return false;
  }

  {
    base::AutoLock lock(response_code_override_lock_);
    if (throttling_) {
      response.set_error_code(SyncEnums::THROTTLED);
      throttling_ = false;
    }

    if (fail_with_auth_invalid_)
      response.set_error_code(SyncEnums::AUTH_INVALID);
  }

  response.SerializeToString(&params->buffer_out);
  if (post.message_contents() == ClientToServerMessage::COMMIT &&
      !mid_commit_callback_.is_null()) {
    mid_commit_callback_.Run();
    mid_commit_callback_.Reset();
  }
  if (mid_commit_observer_) {
    mid_commit_observer_->Observe();
  }

  return result;
}

sync_pb::GetUpdatesResponse* MockConnectionManager::GetUpdateResponse() {
  if (update_queue_.empty()) {
    NextUpdateBatch();
  }
  return &update_queue_.back();
}

void MockConnectionManager::AddDefaultBookmarkData(sync_pb::SyncEntity* entity,
                                                   bool is_folder) {
  if (use_legacy_bookmarks_protocol_) {
    sync_pb::SyncEntity_BookmarkData* data = entity->mutable_bookmarkdata();
    data->set_bookmark_folder(is_folder);

    if (!is_folder) {
      data->set_bookmark_url("http://google.com");
    }
  } else {
    entity->set_folder(is_folder);
    entity->mutable_specifics()->mutable_bookmark();
    if (!is_folder) {
      entity->mutable_specifics()->mutable_bookmark()->
          set_url("http://google.com");
    }
  }
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateDirectory(
    int id,
    int parent_id,
    string name,
    int64 version,
    int64 sync_ts,
    std::string originator_cache_guid,
    std::string originator_client_item_id) {
  return AddUpdateDirectory(TestIdFactory::FromNumber(id),
                            TestIdFactory::FromNumber(parent_id),
                            name,
                            version,
                            sync_ts,
                            originator_cache_guid,
                            originator_client_item_id);
}

void MockConnectionManager::SetGUClientCommand(
    sync_pb::ClientCommand* command) {
  gu_client_command_.reset(command);
}

void MockConnectionManager::SetCommitClientCommand(
    sync_pb::ClientCommand* command) {
  commit_client_command_.reset(command);
}

void MockConnectionManager::SetTransientErrorId(syncable::Id id) {
  transient_error_ids_.push_back(id);
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateBookmark(
    int id, int parent_id,
    string name, int64 version,
    int64 sync_ts,
    string originator_client_item_id,
    string originator_cache_guid) {
  return AddUpdateBookmark(TestIdFactory::FromNumber(id),
                           TestIdFactory::FromNumber(parent_id),
                           name,
                           version,
                           sync_ts,
                           originator_client_item_id,
                           originator_cache_guid);
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateSpecifics(
    int id,
    int parent_id,
    string name,
    int64 version,
    int64 sync_ts,
    bool is_dir,
    int64 position,
    const sync_pb::EntitySpecifics& specifics) {
  sync_pb::SyncEntity* ent = AddUpdateMeta(
      TestIdFactory::FromNumber(id).GetServerId(),
      TestIdFactory::FromNumber(parent_id).GetServerId(),
      name, version, sync_ts);
  ent->set_position_in_parent(position);
  ent->mutable_specifics()->CopyFrom(specifics);
  ent->set_folder(is_dir);
  return ent;
}

sync_pb::SyncEntity* MockConnectionManager::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) {
  sync_pb::SyncEntity* ent = AddUpdateSpecifics(
      id, parent_id, name, version, sync_ts, is_dir, position, specifics);
  ent->set_originator_cache_guid(originator_cache_guid);
  ent->set_originator_client_item_id(originator_client_item_id);
  return ent;
}

sync_pb::SyncEntity* MockConnectionManager::SetNigori(
    int id,
    int64 version,
    int64 sync_ts,
    const sync_pb::EntitySpecifics& specifics) {
  sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
  ent->set_id_string(TestIdFactory::FromNumber(id).GetServerId());
  ent->set_parent_id_string(TestIdFactory::FromNumber(0).GetServerId());
  ent->set_server_defined_unique_tag(ModelTypeToRootTag(NIGORI));
  ent->set_name("Nigori");
  ent->set_non_unique_name("Nigori");
  ent->set_version(version);
  ent->set_sync_timestamp(sync_ts);
  ent->set_mtime(sync_ts);
  ent->set_ctime(1);
  ent->set_position_in_parent(0);
  ent->set_folder(false);
  ent->mutable_specifics()->CopyFrom(specifics);
  return ent;
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdatePref(string id,
                                                          string parent_id,
                                                          string client_tag,
                                                          int64 version,
                                                          int64 sync_ts) {
  sync_pb::SyncEntity* ent =
      AddUpdateMeta(id, parent_id, " ", version, sync_ts);

  ent->set_client_defined_unique_tag(client_tag);

  sync_pb::EntitySpecifics specifics;
  AddDefaultFieldValue(PREFERENCES, &specifics);
  ent->mutable_specifics()->CopyFrom(specifics);

  return ent;
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateFull(
    string id, string parent_id,
    string name, int64 version,
    int64 sync_ts, bool is_dir) {
  sync_pb::SyncEntity* ent =
      AddUpdateMeta(id, parent_id, name, version, sync_ts);
  AddDefaultBookmarkData(ent, is_dir);
  return ent;
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateMeta(
    string id, string parent_id,
    string name, int64 version,
    int64 sync_ts) {
  sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
  ent->set_id_string(id);
  ent->set_parent_id_string(parent_id);
  ent->set_non_unique_name(name);
  ent->set_name(name);
  ent->set_version(version);
  ent->set_sync_timestamp(sync_ts);
  ent->set_mtime(sync_ts);
  ent->set_ctime(1);
  ent->set_position_in_parent(GeneratePositionInParent());

  // This isn't perfect, but it works well enough.  This is an update, which
  // means the ID is a server ID, which means it never changes.  By making
  // kCacheGuid also never change, we guarantee that the same item always has
  // the same originator_cache_guid and originator_client_item_id.
  //
  // Unfortunately, neither this class nor the tests that use it explicitly
  // track sync entitites, so supporting proper cache guids and client item IDs
  // would require major refactoring.  The ID used here ought to be the "c-"
  // style ID that was sent up on the commit.
  ent->set_originator_cache_guid(kCacheGuid);
  ent->set_originator_client_item_id(id);

  return ent;
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateDirectory(
    string id,
    string parent_id,
    string name,
    int64 version,
    int64 sync_ts,
    std::string originator_cache_guid,
    std::string originator_client_item_id) {
  sync_pb::SyncEntity* ret =
      AddUpdateFull(id, parent_id, name, version, sync_ts, true);
  ret->set_originator_cache_guid(originator_cache_guid);
  ret->set_originator_client_item_id(originator_client_item_id);
  return ret;
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateBookmark(
    string id,
    string parent_id,
    string name, int64 version,
    int64 sync_ts,
    string originator_cache_guid,
    string originator_client_item_id) {
  sync_pb::SyncEntity* ret =
      AddUpdateFull(id, parent_id, name, version, sync_ts, false);
  ret->set_originator_cache_guid(originator_cache_guid);
  ret->set_originator_client_item_id(originator_client_item_id);
  return ret;
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateFromLastCommit() {
  EXPECT_EQ(1, last_sent_commit().entries_size());
  EXPECT_EQ(1, last_commit_response().entryresponse_size());
  EXPECT_EQ(CommitResponse::SUCCESS,
      last_commit_response().entryresponse(0).response_type());

  if (last_sent_commit().entries(0).deleted()) {
    AddUpdateTombstone(syncable::Id::CreateFromServerId(
        last_sent_commit().entries(0).id_string()));
  } else {
    sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
    ent->CopyFrom(last_sent_commit().entries(0));
    ent->clear_insert_after_item_id();
    ent->clear_old_parent_id();
    ent->set_position_in_parent(
        last_commit_response().entryresponse(0).position_in_parent());
    ent->set_version(
        last_commit_response().entryresponse(0).version());
    ent->set_id_string(
        last_commit_response().entryresponse(0).id_string());

    // This is the same hack as in AddUpdateMeta.  See the comment in that
    // function for more information.
    ent->set_originator_cache_guid(kCacheGuid);
    ent->set_originator_client_item_id(
        last_commit_response().entryresponse(0).id_string());

    if (last_sent_commit().entries(0).has_unique_position()) {
      ent->mutable_unique_position()->CopyFrom(
          last_sent_commit().entries(0).unique_position());
    }

    // Tests don't currently care about the following:
    // parent_id_string, name, non_unique_name.
  }
  return GetMutableLastUpdate();
}

void MockConnectionManager::AddUpdateTombstone(const syncable::Id& id) {
  // Tombstones have only the ID set and dummy values for the required fields.
  sync_pb::SyncEntity* ent = GetUpdateResponse()->add_entries();
  ent->set_id_string(id.GetServerId());
  ent->set_version(0);
  ent->set_name("");
  ent->set_deleted(true);

  // Make sure we can still extract the ModelType from this tombstone.
  ent->mutable_specifics()->mutable_bookmark();
}

void MockConnectionManager::SetLastUpdateDeleted() {
  // Tombstones have only the ID set.  Wipe anything else.
  string id_string = GetMutableLastUpdate()->id_string();
  GetUpdateResponse()->mutable_entries()->RemoveLast();
  AddUpdateTombstone(syncable::Id::CreateFromServerId(id_string));
}

void MockConnectionManager::SetLastUpdateOriginatorFields(
    const string& client_id,
    const string& entry_id) {
  GetMutableLastUpdate()->set_originator_cache_guid(client_id);
  GetMutableLastUpdate()->set_originator_client_item_id(entry_id);
}

void MockConnectionManager::SetLastUpdateServerTag(const string& tag) {
  GetMutableLastUpdate()->set_server_defined_unique_tag(tag);
}

void MockConnectionManager::SetLastUpdateClientTag(const string& tag) {
  GetMutableLastUpdate()->set_client_defined_unique_tag(tag);
}

void MockConnectionManager::SetLastUpdatePosition(int64 server_position) {
  GetMutableLastUpdate()->set_position_in_parent(server_position);
}

void MockConnectionManager::SetNewTimestamp(int ts) {
  next_token_ = base::StringPrintf("mock connection ts = %d", ts);
  ApplyToken();
}

void MockConnectionManager::ApplyToken() {
  if (!update_queue_.empty()) {
    GetUpdateResponse()->clear_new_progress_marker();
    sync_pb::DataTypeProgressMarker* new_marker =
        GetUpdateResponse()->add_new_progress_marker();
    new_marker->set_data_type_id(-1);  // Invalid -- clients shouldn't see.
    new_marker->set_token(next_token_);
  }
}

void MockConnectionManager::SetChangesRemaining(int64 timestamp) {
  GetUpdateResponse()->set_changes_remaining(timestamp);
}

void MockConnectionManager::ProcessGetUpdates(
    sync_pb::ClientToServerMessage* csm,
    sync_pb::ClientToServerResponse* response) {
  CHECK(csm->has_get_updates());
  ASSERT_EQ(csm->message_contents(), ClientToServerMessage::GET_UPDATES);
  const GetUpdatesMessage& gu = csm->get_updates();
  num_get_updates_requests_++;
  EXPECT_FALSE(gu.has_from_timestamp());
  EXPECT_FALSE(gu.has_requested_types());

  if (fail_non_periodic_get_updates_) {
    EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC,
              gu.caller_info().source());
  }

  // Verify that the items we're about to send back to the client are of
  // the types requested by the client.  If this fails, it probably indicates
  // a test bug.
  EXPECT_TRUE(gu.fetch_folders());
  EXPECT_FALSE(gu.has_requested_types());
  if (update_queue_.empty()) {
    GetUpdateResponse();
  }
  sync_pb::GetUpdatesResponse* updates = &update_queue_.front();
  for (int i = 0; i < updates->entries_size(); ++i) {
    if (!updates->entries(i).deleted()) {
      ModelType entry_type = GetModelType(updates->entries(i));
      EXPECT_TRUE(
          IsModelTypePresentInSpecifics(gu.from_progress_marker(), entry_type))
          << "Syncer did not request updates being provided by the test.";
    }
  }

  response->mutable_get_updates()->CopyFrom(*updates);

  // Set appropriate progress markers, overriding the value squirreled
  // away by ApplyToken().
  std::string token = response->get_updates().new_progress_marker(0).token();
  response->mutable_get_updates()->clear_new_progress_marker();
  for (int i = 0; i < gu.from_progress_marker_size(); ++i) {
    sync_pb::DataTypeProgressMarker* new_marker =
        response->mutable_get_updates()->add_new_progress_marker();
    new_marker->set_data_type_id(gu.from_progress_marker(i).data_type_id());
    new_marker->set_token(token);
  }

  // Fill the keystore key if requested.
  if (gu.need_encryption_key())
    response->mutable_get_updates()->add_encryption_keys(keystore_key_);

  update_queue_.pop_front();

  if (gu_client_command_) {
    response->mutable_client_command()->CopyFrom(*gu_client_command_.get());
  }
}

void MockConnectionManager::SetKeystoreKey(const std::string& key) {
  // Note: this is not a thread-safe set, ok for now.  NOT ok if tests
  // run the syncer on the background thread while this method is called.
  keystore_key_ = key;
}

bool MockConnectionManager::ShouldConflictThisCommit() {
  bool conflict = false;
  if (conflict_all_commits_) {
    conflict = true;
  } else if (conflict_n_commits_ > 0) {
    conflict = true;
    --conflict_n_commits_;
  }
  return conflict;
}

bool MockConnectionManager::ShouldTransientErrorThisId(syncable::Id id) {
  return find(transient_error_ids_.begin(), transient_error_ids_.end(), id)
      != transient_error_ids_.end();
}

void MockConnectionManager::ProcessCommit(
    sync_pb::ClientToServerMessage* csm,
    sync_pb::ClientToServerResponse* response_buffer) {
  CHECK(csm->has_commit());
  ASSERT_EQ(csm->message_contents(), ClientToServerMessage::COMMIT);
  map <string, string> changed_ids;
  const CommitMessage& commit_message = csm->commit();
  CommitResponse* commit_response = response_buffer->mutable_commit();
  commit_messages_.push_back(new CommitMessage);
  commit_messages_.back()->CopyFrom(commit_message);
  map<string, sync_pb::CommitResponse_EntryResponse*> response_map;
  for (int i = 0; i < commit_message.entries_size() ; i++) {
    const sync_pb::SyncEntity& entry = commit_message.entries(i);
    CHECK(entry.has_id_string());
    string id_string = entry.id_string();
    ASSERT_LT(entry.name().length(), 256ul) << " name probably too long. True "
        "server name checking not implemented";
    syncable::Id id;
    if (entry.version() == 0) {
      // Relies on our new item string id format. (string representation of a
      // negative number).
      id = syncable::Id::CreateFromClientString(id_string);
    } else {
      id = syncable::Id::CreateFromServerId(id_string);
    }
    committed_ids_.push_back(id);

    if (response_map.end() == response_map.find(id_string))
      response_map[id_string] = commit_response->add_entryresponse();
    sync_pb::CommitResponse_EntryResponse* er = response_map[id_string];
    if (ShouldConflictThisCommit()) {
      er->set_response_type(CommitResponse::CONFLICT);
      continue;
    }
    if (ShouldTransientErrorThisId(id)) {
      er->set_response_type(CommitResponse::TRANSIENT_ERROR);
      continue;
    }
    er->set_response_type(CommitResponse::SUCCESS);
    er->set_version(entry.version() + 1);
    if (!commit_time_rename_prepended_string_.empty()) {
      // Commit time rename sent down from the server.
      er->set_name(commit_time_rename_prepended_string_ + entry.name());
    }
    string parent_id_string = entry.parent_id_string();
    // Remap id's we've already assigned.
    if (changed_ids.end() != changed_ids.find(parent_id_string)) {
      parent_id_string = changed_ids[parent_id_string];
      er->set_parent_id_string(parent_id_string);
    }
    if (entry.has_version() && 0 != entry.version()) {
      er->set_id_string(id_string);  // Allows verification.
    } else {
      string new_id = base::StringPrintf("mock_server:%d", next_new_id_++);
      changed_ids[id_string] = new_id;
      er->set_id_string(new_id);
    }
  }
  commit_responses_.push_back(new CommitResponse(*commit_response));

  if (commit_client_command_) {
    response_buffer->mutable_client_command()->CopyFrom(
        *commit_client_command_.get());
  }
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateDirectory(
    syncable::Id id,
    syncable::Id parent_id,
    string name,
    int64 version,
    int64 sync_ts,
    string originator_cache_guid,
    string originator_client_item_id) {
  return AddUpdateDirectory(id.GetServerId(), parent_id.GetServerId(),
                            name, version, sync_ts, originator_cache_guid,
                            originator_client_item_id);
}

sync_pb::SyncEntity* MockConnectionManager::AddUpdateBookmark(
    syncable::Id id,
    syncable::Id parent_id,
    string name,
    int64 version,
    int64 sync_ts,
    string originator_cache_guid,
    string originator_client_item_id) {
  return AddUpdateBookmark(id.GetServerId(), parent_id.GetServerId(),
                           name, version, sync_ts, originator_cache_guid,
                           originator_client_item_id);
}

sync_pb::SyncEntity* MockConnectionManager::GetMutableLastUpdate() {
  sync_pb::GetUpdatesResponse* updates = GetUpdateResponse();
  EXPECT_GT(updates->entries_size(), 0);
  return updates->mutable_entries()->Mutable(updates->entries_size() - 1);
}

void MockConnectionManager::NextUpdateBatch() {
  update_queue_.push_back(sync_pb::GetUpdatesResponse::default_instance());
  SetChangesRemaining(0);
  ApplyToken();
}

const CommitMessage& MockConnectionManager::last_sent_commit() const {
  EXPECT_TRUE(!commit_messages_.empty());
  return *commit_messages_.back();
}

const CommitResponse& MockConnectionManager::last_commit_response() const {
  EXPECT_TRUE(!commit_responses_.empty());
  return *commit_responses_.back();
}

const sync_pb::ClientToServerMessage&
    MockConnectionManager::last_request() const {
  EXPECT_TRUE(!requests_.empty());
  return requests_.back();
}

const std::vector<sync_pb::ClientToServerMessage>&
    MockConnectionManager::requests() const {
  return requests_;
}

bool MockConnectionManager::IsModelTypePresentInSpecifics(
    const google::protobuf::RepeatedPtrField<
        sync_pb::DataTypeProgressMarker>& filter,
    ModelType value) {
  int data_type_id = GetSpecificsFieldNumberFromModelType(value);
  for (int i = 0; i < filter.size(); ++i) {
    if (filter.Get(i).data_type_id() == data_type_id) {
      return true;
    }
  }
  return false;
}

sync_pb::DataTypeProgressMarker const*
    MockConnectionManager::GetProgressMarkerForType(
        const google::protobuf::RepeatedPtrField<
            sync_pb::DataTypeProgressMarker>& filter,
        ModelType value) {
  int data_type_id = GetSpecificsFieldNumberFromModelType(value);
  for (int i = 0; i < filter.size(); ++i) {
    if (filter.Get(i).data_type_id() == data_type_id) {
      return &(filter.Get(i));
    }
  }
  return NULL;
}

void MockConnectionManager::SetServerReachable() {
  server_reachable_ = true;
}

void MockConnectionManager::SetServerNotReachable() {
  server_reachable_ = false;
}

void MockConnectionManager::UpdateConnectionStatus() {
  if (!server_reachable_) {
    server_status_ = HttpResponse::CONNECTION_UNAVAILABLE;
  } else {
    server_status_ = HttpResponse::SERVER_CONNECTION_OK;
  }
}

void MockConnectionManager::SetServerStatus(
    HttpResponse::ServerConnectionCode server_status) {
  server_status_ = server_status;
}

}  // namespace syncer

/* [<][>][^][v][top][bottom][index][help] */