| Index: sync/engine/model_type_processor_impl_unittest.cc
 | 
| diff --git a/sync/engine/model_type_processor_impl_unittest.cc b/sync/engine/model_type_processor_impl_unittest.cc
 | 
| deleted file mode 100644
 | 
| index 31fd29f3fe7fff6ea06703e3883801770ead71e2..0000000000000000000000000000000000000000
 | 
| --- a/sync/engine/model_type_processor_impl_unittest.cc
 | 
| +++ /dev/null
 | 
| @@ -1,706 +0,0 @@
 | 
| -// Copyright 2014 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.
 | 
| -
 | 
| -#include "sync/engine/model_type_processor_impl.h"
 | 
| -
 | 
| -#include "base/bind.h"
 | 
| -#include "base/message_loop/message_loop.h"
 | 
| -#include "sync/engine/commit_queue.h"
 | 
| -#include "sync/internal_api/public/activation_context.h"
 | 
| -#include "sync/internal_api/public/base/model_type.h"
 | 
| -#include "sync/internal_api/public/non_blocking_sync_common.h"
 | 
| -#include "sync/protocol/sync.pb.h"
 | 
| -#include "sync/syncable/syncable_util.h"
 | 
| -#include "sync/test/engine/mock_commit_queue.h"
 | 
| -#include "testing/gtest/include/gtest/gtest.h"
 | 
| -
 | 
