123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- // 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/model/processor_entity.h"
- #include <utility>
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/time/time.h"
- #include "components/sync/base/client_tag_hash.h"
- #include "components/sync/base/features.h"
- #include "components/sync/base/model_type.h"
- #include "components/sync/base/time.h"
- #include "components/sync/engine/commit_and_get_updates_types.h"
- #include "components/sync/protocol/entity_metadata.pb.h"
- #include "components/sync/protocol/entity_specifics.pb.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace syncer {
- namespace {
- const char kKey[] = "key";
- const ClientTagHash kHash = ClientTagHash::FromHashed("hash");
- const char kId[] = "id";
- const char kName[] = "name";
- const char kValue1[] = "value1";
- const char kValue2[] = "value2";
- const char kValue3[] = "value3";
- sync_pb::EntitySpecifics GenerateSpecifics(const std::string& name,
- const std::string& value) {
- sync_pb::EntitySpecifics specifics;
- specifics.mutable_preference()->set_name(name);
- specifics.mutable_preference()->set_value(value);
- return specifics;
- }
- std::unique_ptr<EntityData> GenerateEntityData(const ClientTagHash& hash,
- const std::string& name,
- const std::string& value) {
- std::unique_ptr<EntityData> entity_data(new EntityData());
- entity_data->client_tag_hash = hash;
- entity_data->specifics = GenerateSpecifics(name, value);
- entity_data->name = name;
- return entity_data;
- }
- UpdateResponseData GenerateUpdate(const ProcessorEntity& entity,
- const ClientTagHash& hash,
- const std::string& id,
- const std::string& name,
- const std::string& value,
- const base::Time& mtime,
- int64_t version) {
- std::unique_ptr<EntityData> data = GenerateEntityData(hash, name, value);
- data->id = id;
- data->modification_time = mtime;
- UpdateResponseData update;
- update.entity = std::move(*data);
- update.response_version = version;
- return update;
- }
- UpdateResponseData GenerateTombstone(const ProcessorEntity& entity,
- const ClientTagHash& hash,
- const std::string& id,
- const std::string& name,
- const base::Time& mtime,
- int64_t version) {
- std::unique_ptr<EntityData> data = std::make_unique<EntityData>();
- data->client_tag_hash = hash;
- data->name = name;
- data->id = id;
- data->modification_time = mtime;
- UpdateResponseData update;
- update.entity = std::move(*data);
- update.response_version = version;
- return update;
- }
- CommitResponseData GenerateAckData(const CommitRequestData& request,
- const std::string id,
- int64_t version) {
- CommitResponseData response;
- response.id = id;
- response.client_tag_hash = request.entity->client_tag_hash;
- response.sequence_number = request.sequence_number;
- response.response_version = version;
- response.specifics_hash = request.specifics_hash;
- return response;
- }
- } // namespace
- // Some simple sanity tests for the ProcessorEntity.
- //
- // A lot of the more complicated sync logic is implemented in the
- // ClientTagBasedModelTypeProcessor that owns the ProcessorEntity. We
- // can't unit test it here.
- //
- // Instead, we focus on simple tests to make sure that variables are getting
- // properly intialized and flags properly set. Anything more complicated would
- // be a redundant and incomplete version of the ClientTagBasedModelTypeProcessor
- // tests.
- class ProcessorEntityTest : public ::testing::Test {
- public:
- ProcessorEntityTest() : ctime_(base::Time::Now() - base::Seconds(1)) {}
- std::unique_ptr<ProcessorEntity> CreateNew() {
- return ProcessorEntity::CreateNew(kKey, kHash, "", ctime_);
- }
- std::unique_ptr<ProcessorEntity> CreateNewWithEmptyStorageKey() {
- return ProcessorEntity::CreateNew("", kHash, "", ctime_);
- }
- std::unique_ptr<ProcessorEntity> CreateSynced() {
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- UpdateResponseData update =
- GenerateUpdate(*entity, kHash, kId, kName, kValue1, ctime_, 1);
- entity->RecordAcceptedRemoteUpdate(update, /*trimmed_specifics=*/{});
- DCHECK(!entity->IsUnsynced());
- return entity;
- }
- std::unique_ptr<ProcessorEntity> RestoreFromMetadata(
- sync_pb::EntityMetadata entity_metadata) {
- return ProcessorEntity::CreateFromMetadata(kKey,
- std::move(entity_metadata));
- }
- const base::Time ctime_;
- };
- // Test the state of the default new entity.
- TEST_F(ProcessorEntityTest, DefaultEntity) {
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- EXPECT_EQ(kKey, entity->storage_key());
- EXPECT_EQ(kHash.value(), entity->metadata().client_tag_hash());
- EXPECT_EQ("", entity->metadata().server_id());
- EXPECT_FALSE(entity->metadata().is_deleted());
- EXPECT_EQ(0, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, entity->metadata().server_version());
- EXPECT_EQ(TimeToProtoTime(ctime_), entity->metadata().creation_time());
- EXPECT_EQ(0, entity->metadata().modification_time());
- EXPECT_TRUE(entity->metadata().specifics_hash().empty());
- EXPECT_TRUE(entity->metadata().base_specifics_hash().empty());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->IsVersionAlreadyKnown(1));
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Test creating and commiting a new local item.
- TEST_F(ProcessorEntityTest, NewLocalItem) {
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
- /*trimmed_specifics=*/{});
- EXPECT_EQ("", entity->metadata().server_id());
- EXPECT_FALSE(entity->metadata().is_deleted());
- EXPECT_EQ(1, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(kUncommittedVersion, entity->metadata().server_version());
- EXPECT_NE(0, entity->metadata().modification_time());
- EXPECT_FALSE(entity->metadata().specifics_hash().empty());
- EXPECT_TRUE(entity->metadata().base_specifics_hash().empty());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_TRUE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->IsVersionAlreadyKnown(1));
- EXPECT_TRUE(entity->HasCommitData());
- EXPECT_EQ(kValue1, entity->commit_data().specifics.preference().value());
- // Generate a commit request. The metadata should not change.
- const sync_pb::EntityMetadata metadata_v1 = entity->metadata();
- CommitRequestData request;
- entity->InitializeCommitRequestData(&request);
- EXPECT_EQ(metadata_v1.SerializeAsString(),
- entity->metadata().SerializeAsString());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->IsVersionAlreadyKnown(1));
- const EntityData& data = *request.entity;
- EXPECT_EQ("", data.id);
- EXPECT_EQ(kHash, data.client_tag_hash);
- EXPECT_EQ(kName, data.name);
- EXPECT_EQ(kValue1, data.specifics.preference().value());
- EXPECT_EQ(TimeToProtoTime(ctime_), TimeToProtoTime(data.creation_time));
- EXPECT_EQ(entity->metadata().modification_time(),
- TimeToProtoTime(data.modification_time));
- EXPECT_FALSE(data.is_deleted());
- EXPECT_EQ(1, request.sequence_number);
- EXPECT_EQ(kUncommittedVersion, request.base_version);
- EXPECT_EQ(entity->metadata().specifics_hash(), request.specifics_hash);
- // Ack the commit.
- entity->ReceiveCommitResponse(GenerateAckData(request, kId, 1), false);
- EXPECT_EQ(kId, entity->metadata().server_id());
- EXPECT_FALSE(entity->metadata().is_deleted());
- EXPECT_EQ(1, entity->metadata().sequence_number());
- EXPECT_EQ(1, entity->metadata().acked_sequence_number());
- EXPECT_EQ(1, entity->metadata().server_version());
- EXPECT_EQ(metadata_v1.creation_time(), entity->metadata().creation_time());
- EXPECT_EQ(metadata_v1.modification_time(),
- entity->metadata().modification_time());
- EXPECT_FALSE(entity->metadata().specifics_hash().empty());
- EXPECT_TRUE(entity->metadata().base_specifics_hash().empty());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_TRUE(entity->IsVersionAlreadyKnown(1));
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Test state for a newly synced server item.
- TEST_F(ProcessorEntityTest, NewServerItem) {
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- const base::Time mtime = base::Time::Now();
- UpdateResponseData update =
- GenerateUpdate(*entity, kHash, kId, kName, kValue1, mtime, 10);
- entity->RecordAcceptedRemoteUpdate(update, /*trimmed_specifics=*/{});
- EXPECT_EQ(kId, entity->metadata().server_id());
- EXPECT_FALSE(entity->metadata().is_deleted());
- EXPECT_EQ(0, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(10, entity->metadata().server_version());
- EXPECT_EQ(TimeToProtoTime(mtime), entity->metadata().modification_time());
- EXPECT_FALSE(entity->metadata().specifics_hash().empty());
- EXPECT_TRUE(entity->metadata().base_specifics_hash().empty());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_TRUE(entity->IsVersionAlreadyKnown(9));
- EXPECT_TRUE(entity->IsVersionAlreadyKnown(10));
- EXPECT_FALSE(entity->IsVersionAlreadyKnown(11));
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Test creating an entity for new server item with empty storage key, applying
- // update and updating storage key.
- TEST_F(ProcessorEntityTest, NewServerItem_EmptyStorageKey) {
- std::unique_ptr<ProcessorEntity> entity = CreateNewWithEmptyStorageKey();
- EXPECT_EQ("", entity->storage_key());
- const base::Time mtime = base::Time::Now();
- UpdateResponseData update =
- GenerateUpdate(*entity, kHash, kId, kName, kValue1, mtime, 10);
- entity->RecordAcceptedRemoteUpdate(update, /*trimmed_specifics=*/{});
- entity->SetStorageKey(kKey);
- EXPECT_EQ(kKey, entity->storage_key());
- }
- // Test state for a tombstone received for a previously unknown item.
- TEST_F(ProcessorEntityTest, NewServerTombstone) {
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- const base::Time mtime = base::Time::Now();
- UpdateResponseData tombstone =
- GenerateTombstone(*entity, kHash, kId, kName, mtime, 1);
- entity->RecordAcceptedRemoteUpdate(tombstone, /*trimmed_specifics=*/{});
- EXPECT_EQ(kId, entity->metadata().server_id());
- EXPECT_TRUE(entity->metadata().is_deleted());
- EXPECT_EQ(0, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(1, entity->metadata().server_version());
- EXPECT_EQ(TimeToProtoTime(mtime), entity->metadata().modification_time());
- EXPECT_TRUE(entity->metadata().specifics_hash().empty());
- EXPECT_TRUE(entity->metadata().base_specifics_hash().empty());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_TRUE(entity->CanClearMetadata());
- EXPECT_TRUE(entity->IsVersionAlreadyKnown(1));
- EXPECT_FALSE(entity->IsVersionAlreadyKnown(2));
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Apply a deletion update to a synced item.
- TEST_F(ProcessorEntityTest, ServerTombstone) {
- // Start with a non-deleted state with version 1.
- std::unique_ptr<ProcessorEntity> entity = CreateSynced();
- // A deletion update one version later.
- const base::Time mtime = base::Time::Now();
- UpdateResponseData tombstone =
- GenerateTombstone(*entity, kHash, kId, kName, mtime, 2);
- entity->RecordAcceptedRemoteUpdate(tombstone, /*trimmed_specifics=*/{});
- EXPECT_TRUE(entity->metadata().is_deleted());
- EXPECT_EQ(0, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(2, entity->metadata().server_version());
- EXPECT_EQ(TimeToProtoTime(mtime), entity->metadata().modification_time());
- EXPECT_TRUE(entity->metadata().specifics_hash().empty());
- EXPECT_TRUE(entity->metadata().base_specifics_hash().empty());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_TRUE(entity->CanClearMetadata());
- EXPECT_TRUE(entity->IsVersionAlreadyKnown(2));
- EXPECT_FALSE(entity->IsVersionAlreadyKnown(3));
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Test a local change of a synced item.
- TEST_F(ProcessorEntityTest, LocalChange) {
- std::unique_ptr<ProcessorEntity> entity = CreateSynced();
- const int64_t mtime_v0 = entity->metadata().modification_time();
- const std::string specifics_hash_v0 = entity->metadata().specifics_hash();
- // Make a local change with different specifics.
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
- /*trimmed_specifics=*/{});
- const int64_t mtime_v1 = entity->metadata().modification_time();
- const std::string specifics_hash_v1 = entity->metadata().specifics_hash();
- EXPECT_FALSE(entity->metadata().is_deleted());
- EXPECT_EQ(1, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(1, entity->metadata().server_version());
- EXPECT_LT(mtime_v0, mtime_v1);
- EXPECT_NE(specifics_hash_v0, specifics_hash_v1);
- EXPECT_EQ(specifics_hash_v0, entity->metadata().base_specifics_hash());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_TRUE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_TRUE(entity->HasCommitData());
- // Make a commit.
- CommitRequestData request;
- entity->InitializeCommitRequestData(&request);
- EXPECT_EQ(kId, request.entity->id);
- EXPECT_FALSE(entity->RequiresCommitRequest());
- // Ack the commit.
- entity->ReceiveCommitResponse(GenerateAckData(request, kId, 2), false);
- EXPECT_EQ(1, entity->metadata().sequence_number());
- EXPECT_EQ(1, entity->metadata().acked_sequence_number());
- EXPECT_EQ(2, entity->metadata().server_version());
- EXPECT_EQ(mtime_v1, entity->metadata().modification_time());
- EXPECT_EQ(specifics_hash_v1, entity->metadata().specifics_hash());
- EXPECT_EQ("", entity->metadata().base_specifics_hash());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Test a local deletion of a synced item.
- TEST_F(ProcessorEntityTest, LocalDeletion) {
- std::unique_ptr<ProcessorEntity> entity = CreateSynced();
- const int64_t mtime = entity->metadata().modification_time();
- const std::string specifics_hash = entity->metadata().specifics_hash();
- // Make a local delete.
- entity->RecordLocalDeletion();
- EXPECT_TRUE(entity->metadata().is_deleted());
- EXPECT_EQ(1, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(1, entity->metadata().server_version());
- EXPECT_LT(mtime, entity->metadata().modification_time());
- EXPECT_TRUE(entity->metadata().specifics_hash().empty());
- EXPECT_EQ(specifics_hash, entity->metadata().base_specifics_hash());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_TRUE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->HasCommitData());
- // Generate a commit request. The metadata should not change.
- const sync_pb::EntityMetadata metadata_v1 = entity->metadata();
- CommitRequestData request;
- entity->InitializeCommitRequestData(&request);
- EXPECT_EQ(metadata_v1.SerializeAsString(),
- entity->metadata().SerializeAsString());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->HasCommitData());
- const EntityData& data = *request.entity;
- EXPECT_EQ(kId, data.id);
- EXPECT_EQ(kHash, data.client_tag_hash);
- EXPECT_EQ("", data.name);
- EXPECT_EQ(TimeToProtoTime(ctime_), TimeToProtoTime(data.creation_time));
- EXPECT_EQ(entity->metadata().modification_time(),
- TimeToProtoTime(data.modification_time));
- EXPECT_TRUE(data.is_deleted());
- EXPECT_EQ(1, request.sequence_number);
- EXPECT_EQ(1, request.base_version);
- EXPECT_EQ(entity->metadata().specifics_hash(), request.specifics_hash);
- // Ack the deletion.
- entity->ReceiveCommitResponse(GenerateAckData(request, kId, 2), false);
- EXPECT_TRUE(entity->metadata().is_deleted());
- EXPECT_EQ(1, entity->metadata().sequence_number());
- EXPECT_EQ(1, entity->metadata().acked_sequence_number());
- EXPECT_EQ(2, entity->metadata().server_version());
- EXPECT_EQ(metadata_v1.modification_time(),
- entity->metadata().modification_time());
- EXPECT_TRUE(entity->metadata().specifics_hash().empty());
- EXPECT_TRUE(entity->metadata().base_specifics_hash().empty());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_TRUE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Test a local deletion followed by an undeletion (creation).
- TEST_F(ProcessorEntityTest, LocalUndeletion) {
- std::unique_ptr<ProcessorEntity> entity = CreateSynced();
- const std::string specifics_hash = entity->metadata().specifics_hash();
- entity->RecordLocalDeletion();
- ASSERT_TRUE(entity->metadata().is_deleted());
- ASSERT_TRUE(entity->IsUnsynced());
- ASSERT_EQ(1, entity->metadata().sequence_number());
- // Undelete the entity with different specifics.
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
- /*trimmed_specifics=*/{});
- const std::string specifics_hash_v1 = entity->metadata().specifics_hash();
- ASSERT_NE(specifics_hash_v1, specifics_hash);
- EXPECT_FALSE(entity->metadata().is_deleted());
- EXPECT_EQ(2, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_EQ(1, entity->metadata().server_version());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_TRUE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_TRUE(entity->HasCommitData());
- // Make a commit.
- CommitRequestData request;
- entity->InitializeCommitRequestData(&request);
- EXPECT_EQ(kId, request.entity->id);
- EXPECT_FALSE(entity->RequiresCommitRequest());
- // Ack the commit.
- entity->ReceiveCommitResponse(GenerateAckData(request, kId, 2), false);
- EXPECT_EQ(2, entity->metadata().sequence_number());
- EXPECT_EQ(2, entity->metadata().acked_sequence_number());
- EXPECT_EQ(2, entity->metadata().server_version());
- EXPECT_EQ(specifics_hash_v1, entity->metadata().specifics_hash());
- EXPECT_EQ("", entity->metadata().base_specifics_hash());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Test that hashes and sequence numbers are handled correctly for the "commit
- // commit, ack ack" case.
- TEST_F(ProcessorEntityTest, LocalChangesInterleaved) {
- std::unique_ptr<ProcessorEntity> entity = CreateSynced();
- const std::string specifics_hash_v0 = entity->metadata().specifics_hash();
- // Make the first change.
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
- /*trimmed_specifics=*/{});
- const std::string specifics_hash_v1 = entity->metadata().specifics_hash();
- EXPECT_EQ(1, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_NE(specifics_hash_v0, specifics_hash_v1);
- EXPECT_EQ(specifics_hash_v0, entity->metadata().base_specifics_hash());
- // Request the first commit.
- CommitRequestData request_v1;
- entity->InitializeCommitRequestData(&request_v1);
- // Make the second change.
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue3),
- /*trimmed_specifics=*/{});
- const std::string specifics_hash_v2 = entity->metadata().specifics_hash();
- EXPECT_EQ(2, entity->metadata().sequence_number());
- EXPECT_EQ(0, entity->metadata().acked_sequence_number());
- EXPECT_NE(specifics_hash_v1, specifics_hash_v2);
- EXPECT_EQ(specifics_hash_v0, entity->metadata().base_specifics_hash());
- // Request the second commit.
- CommitRequestData request_v2;
- entity->InitializeCommitRequestData(&request_v2);
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- // Ack the first commit.
- entity->ReceiveCommitResponse(GenerateAckData(request_v1, kId, 2), false);
- EXPECT_EQ(2, entity->metadata().sequence_number());
- EXPECT_EQ(1, entity->metadata().acked_sequence_number());
- EXPECT_EQ(2, entity->metadata().server_version());
- EXPECT_EQ(specifics_hash_v2, entity->metadata().specifics_hash());
- EXPECT_EQ(specifics_hash_v1, entity->metadata().base_specifics_hash());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- // Commit data has been moved already to the request.
- EXPECT_FALSE(entity->HasCommitData());
- // Ack the second commit.
- entity->ReceiveCommitResponse(GenerateAckData(request_v2, kId, 3), false);
- EXPECT_EQ(2, entity->metadata().sequence_number());
- EXPECT_EQ(2, entity->metadata().acked_sequence_number());
- EXPECT_EQ(3, entity->metadata().server_version());
- EXPECT_EQ(specifics_hash_v2, entity->metadata().specifics_hash());
- EXPECT_EQ("", entity->metadata().base_specifics_hash());
- EXPECT_FALSE(entity->IsUnsynced());
- EXPECT_FALSE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_FALSE(entity->CanClearMetadata());
- EXPECT_FALSE(entity->HasCommitData());
- }
- // Tests that updating entity id with commit response while next local change is
- // pending correctly updates that change's id and version.
- TEST_F(ProcessorEntityTest, NewLocalChangeUpdatedId) {
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- // Create new local change. Make sure initial id is empty.
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
- /*trimmed_specifics=*/{});
- CommitRequestData request;
- entity->InitializeCommitRequestData(&request);
- EXPECT_TRUE(request.entity->id.empty());
- // Before receiving commit response make local modification to the entity.
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
- /*trimmed_specifics=*/{});
- entity->ReceiveCommitResponse(GenerateAckData(request, kId, 1), false);
- // Receiving commit response with valid id should update
- // ProcessorEntity. Consecutive commit requests should include updated
- // id.
- entity->InitializeCommitRequestData(&request);
- EXPECT_EQ(kId, request.entity->id);
- EXPECT_EQ(1, request.base_version);
- }
- // Tests that entity restored after restart accepts specifics that don't match
- // the ones passed originally to RecordLocalUpdate.
- TEST_F(ProcessorEntityTest, RestoredLocalChangeWithUpdatedSpecifics) {
- // Create new entity and preserver its metadata.
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
- /*trimmed_specifics=*/{});
- sync_pb::EntityMetadata entity_metadata = entity->metadata();
- // Restore entity from metadata and emulate bridge passing different specifics
- // to SetCommitData.
- entity = RestoreFromMetadata(std::move(entity_metadata));
- std::unique_ptr<EntityData> entity_data =
- GenerateEntityData(kHash, kName, kValue2);
- entity->SetCommitData(std::move(entity_data));
- // No verification is necessary. SetCommitData shouldn't DCHECK.
- }
- // Tests the scenario where a local creation conflicts with a remote deletion,
- // where usually (and in this test) local wins. In this case, the remote update
- // should be ignored but the server IDs should be updated.
- TEST_F(ProcessorEntityTest, LocalCreationConflictsWithServerTombstone) {
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
- /*trimmed_specifics=*/{});
- ASSERT_TRUE(entity->IsUnsynced());
- ASSERT_TRUE(entity->RequiresCommitRequest());
- ASSERT_FALSE(entity->RequiresCommitData());
- ASSERT_TRUE(entity->HasCommitData());
- ASSERT_FALSE(entity->metadata().is_deleted());
- ASSERT_TRUE(entity->metadata().server_id().empty());
- // Before anything gets committed, we receive a remote tombstone, but local
- // would usually win so the remote update is ignored.
- UpdateResponseData tombstone =
- GenerateTombstone(*entity, kHash, kId, kName, base::Time::Now(), 2);
- entity->RecordIgnoredRemoteUpdate(tombstone);
- EXPECT_EQ(kId, entity->metadata().server_id());
- EXPECT_TRUE(entity->IsUnsynced());
- EXPECT_TRUE(entity->RequiresCommitRequest());
- EXPECT_FALSE(entity->RequiresCommitData());
- EXPECT_TRUE(entity->HasCommitData());
- EXPECT_FALSE(entity->metadata().is_deleted());
- // Generate a commit request. The server ID should have been reused from the
- // otherwise ignored update.
- const sync_pb::EntityMetadata metadata_v1 = entity->metadata();
- CommitRequestData request;
- entity->InitializeCommitRequestData(&request);
- EXPECT_EQ(kId, request.entity->id);
- }
- TEST_F(ProcessorEntityTest, UpdatesSpecificsCacheOnRemoteUpdates) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- const base::Time mtime = base::Time::Now();
- UpdateResponseData update =
- GenerateUpdate(*entity, kHash, kId, kName, kValue1, mtime, 10);
- sync_pb::EntitySpecifics specifics_for_caching =
- GenerateSpecifics(kName, kValue2);
- entity->RecordAcceptedRemoteUpdate(update, specifics_for_caching);
- EXPECT_EQ(
- specifics_for_caching.SerializeAsString(),
- entity->metadata().possibly_trimmed_base_specifics().SerializeAsString());
- }
- TEST_F(ProcessorEntityTest, UpdatesSpecificsCacheOnLocalUpdates) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
- std::unique_ptr<ProcessorEntity> entity = CreateNew();
- sync_pb::EntitySpecifics specifics_for_caching =
- GenerateSpecifics(kName, kValue2);
- entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
- specifics_for_caching);
- EXPECT_EQ(
- specifics_for_caching.SerializeAsString(),
- entity->metadata().possibly_trimmed_base_specifics().SerializeAsString());
- }
- } // namespace syncer
|