| // Copyright 2018 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_bookmarks/synced_bookmark_tracker.h" |
| |
| #include "base/base64.h" |
| #include "base/sha1.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "components/bookmarks/browser/bookmark_model.h" |
| #include "components/bookmarks/browser/bookmark_node.h" |
| #include "components/bookmarks/browser/bookmark_utils.h" |
| #include "components/bookmarks/test/test_bookmark_client.h" |
| #include "components/sync/base/time.h" |
| #include "components/sync/base/unique_position.h" |
| #include "components/sync/model/entity_data.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::Eq; |
| using testing::IsNull; |
| using testing::NotNull; |
| |
| namespace sync_bookmarks { |
| |
| namespace { |
| |
| // Redefinition of |enum CorruptionReason| in synced_bookmark_tracker.cc to be |
| // used in tests. |
| enum class ExpectedCorruptionReason { |
| NO_CORRUPTION = 0, |
| MISSING_SERVER_ID = 1, |
| BOOKMARK_ID_IN_TOMBSTONE = 2, |
| MISSING_BOOKMARK_ID = 3, |
| COUNT_MISMATCH = 4, |
| IDS_MISMATCH = 5, |
| kMaxValue = IDS_MISMATCH |
| }; |
| |
| sync_pb::EntitySpecifics GenerateSpecifics(const std::string& title, |
| const std::string& url) { |
| sync_pb::EntitySpecifics specifics; |
| specifics.mutable_bookmark()->set_title(title); |
| specifics.mutable_bookmark()->set_url(url); |
| return specifics; |
| } |
| |
| std::unique_ptr<sync_pb::EntityMetadata> CreateEntityMetadata( |
| const std::string& server_id, |
| bool is_deleted) { |
| auto metadata = std::make_unique<sync_pb::EntityMetadata>(); |
| metadata->set_server_id(server_id); |
| metadata->set_is_deleted(is_deleted); |
| return metadata; |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldGetAssociatedNodes) { |
| SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| const std::string kSyncId = "SYNC_ID"; |
| const std::string kTitle = "Title"; |
| const GURL kUrl("http://www.foo.com"); |
| const int64_t kId = 1; |
| const int64_t kServerVersion = 1000; |
| const base::Time kCreationTime(base::Time::Now() - |
| base::TimeDelta::FromSeconds(1)); |
| const syncer::UniquePosition unique_position = |
| syncer::UniquePosition::InitialPosition( |
| syncer::UniquePosition::RandomSuffix()); |
| const sync_pb::EntitySpecifics specifics = |
| GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); |
| |
| bookmarks::BookmarkNode node(kId, kUrl); |
| tracker.Add(kSyncId, &node, kServerVersion, kCreationTime, |
| unique_position.ToProto(), specifics); |
| const SyncedBookmarkTracker::Entity* entity = |
| tracker.GetEntityForSyncId(kSyncId); |
| ASSERT_THAT(entity, NotNull()); |
| EXPECT_THAT(entity->bookmark_node(), Eq(&node)); |
| EXPECT_THAT(entity->metadata()->server_id(), Eq(kSyncId)); |
| EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion)); |
| EXPECT_THAT(entity->metadata()->creation_time(), |
| Eq(syncer::TimeToProtoTime(kCreationTime))); |
| EXPECT_TRUE( |
| syncer::UniquePosition::FromProto(entity->metadata()->unique_position()) |
| .Equals(unique_position)); |
| |
| syncer::EntityData data; |
| *data.specifics.mutable_bookmark() = specifics.bookmark(); |
| data.unique_position = unique_position.ToProto(); |
| EXPECT_TRUE(entity->MatchesDataIgnoringParent(data)); |
| EXPECT_THAT(tracker.GetEntityForSyncId("unknown id"), IsNull()); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldReturnNullForDisassociatedNodes) { |
| SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| const std::string kSyncId = "SYNC_ID"; |
| const int64_t kId = 1; |
| const int64_t kServerVersion = 1000; |
| const base::Time kModificationTime(base::Time::Now() - |
| base::TimeDelta::FromSeconds(1)); |
| const sync_pb::UniquePosition unique_position; |
| const sync_pb::EntitySpecifics specifics = |
| GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); |
| bookmarks::BookmarkNode node(kId, GURL()); |
| tracker.Add(kSyncId, &node, kServerVersion, kModificationTime, |
| unique_position, specifics); |
| ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull()); |
| tracker.Remove(kSyncId); |
| EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull()); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldBuildBookmarkModelMetadata) { |
| SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| const std::string kSyncId = "SYNC_ID"; |
| const std::string kTitle = "Title"; |
| const GURL kUrl("http://www.foo.com"); |
| const int64_t kId = 1; |
| const int64_t kServerVersion = 1000; |
| const base::Time kCreationTime(base::Time::Now() - |
| base::TimeDelta::FromSeconds(1)); |
| const syncer::UniquePosition unique_position = |
| syncer::UniquePosition::InitialPosition( |
| syncer::UniquePosition::RandomSuffix()); |
| const sync_pb::EntitySpecifics specifics = |
| GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); |
| |
| bookmarks::BookmarkNode node(kId, kUrl); |
| tracker.Add(kSyncId, &node, kServerVersion, kCreationTime, |
| unique_position.ToProto(), specifics); |
| |
| sync_pb::BookmarkModelMetadata bookmark_model_metadata = |
| tracker.BuildBookmarkModelMetadata(); |
| |
| ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(1)); |
| EXPECT_THAT( |
| bookmark_model_metadata.bookmarks_metadata(0).metadata().server_id(), |
| Eq(kSyncId)); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, |
| ShouldRequireCommitRequestWhenSequenceNumberIsIncremented) { |
| SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| const std::string kSyncId = "SYNC_ID"; |
| const int64_t kId = 1; |
| const int64_t kServerVersion = 1000; |
| const base::Time kModificationTime(base::Time::Now() - |
| base::TimeDelta::FromSeconds(1)); |
| const sync_pb::UniquePosition unique_position; |
| const sync_pb::EntitySpecifics specifics = |
| GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); |
| bookmarks::BookmarkNode node(kId, GURL()); |
| tracker.Add(kSyncId, &node, kServerVersion, kModificationTime, |
| unique_position, specifics); |
| |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(false)); |
| tracker.IncrementSequenceNumber(kSyncId); |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(true)); |
| // TODO(crbug.com/516866): Test HasLocalChanges after submitting commit |
| // request in a separate test probably. |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldAckSequenceNumber) { |
| SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| const std::string kSyncId = "SYNC_ID"; |
| const int64_t kId = 1; |
| const int64_t kServerVersion = 1000; |
| const base::Time kModificationTime(base::Time::Now() - |
| base::TimeDelta::FromSeconds(1)); |
| const sync_pb::UniquePosition unique_position; |
| const sync_pb::EntitySpecifics specifics = |
| GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); |
| bookmarks::BookmarkNode node(kId, GURL()); |
| tracker.Add(kSyncId, &node, kServerVersion, kModificationTime, |
| unique_position, specifics); |
| |
| // Test simple scenario of ack'ing an incrememented sequence number. |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(false)); |
| tracker.IncrementSequenceNumber(kSyncId); |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(true)); |
| tracker.AckSequenceNumber(kSyncId); |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(false)); |
| |
| // Test ack'ing of a mutliple times incremented sequence number. |
| tracker.IncrementSequenceNumber(kSyncId); |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(true)); |
| tracker.IncrementSequenceNumber(kSyncId); |
| tracker.IncrementSequenceNumber(kSyncId); |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(true)); |
| tracker.AckSequenceNumber(kSyncId); |
| EXPECT_THAT(tracker.HasLocalChanges(), Eq(false)); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldUpdateUponCommitResponseWithNewId) { |
| SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| const std::string kSyncId = "SYNC_ID"; |
| const std::string kNewSyncId = "NEW_SYNC_ID"; |
| const int64_t kId = 1; |
| const int64_t kServerVersion = 1000; |
| const int64_t kNewServerVersion = 1001; |
| const base::Time kModificationTime(base::Time::Now() - |
| base::TimeDelta::FromSeconds(1)); |
| const sync_pb::UniquePosition unique_position; |
| const sync_pb::EntitySpecifics specifics = |
| GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); |
| bookmarks::BookmarkNode node(kId, GURL()); |
| tracker.Add(kSyncId, &node, kServerVersion, kModificationTime, |
| unique_position, specifics); |
| ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull()); |
| // Receive a commit response with a changed id. |
| tracker.UpdateUponCommitResponse( |
| kSyncId, kNewSyncId, /*acked_sequence_number=*/1, kNewServerVersion); |
| // Old id shouldn't be there. |
| EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull()); |
| |
| const SyncedBookmarkTracker::Entity* entity = |
| tracker.GetEntityForSyncId(kNewSyncId); |
| ASSERT_THAT(entity, NotNull()); |
| EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId)); |
| EXPECT_THAT(entity->bookmark_node(), Eq(&node)); |
| EXPECT_THAT(entity->metadata()->server_version(), Eq(kNewServerVersion)); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldUpdateId) { |
| SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| const std::string kSyncId = "SYNC_ID"; |
| const std::string kNewSyncId = "NEW_SYNC_ID"; |
| const int64_t kServerVersion = 1000; |
| const base::Time kModificationTime(base::Time::Now() - |
| base::TimeDelta::FromSeconds(1)); |
| const sync_pb::UniquePosition unique_position; |
| const sync_pb::EntitySpecifics specifics = |
| GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); |
| bookmarks::BookmarkNode node(/*id=*/1, GURL()); |
| // Track a sync entity. |
| tracker.Add(kSyncId, &node, kServerVersion, kModificationTime, |
| unique_position, specifics); |
| |
| ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull()); |
| // Update the sync id. |
| tracker.UpdateSyncForLocalCreationIfNeeded(kSyncId, kNewSyncId); |
| // Old id shouldn't be there. |
| EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull()); |
| |
| const SyncedBookmarkTracker::Entity* entity = |
| tracker.GetEntityForSyncId(kNewSyncId); |
| ASSERT_THAT(entity, NotNull()); |
| EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId)); |
| EXPECT_THAT(entity->bookmark_node(), Eq(&node)); |
| EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion)); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, |
| ShouldMaintainTombstoneOrderBetweenCtorAndBuildBookmarkModelMetadata) { |
| // Feed a metadata batch of 5 entries to the constructor of the tracker. |
| // First 2 are for node, and the last 4 are for tombstones. |
| |
| // Server ids. |
| const std::string kId0 = "id0"; |
| const std::string kId1 = "id1"; |
| const std::string kId2 = "id2"; |
| const std::string kId3 = "id3"; |
| const std::string kId4 = "id4"; |
| |
| const GURL kUrl("http://www.foo.com"); |
| bookmarks::BookmarkNode node0(/*id=*/0, kUrl); |
| bookmarks::BookmarkNode node1(/*id=*/1, kUrl); |
| |
| std::vector<NodeMetadataPair> node_metadata_pairs; |
| node_metadata_pairs.emplace_back( |
| &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| nullptr, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/true)); |
| node_metadata_pairs.emplace_back( |
| nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true)); |
| node_metadata_pairs.emplace_back( |
| nullptr, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/true)); |
| |
| SyncedBookmarkTracker tracker(std::move(node_metadata_pairs), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| |
| sync_pb::BookmarkModelMetadata bookmark_model_metadata = |
| tracker.BuildBookmarkModelMetadata(); |
| |
| // Tombstones should be the last 3 entries in the metadata and in the same |
| // order as given to the constructor. |
| ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(5)); |
| EXPECT_THAT( |
| bookmark_model_metadata.bookmarks_metadata(2).metadata().server_id(), |
| Eq(kId2)); |
| EXPECT_THAT( |
| bookmark_model_metadata.bookmarks_metadata(3).metadata().server_id(), |
| Eq(kId3)); |
| EXPECT_THAT( |
| bookmark_model_metadata.bookmarks_metadata(4).metadata().server_id(), |
| Eq(kId4)); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, |
| ShouldMaintainOrderOfMarkDeletedCallsWhenBuildBookmarkModelMetadata) { |
| // Server ids. |
| const std::string kId0 = "id0"; |
| const std::string kId1 = "id1"; |
| const std::string kId2 = "id2"; |
| const std::string kId3 = "id3"; |
| const std::string kId4 = "id4"; |
| |
| const GURL kUrl("http://www.foo.com"); |
| bookmarks::BookmarkNode node0(/*id=*/0, kUrl); |
| bookmarks::BookmarkNode node1(/*id=*/1, kUrl); |
| bookmarks::BookmarkNode node2(/*id=*/2, kUrl); |
| bookmarks::BookmarkNode node3(/*id=*/3, kUrl); |
| bookmarks::BookmarkNode node4(/*id=*/4, kUrl); |
| |
| std::vector<NodeMetadataPair> node_metadata_pairs; |
| node_metadata_pairs.emplace_back( |
| &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| &node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| &node3, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| &node4, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/false)); |
| |
| SyncedBookmarkTracker tracker(std::move(node_metadata_pairs), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| |
| // Mark entities deleted in that order kId2, kId4, kId1 |
| tracker.MarkDeleted(kId2); |
| tracker.MarkDeleted(kId4); |
| tracker.MarkDeleted(kId1); |
| |
| sync_pb::BookmarkModelMetadata bookmark_model_metadata = |
| tracker.BuildBookmarkModelMetadata(); |
| |
| // Tombstones should be the last 3 entries in the metadata and in the same as |
| // calling MarkDeleted(). |
| ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(5)); |
| EXPECT_THAT( |
| bookmark_model_metadata.bookmarks_metadata(2).metadata().server_id(), |
| Eq(kId2)); |
| EXPECT_THAT( |
| bookmark_model_metadata.bookmarks_metadata(3).metadata().server_id(), |
| Eq(kId4)); |
| EXPECT_THAT( |
| bookmark_model_metadata.bookmarks_metadata(4).metadata().server_id(), |
| Eq(kId1)); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, |
| ShouldOrderParentUpdatesBeforeChildUpdatesAndDeletionsComeLast) { |
| const size_t kMaxEntries = 1000; |
| |
| // Construct this structure: |
| // bookmark_bar |
| // |- node0 |
| // |- node1 |
| // |- node2 |
| |
| std::unique_ptr<bookmarks::BookmarkModel> bookmark_model = |
| bookmarks::TestBookmarkClient::CreateModel(); |
| |
| const bookmarks::BookmarkNode* bookmark_bar_node = |
| bookmark_model->bookmark_bar_node(); |
| const bookmarks::BookmarkNode* node0 = bookmark_model->AddFolder( |
| /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("node0")); |
| const bookmarks::BookmarkNode* node1 = bookmark_model->AddFolder( |
| /*parent=*/node0, /*index=*/0, base::UTF8ToUTF16("node1")); |
| const bookmarks::BookmarkNode* node2 = bookmark_model->AddFolder( |
| /*parent=*/node1, /*index=*/0, base::UTF8ToUTF16("node2")); |
| |
| // Server ids. |
| const std::string kId0 = "id0"; |
| const std::string kId1 = "id1"; |
| const std::string kId2 = "id2"; |
| const std::string kId3 = "id3"; |
| |
| // Prepare the metadata with shuffled order. |
| std::vector<NodeMetadataPair> node_metadata_pairs; |
| node_metadata_pairs.emplace_back( |
| node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true)); |
| node_metadata_pairs.emplace_back( |
| node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false)); |
| node_metadata_pairs.emplace_back( |
| node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false)); |
| |
| SyncedBookmarkTracker tracker(std::move(node_metadata_pairs), |
| std::make_unique<sync_pb::ModelTypeState>()); |
| |
| // Mark the entities that they have local changes. (in shuffled order just to |
| // verify the tracker doesn't simply maintain the order of updates similar to |
| // with deletions). |
| tracker.IncrementSequenceNumber(kId3); |
| tracker.IncrementSequenceNumber(kId1); |
| tracker.IncrementSequenceNumber(kId2); |
| tracker.IncrementSequenceNumber(kId0); |
| |
| std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_change = |
| tracker.GetEntitiesWithLocalChanges(kMaxEntries); |
| |
| ASSERT_THAT(entities_with_local_change.size(), Eq(4U)); |
| // Verify updates are in parent before child order node0 --> node1 --> node2. |
| EXPECT_THAT(entities_with_local_change[0]->metadata()->server_id(), Eq(kId0)); |
| EXPECT_THAT(entities_with_local_change[1]->metadata()->server_id(), Eq(kId1)); |
| EXPECT_THAT(entities_with_local_change[2]->metadata()->server_id(), Eq(kId2)); |
| // Verify that deletion is the last entry. |
| EXPECT_THAT(entities_with_local_change[3]->metadata()->server_id(), Eq(kId3)); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldMatchModelAndMetadata) { |
| std::unique_ptr<bookmarks::BookmarkModel> model = |
| bookmarks::TestBookmarkClient::CreateModel(); |
| |
| const bookmarks::BookmarkNode* bookmark_bar_node = model->bookmark_bar_node(); |
| const bookmarks::BookmarkNode* node = model->AddFolder( |
| /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("node0")); |
| |
| sync_pb::BookmarkModelMetadata model_metadata; |
| model_metadata.mutable_model_type_state()->set_initial_sync_done(true); |
| // Add entries for all the permanent nodes. TestBookmarkClient creates all the |
| // 3 permanent nodes. |
| sync_pb::BookmarkMetadata* bookmark_metadata = |
| model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->bookmark_bar_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId"); |
| |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->other_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId"); |
| |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->mobile_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId"); |
| |
| // Add entry for the extra node. |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(node->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("NodeId"); |
| |
| // Add a tombstone entry. |
| sync_pb::BookmarkMetadata* tombstone = |
| model_metadata.add_bookmarks_metadata(); |
| tombstone->mutable_metadata()->set_server_id("tombstoneId"); |
| tombstone->mutable_metadata()->set_is_deleted(true); |
| |
| base::HistogramTester histogram_tester; |
| EXPECT_TRUE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| histogram_tester.ExpectUniqueSample( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*count=*/1); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, |
| ShouldNotMatchModelAndMetadataIfMissingMobileFolder) { |
| std::unique_ptr<bookmarks::BookmarkModel> model = |
| bookmarks::TestBookmarkClient::CreateModel(); |
| |
| sync_pb::BookmarkModelMetadata model_metadata; |
| model_metadata.mutable_model_type_state()->set_initial_sync_done(true); |
| // Add entries for all the permanent nodes except for the Mobile bookmarks |
| // folder. |
| sync_pb::BookmarkMetadata* bookmark_metadata = |
| model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->bookmark_bar_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId"); |
| |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->other_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId"); |
| |
| base::HistogramTester histogram_tester; |
| EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| histogram_tester.ExpectUniqueSample( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::COUNT_MISMATCH, /*count=*/1); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, ShouldNotMatchModelAndCorruptedMetadata) { |
| std::unique_ptr<bookmarks::BookmarkModel> model = |
| bookmarks::TestBookmarkClient::CreateModel(); |
| |
| sync_pb::BookmarkModelMetadata model_metadata; |
| model_metadata.mutable_model_type_state()->set_initial_sync_done(true); |
| // Add entries for 3 permanent nodes only. TestBookmarkClient creates all the |
| // 4 permanent nodes. |
| sync_pb::BookmarkMetadata* bookmark_metadata = |
| model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->bookmark_bar_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId"); |
| |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->mobile_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId"); |
| |
| base::HistogramTester histogram_tester; |
| // The entry for the Other bookmarks is missing. |
| EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| histogram_tester.ExpectBucketCount( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::COUNT_MISMATCH, /*count=*/1); |
| |
| // The entry for the Other bookmarks is missing a server id. |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->other_node()->id()); |
| EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| |
| histogram_tester.ExpectBucketCount( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::MISSING_SERVER_ID, /*count=*/1); |
| |
| // The entry for the Other bookmarks is missing a node id. |
| bookmark_metadata->clear_id(); |
| bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId"); |
| EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| histogram_tester.ExpectBucketCount( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::MISSING_BOOKMARK_ID, /*count=*/1); |
| |
| // The entry for the Other bookmarks is having a wrong node id. |
| bookmark_metadata->set_id(model->other_node()->id() + 1000); |
| EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| histogram_tester.ExpectBucketCount( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::IDS_MISMATCH, /*count=*/1); |
| |
| // A tombstone shouldn't have a node id. |
| sync_pb::BookmarkMetadata* tombstone = |
| model_metadata.add_bookmarks_metadata(); |
| tombstone->mutable_metadata()->set_server_id("tombstoneId"); |
| tombstone->mutable_metadata()->set_is_deleted(true); |
| tombstone->set_id(10); |
| EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| histogram_tester.ExpectBucketCount( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::BOOKMARK_ID_IN_TOMBSTONE, |
| /*count=*/1); |
| } |
| |
| TEST(SyncedBookmarkTrackerTest, |
| ShouldMatchModelWithUnsyncableNodesAndMetadata) { |
| // Add a managed node with an arbitrary id 100. |
| const int64_t kManagedNodeId = 100; |
| bookmarks::BookmarkPermanentNodeList extra_nodes; |
| extra_nodes.push_back( |
| std::make_unique<bookmarks::BookmarkPermanentNode>(kManagedNodeId)); |
| bookmarks::BookmarkPermanentNode* extra_node = extra_nodes.back().get(); |
| auto client = std::make_unique<bookmarks::TestBookmarkClient>(); |
| client->SetExtraNodesToLoad(std::move(extra_nodes)); |
| |
| std::unique_ptr<bookmarks::BookmarkModel> model = |
| bookmarks::TestBookmarkClient::CreateModelWithClient(std::move(client)); |
| |
| // The model should contain the managed node now. |
| ASSERT_THAT(GetBookmarkNodeByID(model.get(), kManagedNodeId), Eq(extra_node)); |
| |
| sync_pb::BookmarkModelMetadata model_metadata; |
| model_metadata.mutable_model_type_state()->set_initial_sync_done(true); |
| // Add entries for all the permanent nodes. TestBookmarkClient creates all the |
| // 3 permanent nodes. |
| sync_pb::BookmarkMetadata* bookmark_metadata = |
| model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->bookmark_bar_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId"); |
| |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->other_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId"); |
| |
| bookmark_metadata = model_metadata.add_bookmarks_metadata(); |
| bookmark_metadata->set_id(model->mobile_node()->id()); |
| bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId"); |
| |
| base::HistogramTester histogram_tester; |
| EXPECT_TRUE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata( |
| model.get(), model_metadata)); |
| histogram_tester.ExpectUniqueSample( |
| "Sync.BookmarksModelMetadataCorruptionReason", |
| /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*count=*/1); |
| } |
| |
| } // namespace |
| |
| } // namespace sync_bookmarks |