| -namespace syncer_v2 {
 | 
| -
 | 
| -static const syncer::ModelType kModelType = syncer::PREFERENCES;
 | 
| -
 | 
| -// Tests the sync engine parts of ModelTypeProcessorImpl.
 | 
| -//
 | 
| -// The ModelTypeProcessorImpl contains a non-trivial amount of code dedicated
 | 
| -// to turning the sync engine on and off again.  That code is fairly well
 | 
| -// tested in the NonBlockingDataTypeController unit tests and it doesn't need
 | 
| -// to be re-tested here.
 | 
| -//
 | 
| -// These tests skip past initialization and focus on steady state sync engine
 | 
| -// behvior.  This is where we test how the type sync proxy responds to the
 | 
| -// model's requests to make changes to its data, the messages incoming from the
 | 
| -// sync server, and what happens when the two conflict.
 | 
| -//
 | 
| -// Inputs:
 | 
| -// - Initial state from permanent storage. (TODO)
 | 
| -// - Create, update or delete requests from the model.
 | 
| -// - Update responses and commit responses from the server.
 | 
| -//
 | 
| -// Outputs:
 | 
| -// - Writes to permanent storage. (TODO)
 | 
| -// - Callbacks into the model. (TODO)
 | 
| -// - Requests to the sync thread.  Tested with MockCommitQueue.
 | 
| -class ModelTypeProcessorImplTest : public ::testing::Test {
 | 
| - public:
 | 
| -  ModelTypeProcessorImplTest();
 | 
| -  ~ModelTypeProcessorImplTest() override;
 | 
| -
 | 
| -  // Initialize to a "ready-to-commit" state.
 | 
| -  void InitializeToReadyState();
 | 
| -
 | 
| -  // Start our ModelTypeProcessorImpl, which will be unable to commit until it
 | 
| -  // receives notification that initial sync has completed.
 | 
| -  void Start();
 | 
| -
 | 
| -  // Stop and disconnect the CommitQueue from our ModelTypeProcessorImpl.
 | 
| -  void Stop();
 | 
| -
 | 
| -  // Disable sync for this ModelTypeProcessorImpl.  Should cause sync state to
 | 
| -  // be discarded.
 | 
| -  void Disable();
 | 
| -
 | 
| -  // Restart sync after Stop() or Disable().
 | 
| -  void Restart();
 | 
| -
 | 
| -  // Local data modification.  Emulates signals from the model thread.
 | 
| -  void WriteItem(const std::string& tag, const std::string& value);
 | 
| -  void DeleteItem(const std::string& tag);
 | 
| -
 | 
| -  // Emulates an "initial sync done" message from the
 | 
| -  // CommitQueue.
 | 
| -  void OnInitialSyncDone();
 | 
| -
 | 
| -  // Emulate updates from the server.
 | 
| -  // This harness has some functionality to help emulate server behavior.
 | 
| -  // See the definitions of these methods for more information.
 | 
| -  void UpdateFromServer(int64 version_offset,
 | 
| -                        const std::string& tag,
 | 
| -                        const std::string& value);
 | 
| -  void TombstoneFromServer(int64 version_offset, const std::string& tag);
 | 
| -
 | 
| -  // Emulate the receipt of pending updates from the server.
 | 
| -  // Pending updates are usually caused by a temporary decryption failure.
 | 
| -  void PendingUpdateFromServer(int64 version_offset,
 | 
| -                               const std::string& tag,
 | 
| -                               const std::string& value,
 | 
| -                               const std::string& key_name);
 | 
| -
 | 
| -  // Returns true if the proxy has an pending update with specified tag.
 | 
| -  bool HasPendingUpdate(const std::string& tag) const;
 | 
| -
 | 
| -  // Returns the pending update with the specified tag.
 | 
| -  UpdateResponseData GetPendingUpdate(const std::string& tag) const;
 | 
| -
 | 
| -  // Returns the number of pending updates.
 | 
| -  size_t GetNumPendingUpdates() const;
 | 
| -
 | 
| -  // Read emitted commit requests as batches.
 | 
| -  size_t GetNumCommitRequestLists();
 | 
| -  CommitRequestDataList GetNthCommitRequestList(size_t n);
 | 
| -
 | 
| -  // Read emitted commit requests by tag, most recent only.
 | 
| -  bool HasCommitRequestForTag(const std::string& tag);
 | 
| -  CommitRequestData GetLatestCommitRequestForTag(const std::string& tag);
 | 
| -
 | 
| -  // Sends the type sync proxy a successful commit response.
 | 
| -  void SuccessfulCommitResponse(const CommitRequestData& request_data);
 | 
| -
 | 
| -  // Sends the type sync proxy an updated DataTypeState to let it know that
 | 
| -  // the desired encryption key has changed.
 | 
| -  void UpdateDesiredEncryptionKey(const std::string& key_name);
 | 
| -
 | 
| -  // Sets the key_name that the mock CommitQueue will claim is in use
 | 
| -  // when receiving items.
 | 
| -  void SetServerEncryptionKey(const std::string& key_name);
 | 
| -
 | 
| - private:
 | 
| -  static std::string GenerateTagHash(const std::string& tag);
 | 
| -  static sync_pb::EntitySpecifics GenerateSpecifics(const std::string& tag,
 | 
| -                                                    const std::string& value);
 | 
| -  static sync_pb::EntitySpecifics GenerateEncryptedSpecifics(
 | 
| -      const std::string& tag,
 | 
| -      const std::string& value,
 | 
| -      const std::string& key_name);
 | 
| -
 | 
| -  int64 GetServerVersion(const std::string& tag);
 | 
| -  void SetServerVersion(const std::string& tag, int64 version);
 | 
| -
 | 
| -  void StartDone(/*syncer::SyncError,*/ scoped_ptr<ActivationContext> context);
 | 
| -
 | 
| -  // The current mock queue which might be owned by either |mock_queue_ptr_| or
 | 
| -  // |type_processor_|.
 | 
| -  MockCommitQueue* mock_queue_;
 | 
| -  scoped_ptr<MockCommitQueue> mock_queue_ptr_;
 | 
| -  scoped_ptr<ModelTypeProcessorImpl> type_processor_;
 | 
| -
 | 
| -  DataTypeState data_type_state_;
 | 
| -  // This sets ThreadTaskRunnerHandle on the current thread.
 | 
| -  base::MessageLoop message_loop_;
 | 
| -};
 | 
| -
 | 
| -ModelTypeProcessorImplTest::ModelTypeProcessorImplTest()
 | 
| -    : mock_queue_(new MockCommitQueue()),
 | 
| -      mock_queue_ptr_(mock_queue_),
 | 
| -      type_processor_(
 | 
| -          new ModelTypeProcessorImpl(kModelType,
 | 
| -                                     base::WeakPtr<ModelTypeStore>())) {}
 | 
| -
 | 
| -ModelTypeProcessorImplTest::~ModelTypeProcessorImplTest() {
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::InitializeToReadyState() {
 | 
| -  // TODO(rlarocque): This should be updated to inject on-disk state.
 | 
| -  // At the time this code was written, there was no support for on-disk
 | 
| -  // state so this was the only way to inject a data_type_state into
 | 
| -  // the |type_processor_|.
 | 
| -  Start();
 | 
| -  OnInitialSyncDone();
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::Start() {
 | 
| -  type_processor_->Start(base::Bind(&ModelTypeProcessorImplTest::StartDone,
 | 
| -                                    base::Unretained(this)));
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::Stop() {
 | 
| -  type_processor_->Stop();
 | 
| -  mock_queue_ = NULL;
 | 
| -  mock_queue_ptr_.reset();
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::Disable() {
 | 
| -  type_processor_->Disable();
 | 
| -  mock_queue_ = NULL;
 | 
| -  mock_queue_ptr_.reset();
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::Restart() {
 | 
| -  DCHECK(!type_processor_->IsConnected());
 | 
| -
 | 
| -  // Prepare a new MockCommitQueue instance, just as we would
 | 
| -  // if this happened in the real world.
 | 
| -  mock_queue_ptr_.reset(new MockCommitQueue());
 | 
| -  mock_queue_ = mock_queue_ptr_.get();
 | 
| -  // Restart sync with the new CommitQueue.
 | 
| -  Start();
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::StartDone(
 | 
| -    /*syncer::SyncError,*/ scoped_ptr<ActivationContext> context) {
 | 
| -  // Hand off ownership of |mock_queue_ptr_|, while keeping
 | 
| -  // an unsafe pointer to it.  This is why we can only connect once.
 | 
| -  DCHECK(mock_queue_ptr_);
 | 
| -  context->type_processor->OnConnect(mock_queue_ptr_.Pass());
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::WriteItem(const std::string& tag,
 | 
| -                                           const std::string& value) {
 | 
| -  const std::string tag_hash = GenerateTagHash(tag);
 | 
| -  type_processor_->Put(tag, GenerateSpecifics(tag, value));
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::DeleteItem(const std::string& tag) {
 | 
| -  type_processor_->Delete(tag);
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::OnInitialSyncDone() {
 | 
| -  data_type_state_.initial_sync_done = true;
 | 
| -  UpdateResponseDataList empty_update_list;
 | 
| -
 | 
| -  type_processor_->OnUpdateReceived(data_type_state_, empty_update_list,
 | 
| -                                    empty_update_list);
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::UpdateFromServer(int64 version_offset,
 | 
| -                                                  const std::string& tag,
 | 
| -                                                  const std::string& value) {
 | 
| -  const std::string tag_hash = GenerateTagHash(tag);
 | 
| -  UpdateResponseData data = mock_queue_->UpdateFromServer(
 | 
| -      version_offset, tag_hash, GenerateSpecifics(tag, value));
 | 
| -
 | 
| -  UpdateResponseDataList list;
 | 
| -  list.push_back(data);
 | 
| -  type_processor_->OnUpdateReceived(data_type_state_, list,
 | 
| -                                    UpdateResponseDataList());
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::PendingUpdateFromServer(
 | 
| -    int64 version_offset,
 | 
| -    const std::string& tag,
 | 
| -    const std::string& value,
 | 
| -    const std::string& key_name) {
 | 
| -  const std::string tag_hash = GenerateTagHash(tag);
 | 
| -  UpdateResponseData data = mock_queue_->UpdateFromServer(
 | 
| -      version_offset, tag_hash,
 | 
| -      GenerateEncryptedSpecifics(tag, value, key_name));
 | 
| -
 | 
| -  UpdateResponseDataList list;
 | 
| -  list.push_back(data);
 | 
| -  type_processor_->OnUpdateReceived(data_type_state_, UpdateResponseDataList(),
 | 
| -                                    list);
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::TombstoneFromServer(int64 version_offset,
 | 
| -                                                     const std::string& tag) {
 | 
| -  // Overwrite the existing server version if this is the new highest version.
 | 
| -  std::string tag_hash = GenerateTagHash(tag);
 | 
| -
 | 
| -  UpdateResponseData data =
 | 
| -      mock_queue_->TombstoneFromServer(version_offset, tag_hash);
 | 
| -
 | 
| -  UpdateResponseDataList list;
 | 
| -  list.push_back(data);
 | 
| -  type_processor_->OnUpdateReceived(data_type_state_, list,
 | 
| -                                    UpdateResponseDataList());
 | 
| -}
 | 
| -
 | 
| -bool ModelTypeProcessorImplTest::HasPendingUpdate(
 | 
| -    const std::string& tag) const {
 | 
| -  const std::string client_tag_hash = GenerateTagHash(tag);
 | 
| -  const UpdateResponseDataList list = type_processor_->GetPendingUpdates();
 | 
| -  for (UpdateResponseDataList::const_iterator it = list.begin();
 | 
| -       it != list.end(); ++it) {
 | 
| -    if (it->client_tag_hash == client_tag_hash)
 | 
| -      return true;
 | 
| -  }
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -UpdateResponseData ModelTypeProcessorImplTest::GetPendingUpdate(
 | 
| -    const std::string& tag) const {
 | 
| -  DCHECK(HasPendingUpdate(tag));
 | 
| -  const std::string client_tag_hash = GenerateTagHash(tag);
 | 
| -  const UpdateResponseDataList list = type_processor_->GetPendingUpdates();
 | 
| -  for (UpdateResponseDataList::const_iterator it = list.begin();
 | 
| -       it != list.end(); ++it) {
 | 
| -    if (it->client_tag_hash == client_tag_hash)
 | 
| -      return *it;
 | 
| -  }
 | 
| -  NOTREACHED();
 | 
| -  return UpdateResponseData();
 | 
| -}
 | 
| -
 | 
| -size_t ModelTypeProcessorImplTest::GetNumPendingUpdates() const {
 | 
| -  return type_processor_->GetPendingUpdates().size();
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::SuccessfulCommitResponse(
 | 
| -    const CommitRequestData& request_data) {
 | 
| -  CommitResponseDataList list;
 | 
| -  list.push_back(mock_queue_->SuccessfulCommitResponse(request_data));
 | 
| -  type_processor_->OnCommitCompleted(data_type_state_, list);
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::UpdateDesiredEncryptionKey(
 | 
| -    const std::string& key_name) {
 | 
| -  data_type_state_.encryption_key_name = key_name;
 | 
| -  type_processor_->OnUpdateReceived(data_type_state_, UpdateResponseDataList(),
 | 
| -                                    UpdateResponseDataList());
 | 
| -}
 | 
| -
 | 
| -void ModelTypeProcessorImplTest::SetServerEncryptionKey(
 | 
| -    const std::string& key_name) {
 | 
| -  mock_queue_->SetServerEncryptionKey(key_name);
 | 
| -}
 | 
| -
 | 
| -std::string ModelTypeProcessorImplTest::GenerateTagHash(
 | 
| -    const std::string& tag) {
 | 
| -  return syncer::syncable::GenerateSyncableHash(kModelType, tag);
 | 
| -}
 | 
| -
 | 
| -sync_pb::EntitySpecifics ModelTypeProcessorImplTest::GenerateSpecifics(
 | 
| -    const std::string& tag,
 | 
| -    const std::string& value) {
 | 
| -  sync_pb::EntitySpecifics specifics;
 | 
| -  specifics.mutable_preference()->set_name(tag);
 | 
| -  specifics.mutable_preference()->set_value(value);
 | 
| -  return specifics;
 | 
| -}
 | 
| -
 | 
| -// These tests never decrypt anything, so we can get away with faking the
 | 
| -// encryption for now.
 | 
| -sync_pb::EntitySpecifics ModelTypeProcessorImplTest::GenerateEncryptedSpecifics(
 | 
| -    const std::string& tag,
 | 
| -    const std::string& value,
 | 
| -    const std::string& key_name) {
 | 
| -  sync_pb::EntitySpecifics specifics;
 | 
| -  syncer::AddDefaultFieldValue(kModelType, &specifics);
 | 
| -  specifics.mutable_encrypted()->set_key_name(key_name);
 | 
| -  specifics.mutable_encrypted()->set_blob("BLOB" + key_name);
 | 
| -  return specifics;
 | 
| -}
 | 
| -
 | 
| -size_t ModelTypeProcessorImplTest::GetNumCommitRequestLists() {
 | 
| -  return mock_queue_->GetNumCommitRequestLists();
 | 
| -}
 | 
| -
 | 
| -CommitRequestDataList ModelTypeProcessorImplTest::GetNthCommitRequestList(
 | 
| -    size_t n) {
 | 
| -  return mock_queue_->GetNthCommitRequestList(n);
 | 
| -}
 | 
| -
 | 
| -bool ModelTypeProcessorImplTest::HasCommitRequestForTag(
 | 
| -    const std::string& tag) {
 | 
| -  const std::string tag_hash = GenerateTagHash(tag);
 | 
| -  return mock_queue_->HasCommitRequestForTagHash(tag_hash);
 | 
| -}
 | 
| -
 | 
| -CommitRequestData ModelTypeProcessorImplTest::GetLatestCommitRequestForTag(
 | 
| -    const std::string& tag) {
 | 
| -  const std::string tag_hash = GenerateTagHash(tag);
 | 
| -  return mock_queue_->GetLatestCommitRequestForTagHash(tag_hash);
 | 
| -}
 | 
| -
 | 
| -// Creates a new item locally.
 | 
| -// Thoroughly tests the data generated by a local item creation.
 | 
| -TEST_F(ModelTypeProcessorImplTest, CreateLocalItem) {
 | 
| -  InitializeToReadyState();
 | 
| -  EXPECT_EQ(0U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  WriteItem("tag1", "value1");
 | 
| -
 | 
| -  // Verify the commit request this operation has triggered.
 | 
| -  EXPECT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  const CommitRequestData& tag1_data = GetLatestCommitRequestForTag("tag1");
 | 
| -
 | 
| -  EXPECT_TRUE(tag1_data.id.empty());
 | 
| -  EXPECT_EQ(kUncommittedVersion, tag1_data.base_version);
 | 
| -  EXPECT_FALSE(tag1_data.ctime.is_null());
 | 
| -  EXPECT_FALSE(tag1_data.mtime.is_null());
 | 
| -  EXPECT_EQ("tag1", tag1_data.non_unique_name);
 | 
| -  EXPECT_FALSE(tag1_data.deleted);
 | 
| -  EXPECT_EQ("tag1", tag1_data.specifics.preference().name());
 | 
| -  EXPECT_EQ("value1", tag1_data.specifics.preference().value());
 | 
| -}
 | 
| -
 | 
| -// Creates a new local item then modifies it.
 | 
| -// Thoroughly tests data generated by modification of server-unknown item.
 | 
| -TEST_F(ModelTypeProcessorImplTest, CreateAndModifyLocalItem) {
 | 
| -  InitializeToReadyState();
 | 
| -  EXPECT_EQ(0U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  WriteItem("tag1", "value1");
 | 
| -  EXPECT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
 | 
| -
 | 
| -  WriteItem("tag1", "value2");
 | 
| -  EXPECT_EQ(2U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  const CommitRequestData& tag1_v2_data = GetLatestCommitRequestForTag("tag1");
 | 
| -
 | 
| -  // Test some of the relations between old and new commit requests.
 | 
| -  EXPECT_EQ(tag1_v1_data.specifics.preference().value(), "value1");
 | 
| -  EXPECT_GT(tag1_v2_data.sequence_number, tag1_v1_data.sequence_number);
 | 
| -
 | 
| -  // Perform a thorough examination of the update-generated request.
 | 
| -  EXPECT_TRUE(tag1_v2_data.id.empty());
 | 
| -  EXPECT_EQ(kUncommittedVersion, tag1_v2_data.base_version);
 | 
| -  EXPECT_FALSE(tag1_v2_data.ctime.is_null());
 | 
| -  EXPECT_FALSE(tag1_v2_data.mtime.is_null());
 | 
| -  EXPECT_EQ("tag1", tag1_v2_data.non_unique_name);
 | 
| -  EXPECT_FALSE(tag1_v2_data.deleted);
 | 
| -  EXPECT_EQ("tag1", tag1_v2_data.specifics.preference().name());
 | 
| -  EXPECT_EQ("value2", tag1_v2_data.specifics.preference().value());
 | 
| -}
 | 
| -
 | 
| -// Deletes an item we've never seen before.
 | 
| -// Should have no effect and not crash.
 | 
| -TEST_F(ModelTypeProcessorImplTest, DeleteUnknown) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  DeleteItem("tag1");
 | 
| -  EXPECT_EQ(0U, GetNumCommitRequestLists());
 | 
| -}
 | 
| -
 | 
| -// Creates an item locally then deletes it.
 | 
| -//
 | 
| -// In this test, no commit responses are received, so the deleted item is
 | 
| -// server-unknown as far as the model thread is concerned.  That behavior
 | 
| -// is race-dependent; other tests are used to test other races.
 | 
| -TEST_F(ModelTypeProcessorImplTest, DeleteServerUnknown) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  WriteItem("tag1", "value1");
 | 
| -  EXPECT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
 | 
| -
 | 
| -  DeleteItem("tag1");
 | 
| -  EXPECT_EQ(2U, GetNumCommitRequestLists());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  const CommitRequestData& tag1_v2_data = GetLatestCommitRequestForTag("tag1");
 | 
| -
 | 
| -  EXPECT_GT(tag1_v2_data.sequence_number, tag1_v1_data.sequence_number);
 | 
| -
 | 
| -  EXPECT_TRUE(tag1_v2_data.id.empty());
 | 
| -  EXPECT_EQ(kUncommittedVersion, tag1_v2_data.base_version);
 | 
| -  EXPECT_TRUE(tag1_v2_data.deleted);
 | 
| -}
 | 
| -
 | 
| -// Creates an item locally then deletes it.
 | 
| -//
 | 
| -// The item is created locally then enqueued for commit.  The sync thread
 | 
| -// successfully commits it, but, before the commit response is picked up
 | 
| -// by the model thread, the item is deleted by the model thread.
 | 
| -TEST_F(ModelTypeProcessorImplTest, DeleteServerUnknown_RacyCommitResponse) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  WriteItem("tag1", "value1");
 | 
| -  EXPECT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
 | 
| -
 | 
| -  DeleteItem("tag1");
 | 
| -  EXPECT_EQ(2U, GetNumCommitRequestLists());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -
 | 
| -  // This commit happened while the deletion was in progress, but the commit
 | 
| -  // response didn't arrive on our thread until after the delete was issued to
 | 
| -  // the sync thread.  It will update some metadata, but won't do much else.
 | 
| -  SuccessfulCommitResponse(tag1_v1_data);
 | 
| -
 | 
| -  // TODO(rlarocque): Verify the state of the item is correct once we get
 | 
| -  // storage hooked up in these tests.  For example, verify the item is still
 | 
| -  // marked as deleted.
 | 
| -}
 | 
| -
 | 
| -// Creates two different sync items.
 | 
| -// Verifies that the second has no effect on the first.
 | 
| -TEST_F(ModelTypeProcessorImplTest, TwoIndependentItems) {
 | 
| -  InitializeToReadyState();
 | 
| -  EXPECT_EQ(0U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  WriteItem("tag1", "value1");
 | 
| -
 | 
| -  // There should be one commit request for this item only.
 | 
| -  ASSERT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  EXPECT_EQ(1U, GetNthCommitRequestList(0).size());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -
 | 
| -  WriteItem("tag2", "value2");
 | 
| -
 | 
| -  // The second write should trigger another single-item commit request.
 | 
| -  ASSERT_EQ(2U, GetNumCommitRequestLists());
 | 
| -  EXPECT_EQ(1U, GetNthCommitRequestList(1).size());
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag2"));
 | 
| -}
 | 
| -
 | 
| -// Starts the type sync proxy with no local state.
 | 
| -// Verify that it waits until initial sync is complete before requesting
 | 
| -// commits.
 | 
| -TEST_F(ModelTypeProcessorImplTest, NoCommitsUntilInitialSyncDone) {
 | 
| -  Start();
 | 
| -
 | 
| -  WriteItem("tag1", "value1");
 | 
| -  EXPECT_EQ(0U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  OnInitialSyncDone();
 | 
| -  EXPECT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -}
 | 
| -
 | 
| -// Test proper handling of disconnect and reconnect.
 | 
| -//
 | 
| -// Creates items in various states of commit and verifies they re-attempt to
 | 
| -// commit on reconnect.
 | 
| -TEST_F(ModelTypeProcessorImplTest, Stop) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  // The first item is fully committed.
 | 
| -  WriteItem("tag1", "value1");
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1"));
 | 
| -
 | 
| -  // The second item has a commit request in progress.
 | 
| -  WriteItem("tag2", "value2");
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag2"));
 | 
| -
 | 
| -  Stop();
 | 
| -
 | 
| -  // The third item is added after stopping.
 | 
| -  WriteItem("tag3", "value3");
 | 
| -
 | 
| -  Restart();
 | 
| -
 | 
| -  EXPECT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  EXPECT_EQ(2U, GetNthCommitRequestList(0).size());
 | 
| -
 | 
| -  // The first item was already in sync.
 | 
| -  EXPECT_FALSE(HasCommitRequestForTag("tag1"));
 | 
| -
 | 
| -  // The second item's commit was interrupted and should be retried.
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag2"));
 | 
| -
 | 
| -  // The third item's commit was not started until the reconnect.
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag3"));
 | 
| -}
 | 
| -
 | 
| -// Test proper handling of disable and re-enable.
 | 
| -//
 | 
| -// Creates items in various states of commit and verifies they re-attempt to
 | 
| -// commit on re-enable.
 | 
| -TEST_F(ModelTypeProcessorImplTest, Disable) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  // The first item is fully committed.
 | 
| -  WriteItem("tag1", "value1");
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1"));
 | 
| -
 | 
| -  // The second item has a commit request in progress.
 | 
| -  WriteItem("tag2", "value2");
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag2"));
 | 
| -
 | 
| -  Disable();
 | 
| -
 | 
| -  // The third item is added after disable.
 | 
| -  WriteItem("tag3", "value3");
 | 
| -
 | 
| -  // Now we re-enable.
 | 
| -  Restart();
 | 
| -
 | 
| -  // There should be nothing to commit right away, since we need to
 | 
| -  // re-initialize the client state first.
 | 
| -  EXPECT_EQ(0U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  // Once we're ready to commit, all three local items should consider
 | 
| -  // themselves uncommitted and pending for commit.
 | 
| -  OnInitialSyncDone();
 | 
| -  EXPECT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  EXPECT_EQ(3U, GetNthCommitRequestList(0).size());
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag2"));
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("tag3"));
 | 
| -}
 | 
| -
 | 
| -// Test receipt of pending updates.
 | 
| -TEST_F(ModelTypeProcessorImplTest, ReceivePendingUpdates) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  EXPECT_FALSE(HasPendingUpdate("tag1"));
 | 
| -  EXPECT_EQ(0U, GetNumPendingUpdates());
 | 
| -
 | 
| -  // Receive a pending update.
 | 
| -  PendingUpdateFromServer(5, "tag1", "value1", "key1");
 | 
| -  EXPECT_EQ(1U, GetNumPendingUpdates());
 | 
| -  ASSERT_TRUE(HasPendingUpdate("tag1"));
 | 
| -  UpdateResponseData data1 = GetPendingUpdate("tag1");
 | 
| -  EXPECT_EQ(5, data1.response_version);
 | 
| -
 | 
| -  // Receive an updated version of a pending update.
 | 
| -  // It should overwrite the existing item.
 | 
| -  PendingUpdateFromServer(10, "tag1", "value15", "key1");
 | 
| -  EXPECT_EQ(1U, GetNumPendingUpdates());
 | 
| -  ASSERT_TRUE(HasPendingUpdate("tag1"));
 | 
| -  UpdateResponseData data2 = GetPendingUpdate("tag1");
 | 
| -  EXPECT_EQ(15, data2.response_version);
 | 
| -
 | 
| -  // Receive a stale version of a pending update.
 | 
| -  // It should have no effect.
 | 
| -  PendingUpdateFromServer(-3, "tag1", "value12", "key1");
 | 
| -  EXPECT_EQ(1U, GetNumPendingUpdates());
 | 
| -  ASSERT_TRUE(HasPendingUpdate("tag1"));
 | 
| -  UpdateResponseData data3 = GetPendingUpdate("tag1");
 | 
| -  EXPECT_EQ(15, data3.response_version);
 | 
| -}
 | 
| -
 | 
| -// Test that Disable clears pending update state.
 | 
| -TEST_F(ModelTypeProcessorImplTest, DisableWithPendingUpdates) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  PendingUpdateFromServer(5, "tag1", "value1", "key1");
 | 
| -  EXPECT_EQ(1U, GetNumPendingUpdates());
 | 
| -  ASSERT_TRUE(HasPendingUpdate("tag1"));
 | 
| -
 | 
| -  Disable();
 | 
| -  Restart();
 | 
| -
 | 
| -  EXPECT_EQ(0U, GetNumPendingUpdates());
 | 
| -  EXPECT_FALSE(HasPendingUpdate("tag1"));
 | 
| -}
 | 
| -
 | 
| -// Test that Stop does not clear pending update state.
 | 
| -TEST_F(ModelTypeProcessorImplTest, StopWithPendingUpdates) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  PendingUpdateFromServer(5, "tag1", "value1", "key1");
 | 
| -  EXPECT_EQ(1U, GetNumPendingUpdates());
 | 
| -  ASSERT_TRUE(HasPendingUpdate("tag1"));
 | 
| -
 | 
| -  Stop();
 | 
| -  Restart();
 | 
| -
 | 
| -  EXPECT_EQ(1U, GetNumPendingUpdates());
 | 
| -  EXPECT_TRUE(HasPendingUpdate("tag1"));
 | 
| -}
 | 
| -
 | 
| -// Test re-encrypt everything when desired encryption key changes.
 | 
| -TEST_F(ModelTypeProcessorImplTest, ReEncryptCommitsWithNewKey) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  // Commit an item.
 | 
| -  WriteItem("tag1", "value1");
 | 
| -  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
 | 
| -  const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
 | 
| -  SuccessfulCommitResponse(tag1_v1_data);
 | 
| -
 | 
| -  // Create another item and don't wait for its commit response.
 | 
| -  WriteItem("tag2", "value2");
 | 
| -
 | 
| -  ASSERT_EQ(2U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  // Receive notice that the account's desired encryption key has changed.
 | 
| -  UpdateDesiredEncryptionKey("k1");
 | 
| -
 | 
| -  // That should trigger a new commit request.
 | 
| -  ASSERT_EQ(3U, GetNumCommitRequestLists());
 | 
| -  EXPECT_EQ(2U, GetNthCommitRequestList(2).size());
 | 
| -
 | 
| -  const CommitRequestData& tag1_enc = GetLatestCommitRequestForTag("tag1");
 | 
| -  const CommitRequestData& tag2_enc = GetLatestCommitRequestForTag("tag2");
 | 
| -
 | 
| -  SuccessfulCommitResponse(tag1_enc);
 | 
| -  SuccessfulCommitResponse(tag2_enc);
 | 
| -
 | 
| -  // And that should be the end of it.
 | 
| -  ASSERT_EQ(3U, GetNumCommitRequestLists());
 | 
| -}
 | 
| -
 | 
| -// Test receipt of updates with new and old keys.
 | 
| -TEST_F(ModelTypeProcessorImplTest, ReEncryptUpdatesWithNewKey) {
 | 
| -  InitializeToReadyState();
 | 
| -
 | 
| -  // Receive an unencrpted update.
 | 
| -  UpdateFromServer(5, "no_enc", "value1");
 | 
| -
 | 
| -  ASSERT_EQ(0U, GetNumCommitRequestLists());
 | 
| -
 | 
| -  // Set desired encryption key to k2 to force updates to some items.
 | 
| -  UpdateDesiredEncryptionKey("k2");
 | 
| -
 | 
| -  ASSERT_EQ(1U, GetNumCommitRequestLists());
 | 
| -  EXPECT_EQ(1U, GetNthCommitRequestList(0).size());
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("no_enc"));
 | 
| -
 | 
| -  // Receive an update that was encrypted with key k1.
 | 
| -  SetServerEncryptionKey("k1");
 | 
| -  UpdateFromServer(10, "enc_k1", "value1");
 | 
| -
 | 
| -  // Receipt of updates encrypted with old key also forces a re-encrypt commit.
 | 
| -  ASSERT_EQ(2U, GetNumCommitRequestLists());
 | 
| -  EXPECT_EQ(1U, GetNthCommitRequestList(1).size());
 | 
| -  EXPECT_TRUE(HasCommitRequestForTag("enc_k1"));
 | 
| -
 | 
| -  // Receive an update that was encrypted with key k2.
 | 
| -  SetServerEncryptionKey("k2");
 | 
| -  UpdateFromServer(15, "enc_k2", "value1");
 | 
| -
 | 
| -  // That was the correct key, so no re-encryption is required.
 | 
| -  EXPECT_EQ(2U, GetNumCommitRequestLists());
 | 
| -  EXPECT_FALSE(HasCommitRequestForTag("enc_k2"));
 | 
| -}
 | 
| -
 | 
| -}  // namespace syncer
 | 
| 
 |