Index: chrome/browser/sync/profile_sync_service_bookmark_unittest.cc |
diff --git a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc |
index 3f8f10350df1878975ca62c642975acbc2a23098..b678b6e43bfc3f6204eb901063d83483bb2cd832 100644 |
--- a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc |
+++ b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc |
@@ -43,7 +43,7 @@ |
#include "sync/internal_api/public/write_node.h" |
#include "sync/internal_api/public/write_transaction.h" |
#include "sync/internal_api/syncapi_internal.h" |
-#include "sync/syncable/mutable_entry.h" // TODO(tim): Remove. Bug 131130. |
+#include "sync/syncable/mutable_entry.h" |
#include "testing/gmock/include/gmock/gmock.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -374,16 +374,17 @@ class ProfileSyncServiceBookmarkTest : public testing::Test { |
// the sync model directly after ModelAssociation. This function can be |
// invoked prior to model association to set up first-time sync model |
// association scenarios. |
- int64 AddBookmarkToShare(syncer::WriteTransaction *trans, |
+ int64 AddBookmarkToShare(syncer::WriteTransaction* trans, |
int64 parent_id, |
- std::string title) { |
+ const std::string& title, |
+ const std::string& url) { |
EXPECT_FALSE(model_associator_); |
syncer::ReadNode parent(trans); |
EXPECT_EQ(BaseNode::INIT_OK, parent.InitByIdLookup(parent_id)); |
sync_pb::BookmarkSpecifics specifics; |
- specifics.set_url("http://www.google.com/search?q=" + title); |
+ specifics.set_url(url); |
specifics.set_title(title); |
syncer::WriteNode node(trans); |
@@ -788,12 +789,12 @@ TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociate) { |
{ |
syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share()); |
for (int i = 0; i < kNumFolders; ++i) { |
- int64 folder_id = AddFolderToShare(&trans, |
- base::StringPrintf("folder%05d", i)); |
+ int64 folder_id = |
+ AddFolderToShare(&trans, base::StringPrintf("folder%05d", i)); |
for (int j = 0; j < kNumBookmarksPerFolder; ++j) { |
- AddBookmarkToShare(&trans, |
- folder_id, |
- base::StringPrintf("bookmark%05d", j)); |
+ AddBookmarkToShare( |
+ &trans, folder_id, base::StringPrintf("bookmark%05d", j), |
+ base::StringPrintf("http://www.google.com/search?q=%05d", j)); |
} |
} |
} |
@@ -804,6 +805,189 @@ TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociate) { |
ExpectModelMatch(); |
} |
+// Tests bookmark association when nodes exists in the native model only. |
+// These entries should be copied to Sync directory during association process. |
+TEST_F(ProfileSyncServiceBookmarkTest, |
+ InitialModelAssociateWithBookmarkModelNodes) { |
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); |
+ const BookmarkNode* folder = |
+ model_->AddFolder(model_->other_node(), 0, base::ASCIIToUTF16("foobar")); |
+ model_->AddFolder(folder, 0, base::ASCIIToUTF16("nested")); |
+ model_->AddURL(folder, 0, base::ASCIIToUTF16("Internets #1 Pies Site"), |
+ GURL("http://www.easypie.com/")); |
+ model_->AddURL(folder, 1, base::ASCIIToUTF16("Airplanes"), |
+ GURL("http://www.easyjet.com/")); |
+ |
+ StartSync(); |
+ ExpectModelMatch(); |
+} |
+ |
+// Tests bookmark association case when there is an entry in the delete journal |
+// that matches one of native bookmarks. |
+TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociateWithDeleteJournal) { |
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); |
+ const BookmarkNode* folder = model_->AddFolder(model_->bookmark_bar_node(), 0, |
+ base::ASCIIToUTF16("foobar")); |
+ const BookmarkNode* bookmark = |
+ model_->AddURL(folder, 0, base::ASCIIToUTF16("Airplanes"), |
+ GURL("http://www.easyjet.com/")); |
+ |
+ CreatePermanentBookmarkNodes(); |
+ |
+ // Create entries matching the folder and the bookmark above. |
+ int64 folder_id, bookmark_id; |
+ { |
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share()); |
+ folder_id = AddFolderToShare(&trans, "foobar"); |
+ bookmark_id = AddBookmarkToShare(&trans, folder_id, "Airplanes", |
+ "http://www.easyjet.com/"); |
+ } |
+ |
+ // Associate the bookmark sync node with the native model one and make |
+ // it deleted. |
+ { |
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share()); |
+ syncer::WriteNode node(&trans); |
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(bookmark_id)); |
+ |
+ node.GetMutableEntryForTest()->PutLocalExternalId(bookmark->id()); |
+ node.GetMutableEntryForTest()->PutServerIsDel(true); |
+ node.GetMutableEntryForTest()->PutIsDel(true); |
+ } |
+ |
+ ASSERT_TRUE(AssociateModels()); |
+ ExpectModelMatch(); |
+ |
+ // The bookmark node should be deleted. |
+ EXPECT_EQ(0, folder->child_count()); |
+} |
+ |
+// Tests that the external ID is used to match the right folder amoung |
+// multiple folders with the same name during the native model traversal. |
+// Also tests that the external ID is used to match the right bookmark |
+// among multiple identical bookmarks when dealing with the delete journal. |
+TEST_F(ProfileSyncServiceBookmarkTest, |
+ InitialModelAssociateVerifyExternalIdMatch) { |
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); |
+ const int kNumFolders = 10; |
+ const int kNumBookmarks = 10; |
+ const int kFolderToIncludeBookmarks = 7; |
+ const int kBookmarkToDelete = 4; |
+ |
+ int64 folder_ids[kNumFolders]; |
+ int64 bookmark_ids[kNumBookmarks]; |
+ |
+ // Create native folders and bookmarks with identical names. Only |
+ // one of the folders contains bookmarks and others are empty. Here is the |
+ // expected tree shape: |
+ // Bookmarks bar |
+ // +- folder (#0) |
+ // +- folder (#1) |
+ // ... |
+ // +- folder (#7) <-- Only this folder contains bookmarks. |
+ // +- bookmark (#0) |
+ // +- bookmark (#1) |
+ // ... |
+ // +- bookmark (#4) <-- Only this one bookmark should be removed later. |
+ // ... |
+ // +- bookmark (#9) |
+ // ... |
+ // +- folder (#9) |
+ |
+ const BookmarkNode* parent_folder = nullptr; |
+ for (int i = 0; i < kNumFolders; i++) { |
+ const BookmarkNode* folder = model_->AddFolder( |
+ model_->bookmark_bar_node(), i, base::ASCIIToUTF16("folder")); |
+ folder_ids[i] = folder->id(); |
+ if (i == kFolderToIncludeBookmarks) { |
+ parent_folder = folder; |
+ } |
+ } |
+ |
+ for (int i = 0; i < kNumBookmarks; i++) { |
+ const BookmarkNode* bookmark = |
+ model_->AddURL(parent_folder, i, base::ASCIIToUTF16("bookmark"), |
+ GURL("http://www.google.com/")); |
+ bookmark_ids[i] = bookmark->id(); |
+ } |
+ |
+ // Number of nodes in bookmark bar before association. |
+ int total_node_count = model_->bookmark_bar_node()->GetTotalNodeCount(); |
+ |
+ CreatePermanentBookmarkNodes(); |
+ |
+ int64 sync_bookmark_id_to_delete = 0; |
+ { |
+ // Create sync folders matching native folders above. |
+ int64 parent_id = 0; |
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share()); |
+ // Create in reverse order because AddFolderToShare passes NULL for |
+ // |predecessor| argument. |
+ for (int i = kNumFolders - 1; i >= 0; i--) { |
+ int64 id = AddFolderToShare(&trans, "folder"); |
+ |
+ // Pre-map sync folders to native folders by setting |
+ // external ID. This will verify that the association algorithm picks |
+ // the right ones despite all of them having identical names. |
+ // More specifically this will help to avoid cloning bookmarks from |
+ // a wrong folder. |
+ syncer::WriteNode node(&trans); |
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id)); |
+ node.GetMutableEntryForTest()->PutLocalExternalId(folder_ids[i]); |
+ |
+ if (i == kFolderToIncludeBookmarks) { |
+ parent_id = id; |
+ } |
+ } |
+ |
+ // Create sync bookmark matching native bookmarks above in reverse order |
+ // because AddBookmarkToShare passes NULL for |predecessor| argument. |
+ for (int i = kNumBookmarks - 1; i >= 0; i--) { |
+ int id = AddBookmarkToShare(&trans, parent_id, "bookmark", |
+ "http://www.google.com/"); |
+ |
+ // Pre-map sync bookmarks to native bookmarks by setting |
+ // external ID. This will verify that the association algorithm picks |
+ // the right ones despite all of them having identical names and URLs. |
+ syncer::WriteNode node(&trans); |
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id)); |
+ node.GetMutableEntryForTest()->PutLocalExternalId(bookmark_ids[i]); |
+ |
+ if (i == kBookmarkToDelete) { |
+ sync_bookmark_id_to_delete = id; |
+ } |
+ } |
+ } |
+ |
+ // Make one bookmark deleted. |
+ { |
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share()); |
+ syncer::WriteNode node(&trans); |
+ EXPECT_EQ(BaseNode::INIT_OK, |
+ node.InitByIdLookup(sync_bookmark_id_to_delete)); |
+ |
+ node.GetMutableEntryForTest()->PutServerIsDel(true); |
+ node.GetMutableEntryForTest()->PutIsDel(true); |
+ } |
+ |
+ // Perform association. |
+ ASSERT_TRUE(AssociateModels()); |
+ ExpectModelMatch(); |
+ |
+ // Only one native node should have been deleted and no nodes cloned due to |
+ // matching folder names. |
+ EXPECT_EQ(kNumFolders, model_->bookmark_bar_node()->child_count()); |
+ EXPECT_EQ(kNumBookmarks - 1, parent_folder->child_count()); |
+ EXPECT_EQ(total_node_count - 1, |
+ model_->bookmark_bar_node()->GetTotalNodeCount()); |
+ |
+ // Verify that the right bookmark got deleted and no bookmarks reordered. |
+ for (int i = 0; i < parent_folder->child_count(); i++) { |
+ int index_in_bookmark_ids = (i < kBookmarkToDelete) ? i : i + 1; |
+ EXPECT_EQ(bookmark_ids[index_in_bookmark_ids], |
+ parent_folder->GetChild(i)->id()); |
+ } |
+} |
TEST_F(ProfileSyncServiceBookmarkTest, BookmarkModelOperations) { |
LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); |