1 // Copyright (c) 2013 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 "chrome/browser/sync/glue/favicon_cache.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/time/time.h"
11 #include "content/public/browser/notification_service.h"
12 #include "sync/api/attachments/attachment_id.h"
13 #include "sync/api/sync_change_processor_wrapper_for_test.h"
14 #include "sync/api/sync_error_factory_mock.h"
15 #include "sync/api/time.h"
16 #include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
17 #include "sync/protocol/favicon_image_specifics.pb.h"
18 #include "sync/protocol/favicon_tracking_specifics.pb.h"
19 #include "sync/protocol/sync.pb.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace browser_sync
{
26 // Total number of favicons to use in sync test batches.
27 const int kFaviconBatchSize
= 10;
29 // Maximum number of favicons to sync.
30 const int kMaxSyncFavicons
= kFaviconBatchSize
*2;
32 // TestChangeProcessor --------------------------------------------------------
34 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
36 class TestChangeProcessor
: public syncer::SyncChangeProcessor
{
38 TestChangeProcessor();
39 ~TestChangeProcessor() override
;
41 // Store a copy of all the changes passed in so we can examine them later.
42 syncer::SyncError
ProcessSyncChanges(
43 const tracked_objects::Location
& from_here
,
44 const syncer::SyncChangeList
& change_list
) override
;
46 syncer::SyncDataList
GetAllSyncData(syncer::ModelType type
) const override
{
47 return syncer::SyncDataList();
50 bool contains_guid(const std::string
& guid
) const {
51 return change_map_
.count(guid
) != 0;
54 syncer::SyncChange
change_for_guid(const std::string
& guid
) const {
55 DCHECK(contains_guid(guid
));
56 return change_map_
.find(guid
)->second
;
59 // Returns the last change list received, and resets the internal list.
60 syncer::SyncChangeList
GetAndResetChangeList() {
61 syncer::SyncChangeList list
;
62 list
.swap(change_list_
);
66 void set_erroneous(bool erroneous
) { erroneous_
= erroneous
; }
69 // Track the changes received in ProcessSyncChanges.
70 std::map
<std::string
, syncer::SyncChange
> change_map_
;
71 syncer::SyncChangeList change_list_
;
74 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor
);
77 TestChangeProcessor::TestChangeProcessor() : erroneous_(false) {
80 TestChangeProcessor::~TestChangeProcessor() {
83 syncer::SyncError
TestChangeProcessor::ProcessSyncChanges(
84 const tracked_objects::Location
& from_here
,
85 const syncer::SyncChangeList
& change_list
) {
87 return syncer::SyncError(
89 syncer::SyncError::DATATYPE_ERROR
,
91 change_list
[0].sync_data().GetDataType());
94 change_list_
.insert(change_list_
.end(),
97 change_map_
.erase(change_map_
.begin(), change_map_
.end());
98 for (syncer::SyncChangeList::const_iterator iter
= change_list
.begin();
99 iter
!= change_list
.end(); ++iter
) {
100 change_map_
[iter
->sync_data().GetTitle()] = *iter
;
102 return syncer::SyncError();
105 // TestFaviconData ------------------------------------------------------------
106 struct TestFaviconData
{
107 TestFaviconData() : last_visit_time(0), is_bookmarked(false) {}
110 std::string image_16
;
111 std::string image_32
;
112 std::string image_64
;
113 int64 last_visit_time
;
117 TestFaviconData
BuildFaviconData(int index
) {
118 TestFaviconData data
;
119 data
.page_url
= GURL(base::StringPrintf("http://bla.com/%.2i.html", index
));
120 data
.icon_url
= GURL(base::StringPrintf("http://bla.com/%.2i.ico", index
));
121 data
.image_16
= base::StringPrintf("16 %i", index
);
122 // TODO(zea): enable this once the cache supports writing them.
123 // data.image_32 = base::StringPrintf("32 %i", index);
124 // data.image_64 = base::StringPrintf("64 %i", index);
125 data
.last_visit_time
= index
;
129 void FillImageSpecifics(
130 const TestFaviconData
& test_data
,
131 sync_pb::FaviconImageSpecifics
* image_specifics
) {
132 image_specifics
->set_favicon_url(test_data
.icon_url
.spec());
133 if (!test_data
.image_16
.empty()) {
134 image_specifics
->mutable_favicon_web()->set_height(16);
135 image_specifics
->mutable_favicon_web()->set_width(16);
136 image_specifics
->mutable_favicon_web()->set_favicon(test_data
.image_16
);
138 if (!test_data
.image_32
.empty()) {
139 image_specifics
->mutable_favicon_web_32()->set_height(32);
140 image_specifics
->mutable_favicon_web_32()->set_width(32);
141 image_specifics
->mutable_favicon_web_32()->set_favicon(test_data
.image_32
);
143 if (!test_data
.image_64
.empty()) {
144 image_specifics
->mutable_favicon_touch_64()->set_height(64);
145 image_specifics
->mutable_favicon_touch_64()->set_width(64);
146 image_specifics
->mutable_favicon_touch_64()->
147 set_favicon(test_data
.image_64
);
151 void FillTrackingSpecifics(
152 const TestFaviconData
& test_data
,
153 sync_pb::FaviconTrackingSpecifics
* tracking_specifics
) {
154 tracking_specifics
->set_favicon_url(test_data
.icon_url
.spec());
155 tracking_specifics
->set_last_visit_time_ms(test_data
.last_visit_time
);
156 tracking_specifics
->set_is_bookmarked(test_data
.is_bookmarked
);
159 testing::AssertionResult
CompareFaviconDataToSpecifics(
160 const TestFaviconData
& test_data
,
161 const sync_pb::EntitySpecifics
& specifics
) {
162 if (specifics
.has_favicon_image()) {
163 sync_pb::FaviconImageSpecifics image_specifics
= specifics
.favicon_image();
164 if (image_specifics
.favicon_url() != test_data
.icon_url
.spec())
165 return testing::AssertionFailure() << "Image icon url doesn't match.";
166 if (!test_data
.image_16
.empty()) {
167 if (image_specifics
.favicon_web().favicon() != test_data
.image_16
||
168 image_specifics
.favicon_web().height() != 16 ||
169 image_specifics
.favicon_web().width() != 16) {
170 return testing::AssertionFailure() << "16p image data doesn't match.";
172 } else if (image_specifics
.has_favicon_web()) {
173 return testing::AssertionFailure() << "Missing 16p favicon.";
175 if (!test_data
.image_32
.empty()) {
176 if (image_specifics
.favicon_web_32().favicon() != test_data
.image_32
||
177 image_specifics
.favicon_web().height() != 32 ||
178 image_specifics
.favicon_web().width() != 32) {
179 return testing::AssertionFailure() << "32p image data doesn't match.";
181 } else if (image_specifics
.has_favicon_web_32()) {
182 return testing::AssertionFailure() << "Missing 32p favicon.";
184 if (!test_data
.image_64
.empty()) {
185 if (image_specifics
.favicon_touch_64().favicon() != test_data
.image_64
||
186 image_specifics
.favicon_web().height() != 64 ||
187 image_specifics
.favicon_web().width() != 64) {
188 return testing::AssertionFailure() << "64p image data doesn't match.";
190 } else if (image_specifics
.has_favicon_touch_64()) {
191 return testing::AssertionFailure() << "Missing 64p favicon.";
194 sync_pb::FaviconTrackingSpecifics tracking_specifics
=
195 specifics
.favicon_tracking();
196 if (tracking_specifics
.favicon_url() != test_data
.icon_url
.spec())
197 return testing::AssertionFailure() << "Tracking icon url doesn't match.";
198 if (tracking_specifics
.last_visit_time_ms() != test_data
.last_visit_time
)
199 return testing::AssertionFailure() << "Visit time doesn't match.";
200 if (tracking_specifics
.is_bookmarked() != test_data
.is_bookmarked
)
201 return testing::AssertionFailure() << "Bookmark status doens't match.";
203 return testing::AssertionSuccess();
206 testing::AssertionResult
VerifyChanges(
207 syncer::ModelType expected_model_type
,
208 const std::vector
<syncer::SyncChange::SyncChangeType
>&
209 expected_change_types
,
210 const std::vector
<int>& expected_icons
,
211 const syncer::SyncChangeList
& change_list
) {
212 DCHECK_EQ(expected_change_types
.size(), expected_icons
.size());
213 if (change_list
.size() != expected_icons
.size())
214 return testing::AssertionFailure() << "Change list size doesn't match.";
215 for (size_t i
= 0; i
< expected_icons
.size(); ++i
) {
216 TestFaviconData data
= BuildFaviconData(expected_icons
[i
]);
217 if (change_list
[i
].sync_data().GetDataType() != expected_model_type
)
218 return testing::AssertionFailure() << "Change datatype doesn't match.";
219 if (change_list
[i
].change_type() != expected_change_types
[i
])
220 return testing::AssertionFailure() << "Change type doesn't match.";
221 if (change_list
[i
].change_type() == syncer::SyncChange::ACTION_DELETE
) {
222 if (syncer::SyncDataLocal(change_list
[i
].sync_data()).GetTag() !=
223 data
.icon_url
.spec())
224 return testing::AssertionFailure() << "Deletion url does not match.";
226 testing::AssertionResult compare_result
=
227 CompareFaviconDataToSpecifics(
229 change_list
[i
].sync_data().GetSpecifics());
231 return compare_result
;
234 return testing::AssertionSuccess();
237 // Helper to extract the favicon id embedded in the tag of a sync
239 int GetFaviconId(const syncer::SyncChange change
) {
240 std::string tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
241 const std::string kPrefix
= "http://bla.com/";
242 const std::string kSuffix
= ".ico";
243 if (tag
.find(kPrefix
) != 0)
245 std::string temp
= tag
.substr(kPrefix
.length());
246 if (temp
.rfind(kSuffix
) <= 0)
248 temp
= temp
.substr(0, temp
.rfind(kSuffix
));
250 if (!base::StringToInt(temp
, &result
))
257 class SyncFaviconCacheTest
: public testing::Test
{
259 SyncFaviconCacheTest();
260 ~SyncFaviconCacheTest() override
{}
262 void SetUpInitialSync(const syncer::SyncDataList
& initial_image_data
,
263 const syncer::SyncDataList
& initial_tracking_data
);
265 size_t GetFaviconCount() const;
266 size_t GetTaskCount() const;
268 testing::AssertionResult
ExpectFaviconEquals(
269 const std::string
& page_url
,
270 const std::string
& bytes
) const;
271 testing::AssertionResult
VerifyLocalIcons(
272 const std::vector
<int>& expected_icons
);
273 testing::AssertionResult
VerifyLocalCustomIcons(
274 const std::vector
<TestFaviconData
>& expected_icons
);
276 scoped_ptr
<syncer::SyncChangeProcessor
> CreateAndPassProcessor();
277 scoped_ptr
<syncer::SyncErrorFactory
> CreateAndPassSyncErrorFactory();
279 FaviconCache
* cache() { return &cache_
; }
280 TestChangeProcessor
* processor() { return sync_processor_
.get(); }
282 // Finish an outstanding favicon load for the icon described in |test_data|.
283 void OnCustomFaviconDataAvailable(const TestFaviconData
& test_data
);
285 // Helper method to run the message loop after invoking
286 // OnReceivedSyncFavicon, which posts an internal task.
287 void TriggerSyncFaviconReceived(const GURL
& page_url
,
288 const GURL
& icon_url
,
289 const std::string
& icon_bytes
,
290 int64 last_visit_time_ms
);
293 base::MessageLoopForUI message_loop_
;
296 // Our dummy ChangeProcessor used to inspect changes pushed to Sync.
297 scoped_ptr
<TestChangeProcessor
> sync_processor_
;
298 scoped_ptr
<syncer::SyncChangeProcessorWrapperForTest
> sync_processor_wrapper_
;
301 SyncFaviconCacheTest::SyncFaviconCacheTest()
302 : cache_(NULL
, kMaxSyncFavicons
),
303 sync_processor_(new TestChangeProcessor
),
304 sync_processor_wrapper_(new syncer::SyncChangeProcessorWrapperForTest(
305 sync_processor_
.get())) {}
307 void SyncFaviconCacheTest::SetUpInitialSync(
308 const syncer::SyncDataList
& initial_image_data
,
309 const syncer::SyncDataList
& initial_tracking_data
) {
310 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
312 CreateAndPassProcessor(),
313 CreateAndPassSyncErrorFactory());
314 ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
315 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
316 initial_tracking_data
,
317 CreateAndPassProcessor(),
318 CreateAndPassSyncErrorFactory());
319 ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
322 size_t SyncFaviconCacheTest::GetFaviconCount() const {
323 return cache_
.NumFaviconsForTest();
326 size_t SyncFaviconCacheTest::GetTaskCount() const {
327 return cache_
.NumTasksForTest();
330 testing::AssertionResult
SyncFaviconCacheTest::ExpectFaviconEquals(
331 const std::string
& page_url
,
332 const std::string
& bytes
) const {
334 scoped_refptr
<base::RefCountedMemory
> favicon
;
335 if (!cache_
.GetSyncedFaviconForPageURL(gurl
, &favicon
))
336 return testing::AssertionFailure() << "Favicon is missing.";
337 if (favicon
->size() != bytes
.size())
338 return testing::AssertionFailure() << "Favicon sizes don't match.";
339 for (size_t i
= 0; i
< favicon
->size(); ++i
) {
340 if (bytes
[i
] != *(favicon
->front() + i
))
341 return testing::AssertionFailure() << "Favicon data doesn't match.";
343 return testing::AssertionSuccess();
346 testing::AssertionResult
SyncFaviconCacheTest::VerifyLocalIcons(
347 const std::vector
<int>& expected_icons
) {
348 std::vector
<TestFaviconData
> expected_custom_icons
;
349 for (size_t i
= 0; i
< expected_icons
.size(); ++i
) {
350 expected_custom_icons
.push_back(BuildFaviconData(expected_icons
[i
]));
352 return VerifyLocalCustomIcons(expected_custom_icons
);
356 testing::AssertionResult
SyncFaviconCacheTest::VerifyLocalCustomIcons(
357 const std::vector
<TestFaviconData
>& expected_custom_icons
) {
358 syncer::SyncDataList image_data_list
=
359 cache()->GetAllSyncData(syncer::FAVICON_IMAGES
);
360 syncer::SyncDataList tracking_data_list
=
361 cache()->GetAllSyncData(syncer::FAVICON_TRACKING
);
362 if (expected_custom_icons
.size() > image_data_list
.size() ||
363 expected_custom_icons
.size() > tracking_data_list
.size())
364 return testing::AssertionFailure() << "Number of icons doesn't match.";
365 for (size_t i
= 0; i
< expected_custom_icons
.size(); ++i
) {
366 const TestFaviconData
& test_data
= expected_custom_icons
[i
];
367 // Find the test data in the data lists. Assume that both lists have the
368 // same ordering, which may not match the |expected_custom_icons| ordering.
369 bool found_match
= false;
370 for (size_t j
= 0; j
< image_data_list
.size(); ++j
) {
371 if (image_data_list
[j
].GetTitle() != test_data
.icon_url
.spec())
374 const sync_pb::FaviconImageSpecifics
& image_specifics
=
375 image_data_list
[j
].GetSpecifics().favicon_image();
376 sync_pb::FaviconImageSpecifics expected_image_specifics
;
377 FillImageSpecifics(test_data
, &expected_image_specifics
);
378 if (image_specifics
.SerializeAsString() !=
379 expected_image_specifics
.SerializeAsString()) {
380 return testing::AssertionFailure() << "Image data doesn't match.";
382 const sync_pb::FaviconTrackingSpecifics
& tracking_specifics
=
383 tracking_data_list
[j
].GetSpecifics().favicon_tracking();
384 sync_pb::FaviconTrackingSpecifics expected_tracking_specifics
;
385 FillTrackingSpecifics(test_data
, &expected_tracking_specifics
);
386 if (tracking_specifics
.SerializeAsString() !=
387 expected_tracking_specifics
.SerializeAsString()) {
388 return testing::AssertionFailure() << "Tracking data doesn't match.";
392 return testing::AssertionFailure() << "Could not find favicon.";
394 return testing::AssertionSuccess();
397 scoped_ptr
<syncer::SyncChangeProcessor
>
398 SyncFaviconCacheTest::CreateAndPassProcessor() {
399 return scoped_ptr
<syncer::SyncChangeProcessor
>(
400 new syncer::SyncChangeProcessorWrapperForTest(sync_processor_
.get()));
403 scoped_ptr
<syncer::SyncErrorFactory
> SyncFaviconCacheTest::
404 CreateAndPassSyncErrorFactory() {
405 return scoped_ptr
<syncer::SyncErrorFactory
>(
406 new syncer::SyncErrorFactoryMock());
409 void SyncFaviconCacheTest::OnCustomFaviconDataAvailable(
410 const TestFaviconData
& test_data
) {
411 std::vector
<favicon_base::FaviconRawBitmapResult
> bitmap_results
;
412 if (!test_data
.image_16
.empty()) {
413 favicon_base::FaviconRawBitmapResult bitmap_result
;
414 bitmap_result
.icon_url
= test_data
.icon_url
;
415 bitmap_result
.pixel_size
.set_width(16);
416 bitmap_result
.pixel_size
.set_height(16);
417 base::RefCountedString
* temp_string
= new base::RefCountedString();
418 temp_string
->data() = test_data
.image_16
;
419 bitmap_result
.bitmap_data
= temp_string
;
420 bitmap_results
.push_back(bitmap_result
);
422 if (!test_data
.image_32
.empty()) {
423 favicon_base::FaviconRawBitmapResult bitmap_result
;
424 bitmap_result
.icon_url
= test_data
.icon_url
;
425 bitmap_result
.pixel_size
.set_width(32);
426 bitmap_result
.pixel_size
.set_height(32);
427 base::RefCountedString
* temp_string
= new base::RefCountedString();
428 temp_string
->data() = test_data
.image_32
;
429 bitmap_result
.bitmap_data
= temp_string
;
430 bitmap_results
.push_back(bitmap_result
);
432 if (!test_data
.image_64
.empty()) {
433 favicon_base::FaviconRawBitmapResult bitmap_result
;
434 bitmap_result
.icon_url
= test_data
.icon_url
;
435 bitmap_result
.pixel_size
.set_width(64);
436 bitmap_result
.pixel_size
.set_height(64);
437 base::RefCountedString
* temp_string
= new base::RefCountedString();
438 temp_string
->data() = test_data
.image_64
;
439 bitmap_result
.bitmap_data
= temp_string
;
440 bitmap_results
.push_back(bitmap_result
);
442 cache()->OnFaviconDataAvailable(test_data
.page_url
, bitmap_results
);
445 void SyncFaviconCacheTest::TriggerSyncFaviconReceived(
446 const GURL
& page_url
,
447 const GURL
& icon_url
,
448 const std::string
& icon_bytes
,
449 int64 last_visit_time_ms
) {
450 cache()->OnReceivedSyncFavicon(page_url
,
454 message_loop_
.RunUntilIdle();
457 // A freshly constructed cache should be empty.
458 TEST_F(SyncFaviconCacheTest
, Empty
) {
459 EXPECT_EQ(0U, GetFaviconCount());
462 TEST_F(SyncFaviconCacheTest
, ReceiveSyncFavicon
) {
463 std::string page_url
= "http://www.google.com";
464 std::string fav_url
= "http://www.google.com/favicon.ico";
465 std::string bytes
= "bytes";
466 EXPECT_EQ(0U, GetFaviconCount());
467 TriggerSyncFaviconReceived(GURL(page_url
), GURL(fav_url
), bytes
, 0);
468 EXPECT_EQ(1U, GetFaviconCount());
469 EXPECT_TRUE(ExpectFaviconEquals(page_url
, bytes
));
472 TEST_F(SyncFaviconCacheTest
, ReceiveEmptySyncFavicon
) {
473 std::string page_url
= "http://www.google.com";
474 std::string fav_url
= "http://www.google.com/favicon.ico";
475 std::string bytes
= "bytes";
476 EXPECT_EQ(0U, GetFaviconCount());
477 TriggerSyncFaviconReceived(GURL(page_url
),
481 EXPECT_EQ(0U, GetFaviconCount());
482 EXPECT_FALSE(ExpectFaviconEquals(page_url
, std::string()));
484 // Then receive the actual favicon.
485 TriggerSyncFaviconReceived(GURL(page_url
), GURL(fav_url
), bytes
, 0);
486 EXPECT_EQ(1U, GetFaviconCount());
487 EXPECT_TRUE(ExpectFaviconEquals(page_url
, bytes
));
490 TEST_F(SyncFaviconCacheTest
, ReceiveUpdatedSyncFavicon
) {
491 std::string page_url
= "http://www.google.com";
492 std::string fav_url
= "http://www.google.com/favicon.ico";
493 std::string bytes
= "bytes";
494 std::string bytes2
= "bytes2";
495 EXPECT_EQ(0U, GetFaviconCount());
496 TriggerSyncFaviconReceived(GURL(page_url
), GURL(fav_url
), bytes
, 0);
497 EXPECT_EQ(1U, GetFaviconCount());
498 EXPECT_TRUE(ExpectFaviconEquals(page_url
, bytes
));
500 // The cache should not update existing favicons from tab sync favicons
501 // (which can be reassociated several times).
502 TriggerSyncFaviconReceived(GURL(page_url
), GURL(fav_url
), bytes2
, 0);
503 EXPECT_EQ(1U, GetFaviconCount());
504 EXPECT_TRUE(ExpectFaviconEquals(page_url
, bytes
));
505 EXPECT_FALSE(ExpectFaviconEquals(page_url
, bytes2
));
508 TEST_F(SyncFaviconCacheTest
, MultipleMappings
) {
509 std::string page_url
= "http://www.google.com";
510 std::string page2_url
= "http://bla.google.com";
511 std::string fav_url
= "http://www.google.com/favicon.ico";
512 std::string bytes
= "bytes";
513 EXPECT_EQ(0U, GetFaviconCount());
514 TriggerSyncFaviconReceived(GURL(page_url
), GURL(fav_url
), bytes
, 0);
515 EXPECT_EQ(1U, GetFaviconCount());
516 EXPECT_TRUE(ExpectFaviconEquals(page_url
, bytes
));
518 // Map another page to the same favicon. They should share the same data.
519 TriggerSyncFaviconReceived(GURL(page2_url
), GURL(fav_url
), bytes
, 0);
520 EXPECT_EQ(1U, GetFaviconCount());
521 EXPECT_TRUE(ExpectFaviconEquals(page2_url
, bytes
));
524 TEST_F(SyncFaviconCacheTest
, SyncEmpty
) {
525 syncer::SyncMergeResult merge_result
=
526 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
527 syncer::SyncDataList(),
528 CreateAndPassProcessor(),
529 CreateAndPassSyncErrorFactory());
531 EXPECT_EQ(0U, cache()->GetAllSyncData(syncer::FAVICON_IMAGES
).size());
532 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
533 EXPECT_EQ(0, merge_result
.num_items_added());
534 EXPECT_EQ(0, merge_result
.num_items_modified());
535 EXPECT_EQ(0, merge_result
.num_items_deleted());
536 EXPECT_EQ(0, merge_result
.num_items_before_association());
537 EXPECT_EQ(0, merge_result
.num_items_after_association());
540 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
541 syncer::SyncDataList(),
542 CreateAndPassProcessor(),
543 CreateAndPassSyncErrorFactory());
545 EXPECT_EQ(0U, cache()->GetAllSyncData(syncer::FAVICON_TRACKING
).size());
546 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
547 EXPECT_EQ(0, merge_result
.num_items_added());
548 EXPECT_EQ(0, merge_result
.num_items_modified());
549 EXPECT_EQ(0, merge_result
.num_items_deleted());
550 EXPECT_EQ(0, merge_result
.num_items_before_association());
551 EXPECT_EQ(0, merge_result
.num_items_after_association());
554 // Setting up sync with existing local favicons should push those favicons into
556 TEST_F(SyncFaviconCacheTest
, SyncExistingLocal
) {
557 std::vector
<syncer::SyncChange::SyncChangeType
> expected_change_types
;
558 std::vector
<int> expected_icons
;
559 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
560 TestFaviconData favicon
= BuildFaviconData(i
);
561 TriggerSyncFaviconReceived(favicon
.page_url
,
565 expected_change_types
.push_back(syncer::SyncChange::ACTION_ADD
);
566 expected_icons
.push_back(i
);
569 syncer::SyncMergeResult merge_result
=
570 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
571 syncer::SyncDataList(),
572 CreateAndPassProcessor(),
573 CreateAndPassSyncErrorFactory());
574 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
575 cache()->GetAllSyncData(syncer::FAVICON_IMAGES
).size());
576 syncer::SyncChangeList change_list
= processor()->GetAndResetChangeList();
577 EXPECT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES
,
578 expected_change_types
,
581 EXPECT_EQ(0, merge_result
.num_items_added());
582 EXPECT_EQ(0, merge_result
.num_items_modified());
583 EXPECT_EQ(0, merge_result
.num_items_deleted());
584 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_before_association());
585 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
588 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
589 syncer::SyncDataList(),
590 CreateAndPassProcessor(),
591 CreateAndPassSyncErrorFactory());
592 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
593 cache()->GetAllSyncData(syncer::FAVICON_TRACKING
).size());
594 change_list
= processor()->GetAndResetChangeList();
595 EXPECT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING
,
596 expected_change_types
,
599 EXPECT_EQ(0, merge_result
.num_items_added());
600 EXPECT_EQ(0, merge_result
.num_items_modified());
601 EXPECT_EQ(0, merge_result
.num_items_deleted());
602 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_before_association());
603 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
606 // Setting up sync with existing sync data should load that data into the local
608 TEST_F(SyncFaviconCacheTest
, SyncExistingRemote
) {
609 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
610 std::vector
<int> expected_icons
;
611 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
612 expected_icons
.push_back(i
);
613 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
614 FillImageSpecifics(BuildFaviconData(i
),
615 image_specifics
.mutable_favicon_image());
616 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
620 syncer::AttachmentIdList(),
621 syncer::AttachmentServiceProxyForTest::Create()));
622 FillTrackingSpecifics(BuildFaviconData(i
),
623 tracking_specifics
.mutable_favicon_tracking());
624 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
628 syncer::AttachmentIdList(),
629 syncer::AttachmentServiceProxyForTest::Create()));
632 syncer::SyncMergeResult merge_result
=
633 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
635 CreateAndPassProcessor(),
636 CreateAndPassSyncErrorFactory());
637 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
638 cache()->GetAllSyncData(syncer::FAVICON_IMAGES
).size());
639 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
640 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_added());
641 EXPECT_EQ(0, merge_result
.num_items_modified());
642 EXPECT_EQ(0, merge_result
.num_items_deleted());
643 EXPECT_EQ(0, merge_result
.num_items_before_association());
644 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
647 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
648 initial_tracking_data
,
649 CreateAndPassProcessor(),
650 CreateAndPassSyncErrorFactory());
651 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
652 cache()->GetAllSyncData(syncer::FAVICON_TRACKING
).size());
653 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
654 EXPECT_EQ(0, merge_result
.num_items_added());
655 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_modified());
656 EXPECT_EQ(0, merge_result
.num_items_deleted());
657 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_before_association());
658 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
660 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
663 // Setting up sync with local data and sync data should merge the two image
664 // sets, with remote data having priority in case both exist.
665 TEST_F(SyncFaviconCacheTest
, SyncMergesImages
) {
666 // First go through and add local 16p favicons.
667 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
668 TestFaviconData favicon
= BuildFaviconData(i
);
669 TriggerSyncFaviconReceived(favicon
.page_url
,
675 // Then go through and create the initial sync data, which does not have 16p
676 // favicons for the first half, and has custom 16p favicons for the second.
677 std::vector
<syncer::SyncChange::SyncChangeType
> expected_change_types
;
678 std::vector
<int> expected_icons
;
679 std::vector
<TestFaviconData
> expected_data
;
680 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
681 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
682 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
683 TestFaviconData test_data
= BuildFaviconData(i
);
684 if (i
< kFaviconBatchSize
/2) {
685 test_data
.image_16
= std::string();
686 expected_icons
.push_back(i
);
687 expected_change_types
.push_back(syncer::SyncChange::ACTION_UPDATE
);
689 test_data
.image_16
+= "custom";
690 expected_data
.push_back(test_data
);
692 FillImageSpecifics(test_data
,
693 image_specifics
.mutable_favicon_image());
695 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
699 syncer::AttachmentIdList(),
700 syncer::AttachmentServiceProxyForTest::Create()));
701 FillTrackingSpecifics(test_data
,
702 tracking_specifics
.mutable_favicon_tracking());
703 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
707 syncer::AttachmentIdList(),
708 syncer::AttachmentServiceProxyForTest::Create()));
711 syncer::SyncMergeResult merge_result
=
712 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
714 CreateAndPassProcessor(),
715 CreateAndPassSyncErrorFactory());
716 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
717 cache()->GetAllSyncData(syncer::FAVICON_IMAGES
).size());
718 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
719 EXPECT_EQ((unsigned long)kFaviconBatchSize
/2, changes
.size());
720 EXPECT_EQ(0, merge_result
.num_items_added());
721 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_modified());
722 EXPECT_EQ(0, merge_result
.num_items_deleted());
723 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_before_association());
724 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
727 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
728 initial_tracking_data
,
729 CreateAndPassProcessor(),
730 CreateAndPassSyncErrorFactory());
731 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
732 cache()->GetAllSyncData(syncer::FAVICON_TRACKING
).size());
733 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
734 EXPECT_EQ(0, merge_result
.num_items_added());
735 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_modified());
736 EXPECT_EQ(0, merge_result
.num_items_deleted());
737 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_before_association());
738 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
740 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
741 ASSERT_TRUE(VerifyLocalCustomIcons(expected_data
));
742 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES
,
743 expected_change_types
,
748 // Setting up sync with local data and sync data should merge the two tracking
749 // sets, such that the visit time is the most recent.
750 TEST_F(SyncFaviconCacheTest
, SyncMergesTracking
) {
751 // First go through and add local 16p favicons.
752 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
753 TestFaviconData favicon
= BuildFaviconData(i
);
754 TriggerSyncFaviconReceived(favicon
.page_url
,
760 // Then go through and create the initial sync data, which for the first half
761 // the local has a newer visit, and for the second the remote does.
762 std::vector
<syncer::SyncChange::SyncChangeType
> expected_change_types
;
763 std::vector
<int> expected_icons
;
764 std::vector
<TestFaviconData
> expected_data
;
765 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
766 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
767 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
768 TestFaviconData test_data
= BuildFaviconData(i
);
769 if (i
< kFaviconBatchSize
/2) {
770 test_data
.last_visit_time
= i
-1;
771 expected_icons
.push_back(i
);
772 expected_change_types
.push_back(syncer::SyncChange::ACTION_UPDATE
);
774 test_data
.last_visit_time
= i
+1;
775 expected_data
.push_back(test_data
);
777 FillImageSpecifics(test_data
,
778 image_specifics
.mutable_favicon_image());
780 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
784 syncer::AttachmentIdList(),
785 syncer::AttachmentServiceProxyForTest::Create()));
786 FillTrackingSpecifics(test_data
,
787 tracking_specifics
.mutable_favicon_tracking());
788 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
792 syncer::AttachmentIdList(),
793 syncer::AttachmentServiceProxyForTest::Create()));
796 syncer::SyncMergeResult merge_result
=
797 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
799 CreateAndPassProcessor(),
800 CreateAndPassSyncErrorFactory());
801 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
802 cache()->GetAllSyncData(syncer::FAVICON_IMAGES
).size());
803 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
804 EXPECT_EQ(0, merge_result
.num_items_added());
805 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_modified());
806 EXPECT_EQ(0, merge_result
.num_items_deleted());
807 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_before_association());
808 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
811 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
812 initial_tracking_data
,
813 CreateAndPassProcessor(),
814 CreateAndPassSyncErrorFactory());
815 EXPECT_EQ((unsigned long)kFaviconBatchSize
,
816 cache()->GetAllSyncData(syncer::FAVICON_TRACKING
).size());
817 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
818 EXPECT_EQ((unsigned long)kFaviconBatchSize
/2, changes
.size());
819 EXPECT_EQ(0, merge_result
.num_items_added());
820 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_modified());
821 EXPECT_EQ(0, merge_result
.num_items_deleted());
822 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_before_association());
823 EXPECT_EQ(kFaviconBatchSize
, merge_result
.num_items_after_association());
825 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
826 ASSERT_TRUE(VerifyLocalCustomIcons(expected_data
));
827 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING
,
828 expected_change_types
,
833 // Receiving old icons (missing image data) should result in pushing the new
834 // merged icons back to the remote syncer.
835 TEST_F(SyncFaviconCacheTest
, ReceiveStaleImages
) {
836 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
837 syncer::SyncChangeList stale_changes
;
838 std::vector
<int> expected_icons
;
839 std::vector
<syncer::SyncChange::SyncChangeType
> expected_change_types
;
840 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
841 expected_icons
.push_back(i
);
842 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
843 FillImageSpecifics(BuildFaviconData(i
),
844 image_specifics
.mutable_favicon_image());
845 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
849 syncer::AttachmentIdList(),
850 syncer::AttachmentServiceProxyForTest::Create()));
851 expected_change_types
.push_back(syncer::SyncChange::ACTION_UPDATE
);
852 image_specifics
.mutable_favicon_image()->clear_favicon_web();
853 stale_changes
.push_back(syncer::SyncChange(
855 syncer::SyncChange::ACTION_UPDATE
,
856 syncer::SyncData::CreateRemoteData(
860 syncer::AttachmentIdList(),
861 syncer::AttachmentServiceProxyForTest::Create())));
862 FillTrackingSpecifics(BuildFaviconData(i
),
863 tracking_specifics
.mutable_favicon_tracking());
864 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
868 syncer::AttachmentIdList(),
869 syncer::AttachmentServiceProxyForTest::Create()));
872 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
874 // Now receive the same icons as an update, but with missing image data.
875 cache()->ProcessSyncChanges(FROM_HERE
, stale_changes
);
876 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
877 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
878 ASSERT_EQ((unsigned long)kFaviconBatchSize
, changes
.size());
879 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES
,
880 expected_change_types
,
885 // New icons should be added locally without pushing anything back to the
887 TEST_F(SyncFaviconCacheTest
, ReceiveNewImages
) {
888 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
889 syncer::SyncChangeList new_changes
;
890 std::vector
<int> expected_icons
;
891 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
892 expected_icons
.push_back(i
);
893 TestFaviconData test_data
= BuildFaviconData(i
);
894 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
895 FillImageSpecifics(test_data
,
896 image_specifics
.mutable_favicon_image());
897 new_changes
.push_back(syncer::SyncChange(
899 syncer::SyncChange::ACTION_UPDATE
,
900 syncer::SyncData::CreateRemoteData(
904 syncer::AttachmentIdList(),
905 syncer::AttachmentServiceProxyForTest::Create())));
906 image_specifics
.mutable_favicon_image()
907 ->mutable_favicon_web()
910 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
914 syncer::AttachmentIdList(),
915 syncer::AttachmentServiceProxyForTest::Create()));
916 FillTrackingSpecifics(BuildFaviconData(i
),
917 tracking_specifics
.mutable_favicon_tracking());
918 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
922 syncer::AttachmentIdList(),
923 syncer::AttachmentServiceProxyForTest::Create()));
926 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
928 // Now receive the new icons as an update.
929 cache()->ProcessSyncChanges(FROM_HERE
, new_changes
);
930 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
931 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
934 // Recieving the same icons as the local data should have no effect.
935 TEST_F(SyncFaviconCacheTest
, ReceiveSameImages
) {
936 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
937 syncer::SyncChangeList same_changes
;
938 std::vector
<int> expected_icons
;
939 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
940 expected_icons
.push_back(i
);
941 TestFaviconData test_data
= BuildFaviconData(i
);
942 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
943 FillImageSpecifics(test_data
,
944 image_specifics
.mutable_favicon_image());
945 same_changes
.push_back(syncer::SyncChange(
947 syncer::SyncChange::ACTION_UPDATE
,
948 syncer::SyncData::CreateRemoteData(
952 syncer::AttachmentIdList(),
953 syncer::AttachmentServiceProxyForTest::Create())));
954 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
958 syncer::AttachmentIdList(),
959 syncer::AttachmentServiceProxyForTest::Create()));
960 FillTrackingSpecifics(BuildFaviconData(i
),
961 tracking_specifics
.mutable_favicon_tracking());
962 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
966 syncer::AttachmentIdList(),
967 syncer::AttachmentServiceProxyForTest::Create()));
970 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
972 // Now receive the new icons as an update.
973 cache()->ProcessSyncChanges(FROM_HERE
, same_changes
);
974 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
975 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
978 // Receiving stale tracking (old visit times) should result in pushing back
979 // the newer visit times to the remote syncer.
980 TEST_F(SyncFaviconCacheTest
, ReceiveStaleTracking
) {
981 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
982 syncer::SyncChangeList stale_changes
;
983 std::vector
<int> expected_icons
;
984 std::vector
<syncer::SyncChange::SyncChangeType
> expected_change_types
;
985 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
986 expected_icons
.push_back(i
);
987 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
988 FillImageSpecifics(BuildFaviconData(i
),
989 image_specifics
.mutable_favicon_image());
990 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
994 syncer::AttachmentIdList(),
995 syncer::AttachmentServiceProxyForTest::Create()));
996 expected_change_types
.push_back(syncer::SyncChange::ACTION_UPDATE
);
997 FillTrackingSpecifics(BuildFaviconData(i
),
998 tracking_specifics
.mutable_favicon_tracking());
999 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1003 syncer::AttachmentIdList(),
1004 syncer::AttachmentServiceProxyForTest::Create()));
1005 tracking_specifics
.mutable_favicon_tracking()->set_last_visit_time_ms(-1);
1006 stale_changes
.push_back(syncer::SyncChange(
1008 syncer::SyncChange::ACTION_UPDATE
,
1009 syncer::SyncData::CreateRemoteData(
1013 syncer::AttachmentIdList(),
1014 syncer::AttachmentServiceProxyForTest::Create())));
1017 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1019 // Now receive the same icons as an update, but with missing image data.
1020 cache()->ProcessSyncChanges(FROM_HERE
, stale_changes
);
1021 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1022 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
1023 ASSERT_EQ((unsigned long)kFaviconBatchSize
, changes
.size());
1024 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING
,
1025 expected_change_types
,
1030 // New tracking information should be added locally without pushing anything
1031 // back to the remote syncer.
1032 TEST_F(SyncFaviconCacheTest
, ReceiveNewTracking
) {
1033 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1034 syncer::SyncChangeList new_changes
;
1035 std::vector
<int> expected_icons
;
1036 // We start from one here so that we don't have to deal with a -1 visit time.
1037 for (int i
= 1; i
<= kFaviconBatchSize
; ++i
) {
1038 expected_icons
.push_back(i
);
1039 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1040 FillImageSpecifics(BuildFaviconData(i
),
1041 image_specifics
.mutable_favicon_image());
1042 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1046 syncer::AttachmentIdList(),
1047 syncer::AttachmentServiceProxyForTest::Create()));
1048 FillTrackingSpecifics(BuildFaviconData(i
),
1049 tracking_specifics
.mutable_favicon_tracking());
1050 new_changes
.push_back(syncer::SyncChange(
1052 syncer::SyncChange::ACTION_UPDATE
,
1053 syncer::SyncData::CreateRemoteData(
1057 syncer::AttachmentIdList(),
1058 syncer::AttachmentServiceProxyForTest::Create())));
1059 tracking_specifics
.mutable_favicon_tracking()->set_last_visit_time_ms(i
-1);
1060 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1064 syncer::AttachmentIdList(),
1065 syncer::AttachmentServiceProxyForTest::Create()));
1068 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1070 // Now receive the new icons as an update.
1071 cache()->ProcessSyncChanges(FROM_HERE
, new_changes
);
1072 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1073 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
1076 // Receiving the same tracking information as the local data should have no
1078 TEST_F(SyncFaviconCacheTest
, ReceiveSameTracking
) {
1079 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1080 syncer::SyncChangeList same_changes
;
1081 std::vector
<int> expected_icons
;
1082 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1083 expected_icons
.push_back(i
);
1084 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1085 FillImageSpecifics(BuildFaviconData(i
),
1086 image_specifics
.mutable_favicon_image());
1087 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1091 syncer::AttachmentIdList(),
1092 syncer::AttachmentServiceProxyForTest::Create()));
1093 FillTrackingSpecifics(BuildFaviconData(i
),
1094 tracking_specifics
.mutable_favicon_tracking());
1095 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1099 syncer::AttachmentIdList(),
1100 syncer::AttachmentServiceProxyForTest::Create()));
1101 same_changes
.push_back(syncer::SyncChange(
1103 syncer::SyncChange::ACTION_UPDATE
,
1104 syncer::SyncData::CreateRemoteData(
1108 syncer::AttachmentIdList(),
1109 syncer::AttachmentServiceProxyForTest::Create())));
1112 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1114 // Now receive the new icons as an update.
1115 cache()->ProcessSyncChanges(FROM_HERE
, same_changes
);
1116 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1117 ASSERT_TRUE(VerifyLocalIcons(expected_icons
));
1120 // Verify we can delete favicons after setting up sync.
1121 TEST_F(SyncFaviconCacheTest
, DeleteFavicons
) {
1122 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1123 syncer::SyncChangeList tracking_deletions
, image_deletions
;
1124 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1125 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1126 FillImageSpecifics(BuildFaviconData(i
),
1127 image_specifics
.mutable_favicon_image());
1128 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1132 syncer::AttachmentIdList(),
1133 syncer::AttachmentServiceProxyForTest::Create()));
1134 FillTrackingSpecifics(BuildFaviconData(i
),
1135 tracking_specifics
.mutable_favicon_tracking());
1136 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1140 syncer::AttachmentIdList(),
1141 syncer::AttachmentServiceProxyForTest::Create()));
1142 tracking_deletions
.push_back(syncer::SyncChange(
1144 syncer::SyncChange::ACTION_DELETE
,
1145 syncer::SyncData::CreateRemoteData(
1149 syncer::AttachmentIdList(),
1150 syncer::AttachmentServiceProxyForTest::Create())));
1151 image_deletions
.push_back(syncer::SyncChange(
1153 syncer::SyncChange::ACTION_DELETE
,
1154 syncer::SyncData::CreateRemoteData(
1158 syncer::AttachmentIdList(),
1159 syncer::AttachmentServiceProxyForTest::Create())));
1162 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1164 // Now receive the tracking deletions. Since we'll still have orphan data,
1165 // the favicon count should remain the same.
1166 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1167 cache()->ProcessSyncChanges(FROM_HERE
, tracking_deletions
);
1168 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1169 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1171 // Once the image deletions arrive, the favicon count should be 0 again.
1172 cache()->ProcessSyncChanges(FROM_HERE
, image_deletions
);
1173 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1174 EXPECT_EQ(0U, GetFaviconCount());
1177 // Ensure that MergeDataAndStartSyncing enforces the sync favicon limit by
1178 // dropping local icons.
1179 TEST_F(SyncFaviconCacheTest
, ExpireOnMergeData
) {
1180 std::vector
<int> expected_icons
;
1181 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1183 // Set up sync so it has the maximum number of favicons, while the local has
1184 // the same amount of different favicons.
1185 for (int i
= 0; i
< kMaxSyncFavicons
; ++i
) {
1186 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1187 FillImageSpecifics(BuildFaviconData(i
),
1188 image_specifics
.mutable_favicon_image());
1189 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1193 syncer::AttachmentIdList(),
1194 syncer::AttachmentServiceProxyForTest::Create()));
1195 FillTrackingSpecifics(BuildFaviconData(i
),
1196 tracking_specifics
.mutable_favicon_tracking());
1197 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1201 syncer::AttachmentIdList(),
1202 syncer::AttachmentServiceProxyForTest::Create()));
1203 expected_icons
.push_back(i
);
1205 TestFaviconData favicon
= BuildFaviconData(i
+kMaxSyncFavicons
);
1206 TriggerSyncFaviconReceived(favicon
.page_url
,
1209 i
+kMaxSyncFavicons
);
1212 EXPECT_FALSE(VerifyLocalIcons(expected_icons
));
1214 // Drops image part of the unsynced icons.
1215 syncer::SyncMergeResult merge_result
=
1216 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
1218 CreateAndPassProcessor(),
1219 CreateAndPassSyncErrorFactory());
1220 EXPECT_EQ((unsigned long)kMaxSyncFavicons
* 2,
1221 GetFaviconCount()); // Still have tracking.
1222 EXPECT_EQ((unsigned long)kMaxSyncFavicons
,
1223 cache()->GetAllSyncData(syncer::FAVICON_IMAGES
).size());
1224 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1225 EXPECT_EQ(kMaxSyncFavicons
, merge_result
.num_items_added());
1226 EXPECT_EQ(0, merge_result
.num_items_modified());
1227 EXPECT_EQ(kMaxSyncFavicons
, merge_result
.num_items_deleted());
1228 EXPECT_EQ(kMaxSyncFavicons
, merge_result
.num_items_before_association());
1229 EXPECT_EQ(kMaxSyncFavicons
* 2, merge_result
.num_items_after_association());
1231 // Drops tracking part of the unsynced icons.
1233 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
1234 initial_tracking_data
,
1235 CreateAndPassProcessor(),
1236 CreateAndPassSyncErrorFactory());
1237 EXPECT_EQ((unsigned long)kMaxSyncFavicons
,
1238 cache()->GetAllSyncData(syncer::FAVICON_TRACKING
).size());
1239 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1240 EXPECT_EQ(0, merge_result
.num_items_added());
1241 EXPECT_EQ(kMaxSyncFavicons
, merge_result
.num_items_modified());
1242 EXPECT_EQ(kMaxSyncFavicons
, merge_result
.num_items_deleted());
1243 EXPECT_EQ(kMaxSyncFavicons
* 2, merge_result
.num_items_before_association());
1244 EXPECT_EQ(kMaxSyncFavicons
, merge_result
.num_items_after_association());
1246 EXPECT_TRUE(VerifyLocalIcons(expected_icons
));
1249 // Receiving sync additions (via ProcessSyncChanges) should not trigger
1251 TEST_F(SyncFaviconCacheTest
, NoExpireOnProcessSyncChanges
) {
1252 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1253 syncer::SyncChangeList image_changes
, tracking_changes
;
1254 std::vector
<int> expected_icons
;
1255 for (int i
= 0; i
< kMaxSyncFavicons
; ++i
) {
1256 expected_icons
.push_back(i
);
1257 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1258 FillImageSpecifics(BuildFaviconData(i
),
1259 image_specifics
.mutable_favicon_image());
1260 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1264 syncer::AttachmentIdList(),
1265 syncer::AttachmentServiceProxyForTest::Create()));
1266 FillTrackingSpecifics(BuildFaviconData(i
),
1267 tracking_specifics
.mutable_favicon_tracking());
1268 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1272 syncer::AttachmentIdList(),
1273 syncer::AttachmentServiceProxyForTest::Create()));
1274 // Set up new tracking specifics for the icons received at change time.
1275 expected_icons
.push_back(i
+ kMaxSyncFavicons
);
1276 FillImageSpecifics(BuildFaviconData(i
+ kMaxSyncFavicons
),
1277 image_specifics
.mutable_favicon_image());
1278 image_changes
.push_back(syncer::SyncChange(
1280 syncer::SyncChange::ACTION_ADD
,
1281 syncer::SyncData::CreateRemoteData(
1285 syncer::AttachmentIdList(),
1286 syncer::AttachmentServiceProxyForTest::Create())));
1287 FillTrackingSpecifics(BuildFaviconData(i
+ kMaxSyncFavicons
),
1288 tracking_specifics
.mutable_favicon_tracking());
1289 tracking_changes
.push_back(syncer::SyncChange(
1291 syncer::SyncChange::ACTION_ADD
,
1292 syncer::SyncData::CreateRemoteData(
1296 syncer::AttachmentIdList(),
1297 syncer::AttachmentServiceProxyForTest::Create())));
1300 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1302 // Now receive the new icons as an update.
1303 EXPECT_EQ((unsigned long)kMaxSyncFavicons
, GetFaviconCount());
1304 cache()->ProcessSyncChanges(FROM_HERE
, image_changes
);
1305 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1306 cache()->ProcessSyncChanges(FROM_HERE
, tracking_changes
);
1307 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1308 EXPECT_TRUE(VerifyLocalIcons(expected_icons
));
1309 EXPECT_GT(GetFaviconCount(), (unsigned long)kMaxSyncFavicons
);
1312 // Test that visiting a new page triggers a favicon load and a sync addition.
1313 TEST_F(SyncFaviconCacheTest
, AddOnFaviconVisited
) {
1314 EXPECT_EQ(0U, GetFaviconCount());
1315 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1316 std::vector
<int> expected_icons
;
1318 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1319 expected_icons
.push_back(i
);
1320 TestFaviconData test_data
= BuildFaviconData(i
);
1321 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1324 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetTaskCount());
1326 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1327 TestFaviconData test_data
= BuildFaviconData(i
);
1328 OnCustomFaviconDataAvailable(test_data
);
1330 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1331 ASSERT_EQ(2U, changes
.size());
1332 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, changes
[0].change_type());
1333 EXPECT_EQ(syncer::FAVICON_IMAGES
, changes
[0].sync_data().GetDataType());
1335 CompareFaviconDataToSpecifics(test_data
,
1336 changes
[0].sync_data().GetSpecifics()));
1337 EXPECT_EQ(syncer::FAVICON_TRACKING
, changes
[1].sync_data().GetDataType());
1338 // Just verify the favicon url for the tracking specifics and that the
1339 // timestamp is non-null.
1340 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, changes
[1].change_type());
1341 EXPECT_EQ(test_data
.icon_url
.spec(),
1342 changes
[1].sync_data().GetSpecifics().favicon_tracking().
1344 EXPECT_NE(changes
[1].sync_data().GetSpecifics().favicon_tracking().
1345 last_visit_time_ms(), 0);
1348 EXPECT_EQ(0U, GetTaskCount());
1349 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1352 // Test that visiting a known page does not trigger a favicon load and just
1353 // updates the sync tracking info.
1354 TEST_F(SyncFaviconCacheTest
, UpdateOnFaviconVisited
) {
1355 EXPECT_EQ(0U, GetFaviconCount());
1356 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1357 std::vector
<int> expected_icons
;
1359 // Add the favicons.
1360 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1361 expected_icons
.push_back(i
);
1362 TestFaviconData test_data
= BuildFaviconData(i
);
1363 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1364 OnCustomFaviconDataAvailable(test_data
);
1366 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1368 // Visit the favicons again.
1369 EXPECT_EQ(0U, GetTaskCount());
1370 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1371 TestFaviconData test_data
= BuildFaviconData(i
);
1372 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1374 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1375 ASSERT_EQ(1U, changes
.size());
1376 // Just verify the favicon url for the tracking specifics and that the
1377 // timestamp is non-null.
1378 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, changes
[0].change_type());
1379 EXPECT_EQ(test_data
.icon_url
.spec(),
1380 changes
[0].sync_data().GetSpecifics().favicon_tracking().
1382 EXPECT_NE(changes
[0].sync_data().GetSpecifics().favicon_tracking().
1383 last_visit_time_ms(), 0);
1385 EXPECT_EQ(0U, GetTaskCount());
1386 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1389 // Ensure we properly expire old synced favicons as new ones are updated.
1390 TEST_F(SyncFaviconCacheTest
, ExpireOnFaviconVisited
) {
1391 EXPECT_EQ(0U, GetFaviconCount());
1392 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1393 std::vector
<int> expected_icons
;
1395 // Add the initial favicons.
1396 for (int i
= 0; i
< kMaxSyncFavicons
; ++i
) {
1397 expected_icons
.push_back(i
);
1398 TestFaviconData test_data
= BuildFaviconData(i
);
1399 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1400 OnCustomFaviconDataAvailable(test_data
);
1402 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1404 // Visit some new favicons, triggering expirations of the old favicons.
1405 EXPECT_EQ(0U, GetTaskCount());
1406 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1407 TestFaviconData old_favicon
= BuildFaviconData(i
);
1408 TestFaviconData test_data
= BuildFaviconData(i
+ kMaxSyncFavicons
);
1409 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1410 OnCustomFaviconDataAvailable(test_data
);
1412 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1413 ASSERT_EQ(4U, changes
.size());
1414 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, changes
[0].change_type());
1416 CompareFaviconDataToSpecifics(test_data
,
1417 changes
[0].sync_data().GetSpecifics()));
1418 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE
, changes
[1].change_type());
1419 EXPECT_EQ(old_favicon
.icon_url
.spec(),
1420 syncer::SyncDataLocal(changes
[1].sync_data()).GetTag());
1422 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, changes
[2].change_type());
1423 EXPECT_EQ(test_data
.icon_url
.spec(),
1424 changes
[2].sync_data().GetSpecifics().favicon_tracking().
1426 EXPECT_NE(changes
[2].sync_data().GetSpecifics().favicon_tracking().
1427 last_visit_time_ms(), 0);
1428 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE
, changes
[3].change_type());
1429 EXPECT_EQ(old_favicon
.icon_url
.spec(),
1430 syncer::SyncDataLocal(changes
[3].sync_data()).GetTag());
1433 EXPECT_EQ(0U, GetTaskCount());
1434 EXPECT_EQ((unsigned long)kMaxSyncFavicons
, GetFaviconCount());
1437 // A full history clear notification should result in all synced favicons being
1439 TEST_F(SyncFaviconCacheTest
, HistoryFullClear
) {
1440 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1441 std::vector
<int> expected_icons
;
1442 std::vector
<syncer::SyncChange::SyncChangeType
> expected_deletions
;
1443 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1444 expected_icons
.push_back(i
);
1445 expected_deletions
.push_back(syncer::SyncChange::ACTION_DELETE
);
1446 TestFaviconData test_data
= BuildFaviconData(i
);
1447 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1448 FillImageSpecifics(test_data
,
1449 image_specifics
.mutable_favicon_image());
1450 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1454 syncer::AttachmentIdList(),
1455 syncer::AttachmentServiceProxyForTest::Create()));
1456 FillTrackingSpecifics(BuildFaviconData(i
),
1457 tracking_specifics
.mutable_favicon_tracking());
1458 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1462 syncer::AttachmentIdList(),
1463 syncer::AttachmentServiceProxyForTest::Create()));
1466 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1467 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1468 EXPECT_TRUE(changes
.empty());
1470 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1471 cache()->OnURLsDeleted(nullptr, true, false, history::URLRows(),
1473 EXPECT_EQ(0U, GetFaviconCount());
1474 changes
= processor()->GetAndResetChangeList();
1475 ASSERT_EQ(changes
.size(), (unsigned long)kFaviconBatchSize
*2);
1476 syncer::SyncChangeList changes_1
, changes_2
;
1477 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1478 changes_1
.push_back(changes
[i
]);
1479 changes_2
.push_back(changes
[i
+ kFaviconBatchSize
]);
1481 VerifyChanges(syncer::FAVICON_IMAGES
,
1485 VerifyChanges(syncer::FAVICON_TRACKING
,
1491 // A partial history clear notification should result in the expired favicons
1492 // also being deleted from sync.
1493 TEST_F(SyncFaviconCacheTest
, HistorySubsetClear
) {
1494 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1495 std::vector
<int> expected_icons
;
1496 std::vector
<syncer::SyncChange::SyncChangeType
> expected_deletions
;
1497 std::set
<GURL
> favicon_urls_to_delete
;
1498 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1499 TestFaviconData test_data
= BuildFaviconData(i
);
1500 if (i
< kFaviconBatchSize
/2) {
1501 expected_icons
.push_back(i
);
1502 expected_deletions
.push_back(syncer::SyncChange::ACTION_DELETE
);
1503 favicon_urls_to_delete
.insert(test_data
.icon_url
);
1505 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1506 FillImageSpecifics(test_data
,
1507 image_specifics
.mutable_favicon_image());
1508 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1512 syncer::AttachmentIdList(),
1513 syncer::AttachmentServiceProxyForTest::Create()));
1514 FillTrackingSpecifics(BuildFaviconData(i
),
1515 tracking_specifics
.mutable_favicon_tracking());
1516 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1520 syncer::AttachmentIdList(),
1521 syncer::AttachmentServiceProxyForTest::Create()));
1524 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1525 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1526 EXPECT_TRUE(changes
.empty());
1528 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1529 cache()->OnURLsDeleted(nullptr, false, false, history::URLRows(),
1530 favicon_urls_to_delete
);
1531 EXPECT_EQ((unsigned long)kFaviconBatchSize
/2, GetFaviconCount());
1532 changes
= processor()->GetAndResetChangeList();
1533 ASSERT_EQ(changes
.size(), (unsigned long)kFaviconBatchSize
);
1534 syncer::SyncChangeList changes_1
, changes_2
;
1535 for (size_t i
= 0; i
< kFaviconBatchSize
/2; ++i
) {
1536 changes_1
.push_back(changes
[i
]);
1537 changes_2
.push_back(changes
[i
+ kFaviconBatchSize
/2]);
1539 VerifyChanges(syncer::FAVICON_IMAGES
,
1543 VerifyChanges(syncer::FAVICON_TRACKING
,
1549 // Any favicon urls with the "data" scheme should be ignored.
1550 TEST_F(SyncFaviconCacheTest
, IgnoreDataScheme
) {
1551 EXPECT_EQ(0U, GetFaviconCount());
1552 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1553 std::vector
<int> expected_icons
;
1555 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1556 TestFaviconData test_data
= BuildFaviconData(i
);
1557 cache()->OnFaviconVisited(test_data
.page_url
, GURL());
1560 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetTaskCount());
1562 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1563 TestFaviconData test_data
= BuildFaviconData(i
);
1564 test_data
.icon_url
= GURL("data:image/png;base64;blabla");
1565 EXPECT_TRUE(test_data
.icon_url
.is_valid());
1566 OnCustomFaviconDataAvailable(test_data
);
1569 EXPECT_EQ(0U, GetTaskCount());
1570 EXPECT_EQ(0U, GetFaviconCount());
1571 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1572 EXPECT_TRUE(changes
.empty());
1575 // When visiting a page we've already loaded the favicon for, don't attempt to
1576 // reload the favicon, just update the visit time using the cached icon url.
1577 TEST_F(SyncFaviconCacheTest
, ReuseCachedIconUrl
) {
1578 EXPECT_EQ(0U, GetFaviconCount());
1579 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1580 std::vector
<int> expected_icons
;
1582 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1583 expected_icons
.push_back(i
);
1584 TestFaviconData test_data
= BuildFaviconData(i
);
1585 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1588 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetTaskCount());
1590 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1591 TestFaviconData test_data
= BuildFaviconData(i
);
1592 OnCustomFaviconDataAvailable(test_data
);
1594 processor()->GetAndResetChangeList();
1595 EXPECT_EQ(0U, GetTaskCount());
1596 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1598 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1599 TestFaviconData test_data
= BuildFaviconData(i
);
1600 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1601 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1602 ASSERT_EQ(1U, changes
.size());
1603 // Just verify the favicon url for the tracking specifics and that the
1604 // timestamp is non-null.
1605 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, changes
[0].change_type());
1606 EXPECT_EQ(test_data
.icon_url
.spec(),
1607 changes
[0].sync_data().GetSpecifics().favicon_tracking().
1609 EXPECT_NE(changes
[0].sync_data().GetSpecifics().favicon_tracking().
1610 last_visit_time_ms(), 0);
1612 EXPECT_EQ(0U, GetTaskCount());
1615 // If we wind up with orphan image/tracking nodes, then receive an update
1616 // for those favicons, we should lazily create the missing nodes.
1617 TEST_F(SyncFaviconCacheTest
, UpdatedOrphans
) {
1618 EXPECT_EQ(0U, GetFaviconCount());
1619 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1621 syncer::SyncChangeList initial_image_changes
;
1622 syncer::SyncChangeList initial_tracking_changes
;
1623 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1624 TestFaviconData test_data
= BuildFaviconData(i
);
1625 // Even favicons have image data but no tracking data. Odd favicons have
1626 // tracking data but no image data.
1628 sync_pb::EntitySpecifics image_specifics
;
1629 FillImageSpecifics(BuildFaviconData(i
),
1630 image_specifics
.mutable_favicon_image());
1631 initial_image_changes
.push_back(syncer::SyncChange(
1633 syncer::SyncChange::ACTION_ADD
,
1634 syncer::SyncData::CreateRemoteData(
1638 syncer::AttachmentIdList(),
1639 syncer::AttachmentServiceProxyForTest::Create())));
1641 sync_pb::EntitySpecifics tracking_specifics
;
1642 FillTrackingSpecifics(BuildFaviconData(i
),
1643 tracking_specifics
.mutable_favicon_tracking());
1644 initial_tracking_changes
.push_back(syncer::SyncChange(
1646 syncer::SyncChange::ACTION_ADD
,
1647 syncer::SyncData::CreateRemoteData(
1651 syncer::AttachmentIdList(),
1652 syncer::AttachmentServiceProxyForTest::Create())));
1656 cache()->ProcessSyncChanges(FROM_HERE
, initial_image_changes
);
1657 cache()->ProcessSyncChanges(FROM_HERE
, initial_tracking_changes
);
1658 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1659 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1661 for (int i
= 0; i
< kFaviconBatchSize
/2; ++i
) {
1662 TestFaviconData test_data
= BuildFaviconData(i
);
1663 cache()->OnFaviconVisited(test_data
.page_url
, GURL());
1664 EXPECT_EQ(1U, GetTaskCount());
1665 OnCustomFaviconDataAvailable(test_data
);
1666 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1668 // Even favicons had image data, so should now receive new tracking data
1669 // and updated image data (we allow one update after the initial add).
1670 // Odd favicons had tracking so should now receive new image data and
1671 // updated tracking data.
1673 ASSERT_EQ(2U, changes
.size());
1674 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, changes
[0].change_type());
1676 CompareFaviconDataToSpecifics(test_data
,
1677 changes
[0].sync_data().GetSpecifics()));
1678 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, changes
[1].change_type());
1679 EXPECT_EQ(test_data
.icon_url
.spec(),
1680 changes
[1].sync_data().GetSpecifics().favicon_tracking().
1682 EXPECT_NE(changes
[1].sync_data().GetSpecifics().favicon_tracking().
1683 last_visit_time_ms(), 0);
1685 ASSERT_EQ(2U, changes
.size());
1686 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, changes
[0].change_type());
1688 CompareFaviconDataToSpecifics(test_data
,
1689 changes
[0].sync_data().GetSpecifics()));
1690 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, changes
[1].change_type());
1691 EXPECT_EQ(test_data
.icon_url
.spec(),
1692 changes
[1].sync_data().GetSpecifics().favicon_tracking().
1694 EXPECT_NE(changes
[1].sync_data().GetSpecifics().favicon_tracking().
1695 last_visit_time_ms(), 0);
1699 EXPECT_EQ(0U, GetTaskCount());
1700 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1703 // Verify that orphaned favicon images don't result in creating invalid
1704 // favicon tracking data.
1705 TEST_F(SyncFaviconCacheTest
, PartialAssociationInfo
) {
1706 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1707 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1708 sync_pb::EntitySpecifics image_specifics
;
1709 FillImageSpecifics(BuildFaviconData(i
),
1710 image_specifics
.mutable_favicon_image());
1711 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1715 syncer::AttachmentIdList(),
1716 syncer::AttachmentServiceProxyForTest::Create()));
1717 image_specifics
.mutable_favicon_image()->clear_favicon_web();
1720 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1721 syncer::SyncChangeList change_list
= processor()->GetAndResetChangeList();
1722 EXPECT_TRUE(change_list
.empty());
1723 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1726 // Tests that we don't choke if a favicon visit node with a null visit time is
1727 // present (see crbug.com/258196) and an update is made.
1728 TEST_F(SyncFaviconCacheTest
, NullFaviconVisitTime
) {
1729 EXPECT_EQ(0U, GetFaviconCount());
1731 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1732 std::vector
<int> expected_icons
;
1733 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1734 expected_icons
.push_back(i
);
1735 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1736 FillImageSpecifics(BuildFaviconData(i
),
1737 image_specifics
.mutable_favicon_image());
1738 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1742 syncer::AttachmentIdList(),
1743 syncer::AttachmentServiceProxyForTest::Create()));
1744 FillTrackingSpecifics(BuildFaviconData(i
),
1745 tracking_specifics
.mutable_favicon_tracking());
1746 tracking_specifics
.mutable_favicon_tracking()->set_last_visit_time_ms(
1747 syncer::TimeToProtoTime(base::Time()));
1748 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1752 syncer::AttachmentIdList(),
1753 syncer::AttachmentServiceProxyForTest::Create()));
1756 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES
,
1758 CreateAndPassProcessor(),
1759 CreateAndPassSyncErrorFactory());
1760 ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
1761 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING
,
1762 initial_tracking_data
,
1763 CreateAndPassProcessor(),
1764 CreateAndPassSyncErrorFactory());
1765 ASSERT_EQ((unsigned long)kFaviconBatchSize
,
1766 processor()->GetAndResetChangeList().size());
1767 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1769 // Visit the favicons again.
1770 EXPECT_EQ(0U, GetTaskCount());
1771 for (int i
= 0; i
< kFaviconBatchSize
; ++i
) {
1772 TestFaviconData test_data
= BuildFaviconData(i
);
1773 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1775 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1776 ASSERT_EQ(1U, changes
.size());
1777 // Just verify the favicon url for the tracking specifics and that the
1778 // timestamp is non-null.
1779 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, changes
[0].change_type());
1780 EXPECT_EQ(test_data
.icon_url
.spec(),
1781 changes
[0].sync_data().GetSpecifics().favicon_tracking().
1783 EXPECT_NE(changes
[0].sync_data().GetSpecifics().favicon_tracking().
1784 last_visit_time_ms(), 0);
1786 EXPECT_EQ(0U, GetTaskCount());
1787 EXPECT_EQ((unsigned long)kFaviconBatchSize
, GetFaviconCount());
1790 // If another synced client has a clock skewed towards the future, it's possible
1791 // that favicons added locally will be expired as they are added. Ensure this
1792 // doesn't crash (see crbug.com/306150).
1793 TEST_F(SyncFaviconCacheTest
, VisitFaviconClockSkew
) {
1794 EXPECT_EQ(0U, GetFaviconCount());
1795 const int kClockSkew
= 20; // 20 minutes in the future.
1797 // Set up sync with kMaxSyncFavicons starting kClockSkew minutes in the
1799 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1800 for (int i
= 0; i
< kMaxSyncFavicons
; ++i
) {
1801 sync_pb::EntitySpecifics image_specifics
, tracking_specifics
;
1802 TestFaviconData test_data
= BuildFaviconData(i
);
1803 test_data
.last_visit_time
=
1804 syncer::TimeToProtoTime(
1805 base::Time::Now() + base::TimeDelta::FromMinutes(kClockSkew
));
1806 FillImageSpecifics(test_data
,
1807 image_specifics
.mutable_favicon_image());
1808 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1812 syncer::AttachmentIdList(),
1813 syncer::AttachmentServiceProxyForTest::Create()));
1814 FillTrackingSpecifics(test_data
,
1815 tracking_specifics
.mutable_favicon_tracking());
1816 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1820 syncer::AttachmentIdList(),
1821 syncer::AttachmentServiceProxyForTest::Create()));
1823 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1825 // Visit some new favicons with local time, which will be expired as they
1827 EXPECT_EQ(0U, GetTaskCount());
1828 for (int i
= 0; i
< kClockSkew
; ++i
) {
1829 TestFaviconData test_data
= BuildFaviconData(i
+ kMaxSyncFavicons
);
1830 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1831 OnCustomFaviconDataAvailable(test_data
);
1833 // The changes will be an add followed by a delete for both the image and
1835 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1836 ASSERT_EQ(changes
.size(), 4U);
1837 ASSERT_EQ(changes
[0].change_type(), syncer::SyncChange::ACTION_ADD
);
1838 ASSERT_EQ(changes
[0].sync_data().GetDataType(), syncer::FAVICON_IMAGES
);
1839 ASSERT_EQ(changes
[1].change_type(), syncer::SyncChange::ACTION_DELETE
);
1840 ASSERT_EQ(changes
[1].sync_data().GetDataType(), syncer::FAVICON_IMAGES
);
1841 ASSERT_EQ(changes
[2].change_type(), syncer::SyncChange::ACTION_ADD
);
1842 ASSERT_EQ(changes
[2].sync_data().GetDataType(), syncer::FAVICON_TRACKING
);
1843 ASSERT_EQ(changes
[3].change_type(), syncer::SyncChange::ACTION_DELETE
);
1844 ASSERT_EQ(changes
[3].sync_data().GetDataType(), syncer::FAVICON_TRACKING
);
1846 EXPECT_EQ(0U, GetTaskCount());
1847 EXPECT_EQ((unsigned long)kMaxSyncFavicons
, GetFaviconCount());
1850 // Simulate a case where the set of tracking info and image info doesn't match,
1851 // and there is more tracking info than the max. A local update should correctly
1852 // determine whether to update/add an image/tracking entity.
1853 TEST_F(SyncFaviconCacheTest
, MixedThreshold
) {
1854 // First go through and add local favicons.
1855 for (int i
= kMaxSyncFavicons
; i
< kMaxSyncFavicons
+ 5; ++i
) {
1856 TestFaviconData favicon
= BuildFaviconData(i
);
1857 TriggerSyncFaviconReceived(favicon
.page_url
,
1860 favicon
.last_visit_time
);
1863 syncer::SyncDataList initial_image_data
, initial_tracking_data
;
1864 // Then sync with enough favicons such that the tracking info is over the max
1865 // after merge completes.
1866 for (int i
= 0; i
< kMaxSyncFavicons
; ++i
) {
1867 sync_pb::EntitySpecifics image_specifics
;
1868 // Push the images forward by 5, to match the unsynced favicons.
1869 FillImageSpecifics(BuildFaviconData(i
+ 5),
1870 image_specifics
.mutable_favicon_image());
1871 initial_image_data
.push_back(syncer::SyncData::CreateRemoteData(
1875 syncer::AttachmentIdList(),
1876 syncer::AttachmentServiceProxyForTest::Create()));
1878 sync_pb::EntitySpecifics tracking_specifics
;
1879 FillTrackingSpecifics(BuildFaviconData(i
),
1880 tracking_specifics
.mutable_favicon_tracking());
1881 initial_tracking_data
.push_back(syncer::SyncData::CreateRemoteData(
1885 syncer::AttachmentIdList(),
1886 syncer::AttachmentServiceProxyForTest::Create()));
1888 SetUpInitialSync(initial_image_data
, initial_tracking_data
);
1890 // The local unsynced tracking info should be dropped, but not deleted.
1891 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1893 // Because the image and tracking data don't overlap, the total number of
1894 // favicons is still over the limit.
1895 EXPECT_EQ((unsigned long)kMaxSyncFavicons
+ 5, GetFaviconCount());
1897 // Trigger a tracking change for one of the favicons whose tracking info
1898 // was dropped, resulting in a tracking add and expiration of the orphaned
1900 TestFaviconData test_data
= BuildFaviconData(kMaxSyncFavicons
);
1901 cache()->OnFaviconVisited(test_data
.page_url
, test_data
.icon_url
);
1903 syncer::SyncChangeList changes
= processor()->GetAndResetChangeList();
1904 // 1 image update, 5 image deletions, 1 tracking deletion.
1905 ASSERT_EQ(6U, changes
.size());
1906 // Expire image for favicon[kMaxSyncFavicons + 1].
1907 EXPECT_EQ(changes
[0].change_type(), syncer::SyncChange::ACTION_DELETE
);
1908 EXPECT_EQ(changes
[0].sync_data().GetDataType(), syncer::FAVICON_IMAGES
);
1909 EXPECT_EQ(kMaxSyncFavicons
+ 1, GetFaviconId(changes
[0]));
1910 // Expire image for favicon[kMaxSyncFavicons + 2].
1911 EXPECT_EQ(changes
[1].change_type(), syncer::SyncChange::ACTION_DELETE
);
1912 EXPECT_EQ(changes
[1].sync_data().GetDataType(), syncer::FAVICON_IMAGES
);
1913 EXPECT_EQ(kMaxSyncFavicons
+ 2, GetFaviconId(changes
[1]));
1914 // Expire image for favicon[kMaxSyncFavicons + 3].
1915 EXPECT_EQ(changes
[2].change_type(), syncer::SyncChange::ACTION_DELETE
);
1916 EXPECT_EQ(changes
[2].sync_data().GetDataType(), syncer::FAVICON_IMAGES
);
1917 EXPECT_EQ(kMaxSyncFavicons
+ 3, GetFaviconId(changes
[2]));
1918 // Expire image for favicon[kMaxSyncFavicons + 4].
1919 EXPECT_EQ(changes
[3].change_type(), syncer::SyncChange::ACTION_DELETE
);
1920 EXPECT_EQ(changes
[3].sync_data().GetDataType(), syncer::FAVICON_IMAGES
);
1921 EXPECT_EQ(kMaxSyncFavicons
+ 4, GetFaviconId(changes
[3]));
1922 // Update tracking for favicon[kMaxSyncFavicons].
1923 EXPECT_EQ(changes
[4].change_type(), syncer::SyncChange::ACTION_ADD
);
1924 EXPECT_EQ(changes
[4].sync_data().GetDataType(), syncer::FAVICON_TRACKING
);
1925 EXPECT_EQ(kMaxSyncFavicons
, GetFaviconId(changes
[4]));
1926 // Expire tracking for favicon[0].
1927 EXPECT_EQ(changes
[5].change_type(), syncer::SyncChange::ACTION_DELETE
);
1928 EXPECT_EQ(changes
[5].sync_data().GetDataType(), syncer::FAVICON_TRACKING
);
1929 EXPECT_EQ(0, GetFaviconId(changes
[5]));
1932 } // namespace browser_sync