blob: 00c4af28a81fc09059a08fccff74ae93ede777d2 [file] [log] [blame] [edit]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync/engine/bookmark_update_preprocessing.h"
#include <stdint.h>
#include "base/test/metrics/histogram_tester.h"
#include "base/uuid.h"
#include "components/sync/base/unique_position.h"
#include "components/sync/protocol/bookmark_specifics.pb.h"
#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/sync_entity.pb.h"
#include "components/sync/protocol/unique_position.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
namespace {
using testing::Eq;
using testing::IsEmpty;
using testing::Ne;
enum class ExpectedBookmarkGuidSource {
kSpecifics = 0,
kValidOCII = 1,
kDeprecatedLeftEmpty = 2,
kInferred = 3,
kLeftEmptyPossiblyForClientTag = 4,
kMaxValue = kLeftEmptyPossiblyForClientTag,
};
TEST(BookmarkUpdatePreprocessingTest,
ShouldPropagateUniquePositionFromSpecifics) {
const UniquePosition kUniquePosition =
UniquePosition::InitialPosition(UniquePosition::RandomSuffix());
sync_pb::SyncEntity entity;
*entity.mutable_specifics()->mutable_bookmark()->mutable_unique_position() =
*entity.mutable_unique_position() = kUniquePosition.ToProto();
const bool is_preprocessed =
AdaptUniquePositionForBookmark(entity, entity.mutable_specifics());
EXPECT_FALSE(is_preprocessed);
EXPECT_TRUE(
UniquePosition::FromProto(entity.specifics().bookmark().unique_position())
.Equals(kUniquePosition));
}
TEST(BookmarkUpdatePreprocessingTest,
ShouldPropagateUniquePositionFromSyncEntity) {
const UniquePosition kUniquePosition =
UniquePosition::InitialPosition(UniquePosition::RandomSuffix());
sync_pb::SyncEntity entity;
*entity.mutable_unique_position() = kUniquePosition.ToProto();
const bool is_preprocessed =
AdaptUniquePositionForBookmark(entity, entity.mutable_specifics());
EXPECT_TRUE(is_preprocessed);
EXPECT_TRUE(
UniquePosition::FromProto(entity.specifics().bookmark().unique_position())
.Equals(kUniquePosition));
}
TEST(BookmarkUpdatePreprocessingTest,
ShouldComputeUniquePositionFromPositionInParent) {
sync_pb::SyncEntity entity;
entity.set_originator_cache_guid(
base::Uuid::GenerateRandomV4().AsLowercaseString());
entity.set_originator_client_item_id("1");
entity.set_position_in_parent(5);
sync_pb::EntitySpecifics specifics1;
bool is_preprocessed = AdaptUniquePositionForBookmark(entity, &specifics1);
EXPECT_TRUE(is_preprocessed);
sync_pb::EntitySpecifics specifics2;
entity.set_position_in_parent(6);
is_preprocessed = AdaptUniquePositionForBookmark(entity, &specifics2);
EXPECT_TRUE(is_preprocessed);
EXPECT_TRUE(UniquePosition::FromProto(specifics1.bookmark().unique_position())
.IsValid());
EXPECT_TRUE(UniquePosition::FromProto(specifics2.bookmark().unique_position())
.IsValid());
EXPECT_TRUE(UniquePosition::FromProto(specifics1.bookmark().unique_position())
.LessThan(UniquePosition::FromProto(
specifics2.bookmark().unique_position())));
}
TEST(BookmarkUpdatePreprocessingTest,
ShouldComputeUniquePositionFromInsertAfterItemId) {
sync_pb::SyncEntity entity;
entity.set_originator_cache_guid(
base::Uuid::GenerateRandomV4().AsLowercaseString());
entity.set_originator_client_item_id("1");
entity.set_insert_after_item_id("ITEM_ID");
const bool is_preprocessed =
AdaptUniquePositionForBookmark(entity, entity.mutable_specifics());
EXPECT_TRUE(is_preprocessed);
EXPECT_TRUE(
UniquePosition::FromProto(entity.specifics().bookmark().unique_position())
.IsValid());
}
TEST(BookmarkUpdatePreprocessingTest, ShouldFallBackToRandomUniquePosition) {
sync_pb::SyncEntity entity;
const bool is_preprocessed =
AdaptUniquePositionForBookmark(entity, entity.mutable_specifics());
EXPECT_TRUE(is_preprocessed);
EXPECT_TRUE(
UniquePosition::FromProto(entity.specifics().bookmark().unique_position())
.IsValid());
}
// Tests that AdaptGuidForBookmark() propagates GUID in specifics if the field
// is set (even if it doesn't match the originator client item ID).
TEST(BookmarkUpdatePreprocessingTest, ShouldPropagateGuidFromSpecifics) {
const std::string kGuidInSpecifics =
base::Uuid::GenerateRandomV4().AsLowercaseString();
sync_pb::SyncEntity entity;
entity.set_originator_cache_guid(
base::Uuid::GenerateRandomV4().AsLowercaseString());
entity.set_originator_client_item_id(
base::Uuid::GenerateRandomV4().AsLowercaseString());
entity.mutable_specifics()->mutable_bookmark()->set_guid(kGuidInSpecifics);
base::HistogramTester histogram_tester;
sync_pb::EntitySpecifics specifics = entity.specifics();
AdaptGuidForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().guid(), Eq(kGuidInSpecifics));
histogram_tester.ExpectUniqueSample("Sync.BookmarkGUIDSource2",
/*sample=*/
ExpectedBookmarkGuidSource::kSpecifics,
/*expected_bucket_count=*/1);
}
// Tests that AdaptGuidForBookmark() uses the originator client item ID as GUID
// when it is a valid GUID, and the GUID in specifics is not set.
TEST(BookmarkUpdatePreprocessingTest, ShouldUseOriginatorClientItemIdAsGuid) {
const std::string kOriginatorClientItemId =
base::Uuid::GenerateRandomV4().AsLowercaseString();
sync_pb::SyncEntity entity;
entity.set_originator_cache_guid(
base::Uuid::GenerateRandomV4().AsLowercaseString());
entity.set_originator_client_item_id(kOriginatorClientItemId);
entity.mutable_specifics()->mutable_bookmark();
base::HistogramTester histogram_tester;
sync_pb::EntitySpecifics specifics = entity.specifics();
AdaptGuidForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().guid(), Eq(kOriginatorClientItemId));
histogram_tester.ExpectUniqueSample("Sync.BookmarkGUIDSource2",
/*sample=*/
ExpectedBookmarkGuidSource::kValidOCII,
/*expected_bucket_count=*/1);
}
// Tests that AdaptGuidForBookmark() infers the GUID when the field in specifics
// is empty and originator client item ID is not a valid GUID.
TEST(BookmarkUpdatePreprocessingTest, ShouldInferGuid) {
const std::string kOriginatorClientItemId = "1";
sync_pb::SyncEntity entity;
entity.set_originator_cache_guid(
base::Uuid::GenerateRandomV4().AsLowercaseString());
entity.set_originator_client_item_id(kOriginatorClientItemId);
entity.mutable_specifics()->mutable_bookmark();
base::HistogramTester histogram_tester;
sync_pb::EntitySpecifics specifics = entity.specifics();
AdaptGuidForBookmark(entity, &specifics);
EXPECT_TRUE(
base::Uuid::ParseLowercase(specifics.bookmark().guid()).is_valid());
histogram_tester.ExpectUniqueSample("Sync.BookmarkGUIDSource2",
/*sample=*/
ExpectedBookmarkGuidSource::kInferred,
/*expected_bucket_count=*/1);
}
TEST(BookmarkUpdatePreprocessingTest,
ShouldNotInferGuidIfNoOriginatorInformation) {
const std::string kOriginatorClientItemId = "1";
sync_pb::SyncEntity entity;
entity.mutable_specifics()->mutable_bookmark();
base::HistogramTester histogram_tester;
sync_pb::EntitySpecifics specifics = entity.specifics();
AdaptGuidForBookmark(entity, &specifics);
EXPECT_FALSE(specifics.bookmark().has_guid());
histogram_tester.ExpectUniqueSample(
"Sync.BookmarkGUIDSource2",
/*sample=*/
ExpectedBookmarkGuidSource::kLeftEmptyPossiblyForClientTag,
/*expected_bucket_count=*/1);
}
// Tests that inferred GUIDs are computed deterministically.
TEST(BookmarkUpdatePreprocessingTest, ShouldInferDeterministicGuid) {
EXPECT_THAT(InferGuidForLegacyBookmarkForTesting("cacheguid1", "1"),
Eq(InferGuidForLegacyBookmarkForTesting("cacheguid1", "1")));
EXPECT_THAT(InferGuidForLegacyBookmarkForTesting("cacheguid1", "2"),
Eq(InferGuidForLegacyBookmarkForTesting("cacheguid1", "2")));
}
// Tests that unique GUIDs are produced if either of the two involved fields
// changes.
TEST(BookmarkUpdatePreprocessingTest, ShouldInferDistictGuids) {
EXPECT_THAT(InferGuidForLegacyBookmarkForTesting("cacheguid1", "1"),
Ne(InferGuidForLegacyBookmarkForTesting("cacheguid1", "2")));
EXPECT_THAT(InferGuidForLegacyBookmarkForTesting("cacheguid1", "1"),
Ne(InferGuidForLegacyBookmarkForTesting("cacheguid2", "1")));
}
TEST(BookmarkUpdatePreprocessingTest, ShouldUseTypeInSpecifics) {
sync_pb::SyncEntity entity;
sync_pb::EntitySpecifics specifics;
*specifics.mutable_bookmark() =
sync_pb::BookmarkSpecifics::default_instance();
specifics.mutable_bookmark()->set_type(sync_pb::BookmarkSpecifics::FOLDER);
AdaptTypeForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().type(),
Eq(sync_pb::BookmarkSpecifics::FOLDER));
*specifics.mutable_bookmark() =
sync_pb::BookmarkSpecifics::default_instance();
specifics.mutable_bookmark()->set_type(sync_pb::BookmarkSpecifics::URL);
AdaptTypeForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().type(), Eq(sync_pb::BookmarkSpecifics::URL));
// Even if SyncEntity says otherwise, specifics should prevail.
entity.set_folder(true);
*specifics.mutable_bookmark() =
sync_pb::BookmarkSpecifics::default_instance();
specifics.mutable_bookmark()->set_type(sync_pb::BookmarkSpecifics::URL);
AdaptTypeForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().type(), Eq(sync_pb::BookmarkSpecifics::URL));
}
TEST(BookmarkUpdatePreprocessingTest,
ShouldInferTypeFromFolderFieldInSyncEntity) {
sync_pb::SyncEntity entity;
sync_pb::EntitySpecifics specifics;
*specifics.mutable_bookmark() =
sync_pb::BookmarkSpecifics::default_instance();
entity.set_folder(true);
AdaptTypeForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().type(),
Eq(sync_pb::BookmarkSpecifics::FOLDER));
*specifics.mutable_bookmark() =
sync_pb::BookmarkSpecifics::default_instance();
entity.set_folder(false);
AdaptTypeForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().type(), Eq(sync_pb::BookmarkSpecifics::URL));
}
TEST(BookmarkUpdatePreprocessingTest,
ShouldInferTypeFromPresenceOfUrlInSpecifics) {
sync_pb::SyncEntity entity;
sync_pb::EntitySpecifics specifics;
*specifics.mutable_bookmark() =
sync_pb::BookmarkSpecifics::default_instance();
AdaptTypeForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().type(),
Eq(sync_pb::BookmarkSpecifics::FOLDER));
*specifics.mutable_bookmark() =
sync_pb::BookmarkSpecifics::default_instance();
specifics.mutable_bookmark()->set_url("http://foo.com");
AdaptTypeForBookmark(entity, &specifics);
EXPECT_THAT(specifics.bookmark().type(), Eq(sync_pb::BookmarkSpecifics::URL));
}
} // namespace
} // namespace syncer