123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- // 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/bookmark_model_observer_impl.h"
- #include <algorithm>
- #include <list>
- #include <map>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "base/callback_helpers.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/test/mock_callback.h"
- #include "components/bookmarks/browser/bookmark_model.h"
- #include "components/bookmarks/test/test_bookmark_client.h"
- #include "components/favicon_base/favicon_types.h"
- #include "components/sync/base/time.h"
- #include "components/sync/base/unique_position.h"
- #include "components/sync/protocol/bookmark_specifics.pb.h"
- #include "components/sync/protocol/entity_metadata.pb.h"
- #include "components/sync/protocol/entity_specifics.pb.h"
- #include "components/sync/protocol/model_type_state.pb.h"
- #include "components/sync_bookmarks/bookmark_specifics_conversions.h"
- #include "components/sync_bookmarks/synced_bookmark_tracker.h"
- #include "components/sync_bookmarks/synced_bookmark_tracker_entity.h"
- #include "components/undo/bookmark_undo_service.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/skia/include/core/SkBitmap.h"
- #include "ui/gfx/image/image.h"
- namespace sync_bookmarks {
- namespace {
- using testing::ElementsAre;
- using testing::Eq;
- using testing::IsEmpty;
- using testing::IsNull;
- using testing::Ne;
- using testing::NiceMock;
- using testing::NotNull;
- using testing::SizeIs;
- using testing::UnorderedElementsAre;
- const char kBookmarkBarId[] = "bookmark_bar_id";
- const char kBookmarkBarTag[] = "bookmark_bar";
- const char kOtherBookmarksId[] = "other_bookmarks_id";
- const char kOtherBookmarksTag[] = "other_bookmarks";
- const char kMobileBookmarksId[] = "synced_bookmarks_id";
- const char kMobileBookmarksTag[] = "synced_bookmarks";
- // Matches |arg| of type SyncedBookmarkTrackerEntity*.
- MATCHER_P(HasBookmarkNode, node, "") {
- return arg->bookmark_node() == node;
- }
- // Returns a single-color 16x16 image using |color|.
- gfx::Image CreateTestImage(SkColor color) {
- SkBitmap bitmap;
- bitmap.allocN32Pixels(16, 16);
- bitmap.eraseColor(color);
- return gfx::Image::CreateFrom1xBitmap(bitmap);
- }
- class BookmarkModelObserverImplTest : public testing::Test {
- public:
- BookmarkModelObserverImplTest()
- : bookmark_tracker_(
- SyncedBookmarkTracker::CreateEmpty(sync_pb::ModelTypeState())),
- observer_(nudge_for_commit_closure_.Get(),
- /*on_bookmark_model_being_deleted_closure=*/base::DoNothing(),
- bookmark_tracker_.get()),
- bookmark_model_(bookmarks::TestBookmarkClient::CreateModel()) {
- bookmark_model_->AddObserver(&observer_);
- sync_pb::EntitySpecifics specifics;
- specifics.mutable_bookmark()->set_legacy_canonicalized_title(
- kBookmarkBarTag);
- bookmark_tracker_->Add(
- /*bookmark_node=*/bookmark_model()->bookmark_bar_node(),
- /*sync_id=*/kBookmarkBarId,
- /*server_version=*/0, /*creation_time=*/base::Time::Now(), specifics);
- specifics.mutable_bookmark()->set_legacy_canonicalized_title(
- kOtherBookmarksTag);
- bookmark_tracker_->Add(
- /*bookmark_node=*/bookmark_model()->other_node(),
- /*sync_id=*/kOtherBookmarksId,
- /*server_version=*/0, /*creation_time=*/base::Time::Now(), specifics);
- specifics.mutable_bookmark()->set_legacy_canonicalized_title(
- kMobileBookmarksTag);
- bookmark_tracker_->Add(
- /*bookmark_node=*/bookmark_model()->mobile_node(),
- /*sync_id=*/kMobileBookmarksId,
- /*server_version=*/0, /*creation_time=*/base::Time::Now(), specifics);
- }
- ~BookmarkModelObserverImplTest() override {
- bookmark_model_->RemoveObserver(&observer_);
- }
- void SimulateCommitResponseForAllLocalChanges() {
- for (const SyncedBookmarkTrackerEntity* entity :
- bookmark_tracker()->GetEntitiesWithLocalChanges()) {
- const std::string id = entity->metadata().server_id();
- // Don't simulate change in id for simplicity.
- bookmark_tracker()->UpdateUponCommitResponse(
- entity, id,
- /*server_version=*/1,
- /*acked_sequence_number=*/entity->metadata().sequence_number());
- }
- }
- syncer::UniquePosition PositionOf(
- const bookmarks::BookmarkNode* bookmark_node) {
- const SyncedBookmarkTrackerEntity* entity =
- bookmark_tracker()->GetEntityForBookmarkNode(bookmark_node);
- return syncer::UniquePosition::FromProto(
- entity->metadata().unique_position());
- }
- std::vector<const bookmarks::BookmarkNode*> GenerateBookmarkNodes(
- size_t num_bookmarks) {
- const std::string kTitle = "title";
- const std::string kUrl = "http://www.url.com";
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- std::vector<const bookmarks::BookmarkNode*> nodes;
- for (size_t i = 0; i < num_bookmarks; ++i) {
- nodes.push_back(bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/i, base::UTF8ToUTF16(kTitle),
- GURL(kUrl)));
- }
- // Verify number of entities local changes. Should be the same as number of
- // new nodes.
- DCHECK_EQ(bookmark_tracker()->GetEntitiesWithLocalChanges().size(),
- num_bookmarks);
- // All bookmarks should be tracked now (including permanent nodes).
- DCHECK_EQ(bookmark_tracker()->TrackedEntitiesCountForTest(),
- 3 + num_bookmarks);
- return nodes;
- }
- bookmarks::BookmarkModel* bookmark_model() { return bookmark_model_.get(); }
- SyncedBookmarkTracker* bookmark_tracker() { return bookmark_tracker_.get(); }
- BookmarkModelObserverImpl* observer() { return &observer_; }
- base::MockCallback<base::RepeatingClosure>* nudge_for_commit_closure() {
- return &nudge_for_commit_closure_;
- }
- bookmarks::TestBookmarkClient* bookmark_client() {
- return static_cast<bookmarks::TestBookmarkClient*>(
- bookmark_model_->client());
- }
- private:
- NiceMock<base::MockCallback<base::RepeatingClosure>>
- nudge_for_commit_closure_;
- std::unique_ptr<SyncedBookmarkTracker> bookmark_tracker_;
- BookmarkModelObserverImpl observer_;
- std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
- };
- TEST_F(BookmarkModelObserverImplTest,
- BookmarkAddedShouldPutInTheTrackerAndNudgeForCommit) {
- const std::string kTitle = "title";
- const std::string kUrl = "http://www.url.com";
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* bookmark_node = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16(kTitle),
- GURL(kUrl));
- EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
- std::vector<const SyncedBookmarkTrackerEntity*> local_changes =
- bookmark_tracker()->GetEntitiesWithLocalChanges();
- ASSERT_THAT(local_changes.size(), 1U);
- EXPECT_THAT(local_changes[0]->bookmark_node(), Eq(bookmark_node));
- EXPECT_THAT(local_changes[0]->metadata().server_id(),
- Eq(bookmark_node->guid().AsLowercaseString()));
- }
- TEST_F(BookmarkModelObserverImplTest,
- BookmarkChangedShouldUpdateTheTrackerAndNudgeForCommit) {
- const std::string kTitle1 = "title1";
- const std::string kUrl1 = "http://www.url1.com";
- const std::string kNewUrl1 = "http://www.new-url1.com";
- const std::string kTitle2 = "title2";
- const std::string kUrl2 = "http://www.url2.com";
- const std::string kNewTitle2 = "new_title2";
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* bookmark_node1 = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16(kTitle1),
- GURL(kUrl1));
- const bookmarks::BookmarkNode* bookmark_node2 = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16(kTitle2),
- GURL(kUrl2));
- // Both bookmarks should be tracked now.
- ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 5U);
- // There should be two local changes now for both entities.
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 2U);
- SimulateCommitResponseForAllLocalChanges();
- // There should be no local changes now.
- ASSERT_TRUE(bookmark_tracker()->GetEntitiesWithLocalChanges().empty());
- // Now update the title of the 2nd node.
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- bookmark_model()->SetTitle(bookmark_node2, base::UTF8ToUTF16(kNewTitle2));
- // Node 2 should be in the local changes list.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
- ElementsAre(HasBookmarkNode(bookmark_node2)));
- // Now update the url of the 1st node.
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- bookmark_model()->SetURL(bookmark_node1, GURL(kNewUrl1));
- // Node 1 and 2 should be in the local changes list.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
- UnorderedElementsAre(HasBookmarkNode(bookmark_node1),
- HasBookmarkNode(bookmark_node2)));
- // Now update metainfo of the 1st node.
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- bookmark_model()->SetNodeMetaInfo(bookmark_node1, "key", "value");
- }
- TEST_F(BookmarkModelObserverImplTest,
- BookmarkMovedShouldUpdateTheTrackerAndNudgeForCommit) {
- // Build this structure:
- // bookmark_bar
- // |- folder1
- // |- bookmark1
- const GURL kUrl("http://www.url1.com");
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* folder1_node = bookmark_model()->AddFolder(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"folder1");
- const bookmarks::BookmarkNode* bookmark1_node = bookmark_model()->AddURL(
- /*parent=*/folder1_node, /*index=*/0, u"bookmark1", kUrl);
- // Verify number of entities local changes. Should be the same as number of
- // new nodes.
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 2U);
- // All bookmarks should be tracked now.
- ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 5U);
- SimulateCommitResponseForAllLocalChanges();
- // There should be no local changes now.
- ASSERT_TRUE(bookmark_tracker()->GetEntitiesWithLocalChanges().empty());
- // Now change it to this structure.
- // Build this structure:
- // bookmark_bar
- // |- bookmark1
- // |- folder1
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- bookmark_model()->Move(bookmark1_node, bookmark_bar_node, 0);
- EXPECT_TRUE(PositionOf(bookmark1_node).LessThan(PositionOf(folder1_node)));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ReorderChildrenShouldUpdateTheTrackerAndNudgeForCommit) {
- std::vector<const bookmarks::BookmarkNode*> nodes =
- GenerateBookmarkNodes(/*num_bookmarks=*/4);
- SimulateCommitResponseForAllLocalChanges();
- // Reorder it to be (2 bookmarks have been moved):
- // bookmark_bar
- // |- node1
- // |- node3
- // |- node0
- // |- node2
- bookmark_model()->ReorderChildren(bookmark_model()->bookmark_bar_node(),
- {nodes[1], nodes[3], nodes[0], nodes[2]});
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[3])));
- EXPECT_TRUE(PositionOf(nodes[3]).LessThan(PositionOf(nodes[0])));
- EXPECT_TRUE(PositionOf(nodes[0]).LessThan(PositionOf(nodes[2])));
- // Only 2 moved nodes should have local changes to commit.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), SizeIs(2));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldReorderChildrenAndUpdateOnlyMovedToRightBookmark) {
- std::vector<const bookmarks::BookmarkNode*> nodes =
- GenerateBookmarkNodes(/*num_bookmarks=*/4);
- SimulateCommitResponseForAllLocalChanges();
- // Reorder it to be:
- // bookmark_bar
- // |- node1
- // |- node2
- // |- node0 (moved)
- // |- node3
- bookmark_model()->ReorderChildren(bookmark_model()->bookmark_bar_node(),
- {nodes[1], nodes[2], nodes[0], nodes[3]});
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[2])));
- EXPECT_TRUE(PositionOf(nodes[2]).LessThan(PositionOf(nodes[0])));
- EXPECT_TRUE(PositionOf(nodes[0]).LessThan(PositionOf(nodes[3])));
- // Only one moved node should have local changes to commit.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
- UnorderedElementsAre(HasBookmarkNode(nodes[0])));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldReorderChildrenAndUpdateOnlyMovedToLeftBookmark) {
- std::vector<const bookmarks::BookmarkNode*> nodes =
- GenerateBookmarkNodes(/*num_bookmarks=*/4);
- SimulateCommitResponseForAllLocalChanges();
- // Reorder it to be:
- // bookmark_bar
- // |- node0
- // |- node3 (moved)
- // |- node1
- // |- node2
- bookmark_model()->ReorderChildren(bookmark_model()->bookmark_bar_node(),
- {nodes[0], nodes[3], nodes[1], nodes[2]});
- EXPECT_TRUE(PositionOf(nodes[0]).LessThan(PositionOf(nodes[3])));
- EXPECT_TRUE(PositionOf(nodes[3]).LessThan(PositionOf(nodes[1])));
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[2])));
- // Only one moved node should have local changes to commit.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
- UnorderedElementsAre(HasBookmarkNode(nodes[3])));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldReorderWhenBookmarkMovedToLastPosition) {
- std::vector<const bookmarks::BookmarkNode*> nodes =
- GenerateBookmarkNodes(/*num_bookmarks=*/4);
- SimulateCommitResponseForAllLocalChanges();
- // Reorder it to be:
- // bookmark_bar
- // |- node1
- // |- node2
- // |- node3
- // |- node0 (moved)
- bookmark_model()->ReorderChildren(bookmark_model()->bookmark_bar_node(),
- {nodes[1], nodes[2], nodes[3], nodes[0]});
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[2])));
- EXPECT_TRUE(PositionOf(nodes[2]).LessThan(PositionOf(nodes[3])));
- EXPECT_TRUE(PositionOf(nodes[3]).LessThan(PositionOf(nodes[0])));
- // Only one moved node should have local changes to commit.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
- UnorderedElementsAre(HasBookmarkNode(nodes[0])));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldReorderWhenBookmarkMovedToFirstPosition) {
- std::vector<const bookmarks::BookmarkNode*> nodes =
- GenerateBookmarkNodes(/*num_bookmarks=*/4);
- SimulateCommitResponseForAllLocalChanges();
- // Reorder it to be:
- // bookmark_bar
- // |- node3 (moved)
- // |- node0
- // |- node1
- // |- node2
- bookmark_model()->ReorderChildren(bookmark_model()->bookmark_bar_node(),
- {nodes[3], nodes[0], nodes[1], nodes[2]});
- EXPECT_TRUE(PositionOf(nodes[3]).LessThan(PositionOf(nodes[0])));
- EXPECT_TRUE(PositionOf(nodes[0]).LessThan(PositionOf(nodes[1])));
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[2])));
- // Only one moved node should have local changes to commit.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
- UnorderedElementsAre(HasBookmarkNode(nodes[3])));
- }
- TEST_F(BookmarkModelObserverImplTest, ShouldReorderWhenAllBookmarksReversed) {
- // In this case almost all the bookmarks should be updated apart from only one
- // bookmark.
- std::vector<const bookmarks::BookmarkNode*> nodes =
- GenerateBookmarkNodes(/*num_bookmarks=*/4);
- SimulateCommitResponseForAllLocalChanges();
- // Reorder it to be (all nodes are moved):
- // bookmark_bar
- // |- node3
- // |- node2
- // |- node1
- // |- node0
- bookmark_model()->ReorderChildren(bookmark_model()->bookmark_bar_node(),
- {nodes[3], nodes[2], nodes[1], nodes[0]});
- EXPECT_TRUE(PositionOf(nodes[3]).LessThan(PositionOf(nodes[2])));
- EXPECT_TRUE(PositionOf(nodes[2]).LessThan(PositionOf(nodes[1])));
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[0])));
- // Do not verify which nodes exactly have been updated, it depends on the
- // implementation and any of the nodes may become a base node to calculate
- // relative positions of all other nodes.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), SizeIs(3));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldNotReorderIfAllBookmarksStillOrdered) {
- std::vector<const bookmarks::BookmarkNode*> nodes =
- GenerateBookmarkNodes(/*num_bookmarks=*/4);
- SimulateCommitResponseForAllLocalChanges();
- // Keep the original order.
- bookmark_model()->ReorderChildren(bookmark_model()->bookmark_bar_node(),
- {nodes[0], nodes[1], nodes[2], nodes[3]});
- EXPECT_TRUE(PositionOf(nodes[0]).LessThan(PositionOf(nodes[1])));
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[2])));
- EXPECT_TRUE(PositionOf(nodes[2]).LessThan(PositionOf(nodes[3])));
- // The bookmarks remain in the same order, nothing to commit.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), IsEmpty());
- }
- TEST_F(BookmarkModelObserverImplTest,
- BookmarkRemovalShouldUpdateTheTrackerAndNudgeForCommit) {
- // Build this structure:
- // bookmark_bar
- // |- folder1
- // |- bookmark1
- // |- folder2
- // |- bookmark2
- // |- bookmark3
- // and then delete folder2.
- const GURL kUrl("http://www.url1.com");
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* folder1_node = bookmark_model()->AddFolder(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"folder1");
- const bookmarks::BookmarkNode* bookmark1_node = bookmark_model()->AddURL(
- /*parent=*/folder1_node, /*index=*/0, u"bookmark1", kUrl);
- const bookmarks::BookmarkNode* folder2_node = bookmark_model()->AddFolder(
- /*parent=*/folder1_node, /*index=*/1, u"folder2");
- const bookmarks::BookmarkNode* bookmark2_node = bookmark_model()->AddURL(
- /*parent=*/folder2_node, /*index=*/0, u"bookmark2", kUrl);
- const bookmarks::BookmarkNode* bookmark3_node = bookmark_model()->AddURL(
- /*parent=*/folder2_node, /*index=*/1, u"bookmark3", kUrl);
- // All bookmarks should be tracked now.
- ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 8U);
- SimulateCommitResponseForAllLocalChanges();
- // There should be no local changes now.
- ASSERT_TRUE(bookmark_tracker()->GetEntitiesWithLocalChanges().empty());
- const SyncedBookmarkTrackerEntity* folder2_entity =
- bookmark_tracker()->GetEntityForBookmarkNode(folder2_node);
- const SyncedBookmarkTrackerEntity* bookmark2_entity =
- bookmark_tracker()->GetEntityForBookmarkNode(bookmark2_node);
- const SyncedBookmarkTrackerEntity* bookmark3_entity =
- bookmark_tracker()->GetEntityForBookmarkNode(bookmark3_node);
- ASSERT_FALSE(folder2_entity->metadata().is_deleted());
- ASSERT_FALSE(bookmark2_entity->metadata().is_deleted());
- ASSERT_FALSE(bookmark3_entity->metadata().is_deleted());
- const std::string& folder2_entity_id = folder2_entity->metadata().server_id();
- const std::string& bookmark2_entity_id =
- bookmark2_entity->metadata().server_id();
- const std::string& bookmark3_entity_id =
- bookmark3_entity->metadata().server_id();
- // Delete folder2.
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- bookmark_model()->Remove(folder2_node);
- // folder2, bookmark2, and bookmark3 should be marked deleted.
- EXPECT_TRUE(bookmark_tracker()
- ->GetEntityForSyncId(folder2_entity_id)
- ->metadata()
- .is_deleted());
- EXPECT_TRUE(bookmark_tracker()
- ->GetEntityForSyncId(bookmark2_entity_id)
- ->metadata()
- .is_deleted());
- EXPECT_TRUE(bookmark_tracker()
- ->GetEntityForSyncId(bookmark3_entity_id)
- ->metadata()
- .is_deleted());
- // folder2, bookmark2, and bookmark3 should be in the local changes to be
- // committed and folder2 deletion should be the last one (after all children
- // deletions).
- EXPECT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(),
- ElementsAre(bookmark_tracker()->GetEntityForSyncId(bookmark2_entity_id),
- bookmark_tracker()->GetEntityForSyncId(bookmark3_entity_id),
- bookmark_tracker()->GetEntityForSyncId(folder2_entity_id)));
- // folder1 and bookmark1 are still tracked.
- EXPECT_TRUE(bookmark_tracker()->GetEntityForBookmarkNode(folder1_node));
- EXPECT_TRUE(bookmark_tracker()->GetEntityForBookmarkNode(bookmark1_node));
- }
- TEST_F(BookmarkModelObserverImplTest,
- BookmarkCreationAndRemovalShouldRequireTwoCommitResponsesBeforeRemoval) {
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* folder_node = bookmark_model()->AddFolder(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"folder");
- // Node should be tracked now.
- ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
- const SyncedBookmarkTrackerEntity* entity =
- bookmark_tracker()->GetEntityForBookmarkNode(folder_node);
- const std::string id = entity->metadata().server_id();
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 1U);
- bookmark_tracker()->MarkCommitMayHaveStarted(entity);
- // Remove the folder.
- bookmark_model()->Remove(folder_node);
- // Simulate a commit response for the first commit request (the creation).
- // Don't simulate change in id for simplicity.
- bookmark_tracker()->UpdateUponCommitResponse(entity, id,
- /*server_version=*/1,
- /*acked_sequence_number=*/1);
- // There should still be one local change (the deletion).
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 1U);
- // Entity is still tracked.
- EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
- // Commit the deletion.
- bookmark_tracker()->UpdateUponCommitResponse(entity, id,
- /*server_version=*/2,
- /*acked_sequence_number=*/2);
- // Entity should have been dropped.
- EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 3U);
- }
- TEST_F(BookmarkModelObserverImplTest,
- BookmarkCreationAndRemovalBeforeCommitRequestShouldBeRemovedDirectly) {
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* folder_node = bookmark_model()->AddFolder(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"folder");
- // Node should be tracked now.
- ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
- const std::string id = bookmark_tracker()
- ->GetEntityForBookmarkNode(folder_node)
- ->metadata()
- .server_id();
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 1U);
- // Remove the folder.
- bookmark_model()->Remove(folder_node);
- // Entity should have been dropped.
- EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 3U);
- }
- TEST_F(BookmarkModelObserverImplTest, ShouldPositionSiblings) {
- const std::string kTitle = "title";
- const std::string kUrl = "http://www.url.com";
- // Build this structure:
- // bookmark_bar
- // |- node1
- // |- node2
- // Expectation:
- // p1 < p2
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* bookmark_node1 = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16(kTitle),
- GURL(kUrl));
- const bookmarks::BookmarkNode* bookmark_node2 = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/1, base::UTF8ToUTF16(kTitle),
- GURL(kUrl));
- EXPECT_TRUE(PositionOf(bookmark_node1).LessThan(PositionOf(bookmark_node2)));
- // Now insert node3 at index 1 to build this structure:
- // bookmark_bar
- // |- node1
- // |- node3
- // |- node2
- // Expectation:
- // p1 < p2 (still holds)
- // p1 < p3
- // p3 < p2
- const bookmarks::BookmarkNode* bookmark_node3 = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/1, base::UTF8ToUTF16(kTitle),
- GURL(kUrl));
- EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), Eq(6U));
- EXPECT_TRUE(PositionOf(bookmark_node1).LessThan(PositionOf(bookmark_node2)));
- EXPECT_TRUE(PositionOf(bookmark_node1).LessThan(PositionOf(bookmark_node3)));
- EXPECT_TRUE(PositionOf(bookmark_node3).LessThan(PositionOf(bookmark_node2)));
- }
- TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) {
- auto client = std::make_unique<bookmarks::TestBookmarkClient>();
- bookmarks::BookmarkNode* managed_node = client->EnableManagedNode();
- std::unique_ptr<bookmarks::BookmarkModel> model =
- bookmarks::TestBookmarkClient::CreateModelWithClient(std::move(client));
- std::unique_ptr<SyncedBookmarkTracker> bookmark_tracker =
- SyncedBookmarkTracker::CreateEmpty(sync_pb::ModelTypeState());
- sync_pb::EntitySpecifics specifics;
- specifics.mutable_bookmark()->set_legacy_canonicalized_title(kBookmarkBarTag);
- *specifics.mutable_bookmark()->mutable_unique_position() =
- syncer::UniquePosition::InitialPosition(
- syncer::UniquePosition::RandomSuffix())
- .ToProto();
- bookmark_tracker->Add(
- /*bookmark_node=*/model->bookmark_bar_node(),
- /*sync_id=*/kBookmarkBarId,
- /*server_version=*/0, /*creation_time=*/base::Time::Now(), specifics);
- specifics.mutable_bookmark()->set_legacy_canonicalized_title(
- kOtherBookmarksTag);
- bookmark_tracker->Add(
- /*bookmark_node=*/model->other_node(),
- /*sync_id=*/kOtherBookmarksId,
- /*server_version=*/0, /*creation_time=*/base::Time::Now(), specifics);
- specifics.mutable_bookmark()->set_legacy_canonicalized_title(
- kMobileBookmarksTag);
- bookmark_tracker->Add(
- /*bookmark_node=*/model->mobile_node(),
- /*sync_id=*/kMobileBookmarksId,
- /*server_version=*/0, /*creation_time=*/base::Time::Now(), specifics);
- BookmarkModelObserverImpl observer(
- nudge_for_commit_closure()->Get(),
- /*on_bookmark_model_being_deleted_closure=*/base::DoNothing(),
- bookmark_tracker.get());
- model->AddObserver(&observer);
- EXPECT_CALL(*nudge_for_commit_closure(), Run()).Times(0);
- // In the TestBookmarkClient, descendants of managed nodes shouldn't be
- // synced.
- const bookmarks::BookmarkNode* unsyncable_node =
- model->AddURL(/*parent=*/managed_node, /*index=*/0, u"Title",
- GURL("http://www.url.com"));
- // Only permanent folders should be tracked.
- EXPECT_THAT(bookmark_tracker->TrackedEntitiesCountForTest(), 3U);
- EXPECT_CALL(*nudge_for_commit_closure(), Run()).Times(0);
- // In the TestBookmarkClient, descendants of managed nodes shouldn't be
- // synced.
- model->SetTitle(unsyncable_node, u"NewTitle");
- // Only permanent folders should be tracked.
- EXPECT_THAT(bookmark_tracker->TrackedEntitiesCountForTest(), 3U);
- EXPECT_CALL(*nudge_for_commit_closure(), Run()).Times(0);
- // In the TestBookmarkClient, descendants of managed nodes shouldn't be
- // synced.
- model->Remove(unsyncable_node);
- // Only permanent folders should be tracked.
- EXPECT_THAT(bookmark_tracker->TrackedEntitiesCountForTest(), 3U);
- model->RemoveObserver(&observer);
- }
- TEST_F(BookmarkModelObserverImplTest, ShouldAddChildrenInArbitraryOrder) {
- std::unique_ptr<SyncedBookmarkTracker> bookmark_tracker =
- SyncedBookmarkTracker::CreateEmpty(sync_pb::ModelTypeState());
- BookmarkModelObserverImpl observer(
- /*nudge_for_commit_closure=*/base::DoNothing(),
- /*on_bookmark_model_being_deleted_closure=*/base::DoNothing(),
- bookmark_tracker.get());
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- // Add the bookmark bar to the tracker.
- sync_pb::EntitySpecifics specifics;
- specifics.mutable_bookmark()->set_legacy_canonicalized_title(kBookmarkBarTag);
- *specifics.mutable_bookmark()->mutable_unique_position() =
- syncer::UniquePosition::InitialPosition(
- syncer::UniquePosition::RandomSuffix())
- .ToProto();
- bookmark_tracker->Add(
- /*bookmark_node=*/bookmark_model()->bookmark_bar_node(),
- /*sync_id=*/kBookmarkBarId,
- /*server_version=*/0, /*creation_time=*/base::Time::Now(), specifics);
- // Build this structure:
- // bookmark_bar
- // |- folder0
- // |- folder1
- // |- folder2
- // |- folder3
- // |- folder4
- const bookmarks::BookmarkNode* nodes[5];
- for (size_t i = 0; i < 5; i++) {
- nodes[i] = bookmark_model()->AddFolder(
- /*parent=*/bookmark_bar_node, /*index=*/i,
- base::UTF8ToUTF16("folder" + std::to_string(i)));
- }
- // Now simulate calling the observer as if the nodes are added in that order.
- // 4,0,2,3,1.
- observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 4);
- observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 0);
- observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 2);
- observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 3);
- observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 1);
- ASSERT_THAT(bookmark_tracker->TrackedEntitiesCountForTest(), 6U);
- // Check that position information match the children order.
- EXPECT_TRUE(PositionOf(nodes[0]).LessThan(PositionOf(nodes[1])));
- EXPECT_TRUE(PositionOf(nodes[1]).LessThan(PositionOf(nodes[2])));
- EXPECT_TRUE(PositionOf(nodes[2]).LessThan(PositionOf(nodes[3])));
- EXPECT_TRUE(PositionOf(nodes[3]).LessThan(PositionOf(nodes[4])));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldCallOnBookmarkModelBeingDeletedClosure) {
- std::unique_ptr<SyncedBookmarkTracker> bookmark_tracker =
- SyncedBookmarkTracker::CreateEmpty(sync_pb::ModelTypeState());
- NiceMock<base::MockCallback<base::OnceClosure>>
- on_bookmark_model_being_deleted_closure_mock;
- BookmarkModelObserverImpl observer(
- /*nudge_for_commit_closure=*/base::DoNothing(),
- on_bookmark_model_being_deleted_closure_mock.Get(),
- bookmark_tracker.get());
- EXPECT_CALL(on_bookmark_model_being_deleted_closure_mock, Run());
- observer.BookmarkModelBeingDeleted(/*model=*/nullptr);
- }
- TEST_F(BookmarkModelObserverImplTest, ShouldNotIssueCommitUponFaviconLoad) {
- const GURL kBookmarkUrl("http://www.url.com");
- const GURL kIconUrl("http://www.url.com/favicon.ico");
- const SkColor kColor = SK_ColorRED;
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* bookmark_node = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"title", kBookmarkUrl);
- ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
- kBookmarkUrl, kIconUrl, CreateTestImage(kColor)));
- SimulateCommitResponseForAllLocalChanges();
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), IsEmpty());
- const SyncedBookmarkTrackerEntity* entity =
- bookmark_tracker()->GetEntityForBookmarkNode(bookmark_node);
- ASSERT_THAT(entity, NotNull());
- ASSERT_TRUE(entity->metadata().has_bookmark_favicon_hash());
- const uint32_t initial_favicon_hash =
- entity->metadata().bookmark_favicon_hash();
- // Clear the specifics hash (as if the proto definition would have changed).
- // This is needed because otherwise the commit is trivially optimized away
- // (i.e. literally nothing changed).
- bookmark_tracker()->ClearSpecificsHashForTest(entity);
- // Mimic the very same favicon being loaded again (similar to a startup
- // scenario). Note that OnFaviconsChanged() needs no icon URL to invalidate
- // the favicon of a bookmark.
- EXPECT_CALL(*nudge_for_commit_closure(), Run()).Times(0);
- bookmark_model()->OnFaviconsChanged(/*page_urls=*/{kBookmarkUrl},
- /*icon_url=*/GURL());
- ASSERT_TRUE(bookmark_node->is_favicon_loading());
- ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
- kBookmarkUrl, kIconUrl, CreateTestImage(kColor)));
- EXPECT_TRUE(entity->metadata().has_bookmark_favicon_hash());
- EXPECT_THAT(entity->metadata().bookmark_favicon_hash(),
- Eq(initial_favicon_hash));
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), IsEmpty());
- }
- TEST_F(BookmarkModelObserverImplTest, ShouldCommitLocalFaviconChange) {
- const GURL kBookmarkUrl("http://www.url.com");
- const GURL kInitialIconUrl("http://www.url.com/initial.ico");
- const GURL kFinalIconUrl("http://www.url.com/final.ico");
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* bookmark_node = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"title", kBookmarkUrl);
- ASSERT_TRUE(bookmark_node->is_favicon_loading());
- ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
- kBookmarkUrl, kInitialIconUrl, CreateTestImage(SK_ColorRED)));
- SimulateCommitResponseForAllLocalChanges();
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), IsEmpty());
- const SyncedBookmarkTrackerEntity* entity =
- bookmark_tracker()->GetEntityForBookmarkNode(bookmark_node);
- ASSERT_THAT(entity, NotNull());
- ASSERT_TRUE(entity->metadata().has_bookmark_favicon_hash());
- const uint32_t initial_favicon_hash =
- entity->metadata().bookmark_favicon_hash();
- // A favicon change should trigger a commit nudge once the favicon loads, but
- // not earlier. Note that OnFaviconsChanged() needs no icon URL to invalidate
- // the favicon of a bookmark.
- EXPECT_CALL(*nudge_for_commit_closure(), Run()).Times(0);
- bookmark_model()->OnFaviconsChanged(/*page_urls=*/{kBookmarkUrl},
- /*icon_url=*/GURL());
- ASSERT_TRUE(bookmark_node->is_favicon_loading());
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
- kBookmarkUrl, kFinalIconUrl, CreateTestImage(SK_ColorBLUE)));
- EXPECT_TRUE(entity->metadata().has_bookmark_favicon_hash());
- EXPECT_THAT(entity->metadata().bookmark_favicon_hash(),
- Ne(initial_favicon_hash));
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
- ElementsAre(HasBookmarkNode(bookmark_node)));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldNudgeForCommitOnFaviconLoadAfterRestart) {
- const GURL kBookmarkUrl("http://www.url.com");
- const GURL kIconUrl("http://www.url.com/favicon.ico");
- const SkColor kColor = SK_ColorRED;
- // Simulate work after restart. Add a new bookmark to a model and its
- // specifics to the tracker without loading favicon.
- bookmark_model()->RemoveObserver(observer());
- // Add a new node with specifics and mark it unsynced.
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* bookmark_node = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"title", kBookmarkUrl);
- sync_pb::EntitySpecifics specifics = CreateSpecificsFromBookmarkNode(
- bookmark_node, bookmark_model(),
- syncer::UniquePosition::InitialPosition(
- syncer::UniquePosition::RandomSuffix())
- .ToProto(),
- /*force_favicon_load=*/false);
- const gfx::Image favicon_image = CreateTestImage(kColor);
- scoped_refptr<base::RefCountedMemory> favicon_bytes =
- favicon_image.As1xPNGBytes();
- specifics.mutable_bookmark()->set_favicon(favicon_bytes->front(),
- favicon_bytes->size());
- specifics.mutable_bookmark()->set_icon_url(kIconUrl.spec());
- *specifics.mutable_bookmark()->mutable_unique_position() =
- syncer::UniquePosition::InitialPosition(
- syncer::UniquePosition::RandomSuffix())
- .ToProto();
- const SyncedBookmarkTrackerEntity* entity = bookmark_tracker()->Add(
- bookmark_node, "id", /*server_version=*/1, base::Time::Now(), specifics);
- bookmark_tracker()->IncrementSequenceNumber(entity);
- // Restore state.
- bookmark_model()->AddObserver(observer());
- // Currently there is the unsynced |entity| which has no loaded favicon.
- ASSERT_FALSE(bookmark_node->is_favicon_loaded());
- ASSERT_TRUE(entity->IsUnsynced());
- EXPECT_CALL(*nudge_for_commit_closure(), Run());
- bookmark_model()->GetFavicon(bookmark_node);
- ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
- kBookmarkUrl, kIconUrl, CreateTestImage(SK_ColorRED)));
- }
- TEST_F(BookmarkModelObserverImplTest,
- ShouldAddRestoredBookmarkWhenTombstoneCommitMayHaveStarted) {
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* folder =
- bookmark_model()->AddFolder(bookmark_bar_node, 0, u"Title");
- const syncer::ClientTagHash folder_client_tag_hash =
- SyncedBookmarkTracker::GetClientTagHashFromGUID(folder->guid());
- // Check that the bookmark was added by observer.
- const SyncedBookmarkTrackerEntity* folder_entity =
- bookmark_tracker()->GetEntityForBookmarkNode(folder);
- ASSERT_THAT(folder_entity, NotNull());
- ASSERT_TRUE(folder_entity->IsUnsynced());
- SimulateCommitResponseForAllLocalChanges();
- ASSERT_FALSE(folder_entity->IsUnsynced());
- // Now delete the entity and restore it with the same bookmark node.
- BookmarkUndoService undo_service;
- undo_service.Start(bookmark_model());
- bookmark_model()->Remove(folder);
- // The removed bookmark must be saved in the undo service.
- ASSERT_EQ(undo_service.undo_manager()->undo_count(), 1u);
- ASSERT_THAT(bookmark_tracker()->GetEntityForBookmarkNode(folder), IsNull());
- // Check that the entity is a tombstone now.
- const std::vector<const SyncedBookmarkTrackerEntity*> local_changes =
- bookmark_tracker()->GetEntitiesWithLocalChanges();
- ASSERT_THAT(local_changes, ElementsAre(folder_entity));
- ASSERT_TRUE(folder_entity->metadata().is_deleted());
- ASSERT_EQ(
- bookmark_tracker()->GetEntityForClientTagHash(folder_client_tag_hash),
- folder_entity);
- // Restore the removed bookmark.
- undo_service.undo_manager()->Undo();
- undo_service.Shutdown();
- EXPECT_EQ(folder_entity,
- bookmark_tracker()->GetEntityForBookmarkNode(folder));
- EXPECT_EQ(
- bookmark_tracker()->GetEntityForClientTagHash(folder_client_tag_hash),
- folder_entity);
- EXPECT_TRUE(folder_entity->IsUnsynced());
- EXPECT_FALSE(folder_entity->metadata().is_deleted());
- EXPECT_EQ(folder_entity->bookmark_node(), folder);
- }
- // Tests that the bookmark entity will be committed if its favicon is deleted.
- TEST_F(BookmarkModelObserverImplTest, ShouldCommitOnDeleteFavicon) {
- const GURL kBookmarkUrl("http://www.url.com");
- const GURL kIconUrl("http://www.url.com/favicon.ico");
- // Add a new node with specifics.
- const bookmarks::BookmarkNode* bookmark_bar_node =
- bookmark_model()->bookmark_bar_node();
- const bookmarks::BookmarkNode* bookmark_node = bookmark_model()->AddURL(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"title", kBookmarkUrl);
- ASSERT_TRUE(bookmark_node->is_favicon_loading());
- ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
- kBookmarkUrl, kIconUrl, CreateTestImage(SK_ColorRED)));
- const SyncedBookmarkTrackerEntity* entity =
- bookmark_tracker()->GetEntityForBookmarkNode(bookmark_node);
- ASSERT_THAT(entity, NotNull());
- ASSERT_TRUE(entity->IsUnsynced());
- SimulateCommitResponseForAllLocalChanges();
- ASSERT_FALSE(bookmark_tracker()->HasLocalChanges());
- // Delete favicon and check that its deletion is committed.
- bookmark_model()->OnFaviconsChanged({kBookmarkUrl}, GURL());
- ASSERT_TRUE(bookmark_node->is_favicon_loading());
- ASSERT_TRUE(bookmark_client()->SimulateEmptyFaviconLoaded(kBookmarkUrl));
- EXPECT_TRUE(entity->IsUnsynced());
- }
- } // namespace
- } // namespace sync_bookmarks
|