#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;
}
}
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, {});
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_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_F(ProcessorEntityTest, NewLocalItem) {
std::unique_ptr<ProcessorEntity> entity = CreateNew();
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
{});
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());
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);
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_F(ProcessorEntityTest,
ShouldIgnoreCommitResponseWithInvalidServerVersion) {
std::unique_ptr<ProcessorEntity> entity = CreateNew();
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
{});
CommitRequestData request;
entity->InitializeCommitRequestData(&request);
entity->ReceiveCommitResponse(GenerateAckData(request, kId, 2), false);
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
{});
ASSERT_EQ(2, entity->metadata().server_version());
ASSERT_EQ(2, entity->metadata().sequence_number());
ASSERT_EQ(1, entity->metadata().acked_sequence_number());
entity->InitializeCommitRequestData(&request);
entity->ReceiveCommitResponse(GenerateAckData(request, kId, 1), false);
EXPECT_EQ(2, entity->metadata().server_version());
}
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, {});
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_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, {});
entity->SetStorageKey(kKey);
EXPECT_EQ(kKey, entity->storage_key());
}
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, {});
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());
}
TEST_F(ProcessorEntityTest, ServerTombstone) {
std::unique_ptr<ProcessorEntity> entity = CreateSynced();
const base::Time mtime = base::Time::Now();
UpdateResponseData tombstone =
GenerateTombstone(*entity, kHash, kId, kName, mtime, 2);
entity->RecordAcceptedRemoteUpdate(tombstone, {});
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_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();
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
{});
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());
CommitRequestData request;
entity->InitializeCommitRequestData(&request);
EXPECT_EQ(kId, request.entity->id);
EXPECT_FALSE(entity->RequiresCommitRequest());
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_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();
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());
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);
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_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());
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
{});
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());
CommitRequestData request;
entity->InitializeCommitRequestData(&request);
EXPECT_EQ(kId, request.entity->id);
EXPECT_FALSE(entity->RequiresCommitRequest());
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_F(ProcessorEntityTest, LocalChangesInterleaved) {
std::unique_ptr<ProcessorEntity> entity = CreateSynced();
const std::string specifics_hash_v0 = entity->metadata().specifics_hash();
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
{});
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());
CommitRequestData request_v1;
entity->InitializeCommitRequestData(&request_v1);
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue3),
{});
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());
CommitRequestData request_v2;
entity->InitializeCommitRequestData(&request_v2);
EXPECT_TRUE(entity->IsUnsynced());
EXPECT_FALSE(entity->RequiresCommitRequest());
EXPECT_FALSE(entity->RequiresCommitData());
EXPECT_FALSE(entity->CanClearMetadata());
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());
EXPECT_FALSE(entity->HasCommitData());
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());
}
TEST_F(ProcessorEntityTest, NewLocalChangeUpdatedId) {
std::unique_ptr<ProcessorEntity> entity = CreateNew();
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
{});
CommitRequestData request;
entity->InitializeCommitRequestData(&request);
EXPECT_TRUE(request.entity->id.empty());
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue2),
{});
entity->ReceiveCommitResponse(GenerateAckData(request, kId, 1), false);
entity->InitializeCommitRequestData(&request);
EXPECT_EQ(kId, request.entity->id);
EXPECT_EQ(1, request.base_version);
}
TEST_F(ProcessorEntityTest, RestoredLocalChangeWithUpdatedSpecifics) {
std::unique_ptr<ProcessorEntity> entity = CreateNew();
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
{});
sync_pb::EntityMetadata entity_metadata = entity->metadata();
entity = RestoreFromMetadata(std::move(entity_metadata));
std::unique_ptr<EntityData> entity_data =
GenerateEntityData(kHash, kName, kValue2);
entity->SetCommitData(std::move(entity_data));
}
TEST_F(ProcessorEntityTest, LocalCreationConflictsWithServerTombstone) {
std::unique_ptr<ProcessorEntity> entity = CreateNew();
entity->RecordLocalUpdate(GenerateEntityData(kHash, kName, kValue1),
{});
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());
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());
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());
}
}