1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/strings/utf_string_conversions.h" 6 #include "chrome/browser/profiles/profile.h" 7 #include "chrome/browser/sync/profile_sync_service.h" 8 #include "chrome/browser/sync/test/integration/bookmarks_helper.h" 9 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" 10 #include "chrome/browser/sync/test/integration/sync_test.h" 11 #include "components/bookmarks/browser/bookmark_model.h" 12 #include "sync/test/fake_server/bookmark_entity_builder.h" 13 #include "sync/test/fake_server/entity_builder_factory.h" 14 #include "sync/test/fake_server/fake_server_verifier.h" 15 #include "ui/base/layout.h" 16 17 using bookmarks_helper::AddFolder; 18 using bookmarks_helper::AddURL; 19 using bookmarks_helper::CountBookmarksWithTitlesMatching; 20 using bookmarks_helper::Create1xFaviconFromPNGFile; 21 using bookmarks_helper::GetBookmarkBarNode; 22 using bookmarks_helper::GetBookmarkModel; 23 using bookmarks_helper::GetOtherNode; 24 using bookmarks_helper::ModelMatchesVerifier; 25 using bookmarks_helper::Move; 26 using bookmarks_helper::Remove; 27 using bookmarks_helper::RemoveAll; 28 using bookmarks_helper::SetFavicon; 29 using bookmarks_helper::SetTitle; 30 using sync_integration_test_util::AwaitCommitActivityCompletion; 31 32 class SingleClientBookmarksSyncTest : public SyncTest { 33 public: 34 SingleClientBookmarksSyncTest() : SyncTest(SINGLE_CLIENT) {} 35 virtual ~SingleClientBookmarksSyncTest() {} 36 37 // Verify that the local bookmark model (for the Profile corresponding to 38 // |index|) matches the data on the FakeServer. It is assumed that FakeServer 39 // is being used and each bookmark has a unique title. Folders are not 40 // verified. 41 void VerifyBookmarkModelMatchesFakeServer(int index); 42 43 private: 44 DISALLOW_COPY_AND_ASSIGN(SingleClientBookmarksSyncTest); 45 }; 46 47 void SingleClientBookmarksSyncTest::VerifyBookmarkModelMatchesFakeServer( 48 int index) { 49 fake_server::FakeServerVerifier fake_server_verifier(GetFakeServer()); 50 std::vector<BookmarkModel::URLAndTitle> local_bookmarks; 51 GetBookmarkModel(index)->GetBookmarks(&local_bookmarks); 52 53 // Verify that the number of local bookmarks matches the number in the 54 // server. 55 ASSERT_TRUE(fake_server_verifier.VerifyEntityCountByType( 56 local_bookmarks.size(), 57 syncer::BOOKMARKS)); 58 59 // Verify that all local bookmark titles exist once on the server. 60 std::vector<BookmarkModel::URLAndTitle>::const_iterator it; 61 for (it = local_bookmarks.begin(); it != local_bookmarks.end(); ++it) { 62 ASSERT_TRUE(fake_server_verifier.VerifyEntityCountByTypeAndName( 63 1, 64 syncer::BOOKMARKS, 65 base::UTF16ToUTF8(it->title))); 66 } 67 } 68 69 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, Sanity) { 70 ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; 71 72 // Starting state: 73 // other_node 74 // -> top 75 // -> tier1_a 76 // -> http://mail.google.com "tier1_a_url0" 77 // -> http://www.pandora.com "tier1_a_url1" 78 // -> http://www.facebook.com "tier1_a_url2" 79 // -> tier1_b 80 // -> http://www.nhl.com "tier1_b_url0" 81 const BookmarkNode* top = AddFolder(0, GetOtherNode(0), 0, "top"); 82 const BookmarkNode* tier1_a = AddFolder(0, top, 0, "tier1_a"); 83 const BookmarkNode* tier1_b = AddFolder(0, top, 1, "tier1_b"); 84 const BookmarkNode* tier1_a_url0 = AddURL( 85 0, tier1_a, 0, "tier1_a_url0", GURL("http://mail.google.com")); 86 const BookmarkNode* tier1_a_url1 = AddURL( 87 0, tier1_a, 1, "tier1_a_url1", GURL("http://www.pandora.com")); 88 const BookmarkNode* tier1_a_url2 = AddURL( 89 0, tier1_a, 2, "tier1_a_url2", GURL("http://www.facebook.com")); 90 const BookmarkNode* tier1_b_url0 = AddURL( 91 0, tier1_b, 0, "tier1_b_url0", GURL("http://www.nhl.com")); 92 93 // Setup sync, wait for its completion, and make sure changes were synced. 94 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 95 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 96 ASSERT_TRUE(ModelMatchesVerifier(0)); 97 98 // Ultimately we want to end up with the following model; but this test is 99 // more about the journey than the destination. 100 // 101 // bookmark_bar 102 // -> CNN (www.cnn.com) 103 // -> tier1_a 104 // -> tier1_a_url2 (www.facebook.com) 105 // -> tier1_a_url1 (www.pandora.com) 106 // -> Porsche (www.porsche.com) 107 // -> Bank of America (www.bankofamerica.com) 108 // -> Seattle Bubble 109 // other_node 110 // -> top 111 // -> tier1_b 112 // -> Wired News (www.wired.com) 113 // -> tier2_b 114 // -> tier1_b_url0 115 // -> tier3_b 116 // -> Toronto Maple Leafs (mapleleafs.nhl.com) 117 // -> Wynn (www.wynnlasvegas.com) 118 // -> tier1_a_url0 119 const BookmarkNode* bar = GetBookmarkBarNode(0); 120 const BookmarkNode* cnn = AddURL(0, bar, 0, "CNN", 121 GURL("http://www.cnn.com")); 122 ASSERT_TRUE(cnn != NULL); 123 Move(0, tier1_a, bar, 1); 124 125 // Wait for the bookmark position change to sync. 126 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 127 ASSERT_TRUE(ModelMatchesVerifier(0)); 128 129 const BookmarkNode* porsche = AddURL(0, bar, 2, "Porsche", 130 GURL("http://www.porsche.com")); 131 // Rearrange stuff in tier1_a. 132 ASSERT_EQ(tier1_a, tier1_a_url2->parent()); 133 ASSERT_EQ(tier1_a, tier1_a_url1->parent()); 134 Move(0, tier1_a_url2, tier1_a, 0); 135 Move(0, tier1_a_url1, tier1_a, 2); 136 137 // Wait for the rearranged hierarchy to sync. 138 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 139 ASSERT_TRUE(ModelMatchesVerifier(0)); 140 141 ASSERT_EQ(1, tier1_a_url0->parent()->GetIndexOf(tier1_a_url0)); 142 Move(0, tier1_a_url0, bar, bar->child_count()); 143 const BookmarkNode* boa = AddURL(0, bar, bar->child_count(), 144 "Bank of America", GURL("https://www.bankofamerica.com")); 145 ASSERT_TRUE(boa != NULL); 146 Move(0, tier1_a_url0, top, top->child_count()); 147 const BookmarkNode* bubble = AddURL( 148 0, bar, bar->child_count(), "Seattle Bubble", 149 GURL("http://seattlebubble.com")); 150 ASSERT_TRUE(bubble != NULL); 151 const BookmarkNode* wired = AddURL(0, bar, 2, "Wired News", 152 GURL("http://www.wired.com")); 153 const BookmarkNode* tier2_b = AddFolder( 154 0, tier1_b, 0, "tier2_b"); 155 Move(0, tier1_b_url0, tier2_b, 0); 156 Move(0, porsche, bar, 0); 157 SetTitle(0, wired, "News Wired"); 158 SetTitle(0, porsche, "ICanHazPorsche?"); 159 160 // Wait for the title change to sync. 161 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 162 ASSERT_TRUE(ModelMatchesVerifier(0)); 163 164 ASSERT_EQ(tier1_a_url0->id(), top->GetChild(top->child_count() - 1)->id()); 165 Remove(0, top, top->child_count() - 1); 166 Move(0, wired, tier1_b, 0); 167 Move(0, porsche, bar, 3); 168 const BookmarkNode* tier3_b = AddFolder(0, tier2_b, 1, "tier3_b"); 169 const BookmarkNode* leafs = AddURL( 170 0, tier1_a, 0, "Toronto Maple Leafs", GURL("http://mapleleafs.nhl.com")); 171 const BookmarkNode* wynn = AddURL(0, bar, 1, "Wynn", 172 GURL("http://www.wynnlasvegas.com")); 173 174 Move(0, wynn, tier3_b, 0); 175 Move(0, leafs, tier3_b, 0); 176 177 // Wait for newly added bookmarks to sync. 178 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 179 ASSERT_TRUE(ModelMatchesVerifier(0)); 180 181 // Only verify FakeServer data if FakeServer is being used. 182 // TODO(pvalenzuela): Use this style of verification in more tests once it is 183 // proven stable. 184 if (GetFakeServer()) 185 VerifyBookmarkModelMatchesFakeServer(0); 186 } 187 188 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, InjectedBookmark) { 189 std::string title = "Montreal Canadiens"; 190 fake_server::EntityBuilderFactory entity_builder_factory; 191 scoped_ptr<fake_server::FakeServerEntity> entity = 192 entity_builder_factory.NewBookmarkEntityBuilder( 193 title, GURL("http://canadiens.nhl.com")).Build(); 194 fake_server_->InjectEntity(entity.Pass()); 195 196 DisableVerifier(); 197 ASSERT_TRUE(SetupClients()); 198 ASSERT_TRUE(SetupSync()); 199 200 ASSERT_EQ(1, CountBookmarksWithTitlesMatching(0, title)); 201 } 202 203 // Test that a client doesn't mutate the favicon data in the process 204 // of storing the favicon data from sync to the database or in the process 205 // of requesting data from the database for sync. 206 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, 207 SetFaviconHiDPIDifferentCodec) { 208 // Set the supported scale factors to 1x and 2x such that 209 // BookmarkModel::GetFavicon() requests both 1x and 2x. 210 // 1x -> for sync, 2x -> for the UI. 211 std::vector<ui::ScaleFactor> supported_scale_factors; 212 supported_scale_factors.push_back(ui::SCALE_FACTOR_100P); 213 supported_scale_factors.push_back(ui::SCALE_FACTOR_200P); 214 ui::SetSupportedScaleFactors(supported_scale_factors); 215 216 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 217 ASSERT_TRUE(ModelMatchesVerifier(0)); 218 219 const GURL page_url("http://www.google.com"); 220 const GURL icon_url("http://www.google.com/favicon.ico"); 221 const BookmarkNode* bookmark = AddURL(0, "title", page_url); 222 223 // Simulate receiving a favicon from sync encoded by a different PNG encoder 224 // than the one native to the OS. This tests the PNG data is not decoded to 225 // SkBitmap (or any other image format) then encoded back to PNG on the path 226 // between sync and the database. 227 gfx::Image original_favicon = Create1xFaviconFromPNGFile( 228 "favicon_cocoa_png_codec.png"); 229 ASSERT_FALSE(original_favicon.IsEmpty()); 230 SetFavicon(0, bookmark, icon_url, original_favicon, 231 bookmarks_helper::FROM_SYNC); 232 233 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 234 ASSERT_TRUE(ModelMatchesVerifier(0)); 235 236 scoped_refptr<base::RefCountedMemory> original_favicon_bytes = 237 original_favicon.As1xPNGBytes(); 238 gfx::Image final_favicon = GetBookmarkModel(0)->GetFavicon(bookmark); 239 scoped_refptr<base::RefCountedMemory> final_favicon_bytes = 240 final_favicon.As1xPNGBytes(); 241 242 // Check that the data was not mutated from the original. 243 EXPECT_TRUE(original_favicon_bytes.get()); 244 EXPECT_TRUE(original_favicon_bytes->Equals(final_favicon_bytes)); 245 } 246 247 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, 248 BookmarkAllNodesRemovedEvent) { 249 ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; 250 // Starting state: 251 // other_node 252 // -> folder0 253 // -> tier1_a 254 // -> http://mail.google.com 255 // -> http://www.google.com 256 // -> http://news.google.com 257 // -> http://yahoo.com 258 // -> http://www.cnn.com 259 // bookmark_bar 260 // -> empty_folder 261 // -> folder1 262 // -> http://yahoo.com 263 // -> http://gmail.com 264 265 const BookmarkNode* folder0 = AddFolder(0, GetOtherNode(0), 0, "folder0"); 266 const BookmarkNode* tier1_a = AddFolder(0, folder0, 0, "tier1_a"); 267 ASSERT_TRUE(AddURL(0, folder0, 1, "News", GURL("http://news.google.com"))); 268 ASSERT_TRUE(AddURL(0, folder0, 2, "Yahoo", GURL("http://www.yahoo.com"))); 269 ASSERT_TRUE(AddURL(0, tier1_a, 0, "Gmai", GURL("http://mail.google.com"))); 270 ASSERT_TRUE(AddURL(0, tier1_a, 1, "Google", GURL("http://www.google.com"))); 271 ASSERT_TRUE( 272 AddURL(0, GetOtherNode(0), 1, "CNN", GURL("http://www.cnn.com"))); 273 274 ASSERT_TRUE(AddFolder(0, GetBookmarkBarNode(0), 0, "empty_folder")); 275 const BookmarkNode* folder1 = 276 AddFolder(0, GetBookmarkBarNode(0), 1, "folder1"); 277 ASSERT_TRUE(AddURL(0, folder1, 0, "Yahoo", GURL("http://www.yahoo.com"))); 278 ASSERT_TRUE( 279 AddURL(0, GetBookmarkBarNode(0), 2, "Gmai", GURL("http://gmail.com"))); 280 281 // Set up sync, wait for its completion and verify that changes propagated. 282 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; 283 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 284 ASSERT_TRUE(ModelMatchesVerifier(0)); 285 286 // Remove all bookmarks and wait for sync completion. 287 RemoveAll(0); 288 ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); 289 // Verify other node has no children now. 290 EXPECT_EQ(0, GetOtherNode(0)->child_count()); 291 EXPECT_EQ(0, GetBookmarkBarNode(0)->child_count()); 292 // Verify model matches verifier. 293 ASSERT_TRUE(ModelMatchesVerifier(0)); 294 } 295