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.
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/single_client_status_change_checker.h"
10 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
11 #include "chrome/browser/sync/test/integration/sync_test.h"
12 #include "components/bookmarks/browser/bookmark_model.h"
13 #include "sync/test/fake_server/bookmark_entity_builder.h"
14 #include "sync/test/fake_server/entity_builder_factory.h"
15 #include "sync/test/fake_server/fake_server_verifier.h"
16 #include "sync/test/fake_server/tombstone_entity.h"
17 #include "ui/base/layout.h"
19 using bookmarks::BookmarkModel
;
20 using bookmarks::BookmarkNode
;
21 using bookmarks_helper::AddFolder
;
22 using bookmarks_helper::AddURL
;
23 using bookmarks_helper::AwaitCountBookmarksWithTitlesMatching
;
24 using bookmarks_helper::AwaitCountBookmarksWithUrlsMatching
;
25 using bookmarks_helper::CountBookmarksWithTitlesMatching
;
26 using bookmarks_helper::CountBookmarksWithUrlsMatching
;
27 using bookmarks_helper::CountFoldersWithTitlesMatching
;
28 using bookmarks_helper::Create1xFaviconFromPNGFile
;
29 using bookmarks_helper::GetBookmarkBarNode
;
30 using bookmarks_helper::GetBookmarkModel
;
31 using bookmarks_helper::GetOtherNode
;
32 using bookmarks_helper::ModelMatchesVerifier
;
33 using bookmarks_helper::Move
;
34 using bookmarks_helper::Remove
;
35 using bookmarks_helper::RemoveAll
;
36 using bookmarks_helper::SetFavicon
;
37 using bookmarks_helper::SetTitle
;
38 using sync_integration_test_util::AwaitCommitActivityCompletion
;
40 // All tests in this file utilize a single profile.
41 // TODO(pvalenzuela): Standardize this pattern by moving this constant to
42 // SyncTest and using it in all single client tests.
43 const int kSingleProfileIndex
= 0;
45 class SingleClientBookmarksSyncTest
: public SyncTest
{
47 SingleClientBookmarksSyncTest() : SyncTest(SINGLE_CLIENT
) {}
48 ~SingleClientBookmarksSyncTest() override
{}
50 // Verify that the local bookmark model (for the Profile corresponding to
51 // |index|) matches the data on the FakeServer. It is assumed that FakeServer
52 // is being used and each bookmark has a unique title. Folders are not
54 void VerifyBookmarkModelMatchesFakeServer(int index
);
57 DISALLOW_COPY_AND_ASSIGN(SingleClientBookmarksSyncTest
);
60 void SingleClientBookmarksSyncTest::VerifyBookmarkModelMatchesFakeServer(
62 fake_server::FakeServerVerifier
fake_server_verifier(GetFakeServer());
63 std::vector
<BookmarkModel::URLAndTitle
> local_bookmarks
;
64 GetBookmarkModel(index
)->GetBookmarks(&local_bookmarks
);
66 // Verify that all local bookmark titles exist once on the server.
67 std::vector
<BookmarkModel::URLAndTitle
>::const_iterator it
;
68 for (it
= local_bookmarks
.begin(); it
!= local_bookmarks
.end(); ++it
) {
69 ASSERT_TRUE(fake_server_verifier
.VerifyEntityCountByTypeAndName(
72 base::UTF16ToUTF8(it
->title
)));
76 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest
, Sanity
) {
77 ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
83 // -> http://mail.google.com "tier1_a_url0"
84 // -> http://www.pandora.com "tier1_a_url1"
85 // -> http://www.facebook.com "tier1_a_url2"
87 // -> http://www.nhl.com "tier1_b_url0"
88 const BookmarkNode
* top
= AddFolder(
89 kSingleProfileIndex
, GetOtherNode(kSingleProfileIndex
), 0, "top");
90 const BookmarkNode
* tier1_a
= AddFolder(
91 kSingleProfileIndex
, top
, 0, "tier1_a");
92 const BookmarkNode
* tier1_b
= AddFolder(
93 kSingleProfileIndex
, top
, 1, "tier1_b");
94 const BookmarkNode
* tier1_a_url0
= AddURL(
95 kSingleProfileIndex
, tier1_a
, 0, "tier1_a_url0",
96 GURL("http://mail.google.com"));
97 const BookmarkNode
* tier1_a_url1
= AddURL(
98 kSingleProfileIndex
, tier1_a
, 1, "tier1_a_url1",
99 GURL("http://www.pandora.com"));
100 const BookmarkNode
* tier1_a_url2
= AddURL(
101 kSingleProfileIndex
, tier1_a
, 2, "tier1_a_url2",
102 GURL("http://www.facebook.com"));
103 const BookmarkNode
* tier1_b_url0
= AddURL(
104 kSingleProfileIndex
, tier1_b
, 0, "tier1_b_url0",
105 GURL("http://www.nhl.com"));
107 // Setup sync, wait for its completion, and make sure changes were synced.
108 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
109 ASSERT_TRUE(AwaitCommitActivityCompletion(
110 GetSyncService((kSingleProfileIndex
))));
111 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
113 // Ultimately we want to end up with the following model; but this test is
114 // more about the journey than the destination.
117 // -> CNN (www.cnn.com)
119 // -> tier1_a_url2 (www.facebook.com)
120 // -> tier1_a_url1 (www.pandora.com)
121 // -> Porsche (www.porsche.com)
122 // -> Bank of America (www.bankofamerica.com)
127 // -> Wired News (www.wired.com)
131 // -> Toronto Maple Leafs (mapleleafs.nhl.com)
132 // -> Wynn (www.wynnlasvegas.com)
134 const BookmarkNode
* bar
= GetBookmarkBarNode(kSingleProfileIndex
);
135 const BookmarkNode
* cnn
= AddURL(
136 kSingleProfileIndex
, bar
, 0, "CNN", GURL("http://www.cnn.com"));
137 ASSERT_TRUE(cnn
!= NULL
);
138 Move(kSingleProfileIndex
, tier1_a
, bar
, 1);
140 // Wait for the bookmark position change to sync.
141 ASSERT_TRUE(AwaitCommitActivityCompletion(
142 GetSyncService((kSingleProfileIndex
))));
143 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
145 const BookmarkNode
* porsche
= AddURL(
146 kSingleProfileIndex
, bar
, 2, "Porsche", GURL("http://www.porsche.com"));
147 // Rearrange stuff in tier1_a.
148 ASSERT_EQ(tier1_a
, tier1_a_url2
->parent());
149 ASSERT_EQ(tier1_a
, tier1_a_url1
->parent());
150 Move(kSingleProfileIndex
, tier1_a_url2
, tier1_a
, 0);
151 Move(kSingleProfileIndex
, tier1_a_url1
, tier1_a
, 2);
153 // Wait for the rearranged hierarchy to sync.
154 ASSERT_TRUE(AwaitCommitActivityCompletion(
155 GetSyncService((kSingleProfileIndex
))));
156 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
158 ASSERT_EQ(1, tier1_a_url0
->parent()->GetIndexOf(tier1_a_url0
));
159 Move(kSingleProfileIndex
, tier1_a_url0
, bar
, bar
->child_count());
160 const BookmarkNode
* boa
= AddURL(
161 kSingleProfileIndex
, bar
, bar
->child_count(),
162 "Bank of America", GURL("https://www.bankofamerica.com"));
163 ASSERT_TRUE(boa
!= NULL
);
164 Move(kSingleProfileIndex
, tier1_a_url0
, top
, top
->child_count());
165 const BookmarkNode
* bubble
= AddURL(
166 kSingleProfileIndex
, bar
, bar
->child_count(), "Seattle Bubble",
167 GURL("http://seattlebubble.com"));
168 ASSERT_TRUE(bubble
!= NULL
);
169 const BookmarkNode
* wired
= AddURL(
170 kSingleProfileIndex
, bar
, 2, "Wired News", GURL("http://www.wired.com"));
171 const BookmarkNode
* tier2_b
= AddFolder(
172 kSingleProfileIndex
, tier1_b
, 0, "tier2_b");
173 Move(kSingleProfileIndex
, tier1_b_url0
, tier2_b
, 0);
174 Move(kSingleProfileIndex
, porsche
, bar
, 0);
175 SetTitle(kSingleProfileIndex
, wired
, "News Wired");
176 SetTitle(kSingleProfileIndex
, porsche
, "ICanHazPorsche?");
178 // Wait for the title change to sync.
179 ASSERT_TRUE(AwaitCommitActivityCompletion(
180 GetSyncService((kSingleProfileIndex
))));
181 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
183 ASSERT_EQ(tier1_a_url0
->id(), top
->GetChild(top
->child_count() - 1)->id());
184 Remove(kSingleProfileIndex
, top
, top
->child_count() - 1);
185 Move(kSingleProfileIndex
, wired
, tier1_b
, 0);
186 Move(kSingleProfileIndex
, porsche
, bar
, 3);
187 const BookmarkNode
* tier3_b
= AddFolder(
188 kSingleProfileIndex
, tier2_b
, 1, "tier3_b");
189 const BookmarkNode
* leafs
= AddURL(
190 kSingleProfileIndex
, tier1_a
, 0, "Toronto Maple Leafs",
191 GURL("http://mapleleafs.nhl.com"));
192 const BookmarkNode
* wynn
= AddURL(
193 kSingleProfileIndex
, bar
, 1, "Wynn", GURL("http://www.wynnlasvegas.com"));
195 Move(kSingleProfileIndex
, wynn
, tier3_b
, 0);
196 Move(kSingleProfileIndex
, leafs
, tier3_b
, 0);
198 // Wait for newly added bookmarks to sync.
199 ASSERT_TRUE(AwaitCommitActivityCompletion(
200 GetSyncService((kSingleProfileIndex
))));
201 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
203 // Only verify FakeServer data if FakeServer is being used.
204 // TODO(pvalenzuela): Use this style of verification in more tests once it is
207 VerifyBookmarkModelMatchesFakeServer(kSingleProfileIndex
);
210 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest
, InjectedBookmark
) {
211 std::string title
= "Montreal Canadiens";
212 fake_server::EntityBuilderFactory entity_builder_factory
;
213 fake_server::BookmarkEntityBuilder bookmark_builder
=
214 entity_builder_factory
.NewBookmarkEntityBuilder(title
);
215 fake_server_
->InjectEntity(bookmark_builder
.BuildBookmark(
216 GURL("http://canadiens.nhl.com")));
219 ASSERT_TRUE(SetupClients());
220 ASSERT_TRUE(SetupSync());
222 ASSERT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex
, title
));
225 // Test that a client doesn't mutate the favicon data in the process
226 // of storing the favicon data from sync to the database or in the process
227 // of requesting data from the database for sync.
228 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest
,
229 SetFaviconHiDPIDifferentCodec
) {
230 // Set the supported scale factors to 1x and 2x such that
231 // BookmarkModel::GetFavicon() requests both 1x and 2x.
232 // 1x -> for sync, 2x -> for the UI.
233 std::vector
<ui::ScaleFactor
> supported_scale_factors
;
234 supported_scale_factors
.push_back(ui::SCALE_FACTOR_100P
);
235 supported_scale_factors
.push_back(ui::SCALE_FACTOR_200P
);
236 ui::SetSupportedScaleFactors(supported_scale_factors
);
238 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
239 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
241 const GURL
page_url("http://www.google.com");
242 const GURL
icon_url("http://www.google.com/favicon.ico");
243 const BookmarkNode
* bookmark
= AddURL(kSingleProfileIndex
, "title", page_url
);
245 // Simulate receiving a favicon from sync encoded by a different PNG encoder
246 // than the one native to the OS. This tests the PNG data is not decoded to
247 // SkBitmap (or any other image format) then encoded back to PNG on the path
248 // between sync and the database.
249 gfx::Image original_favicon
= Create1xFaviconFromPNGFile(
250 "favicon_cocoa_png_codec.png");
251 ASSERT_FALSE(original_favicon
.IsEmpty());
252 SetFavicon(kSingleProfileIndex
, bookmark
, icon_url
, original_favicon
,
253 bookmarks_helper::FROM_SYNC
);
255 ASSERT_TRUE(AwaitCommitActivityCompletion(
256 GetSyncService((kSingleProfileIndex
))));
257 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
259 scoped_refptr
<base::RefCountedMemory
> original_favicon_bytes
=
260 original_favicon
.As1xPNGBytes();
261 gfx::Image final_favicon
=
262 GetBookmarkModel(kSingleProfileIndex
)->GetFavicon(bookmark
);
263 scoped_refptr
<base::RefCountedMemory
> final_favicon_bytes
=
264 final_favicon
.As1xPNGBytes();
266 // Check that the data was not mutated from the original.
267 EXPECT_TRUE(original_favicon_bytes
.get());
268 EXPECT_TRUE(original_favicon_bytes
->Equals(final_favicon_bytes
));
271 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest
,
272 BookmarkAllNodesRemovedEvent
) {
273 ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
278 // -> http://mail.google.com
279 // -> http://www.google.com
280 // -> http://news.google.com
281 // -> http://yahoo.com
282 // -> http://www.cnn.com
286 // -> http://yahoo.com
287 // -> http://gmail.com
289 const BookmarkNode
* folder0
= AddFolder(
290 kSingleProfileIndex
, GetOtherNode(kSingleProfileIndex
), 0, "folder0");
291 const BookmarkNode
* tier1_a
= AddFolder(
292 kSingleProfileIndex
, folder0
, 0, "tier1_a");
294 kSingleProfileIndex
, folder0
, 1, "News", GURL("http://news.google.com")));
296 kSingleProfileIndex
, folder0
, 2, "Yahoo", GURL("http://www.yahoo.com")));
298 kSingleProfileIndex
, tier1_a
, 0, "Gmai", GURL("http://mail.google.com")));
300 kSingleProfileIndex
, tier1_a
, 1, "Google", GURL("http://www.google.com")));
302 kSingleProfileIndex
, GetOtherNode(kSingleProfileIndex
), 1, "CNN",
303 GURL("http://www.cnn.com")));
305 ASSERT_TRUE(AddFolder(
306 kSingleProfileIndex
, GetBookmarkBarNode(kSingleProfileIndex
), 0,
308 const BookmarkNode
* folder1
= AddFolder(
309 kSingleProfileIndex
, GetBookmarkBarNode(kSingleProfileIndex
), 1,
312 kSingleProfileIndex
, folder1
, 0, "Yahoo", GURL("http://www.yahoo.com")));
314 kSingleProfileIndex
, GetBookmarkBarNode(0), 2, "Gmai",
315 GURL("http://gmail.com")));
317 // Set up sync, wait for its completion and verify that changes propagated.
318 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
319 ASSERT_TRUE(AwaitCommitActivityCompletion(
320 GetSyncService((kSingleProfileIndex
))));
321 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
323 // Remove all bookmarks and wait for sync completion.
324 RemoveAll(kSingleProfileIndex
);
325 ASSERT_TRUE(AwaitCommitActivityCompletion(
326 GetSyncService((kSingleProfileIndex
))));
327 // Verify other node has no children now.
328 EXPECT_EQ(0, GetOtherNode(kSingleProfileIndex
)->child_count());
329 EXPECT_EQ(0, GetBookmarkBarNode(kSingleProfileIndex
)->child_count());
330 // Verify model matches verifier.
331 ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex
));
334 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest
,
335 DownloadDeletedBookmark
) {
336 std::string title
= "Patrick Star";
337 fake_server::EntityBuilderFactory entity_builder_factory
;
338 fake_server::BookmarkEntityBuilder bookmark_builder
=
339 entity_builder_factory
.NewBookmarkEntityBuilder(title
);
340 fake_server_
->InjectEntity(bookmark_builder
.BuildBookmark(
341 GURL("http://en.wikipedia.org/wiki/Patrick_Star")));
344 ASSERT_TRUE(SetupSync());
346 ASSERT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex
, title
));
348 std::vector
<sync_pb::SyncEntity
> server_bookmarks
=
349 GetFakeServer()->GetSyncEntitiesByModelType(syncer::BOOKMARKS
);
350 ASSERT_EQ(1ul, server_bookmarks
.size());
351 std::string entity_id
= server_bookmarks
[0].id_string();
352 scoped_ptr
<fake_server::FakeServerEntity
> tombstone(
353 fake_server::TombstoneEntity::Create(entity_id
));
354 GetFakeServer()->InjectEntity(tombstone
.Pass());
356 const syncer::ModelTypeSet
kBookmarksType(syncer::BOOKMARKS
);
357 TriggerSyncForModelTypes(kSingleProfileIndex
, kBookmarksType
);
359 const int kExpectedCountAfterDeletion
= 0;
360 ASSERT_TRUE(AwaitCountBookmarksWithTitlesMatching(
361 kSingleProfileIndex
, title
, kExpectedCountAfterDeletion
));
364 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest
,
365 DownloadModifiedBookmark
) {
366 std::string title
= "Syrup";
367 GURL original_url
= GURL("https://en.wikipedia.org/?title=Maple_syrup");
368 GURL updated_url
= GURL("https://en.wikipedia.org/wiki/Xylem");
370 fake_server::EntityBuilderFactory entity_builder_factory
;
371 fake_server::BookmarkEntityBuilder bookmark_builder
=
372 entity_builder_factory
.NewBookmarkEntityBuilder(title
);
373 fake_server_
->InjectEntity(bookmark_builder
.BuildBookmark(original_url
));
376 ASSERT_TRUE(SetupSync());
378 ASSERT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex
, title
));
379 ASSERT_EQ(1, CountBookmarksWithUrlsMatching(kSingleProfileIndex
,
381 ASSERT_EQ(0, CountBookmarksWithUrlsMatching(kSingleProfileIndex
,
384 std::vector
<sync_pb::SyncEntity
> server_bookmarks
=
385 GetFakeServer()->GetSyncEntitiesByModelType(syncer::BOOKMARKS
);
386 ASSERT_EQ(1ul, server_bookmarks
.size());
387 std::string entity_id
= server_bookmarks
[0].id_string();
389 sync_pb::EntitySpecifics specifics
= server_bookmarks
[0].specifics();
390 sync_pb::BookmarkSpecifics
* bookmark_specifics
= specifics
.mutable_bookmark();
391 bookmark_specifics
->set_url(updated_url
.spec());
392 ASSERT_TRUE(GetFakeServer()->ModifyEntitySpecifics(entity_id
, specifics
));
394 const syncer::ModelTypeSet
kBookmarksType(syncer::BOOKMARKS
);
395 TriggerSyncForModelTypes(kSingleProfileIndex
, kBookmarksType
);
397 ASSERT_TRUE(AwaitCountBookmarksWithUrlsMatching(
398 kSingleProfileIndex
, updated_url
, 1));
399 ASSERT_EQ(0, CountBookmarksWithUrlsMatching(kSingleProfileIndex
,
401 ASSERT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex
, title
));
404 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest
, DownloadBookmarkFolder
) {
405 const std::string title
= "Seattle Sounders FC";
406 fake_server::EntityBuilderFactory entity_builder_factory
;
407 fake_server::BookmarkEntityBuilder bookmark_builder
=
408 entity_builder_factory
.NewBookmarkEntityBuilder(title
);
409 fake_server_
->InjectEntity(bookmark_builder
.BuildFolder());
412 ASSERT_TRUE(SetupClients());
413 ASSERT_EQ(0, CountFoldersWithTitlesMatching(kSingleProfileIndex
, title
));
415 ASSERT_TRUE(SetupSync());
417 ASSERT_EQ(1, CountFoldersWithTitlesMatching(kSingleProfileIndex
, title
));