Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Unified Diff: components/sync/core/shared_model_type_processor_unittest.cc

Issue 2412193002: [Sync] Move SharedModelTypeProcessor to model_impl/. (Closed)
Patch Set: Address comment from Sky. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/sync/core/shared_model_type_processor_unittest.cc
diff --git a/components/sync/core/shared_model_type_processor_unittest.cc b/components/sync/core/shared_model_type_processor_unittest.cc
deleted file mode 100644
index 853f6b0642bec3075364b3204fd0fa42a71d60c0..0000000000000000000000000000000000000000
--- a/components/sync/core/shared_model_type_processor_unittest.cc
+++ /dev/null
@@ -1,1273 +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 "components/sync/core/shared_model_type_processor.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "components/sync/base/time.h"
-#include "components/sync/core/activation_context.h"
-#include "components/sync/core/simple_metadata_change_list.h"
-#include "components/sync/engine/commit_queue.h"
-#include "components/sync/model/data_type_error_handler_mock.h"
-#include "components/sync/model/fake_model_type_service.h"
-#include "components/sync/test/engine/mock_model_type_worker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using sync_pb::EntitySpecifics;
-using sync_pb::EntityMetadata;
-using sync_pb::ModelTypeState;
-
-namespace syncer {
-
-namespace {
-
-const char kKey1[] = "key1";
-const char kKey2[] = "key2";
-const char kKey3[] = "key3";
-const char kKey4[] = "key4";
-const char kKey5[] = "key5";
-const char kValue1[] = "value1";
-const char kValue2[] = "value2";
-const char kValue3[] = "value3";
-const std::string kHash1(FakeModelTypeService::TagHashFromKey(kKey1));
-const std::string kHash2(FakeModelTypeService::TagHashFromKey(kKey2));
-const std::string kHash3(FakeModelTypeService::TagHashFromKey(kKey3));
-const std::string kHash4(FakeModelTypeService::TagHashFromKey(kKey4));
-const std::string kHash5(FakeModelTypeService::TagHashFromKey(kKey5));
-
-// Typically used for verification after a delete. The specifics given to the
-// worker/processor will not have been initialized and thus empty.
-const EntitySpecifics kEmptySpecifics;
-
-SyncError CreateSyncError(SyncError::ErrorType error_type) {
- return SyncError(FROM_HERE, error_type, "TestError", PREFERENCES);
-}
-
-} // namespace
-
-// Tests the various functionality of SharedModelTypeProcessor.
-//
-// The processor sits between the service (implemented by this test class) and
-// the worker, which is represented by a MockModelTypeWorker. This test suite
-// exercises the initialization flows (whether initial sync is done, performing
-// the initial merge, etc) as well as normal functionality:
-//
-// - Initialization before the initial sync and merge correctly performs a merge
-// and initializes the metadata in storage.
-// - Initialization after the initial sync correctly loads metadata and queues
-// any pending commits.
-// - Put and Delete calls from the service result in the correct metadata in
-// storage and the correct commit requests on the worker side.
-// - Updates and commit responses from the worker correctly affect data and
-// metadata in storage on the service side.
-class SharedModelTypeProcessorTest : public ::testing::Test,
- public FakeModelTypeService {
- public:
- SharedModelTypeProcessorTest()
- : FakeModelTypeService(
- base::Bind(&SharedModelTypeProcessor::CreateAsChangeProcessor)) {}
-
- void InitializeToMetadataLoaded() {
- CreateChangeProcessor();
- ModelTypeState model_type_state(db_.model_type_state());
- model_type_state.set_initial_sync_done(true);
- db_.set_model_type_state(model_type_state);
- OnMetadataLoaded();
- }
-
- // Initialize to a "ready-to-commit" state.
- void InitializeToReadyState() {
- InitializeToMetadataLoaded();
- if (!data_callback_.is_null()) {
- OnPendingCommitDataLoaded();
- }
- OnSyncStarting();
- }
-
- void OnMetadataLoaded() {
- type_processor()->OnMetadataLoaded(SyncError(), db_.CreateMetadataBatch());
- }
-
- void OnPendingCommitDataLoaded() {
- DCHECK(!data_callback_.is_null());
- data_callback_.Run();
- data_callback_.Reset();
- }
-
- void OnSyncStarting() {
- std::unique_ptr<DataTypeErrorHandlerMock> error_handler =
- base::MakeUnique<DataTypeErrorHandlerMock>();
- error_handler_ = error_handler.get();
- type_processor()->OnSyncStarting(
- std::move(error_handler),
- base::Bind(&SharedModelTypeProcessorTest::OnReadyToConnect,
- base::Unretained(this)));
- }
-
- void DisconnectSync() {
- type_processor()->DisconnectSync();
- worker_ = nullptr;
- }
-
- // Writes data for |key| and simulates a commit response for it.
- EntitySpecifics WriteItemAndAck(const std::string& key,
- const std::string& value) {
- EntitySpecifics specifics = WriteItem(key, value);
- worker()->ExpectPendingCommits({TagHashFromKey(key)});
- worker()->AckOnePendingCommit();
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
- return specifics;
- }
-
- void ResetState() {
- clear_change_processor();
- db_.Reset();
- worker_ = nullptr;
- CheckPostConditions();
- }
-
- // Wipes existing DB and simulates a pending update of a server-known item.
- EntitySpecifics ResetStateWriteItem(const std::string& name,
- const std::string& value) {
- ResetState();
- InitializeToReadyState();
- EXPECT_EQ(0U, ProcessorEntityCount());
- WriteItemAndAck(name, "acked-value");
- EntitySpecifics specifics = WriteItem(name, value);
- EXPECT_EQ(1U, ProcessorEntityCount());
- clear_change_processor();
- worker_ = nullptr;
- return specifics;
- }
-
- // Wipes existing DB and simulates a pending deletion of a server-known item.
- void ResetStateDeleteItem(const std::string& name, const std::string& value) {
- ResetState();
- InitializeToReadyState();
- EXPECT_EQ(0U, ProcessorEntityCount());
- WriteItemAndAck(name, value);
- EXPECT_EQ(1U, ProcessorEntityCount());
- DeleteItem(name);
- EXPECT_EQ(1U, ProcessorEntityCount());
- clear_change_processor();
- worker_ = nullptr;
- }
-
- // Return the number of entities the processor has metadata for.
- size_t ProcessorEntityCount() const {
- DCHECK(type_processor());
- return type_processor()->entities_.size();
- }
-
- // Sets the error type that OnReadyToConnect (our StartCallback) expects to
- // receive.
- void ExpectStartError(SyncError::ErrorType error_type) {
- DCHECK(expected_start_error_ == SyncError::UNSET);
- expected_start_error_ = error_type;
- }
-
- MockModelTypeWorker* worker() { return worker_; }
-
- SharedModelTypeProcessor* type_processor() const {
- return static_cast<SharedModelTypeProcessor*>(change_processor());
- }
-
- DataTypeErrorHandlerMock* error_handler() {
- DCHECK(error_handler_);
- return error_handler_;
- }
-
- int merge_call_count() const { return merge_call_count_; }
-
- private:
- void CheckPostConditions() override {
- FakeModelTypeService::CheckPostConditions();
- DCHECK(data_callback_.is_null());
- DCHECK_EQ(SyncError::UNSET, expected_start_error_);
- }
-
- void OnReadyToConnect(SyncError error,
- std::unique_ptr<ActivationContext> context) {
- if (expected_start_error_ != SyncError::UNSET) {
- EXPECT_TRUE(error.IsSet());
- EXPECT_EQ(expected_start_error_, error.error_type());
- EXPECT_EQ(nullptr, context);
- expected_start_error_ = SyncError::UNSET;
- return;
- }
-
- std::unique_ptr<MockModelTypeWorker> worker(
- new MockModelTypeWorker(context->model_type_state, type_processor()));
- // Keep an unsafe pointer to the commit queue the processor will use.
- worker_ = worker.get();
- // The context contains a proxy to the processor, but this call is
- // side-stepping that completely and connecting directly to the real
- // processor, since these tests are single-threaded and don't need proxies.
- type_processor()->ConnectSync(std::move(worker));
- }
-
- // FakeModelTypeService overrides.
-
- SyncError MergeSyncData(std::unique_ptr<MetadataChangeList> mcl,
- EntityDataMap entity_data_map) override {
- merge_call_count_++;
- return FakeModelTypeService::MergeSyncData(std::move(mcl), entity_data_map);
- }
-
- void CaptureDataCallback(DataCallback callback,
- SyncError error,
- std::unique_ptr<DataBatch> data) {
- data_callback_ = base::Bind(callback, error, base::Passed(std::move(data)));
- }
-
- void GetData(StorageKeyList keys, DataCallback callback) override {
- FakeModelTypeService::GetData(
- keys, base::Bind(&SharedModelTypeProcessorTest::CaptureDataCallback,
- base::Unretained(this), callback));
- }
-
- // This sets ThreadTaskRunnerHandle on the current thread, which the type
- // processor will pick up as the sync task runner.
- base::MessageLoop sync_loop_;
-
- // The current mock queue, which is owned by |type_processor()|.
- MockModelTypeWorker* worker_;
-
- // Stores the data callback between GetData() and OnPendingCommitDataLoaded().
- base::Closure data_callback_;
-
- // The processor's error handler.
- DataTypeErrorHandlerMock* error_handler_;
-
- // The error to expect in OnReadyToConnect().
- SyncError::ErrorType expected_start_error_ = SyncError::UNSET;
-
- // The number of times MergeSyncData has been called.
- int merge_call_count_ = 0;
-};
-
-// Test that an initial sync handles local and remote items properly.
-TEST_F(SharedModelTypeProcessorTest, InitialSync) {
- CreateChangeProcessor();
- OnMetadataLoaded();
- OnSyncStarting();
-
- // Local write before initial sync.
- WriteItem(kKey1, kValue1);
-
- // Has data, but no metadata, entity in the processor, or commit request.
- EXPECT_EQ(1U, db().data_count());
- EXPECT_EQ(0U, db().metadata_count());
- EXPECT_EQ(0U, ProcessorEntityCount());
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- EXPECT_EQ(0, merge_call_count());
- // Initial sync with one server item.
- worker()->UpdateFromServer(kHash2, GenerateSpecifics(kKey2, kValue2));
- EXPECT_EQ(1, merge_call_count());
-
- // Now have data and metadata for both items, as well as a commit request for
- // the local item.
- EXPECT_EQ(2U, db().data_count());
- EXPECT_EQ(2U, db().metadata_count());
- EXPECT_EQ(2U, ProcessorEntityCount());
- EXPECT_EQ(1, db().GetMetadata(kKey1).sequence_number());
- EXPECT_EQ(0, db().GetMetadata(kKey2).sequence_number());
- worker()->ExpectPendingCommits({kHash1});
-}
-
-// Test that subsequent starts don't call MergeSyncData.
-TEST_F(SharedModelTypeProcessorTest, NonInitialSync) {
- // This sets initial_sync_done to true.
- InitializeToMetadataLoaded();
-
- // Write an item before sync connects.
- WriteItem(kKey1, kValue1);
- EXPECT_EQ(1U, db().data_count());
- EXPECT_EQ(1U, db().metadata_count());
-
- // Check that data coming from sync is treated as a normal GetUpdates.
- OnSyncStarting();
- worker()->UpdateFromServer(kHash2, GenerateSpecifics(kKey2, kValue2));
- EXPECT_EQ(0, merge_call_count());
- EXPECT_EQ(2U, db().data_count());
- EXPECT_EQ(2U, db().metadata_count());
-}
-
-// Test that an error during the merge is propagated to the error handler.
-TEST_F(SharedModelTypeProcessorTest, InitialSyncError) {
- CreateChangeProcessor();
- OnMetadataLoaded();
- OnSyncStarting();
-
- SetServiceError(SyncError::DATATYPE_ERROR);
- error_handler()->ExpectError(SyncError::DATATYPE_ERROR);
- worker()->UpdateFromServer();
-}
-
-// Test that errors before it's called are passed to |start_callback| correctly.
-TEST_F(SharedModelTypeProcessorTest, StartErrors) {
- CreateChangeProcessor();
- type_processor()->OnMetadataLoaded(CreateSyncError(SyncError::DATATYPE_ERROR),
- nullptr);
- ExpectStartError(SyncError::DATATYPE_ERROR);
- OnSyncStarting();
-
- // Test OnSyncStarting happening first.
- ResetState();
- CreateChangeProcessor();
- OnSyncStarting();
- ExpectStartError(SyncError::DATATYPE_ERROR);
- type_processor()->OnMetadataLoaded(CreateSyncError(SyncError::DATATYPE_ERROR),
- nullptr);
-
- // Test an error loading pending data.
- ResetStateWriteItem(kKey1, kValue1);
- SetServiceError(SyncError::DATATYPE_ERROR);
- InitializeToMetadataLoaded();
- OnPendingCommitDataLoaded();
- ExpectStartError(SyncError::DATATYPE_ERROR);
- OnSyncStarting();
-}
-
-// This test covers race conditions during loading pending data. All cases
-// start with no processor and one acked (committed to the server) item with a
-// pending commit. There are three different events that can occur in any order
-// once metadata is loaded:
-//
-// - Pending commit data is loaded.
-// - Sync gets connected.
-// - Optionally, a put or delete happens to the item.
-//
-// This results in 2 + 12 = 14 orderings of the events.
-TEST_F(SharedModelTypeProcessorTest, LoadPendingCommit) {
- // Data, connect.
- EntitySpecifics specifics1 = ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnPendingCommitDataLoaded();
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics1);
-
- // Connect, data.
- EntitySpecifics specifics2 = ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- EXPECT_EQ(nullptr, worker());
- OnPendingCommitDataLoaded();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
-
- // Data, connect, put.
- EntitySpecifics specifics3 = ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnPendingCommitDataLoaded();
- OnSyncStarting();
- EntitySpecifics specifics4 = WriteItem(kKey1, kValue2);
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics3);
- worker()->ExpectNthPendingCommit(1, kHash1, specifics4);
-
- // Data, put, connect.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnPendingCommitDataLoaded();
- EntitySpecifics specifics5 = WriteItem(kKey1, kValue2);
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics5);
-
- // Connect, data, put.
- EntitySpecifics specifics6 = ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- OnPendingCommitDataLoaded();
- EntitySpecifics specifics7 = WriteItem(kKey1, kValue2);
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics6);
- worker()->ExpectNthPendingCommit(1, kHash1, specifics7);
-
- // Connect, put, data.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- EntitySpecifics specifics8 = WriteItem(kKey1, kValue2);
- EXPECT_EQ(nullptr, worker());
- OnPendingCommitDataLoaded();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics8);
-
- // Put, data, connect.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- EntitySpecifics specifics9 = WriteItem(kKey1, kValue2);
- OnPendingCommitDataLoaded();
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics9);
-
- // Put, connect, data.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- EntitySpecifics specifics10 = WriteItem(kKey1, kValue2);
- OnSyncStarting();
- EXPECT_EQ(nullptr, worker());
- OnPendingCommitDataLoaded();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics10);
-
- // Data, connect, delete.
- EntitySpecifics specifics11 = ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnPendingCommitDataLoaded();
- OnSyncStarting();
- DeleteItem(kKey1);
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics11);
- worker()->ExpectNthPendingCommit(1, kHash1, kEmptySpecifics);
-
- // Data, delete, connect.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnPendingCommitDataLoaded();
- DeleteItem(kKey1);
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-
- // Connect, data, delete.
- EntitySpecifics specifics12 = ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- OnPendingCommitDataLoaded();
- DeleteItem(kKey1);
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics12);
- worker()->ExpectNthPendingCommit(1, kHash1, kEmptySpecifics);
-
- // Connect, delete, data.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- DeleteItem(kKey1);
- EXPECT_EQ(nullptr, worker());
- OnPendingCommitDataLoaded();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-
- // Delete, data, connect.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- DeleteItem(kKey1);
- OnPendingCommitDataLoaded();
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-
- // Delete, connect, data.
- ResetStateWriteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- DeleteItem(kKey1);
- OnSyncStarting();
- EXPECT_EQ(nullptr, worker());
- OnPendingCommitDataLoaded();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-}
-
-// This test covers race conditions during loading a pending delete. All cases
-// start with no processor and one item with a pending delete. There are two
-// different events that can occur in any order once metadata is loaded, since
-// for a deletion there is no data to load:
-//
-// - Sync gets connected.
-// - Optionally, a put or delete happens to the item (repeated deletes should be
-// handled properly).
-//
-// This results in 1 + 4 = 5 orderings of the events.
-TEST_F(SharedModelTypeProcessorTest, LoadPendingDelete) {
- // Connect.
- ResetStateDeleteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-
- // Connect, put.
- ResetStateDeleteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- EntitySpecifics specifics1 = WriteItem(kKey1, kValue2);
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
- worker()->ExpectNthPendingCommit(1, kHash1, specifics1);
-
- // Put, connect.
- ResetStateDeleteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- EntitySpecifics specifics2 = WriteItem(kKey1, kValue2);
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
-
- // Connect, delete.
- ResetStateDeleteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- DeleteItem(kKey1);
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
- worker()->ExpectNthPendingCommit(1, kHash1, kEmptySpecifics);
-
- // Delete, connect.
- ResetStateDeleteItem(kKey1, kValue1);
- InitializeToMetadataLoaded();
- DeleteItem(kKey1);
- OnSyncStarting();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-}
-
-// Test that loading a committed item does not queue another commit.
-TEST_F(SharedModelTypeProcessorTest, LoadCommited) {
- InitializeToReadyState();
- WriteItemAndAck(kKey1, kValue1);
- clear_change_processor();
-
- // Test that a new processor loads the metadata without committing.
- InitializeToReadyState();
- EXPECT_EQ(1U, ProcessorEntityCount());
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-}
-
-// Creates a new item locally.
-// Thoroughly tests the data generated by a local item creation.
-TEST_F(SharedModelTypeProcessorTest, LocalCreateItem) {
- InitializeToReadyState();
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- WriteItem(kKey1, kValue1);
-
- // Verify the commit request this operation has triggered.
- worker()->ExpectPendingCommits({kHash1});
- const CommitRequestData& tag1_request_data =
- worker()->GetLatestPendingCommitForHash(kHash1);
- const EntityData& tag1_data = tag1_request_data.entity.value();
-
- EXPECT_EQ(kUncommittedVersion, tag1_request_data.base_version);
- EXPECT_TRUE(tag1_data.id.empty());
- EXPECT_FALSE(tag1_data.creation_time.is_null());
- EXPECT_FALSE(tag1_data.modification_time.is_null());
- EXPECT_EQ(kKey1, tag1_data.non_unique_name);
- EXPECT_FALSE(tag1_data.is_deleted());
- EXPECT_EQ(kKey1, tag1_data.specifics.preference().name());
- EXPECT_EQ(kValue1, tag1_data.specifics.preference().value());
-
- EXPECT_EQ(1U, db().metadata_count());
- const EntityMetadata metadata = db().GetMetadata(kKey1);
- EXPECT_TRUE(metadata.has_client_tag_hash());
- EXPECT_FALSE(metadata.has_server_id());
- EXPECT_FALSE(metadata.is_deleted());
- EXPECT_EQ(1, metadata.sequence_number());
- EXPECT_EQ(0, metadata.acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, metadata.server_version());
- EXPECT_TRUE(metadata.has_creation_time());
- EXPECT_TRUE(metadata.has_modification_time());
- EXPECT_TRUE(metadata.has_specifics_hash());
-
- worker()->AckOnePendingCommit();
- EXPECT_EQ(1U, db().metadata_count());
- const EntityMetadata acked_metadata = db().GetMetadata(kKey1);
- EXPECT_TRUE(acked_metadata.has_server_id());
- EXPECT_EQ(1, acked_metadata.sequence_number());
- EXPECT_EQ(1, acked_metadata.acked_sequence_number());
- EXPECT_EQ(1, acked_metadata.server_version());
-}
-
-// Test that an error applying metadata changes from a commit response is
-// propagated to the error handler.
-TEST_F(SharedModelTypeProcessorTest, ErrorApplyingAck) {
- InitializeToReadyState();
- WriteItem(kKey1, kValue1);
- SetServiceError(SyncError::DATATYPE_ERROR);
- error_handler()->ExpectError(SyncError::DATATYPE_ERROR);
- worker()->AckOnePendingCommit();
-}
-
-// The purpose of this test case is to test setting |client_tag_hash| and |id|
-// on the EntityData object as we pass it into the Put method of the processor.
-TEST_F(SharedModelTypeProcessorTest, LocalUpdateItemWithOverrides) {
- const std::string kId1 = "cid1";
- const std::string kId2 = "cid2";
-
- InitializeToReadyState();
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- std::unique_ptr<EntityData> entity_data = base::WrapUnique(new EntityData());
- entity_data->specifics.mutable_preference()->set_name(kKey1);
- entity_data->specifics.mutable_preference()->set_value(kValue1);
-
- entity_data->non_unique_name = kKey1;
- entity_data->client_tag_hash = kHash3;
- entity_data->id = kId1;
- WriteItem(kKey1, std::move(entity_data));
-
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- ASSERT_FALSE(worker()->HasPendingCommitForHash(kHash3));
- ASSERT_TRUE(worker()->HasPendingCommitForHash(kHash1));
- EXPECT_EQ(1U, db().metadata_count());
- const EntityData& out_entity1 =
- worker()->GetLatestPendingCommitForHash(kHash1).entity.value();
- const EntityMetadata metadata_v1 = db().GetMetadata(kKey1);
-
- EXPECT_EQ(kId1, out_entity1.id);
- EXPECT_NE(kHash3, out_entity1.client_tag_hash);
- EXPECT_EQ(kValue1, out_entity1.specifics.preference().value());
- EXPECT_EQ(kId1, metadata_v1.server_id());
- EXPECT_EQ(metadata_v1.client_tag_hash(), out_entity1.client_tag_hash);
-
- entity_data.reset(new EntityData());
- // This is a sketchy move here, changing the name will change the generated
- // storage key and client tag values.
- entity_data->specifics.mutable_preference()->set_name(kKey2);
- entity_data->specifics.mutable_preference()->set_value(kValue2);
- entity_data->non_unique_name = kKey2;
- entity_data->client_tag_hash = kHash3;
- // Make sure ID isn't overwritten either.
- entity_data->id = kId2;
- WriteItem(kKey1, std::move(entity_data));
-
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- ASSERT_FALSE(worker()->HasPendingCommitForHash(kHash3));
- ASSERT_TRUE(worker()->HasPendingCommitForHash(kHash1));
- EXPECT_EQ(1U, db().metadata_count());
- const EntityData& out_entity2 =
- worker()->GetLatestPendingCommitForHash(kHash1).entity.value();
- const EntityMetadata metadata_v2 = db().GetMetadata(kKey1);
-
- EXPECT_EQ(kValue2, out_entity2.specifics.preference().value());
- // Should still see old cid1 value, override is not respected on update.
- EXPECT_EQ(kId1, out_entity2.id);
- EXPECT_EQ(kId1, metadata_v2.server_id());
- EXPECT_EQ(metadata_v2.client_tag_hash(), out_entity2.client_tag_hash);
-
- // Specifics have changed so the hashes should not match.
- EXPECT_NE(metadata_v1.specifics_hash(), metadata_v2.specifics_hash());
-}
-
-// Creates a new local item then modifies it.
-// Thoroughly tests data generated by modification of server-unknown item.
-TEST_F(SharedModelTypeProcessorTest, LocalUpdateItem) {
- InitializeToReadyState();
-
- WriteItem(kKey1, kValue1);
- EXPECT_EQ(1U, db().metadata_count());
- worker()->ExpectPendingCommits({kHash1});
-
- const CommitRequestData& request_data_v1 =
- worker()->GetLatestPendingCommitForHash(kHash1);
- const EntityData& data_v1 = request_data_v1.entity.value();
- const EntityMetadata metadata_v1 = db().GetMetadata(kKey1);
-
- WriteItem(kKey1, kValue2);
- EXPECT_EQ(1U, db().metadata_count());
- worker()->ExpectPendingCommits({kHash1, kHash1});
-
- const CommitRequestData& request_data_v2 =
- worker()->GetLatestPendingCommitForHash(kHash1);
- const EntityData& data_v2 = request_data_v2.entity.value();
- const EntityMetadata metadata_v2 = db().GetMetadata(kKey1);
-
- // Test some of the relations between old and new commit requests.
- EXPECT_GT(request_data_v2.sequence_number, request_data_v1.sequence_number);
- EXPECT_EQ(data_v1.specifics.preference().value(), kValue1);
-
- // Perform a thorough examination of the update-generated request.
- EXPECT_EQ(kUncommittedVersion, request_data_v2.base_version);
- EXPECT_TRUE(data_v2.id.empty());
- EXPECT_FALSE(data_v2.creation_time.is_null());
- EXPECT_FALSE(data_v2.modification_time.is_null());
- EXPECT_EQ(kKey1, data_v2.non_unique_name);
- EXPECT_FALSE(data_v2.is_deleted());
- EXPECT_EQ(kKey1, data_v2.specifics.preference().name());
- EXPECT_EQ(kValue2, data_v2.specifics.preference().value());
-
- EXPECT_FALSE(metadata_v1.has_server_id());
- EXPECT_FALSE(metadata_v1.is_deleted());
- EXPECT_EQ(1, metadata_v1.sequence_number());
- EXPECT_EQ(0, metadata_v1.acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, metadata_v1.server_version());
-
- EXPECT_FALSE(metadata_v2.has_server_id());
- EXPECT_FALSE(metadata_v2.is_deleted());
- EXPECT_EQ(2, metadata_v2.sequence_number());
- EXPECT_EQ(0, metadata_v2.acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, metadata_v2.server_version());
-
- EXPECT_EQ(metadata_v1.client_tag_hash(), metadata_v2.client_tag_hash());
- EXPECT_NE(metadata_v1.specifics_hash(), metadata_v2.specifics_hash());
-}
-
-// Tests that a local update that doesn't change specifics doesn't generate a
-// commit request.
-TEST_F(SharedModelTypeProcessorTest, LocalUpdateItemRedundant) {
- InitializeToReadyState();
- WriteItem(kKey1, kValue1);
- EXPECT_EQ(1U, db().metadata_count());
- worker()->ExpectPendingCommits({kHash1});
-
- WriteItem(kKey1, kValue1);
- worker()->ExpectPendingCommits({kHash1});
-}
-
-// Thoroughly tests the data generated by a server item creation.
-TEST_F(SharedModelTypeProcessorTest, ServerCreateItem) {
- InitializeToReadyState();
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue1));
- EXPECT_EQ(1U, db().data_count());
- EXPECT_EQ(1U, db().metadata_count());
- EXPECT_EQ(1U, ProcessorEntityCount());
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- const EntityData& data = db().GetData(kKey1);
- EXPECT_FALSE(data.id.empty());
- EXPECT_EQ(kKey1, data.specifics.preference().name());
- EXPECT_EQ(kValue1, data.specifics.preference().value());
- EXPECT_FALSE(data.creation_time.is_null());
- EXPECT_FALSE(data.modification_time.is_null());
- EXPECT_EQ(kKey1, data.non_unique_name);
- EXPECT_FALSE(data.is_deleted());
-
- const EntityMetadata metadata = db().GetMetadata(kKey1);
- EXPECT_TRUE(metadata.has_client_tag_hash());
- EXPECT_TRUE(metadata.has_server_id());
- EXPECT_FALSE(metadata.is_deleted());
- EXPECT_EQ(0, metadata.sequence_number());
- EXPECT_EQ(0, metadata.acked_sequence_number());
- EXPECT_EQ(1, metadata.server_version());
- EXPECT_TRUE(metadata.has_creation_time());
- EXPECT_TRUE(metadata.has_modification_time());
- EXPECT_TRUE(metadata.has_specifics_hash());
-}
-
-// Test that an error applying changes from a server update is
-// propagated to the error handler.
-TEST_F(SharedModelTypeProcessorTest, ErrorApplyingUpdate) {
- InitializeToReadyState();
- SetServiceError(SyncError::DATATYPE_ERROR);
- error_handler()->ExpectError(SyncError::DATATYPE_ERROR);
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue1));
-}
-
-// Thoroughly tests the data generated by a server item creation.
-TEST_F(SharedModelTypeProcessorTest, ServerUpdateItem) {
- InitializeToReadyState();
-
- // Local add writes data and metadata; ack writes metadata again.
- WriteItemAndAck(kKey1, kValue1);
- EXPECT_EQ(1U, db().data_change_count());
- EXPECT_EQ(2U, db().metadata_change_count());
-
- // Redundant update from server doesn't write data but updates metadata.
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue1));
- EXPECT_EQ(1U, db().data_change_count());
- EXPECT_EQ(3U, db().metadata_change_count());
-
- // A reflection (update already received) is ignored completely.
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue1),
- 0 /* version_offset */);
- EXPECT_EQ(1U, db().data_change_count());
- EXPECT_EQ(3U, db().metadata_change_count());
-}
-
-// Tests locally deleting an acknowledged item.
-TEST_F(SharedModelTypeProcessorTest, LocalDeleteItem) {
- InitializeToReadyState();
- WriteItemAndAck(kKey1, kValue1);
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- const EntityMetadata metadata_v1 = db().GetMetadata(kKey1);
- EXPECT_FALSE(metadata_v1.is_deleted());
- EXPECT_EQ(1, metadata_v1.sequence_number());
- EXPECT_EQ(1, metadata_v1.acked_sequence_number());
- EXPECT_EQ(1, metadata_v1.server_version());
-
- DeleteItem(kKey1);
- EXPECT_EQ(0U, db().data_count());
- // Metadata is not removed until the commit response comes back.
- EXPECT_EQ(1U, db().metadata_count());
- EXPECT_EQ(1U, ProcessorEntityCount());
- worker()->ExpectPendingCommits({kHash1});
-
- const EntityMetadata metadata_v2 = db().GetMetadata(kKey1);
- EXPECT_TRUE(metadata_v2.is_deleted());
- EXPECT_EQ(2, metadata_v2.sequence_number());
- EXPECT_EQ(1, metadata_v2.acked_sequence_number());
- EXPECT_EQ(1, metadata_v2.server_version());
-
- // Ack the delete and check that the metadata is cleared.
- worker()->AckOnePendingCommit();
- EXPECT_EQ(0U, db().metadata_count());
- EXPECT_EQ(0U, ProcessorEntityCount());
-}
-
-// Tests creating and deleting an item locally before receiving a commit
-// response, then getting the commit responses.
-TEST_F(SharedModelTypeProcessorTest, LocalDeleteItemInterleaved) {
- InitializeToReadyState();
- WriteItem(kKey1, kValue1);
- worker()->ExpectPendingCommits({kHash1});
- const CommitRequestData& data_v1 =
- worker()->GetLatestPendingCommitForHash(kHash1);
-
- const EntityMetadata metadata_v1 = db().GetMetadata(kKey1);
- EXPECT_FALSE(metadata_v1.is_deleted());
- EXPECT_EQ(1, metadata_v1.sequence_number());
- EXPECT_EQ(0, metadata_v1.acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, metadata_v1.server_version());
-
- DeleteItem(kKey1);
- EXPECT_EQ(0U, db().data_count());
- EXPECT_EQ(1U, db().metadata_count());
- EXPECT_EQ(1U, ProcessorEntityCount());
- worker()->ExpectPendingCommits({kHash1, kHash1});
-
- const CommitRequestData& data_v2 =
- worker()->GetLatestPendingCommitForHash(kHash1);
- EXPECT_GT(data_v2.sequence_number, data_v1.sequence_number);
- EXPECT_TRUE(data_v2.entity->id.empty());
- EXPECT_EQ(kUncommittedVersion, data_v2.base_version);
- EXPECT_TRUE(data_v2.entity->is_deleted());
-
- const EntityMetadata metadata_v2 = db().GetMetadata(kKey1);
- EXPECT_TRUE(metadata_v2.is_deleted());
- EXPECT_EQ(2, metadata_v2.sequence_number());
- EXPECT_EQ(0, metadata_v2.acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, metadata_v2.server_version());
-
- // A response for the first commit doesn't change much.
- worker()->AckOnePendingCommit();
- EXPECT_EQ(0U, db().data_count());
- EXPECT_EQ(1U, db().metadata_count());
- EXPECT_EQ(1U, ProcessorEntityCount());
-
- const EntityMetadata metadata_v3 = db().GetMetadata(kKey1);
- EXPECT_TRUE(metadata_v3.is_deleted());
- EXPECT_EQ(2, metadata_v3.sequence_number());
- EXPECT_EQ(1, metadata_v3.acked_sequence_number());
- EXPECT_EQ(1, metadata_v3.server_version());
-
- worker()->AckOnePendingCommit();
- // The delete was acked so the metadata should now be cleared.
- EXPECT_EQ(0U, db().metadata_count());
- EXPECT_EQ(0U, ProcessorEntityCount());
-}
-
-TEST_F(SharedModelTypeProcessorTest, ServerDeleteItem) {
- InitializeToReadyState();
- WriteItemAndAck(kKey1, kValue1);
- EXPECT_EQ(1U, ProcessorEntityCount());
- EXPECT_EQ(1U, db().metadata_count());
- EXPECT_EQ(1U, db().data_count());
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- worker()->TombstoneFromServer(kHash1);
- // Delete from server should clear the data and all the metadata.
- EXPECT_EQ(0U, db().data_count());
- EXPECT_EQ(0U, db().metadata_count());
- EXPECT_EQ(0U, ProcessorEntityCount());
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-}
-
-// Deletes an item we've never seen before.
-// Should have no effect and not crash.
-TEST_F(SharedModelTypeProcessorTest, LocalDeleteUnknown) {
- InitializeToReadyState();
- DeleteItem(kKey1);
- EXPECT_EQ(0U, db().data_count());
- EXPECT_EQ(0U, db().metadata_count());
- EXPECT_EQ(0U, ProcessorEntityCount());
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-}
-
-// Deletes an item we've never seen before.
-// Should have no effect and not crash.
-TEST_F(SharedModelTypeProcessorTest, ServerDeleteUnknown) {
- InitializeToReadyState();
- worker()->TombstoneFromServer(kHash1);
- EXPECT_EQ(0U, db().data_count());
- EXPECT_EQ(0U, db().metadata_count());
- EXPECT_EQ(0U, ProcessorEntityCount());
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-}
-
-// Creates two different sync items.
-// Verifies that the second has no effect on the first.
-TEST_F(SharedModelTypeProcessorTest, TwoIndependentItems) {
- InitializeToReadyState();
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- WriteItem(kKey1, kValue1);
- EXPECT_EQ(1U, db().data_count());
- EXPECT_EQ(1U, db().metadata_count());
- const EntityMetadata metadata1 = db().GetMetadata(kKey1);
-
- // There should be one commit request for this item only.
- worker()->ExpectPendingCommits({kHash1});
-
- WriteItem(kKey2, kValue2);
- EXPECT_EQ(2U, db().data_count());
- EXPECT_EQ(2U, db().metadata_count());
- const EntityMetadata metadata2 = db().GetMetadata(kKey2);
-
- // The second write should trigger another single-item commit request.
- worker()->ExpectPendingCommits({kHash1, kHash2});
-
- EXPECT_FALSE(metadata1.is_deleted());
- EXPECT_EQ(1, metadata1.sequence_number());
- EXPECT_EQ(0, metadata1.acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, metadata1.server_version());
-
- EXPECT_FALSE(metadata2.is_deleted());
- EXPECT_EQ(1, metadata2.sequence_number());
- EXPECT_EQ(0, metadata2.acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, metadata2.server_version());
-}
-
-TEST_F(SharedModelTypeProcessorTest, ConflictResolutionChangesMatch) {
- InitializeToReadyState();
- EntitySpecifics specifics = WriteItem(kKey1, kValue1);
- EXPECT_EQ(1U, db().data_change_count());
- EXPECT_EQ(kValue1, db().GetValue(kKey1));
- EXPECT_EQ(1U, db().metadata_change_count());
- EXPECT_EQ(kUncommittedVersion, db().GetMetadata(kKey1).server_version());
- worker()->ExpectPendingCommits({kHash1});
- worker()->ExpectNthPendingCommit(0, kHash1, specifics);
-
- // Changes match doesn't call ResolveConflict.
- worker()->UpdateFromServer(kHash1, specifics);
-
- // Updated metadata but not data; no new commit request.
- EXPECT_EQ(1U, db().data_change_count());
- EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
- worker()->ExpectPendingCommits({kHash1});
-}
-
-TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseLocal) {
- InitializeToReadyState();
- EntitySpecifics specifics = WriteItem(kKey1, kValue1);
- SetConflictResolution(ConflictResolution::UseLocal());
-
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
-
- // Updated metadata but not data; new commit request.
- EXPECT_EQ(1U, db().data_change_count());
- EXPECT_EQ(2U, db().metadata_change_count());
- EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
- worker()->ExpectPendingCommits({kHash1, kHash1});
- worker()->ExpectNthPendingCommit(1, kHash1, specifics);
-}
-
-TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseRemote) {
- InitializeToReadyState();
- WriteItem(kKey1, kValue1);
- SetConflictResolution(ConflictResolution::UseRemote());
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
-
- // Updated client data and metadata; no new commit request.
- EXPECT_EQ(2U, db().data_change_count());
- EXPECT_EQ(kValue2, db().GetValue(kKey1));
- EXPECT_EQ(2U, db().metadata_change_count());
- EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
- worker()->ExpectPendingCommits({kHash1});
-}
-
-TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseNew) {
- InitializeToReadyState();
- WriteItem(kKey1, kValue1);
- SetConflictResolution(
- ConflictResolution::UseNew(GenerateEntityData(kKey1, kValue3)));
-
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
- EXPECT_EQ(2U, db().data_change_count());
- EXPECT_EQ(kValue3, db().GetValue(kKey1));
- EXPECT_EQ(2U, db().metadata_change_count());
- EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
- worker()->ExpectPendingCommits({kHash1, kHash1});
- worker()->ExpectNthPendingCommit(1, kHash1,
- GenerateSpecifics(kKey1, kValue3));
-}
-
-// 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(SharedModelTypeProcessorTest, Disconnect) {
- InitializeToReadyState();
-
- // The first item is fully committed.
- WriteItemAndAck(kKey1, kValue1);
-
- // The second item has a commit request in progress.
- WriteItem(kKey2, kValue2);
- EXPECT_TRUE(worker()->HasPendingCommitForHash(kHash2));
-
- DisconnectSync();
-
- // The third item is added after stopping.
- WriteItem(kKey3, kValue3);
-
- // Reconnect.
- OnSyncStarting();
-
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- EXPECT_EQ(2U, worker()->GetNthPendingCommit(0).size());
-
- // The first item was already in sync.
- EXPECT_FALSE(worker()->HasPendingCommitForHash(kHash1));
-
- // The second item's commit was interrupted and should be retried.
- EXPECT_TRUE(worker()->HasPendingCommitForHash(kHash2));
-
- // The third item's commit was not started until the reconnect.
- EXPECT_TRUE(worker()->HasPendingCommitForHash(kHash3));
-}
-
-// 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(SharedModelTypeProcessorTest, Disable) {
- InitializeToReadyState();
-
- // The first item is fully committed.
- WriteItemAndAck(kKey1, kValue1);
-
- // The second item has a commit request in progress.
- WriteItem(kKey2, kValue2);
- EXPECT_TRUE(worker()->HasPendingCommitForHash(kHash2));
-
- DisableSync();
-
- // The third item is added after disable.
- WriteItem(kKey3, kValue3);
-
- // Now we re-enable.
- CreateChangeProcessor();
- OnMetadataLoaded();
- OnSyncStarting();
- worker()->UpdateFromServer();
-
- // Once we're ready to commit, all three local items should consider
- // themselves uncommitted and pending for commit.
- worker()->ExpectPendingCommits({kHash1, kHash2, kHash3});
-}
-
-// Test re-encrypt everything when desired encryption key changes.
-TEST_F(SharedModelTypeProcessorTest, ReEncryptCommitsWithNewKey) {
- InitializeToReadyState();
-
- // Commit an item.
- EntitySpecifics specifics1 = WriteItemAndAck(kKey1, kValue1);
- // Create another item and don't wait for its commit response.
- EntitySpecifics specifics2 = WriteItem(kKey2, kValue2);
- worker()->ExpectPendingCommits({kHash2});
- EXPECT_EQ(1U, db().GetMetadata(kKey1).sequence_number());
- EXPECT_EQ(1U, db().GetMetadata(kKey2).sequence_number());
-
- // Receive notice that the account's desired encryption key has changed.
- worker()->UpdateWithEncryptionKey("k1");
- // Tag 2 is recommitted immediately because the data was in memory.
- ASSERT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(1, kHash2, specifics2);
- // Sequence numbers in the store are updated.
- EXPECT_EQ(2U, db().GetMetadata(kKey1).sequence_number());
- EXPECT_EQ(2U, db().GetMetadata(kKey2).sequence_number());
-
- // Tag 1 needs to go to the store to load its data before recommitting.
- OnPendingCommitDataLoaded();
- ASSERT_EQ(3U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(2, kHash1, specifics1);
-}
-
-// Test that an error loading pending commit data for re-encryption is
-// propagated to the error handler.
-TEST_F(SharedModelTypeProcessorTest, ReEncryptErrorLoadingData) {
- InitializeToReadyState();
- WriteItemAndAck(kKey1, kValue1);
- SetServiceError(SyncError::DATATYPE_ERROR);
- worker()->UpdateWithEncryptionKey("k1");
- error_handler()->ExpectError(SyncError::DATATYPE_ERROR);
- OnPendingCommitDataLoaded();
-}
-
-// Test receipt of updates with new and old keys.
-TEST_F(SharedModelTypeProcessorTest, ReEncryptUpdatesWithNewKey) {
- InitializeToReadyState();
-
- // Receive an unencrypted update.
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue1));
- ASSERT_EQ(0U, worker()->GetNumPendingCommits());
-
- UpdateResponseDataList update;
- // Receive an entity with old encryption as part of the update.
- update.push_back(worker()->GenerateUpdateData(
- kHash2, GenerateSpecifics(kKey2, kValue2), 1, "k1"));
- // Receive an entity with up-to-date encryption as part of the update.
- update.push_back(worker()->GenerateUpdateData(
- kHash3, GenerateSpecifics(kKey3, kValue3), 1, "k2"));
- // Set desired encryption key to k2 to force updates to some items.
- worker()->UpdateWithEncryptionKey("k2", update);
-
- // kKey2 needed to be re-encrypted and had data so it was queued immediately.
- worker()->ExpectPendingCommits({kHash2});
- OnPendingCommitDataLoaded();
- // kKey1 needed data so once that's loaded, it is also queued.
- worker()->ExpectPendingCommits({kHash2, kHash1});
-
- // Receive a separate update that was encrypted with key k1.
- worker()->UpdateFromServer(kHash4, GenerateSpecifics(kKey4, kValue1), 1,
- "k1");
- // Receipt of updates encrypted with old key also forces a re-encrypt commit.
- worker()->ExpectPendingCommits({kHash2, kHash1, kHash4});
-
- // Receive an update that was encrypted with key k2.
- worker()->UpdateFromServer(kHash5, GenerateSpecifics(kKey5, kValue1), 1,
- "k2");
- // That was the correct key, so no re-encryption is required.
- worker()->ExpectPendingCommits({kHash2, kHash1, kHash4});
-}
-
-// Test that re-encrypting enqueues the right data for USE_LOCAL conflicts.
-TEST_F(SharedModelTypeProcessorTest, ReEncryptConflictResolutionUseLocal) {
- InitializeToReadyState();
- worker()->UpdateWithEncryptionKey("k1");
- EntitySpecifics specifics = WriteItem(kKey1, kValue1);
- worker()->ExpectPendingCommits({kHash1});
-
- SetConflictResolution(ConflictResolution::UseLocal());
- // Unencrypted update needs to be re-commited with key k1.
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2), 1, "");
-
- // Ensure the re-commit has the correct value.
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(1, kHash1, specifics);
- EXPECT_EQ(kValue1, db().GetValue(kKey1));
-}
-
-// Test that re-encrypting enqueues the right data for USE_REMOTE conflicts.
-TEST_F(SharedModelTypeProcessorTest, ReEncryptConflictResolutionUseRemote) {
- InitializeToReadyState();
- worker()->UpdateWithEncryptionKey("k1");
- WriteItem(kKey1, kValue1);
-
- SetConflictResolution(ConflictResolution::UseRemote());
- // Unencrypted update needs to be re-commited with key k1.
- EntitySpecifics specifics = GenerateSpecifics(kKey1, kValue2);
- worker()->UpdateFromServer(kHash1, specifics, 1, "");
-
- // Ensure the re-commit has the correct value.
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(1, kHash1, specifics);
- EXPECT_EQ(kValue2, db().GetValue(kKey1));
-}
-
-// Test that re-encrypting enqueues the right data for USE_NEW conflicts.
-TEST_F(SharedModelTypeProcessorTest, ReEncryptConflictResolutionUseNew) {
- InitializeToReadyState();
- worker()->UpdateWithEncryptionKey("k1");
- WriteItem(kKey1, kValue1);
-
- SetConflictResolution(
- ConflictResolution::UseNew(GenerateEntityData(kKey1, kValue3)));
- // Unencrypted update needs to be re-commited with key k1.
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2), 1, "");
-
- // Ensure the re-commit has the correct value.
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(1, kHash1,
- GenerateSpecifics(kKey1, kValue3));
- EXPECT_EQ(kValue3, db().GetValue(kKey1));
-}
-
-TEST_F(SharedModelTypeProcessorTest, ReEncryptConflictWhileLoading) {
- InitializeToReadyState();
- // Create item and ack so its data is no longer cached.
- WriteItemAndAck(kKey1, kValue1);
- // Update key so that it needs to fetch data to re-commit.
- worker()->UpdateWithEncryptionKey("k1");
- EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
- // Unencrypted update needs to be re-commited with key k1.
- EntitySpecifics specifics = GenerateSpecifics(kKey1, kValue2);
- worker()->UpdateFromServer(kHash1, specifics, 1, "");
-
- // Ensure the re-commit has the correct value.
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics);
- EXPECT_EQ(kValue2, db().GetValue(kKey1));
-
- // Data load completing shouldn't change anything.
- OnPendingCommitDataLoaded();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-}
-
-// Tests that a real remote change wins over a local encryption-only change.
-TEST_F(SharedModelTypeProcessorTest, IgnoreLocalEncryption) {
- InitializeToReadyState();
- EntitySpecifics specifics = WriteItemAndAck(kKey1, kValue1);
- worker()->UpdateWithEncryptionKey("k1");
- OnPendingCommitDataLoaded();
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics);
-
- worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-}
-
-// Tests that a real local change wins over a remote encryption-only change.
-TEST_F(SharedModelTypeProcessorTest, IgnoreRemoteEncryption) {
- InitializeToReadyState();
- EntitySpecifics specifics1 = WriteItemAndAck(kKey1, kValue1);
-
- EntitySpecifics specifics2 = WriteItem(kKey1, kValue2);
- UpdateResponseDataList update;
- update.push_back(worker()->GenerateUpdateData(kHash1, specifics1, 1, "k1"));
- worker()->UpdateWithEncryptionKey("k1", update);
-
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(1, kHash1, specifics2);
-}
-
-// Same as above but with two commit requests before one ack.
-TEST_F(SharedModelTypeProcessorTest, IgnoreRemoteEncryptionInterleaved) {
- InitializeToReadyState();
- EntitySpecifics specifics1 = WriteItem(kKey1, kValue1);
- EntitySpecifics specifics2 = WriteItem(kKey1, kValue2);
- worker()->AckOnePendingCommit();
- // kValue1 is now the base value.
- EXPECT_EQ(1U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
-
- UpdateResponseDataList update;
- update.push_back(worker()->GenerateUpdateData(kHash1, specifics1, 1, "k1"));
- worker()->UpdateWithEncryptionKey("k1", update);
-
- EXPECT_EQ(2U, worker()->GetNumPendingCommits());
- worker()->ExpectNthPendingCommit(1, kHash1, specifics2);
-}
-
-} // namespace syncer
« no previous file with comments | « components/sync/core/shared_model_type_processor.cc ('k') | components/sync/core_impl/model_type_connector_proxy_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698