Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / glue / favicon_cache_unittest.cc
blob7bfdc7eb1e923048b31f02598865fed71fe8a45b
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/stringprintf.h"
9 #include "base/time/time.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/history/history_notifications.h"
12 #include "content/public/browser/notification_service.h"
13 #include "sync/api/sync_error_factory_mock.h"
14 #include "sync/api/time.h"
15 #include "sync/protocol/favicon_image_specifics.pb.h"
16 #include "sync/protocol/favicon_tracking_specifics.pb.h"
17 #include "sync/protocol/sync.pb.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace browser_sync {
22 namespace {
24 // Total number of favicons to use in sync test batches.
25 const int kFaviconBatchSize = 10;
27 // Maximum number of favicons to sync.
28 const int kMaxSyncFavicons = kFaviconBatchSize*2;
30 // TestChangeProcessor --------------------------------------------------------
32 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
33 // back up to Sync.
34 class TestChangeProcessor : public syncer::SyncChangeProcessor {
35 public:
36 TestChangeProcessor();
37 virtual ~TestChangeProcessor();
39 // Store a copy of all the changes passed in so we can examine them later.
40 virtual syncer::SyncError ProcessSyncChanges(
41 const tracked_objects::Location& from_here,
42 const syncer::SyncChangeList& change_list) OVERRIDE;
44 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const
45 OVERRIDE {
46 return syncer::SyncDataList();
49 bool contains_guid(const std::string& guid) const {
50 return change_map_.count(guid) != 0;
53 syncer::SyncChange change_for_guid(const std::string& guid) const {
54 DCHECK(contains_guid(guid));
55 return change_map_.find(guid)->second;
58 // Returns the last change list received, and resets the internal list.
59 syncer::SyncChangeList GetAndResetChangeList() {
60 syncer::SyncChangeList list;
61 list.swap(change_list_);
62 return list;
65 void set_erroneous(bool erroneous) { erroneous_ = erroneous; }
67 private:
68 // Track the changes received in ProcessSyncChanges.
69 std::map<std::string, syncer::SyncChange> change_map_;
70 syncer::SyncChangeList change_list_;
71 bool erroneous_;
73 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
76 TestChangeProcessor::TestChangeProcessor() : erroneous_(false) {
79 TestChangeProcessor::~TestChangeProcessor() {
82 syncer::SyncError TestChangeProcessor::ProcessSyncChanges(
83 const tracked_objects::Location& from_here,
84 const syncer::SyncChangeList& change_list) {
85 if (erroneous_) {
86 return syncer::SyncError(
87 FROM_HERE,
88 syncer::SyncError::DATATYPE_ERROR,
89 "Some error.",
90 change_list[0].sync_data().GetDataType());
93 change_list_.insert(change_list_.end(),
94 change_list.begin(),
95 change_list.end());
96 change_map_.erase(change_map_.begin(), change_map_.end());
97 for (syncer::SyncChangeList::const_iterator iter = change_list.begin();
98 iter != change_list.end(); ++iter) {
99 change_map_[iter->sync_data().GetTitle()] = *iter;
101 return syncer::SyncError();
105 // SyncChangeProcessorDelegate ------------------------------------------------
107 class SyncChangeProcessorDelegate : public syncer::SyncChangeProcessor {
108 public:
109 explicit SyncChangeProcessorDelegate(syncer::SyncChangeProcessor* recipient);
110 virtual ~SyncChangeProcessorDelegate();
112 // syncer::SyncChangeProcessor implementation.
113 virtual syncer::SyncError ProcessSyncChanges(
114 const tracked_objects::Location& from_here,
115 const syncer::SyncChangeList& change_list) OVERRIDE;
117 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const
118 OVERRIDE {
119 return recipient_->GetAllSyncData(type);
122 private:
123 // The recipient of all sync changes.
124 syncer::SyncChangeProcessor* recipient_;
126 DISALLOW_COPY_AND_ASSIGN(SyncChangeProcessorDelegate);
129 SyncChangeProcessorDelegate::SyncChangeProcessorDelegate(
130 syncer::SyncChangeProcessor* recipient)
131 : recipient_(recipient) {
132 DCHECK(recipient_);
135 SyncChangeProcessorDelegate::~SyncChangeProcessorDelegate() {
138 syncer::SyncError SyncChangeProcessorDelegate::ProcessSyncChanges(
139 const tracked_objects::Location& from_here,
140 const syncer::SyncChangeList& change_list) {
141 return recipient_->ProcessSyncChanges(from_here, change_list);
144 // TestFaviconData ------------------------------------------------------------
145 struct TestFaviconData {
146 TestFaviconData() : last_visit_time(0), is_bookmarked(false) {}
147 GURL page_url;
148 GURL icon_url;
149 std::string image_16;
150 std::string image_32;
151 std::string image_64;
152 int64 last_visit_time;
153 bool is_bookmarked;
156 TestFaviconData BuildFaviconData(int index) {
157 TestFaviconData data;
158 data.page_url = GURL(base::StringPrintf("http://bla.com/%.2i.html", index));
159 data.icon_url = GURL(base::StringPrintf("http://bla.com/%.2i.ico", index));
160 data.image_16 = base::StringPrintf("16 %i", index);
161 // TODO(zea): enable this once the cache supports writing them.
162 // data.image_32 = base::StringPrintf("32 %i", index);
163 // data.image_64 = base::StringPrintf("64 %i", index);
164 data.last_visit_time = index;
165 return data;
168 void FillImageSpecifics(
169 const TestFaviconData& test_data,
170 sync_pb::FaviconImageSpecifics* image_specifics) {
171 image_specifics->set_favicon_url(test_data.icon_url.spec());
172 if (!test_data.image_16.empty()) {
173 image_specifics->mutable_favicon_web()->set_height(16);
174 image_specifics->mutable_favicon_web()->set_width(16);
175 image_specifics->mutable_favicon_web()->set_favicon(test_data.image_16);
177 if (!test_data.image_32.empty()) {
178 image_specifics->mutable_favicon_web_32()->set_height(32);
179 image_specifics->mutable_favicon_web_32()->set_width(32);
180 image_specifics->mutable_favicon_web_32()->set_favicon(test_data.image_32);
182 if (!test_data.image_64.empty()) {
183 image_specifics->mutable_favicon_touch_64()->set_height(64);
184 image_specifics->mutable_favicon_touch_64()->set_width(64);
185 image_specifics->mutable_favicon_touch_64()->
186 set_favicon(test_data.image_64);
190 void FillTrackingSpecifics(
191 const TestFaviconData& test_data,
192 sync_pb::FaviconTrackingSpecifics* tracking_specifics) {
193 tracking_specifics->set_favicon_url(test_data.icon_url.spec());
194 tracking_specifics->set_last_visit_time_ms(test_data.last_visit_time);
195 tracking_specifics->set_is_bookmarked(test_data.is_bookmarked);
198 testing::AssertionResult CompareFaviconDataToSpecifics(
199 const TestFaviconData& test_data,
200 const sync_pb::EntitySpecifics& specifics) {
201 if (specifics.has_favicon_image()) {
202 sync_pb::FaviconImageSpecifics image_specifics = specifics.favicon_image();
203 if (image_specifics.favicon_url() != test_data.icon_url.spec())
204 return testing::AssertionFailure() << "Image icon url doesn't match.";
205 if (!test_data.image_16.empty()) {
206 if (image_specifics.favicon_web().favicon() != test_data.image_16 ||
207 image_specifics.favicon_web().height() != 16 ||
208 image_specifics.favicon_web().width() != 16) {
209 return testing::AssertionFailure() << "16p image data doesn't match.";
211 } else if (image_specifics.has_favicon_web()) {
212 return testing::AssertionFailure() << "Missing 16p favicon.";
214 if (!test_data.image_32.empty()) {
215 if (image_specifics.favicon_web_32().favicon() != test_data.image_32 ||
216 image_specifics.favicon_web().height() != 32 ||
217 image_specifics.favicon_web().width() != 32) {
218 return testing::AssertionFailure() << "32p image data doesn't match.";
220 } else if (image_specifics.has_favicon_web_32()) {
221 return testing::AssertionFailure() << "Missing 32p favicon.";
223 if (!test_data.image_64.empty()) {
224 if (image_specifics.favicon_touch_64().favicon() != test_data.image_64 ||
225 image_specifics.favicon_web().height() != 64 ||
226 image_specifics.favicon_web().width() != 64) {
227 return testing::AssertionFailure() << "64p image data doesn't match.";
229 } else if (image_specifics.has_favicon_touch_64()) {
230 return testing::AssertionFailure() << "Missing 64p favicon.";
232 } else {
233 sync_pb::FaviconTrackingSpecifics tracking_specifics =
234 specifics.favicon_tracking();
235 if (tracking_specifics.favicon_url() != test_data.icon_url.spec())
236 return testing::AssertionFailure() << "Tracking icon url doesn't match.";
237 if (tracking_specifics.last_visit_time_ms() != test_data.last_visit_time)
238 return testing::AssertionFailure() << "Visit time doesn't match.";
239 if (tracking_specifics.is_bookmarked() != test_data.is_bookmarked)
240 return testing::AssertionFailure() << "Bookmark status doens't match.";
242 return testing::AssertionSuccess();
245 testing::AssertionResult VerifyChanges(
246 syncer::ModelType expected_model_type,
247 const std::vector<syncer::SyncChange::SyncChangeType>&
248 expected_change_types,
249 const std::vector<int>& expected_icons,
250 const syncer::SyncChangeList& change_list) {
251 DCHECK_EQ(expected_change_types.size(), expected_icons.size());
252 if (change_list.size() != expected_icons.size())
253 return testing::AssertionFailure() << "Change list size doesn't match.";
254 for (size_t i = 0; i < expected_icons.size(); ++i) {
255 TestFaviconData data = BuildFaviconData(expected_icons[i]);
256 if (change_list[i].sync_data().GetDataType() != expected_model_type)
257 return testing::AssertionFailure() << "Change datatype doesn't match.";
258 if (change_list[i].change_type() != expected_change_types[i])
259 return testing::AssertionFailure() << "Change type doesn't match.";
260 if (change_list[i].change_type() == syncer::SyncChange::ACTION_DELETE) {
261 if (change_list[i].sync_data().GetTag() != data.icon_url.spec())
262 return testing::AssertionFailure() << "Deletion url does not match.";
263 } else {
264 testing::AssertionResult compare_result =
265 CompareFaviconDataToSpecifics(
266 data,
267 change_list[i].sync_data().GetSpecifics());
268 if (!compare_result)
269 return compare_result;
272 return testing::AssertionSuccess();
275 } // namespace
277 class SyncFaviconCacheTest : public testing::Test {
278 public:
279 SyncFaviconCacheTest();
280 virtual ~SyncFaviconCacheTest() {}
282 void SetUpInitialSync(const syncer::SyncDataList& initial_image_data,
283 const syncer::SyncDataList& initial_tracking_data);
285 size_t GetFaviconCount() const;
286 size_t GetTaskCount() const;
288 testing::AssertionResult ExpectFaviconEquals(
289 const std::string& page_url,
290 const std::string& bytes) const;
291 testing::AssertionResult VerifyLocalIcons(
292 const std::vector<int>& expected_icons);
293 testing::AssertionResult VerifyLocalCustomIcons(
294 const std::vector<TestFaviconData>& expected_icons);
296 scoped_ptr<syncer::SyncChangeProcessor> CreateAndPassProcessor();
297 scoped_ptr<syncer::SyncErrorFactory> CreateAndPassSyncErrorFactory();
299 FaviconCache* cache() { return &cache_; }
300 TestChangeProcessor* processor() { return sync_processor_.get(); }
302 // Finish an outstanding favicon load for the icon described in |test_data|.
303 void OnCustomFaviconDataAvailable(const TestFaviconData& test_data);
305 // Helper method to run the message loop after invoking
306 // OnReceivedSyncFavicon, which posts an internal task.
307 void TriggerSyncFaviconReceived(const GURL& page_url,
308 const GURL& icon_url,
309 const std::string& icon_bytes,
310 int64 last_visit_time_ms);
312 private:
313 base::MessageLoopForUI message_loop_;
314 FaviconCache cache_;
316 // Our dummy ChangeProcessor used to inspect changes pushed to Sync.
317 scoped_ptr<TestChangeProcessor> sync_processor_;
318 scoped_ptr<SyncChangeProcessorDelegate> sync_processor_delegate_;
321 SyncFaviconCacheTest::SyncFaviconCacheTest()
322 : cache_(NULL, kMaxSyncFavicons),
323 sync_processor_(new TestChangeProcessor),
324 sync_processor_delegate_(new SyncChangeProcessorDelegate(
325 sync_processor_.get())) {
328 void SyncFaviconCacheTest::SetUpInitialSync(
329 const syncer::SyncDataList& initial_image_data,
330 const syncer::SyncDataList& initial_tracking_data) {
331 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
332 initial_image_data,
333 CreateAndPassProcessor(),
334 CreateAndPassSyncErrorFactory());
335 ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
336 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
337 initial_tracking_data,
338 CreateAndPassProcessor(),
339 CreateAndPassSyncErrorFactory());
340 ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
343 size_t SyncFaviconCacheTest::GetFaviconCount() const {
344 return cache_.NumFaviconsForTest();
347 size_t SyncFaviconCacheTest::GetTaskCount() const {
348 return cache_.NumTasksForTest();
351 testing::AssertionResult SyncFaviconCacheTest::ExpectFaviconEquals(
352 const std::string& page_url,
353 const std::string& bytes) const {
354 GURL gurl(page_url);
355 scoped_refptr<base::RefCountedMemory> favicon;
356 if (!cache_.GetSyncedFaviconForPageURL(gurl, &favicon))
357 return testing::AssertionFailure() << "Favicon is missing.";
358 if (favicon->size() != bytes.size())
359 return testing::AssertionFailure() << "Favicon sizes don't match.";
360 for (size_t i = 0; i < favicon->size(); ++i) {
361 if (bytes[i] != *(favicon->front() + i))
362 return testing::AssertionFailure() << "Favicon data doesn't match.";
364 return testing::AssertionSuccess();
367 testing::AssertionResult SyncFaviconCacheTest::VerifyLocalIcons(
368 const std::vector<int>& expected_icons) {
369 std::vector<TestFaviconData> expected_custom_icons;
370 for (size_t i = 0; i < expected_icons.size(); ++i) {
371 expected_custom_icons.push_back(BuildFaviconData(expected_icons[i]));
373 return VerifyLocalCustomIcons(expected_custom_icons);
377 testing::AssertionResult SyncFaviconCacheTest::VerifyLocalCustomIcons(
378 const std::vector<TestFaviconData>& expected_custom_icons) {
379 syncer::SyncDataList image_data_list =
380 cache()->GetAllSyncData(syncer::FAVICON_IMAGES);
381 syncer::SyncDataList tracking_data_list =
382 cache()->GetAllSyncData(syncer::FAVICON_TRACKING);
383 if (expected_custom_icons.size() > image_data_list.size() ||
384 expected_custom_icons.size() > tracking_data_list.size())
385 return testing::AssertionFailure() << "Number of icons doesn't match.";
386 for (size_t i = 0; i < expected_custom_icons.size(); ++i) {
387 const TestFaviconData& test_data = expected_custom_icons[i];
388 // Find the test data in the data lists. Assume that both lists have the
389 // same ordering, which may not match the |expected_custom_icons| ordering.
390 bool found_match = false;
391 for (size_t j = 0; j < image_data_list.size(); ++j) {
392 if (image_data_list[j].GetTitle() != test_data.icon_url.spec())
393 continue;
394 found_match = true;
395 const sync_pb::FaviconImageSpecifics& image_specifics =
396 image_data_list[j].GetSpecifics().favicon_image();
397 sync_pb::FaviconImageSpecifics expected_image_specifics;
398 FillImageSpecifics(test_data, &expected_image_specifics);
399 if (image_specifics.SerializeAsString() !=
400 expected_image_specifics.SerializeAsString()) {
401 return testing::AssertionFailure() << "Image data doesn't match.";
403 const sync_pb::FaviconTrackingSpecifics& tracking_specifics =
404 tracking_data_list[j].GetSpecifics().favicon_tracking();
405 sync_pb::FaviconTrackingSpecifics expected_tracking_specifics;
406 FillTrackingSpecifics(test_data, &expected_tracking_specifics);
407 if (tracking_specifics.SerializeAsString() !=
408 expected_tracking_specifics.SerializeAsString()) {
409 return testing::AssertionFailure() << "Tracking data doesn't match.";
412 if (!found_match)
413 return testing::AssertionFailure() << "Could not find favicon.";
415 return testing::AssertionSuccess();
418 scoped_ptr<syncer::SyncChangeProcessor>
419 SyncFaviconCacheTest::CreateAndPassProcessor() {
420 return scoped_ptr<syncer::SyncChangeProcessor>(
421 new SyncChangeProcessorDelegate(sync_processor_.get()));
424 scoped_ptr<syncer::SyncErrorFactory> SyncFaviconCacheTest::
425 CreateAndPassSyncErrorFactory() {
426 return scoped_ptr<syncer::SyncErrorFactory>(
427 new syncer::SyncErrorFactoryMock());
430 void SyncFaviconCacheTest::OnCustomFaviconDataAvailable(
431 const TestFaviconData& test_data) {
432 std::vector<chrome::FaviconBitmapResult> bitmap_results;
433 if (!test_data.image_16.empty()) {
434 chrome::FaviconBitmapResult bitmap_result;
435 bitmap_result.icon_url = test_data.icon_url;
436 bitmap_result.pixel_size.set_width(16);
437 bitmap_result.pixel_size.set_height(16);
438 base::RefCountedString* temp_string = new base::RefCountedString();
439 temp_string->data() = test_data.image_16;
440 bitmap_result.bitmap_data = temp_string;
441 bitmap_results.push_back(bitmap_result);
443 if (!test_data.image_32.empty()) {
444 chrome::FaviconBitmapResult bitmap_result;
445 bitmap_result.icon_url = test_data.icon_url;
446 bitmap_result.pixel_size.set_width(32);
447 bitmap_result.pixel_size.set_height(32);
448 base::RefCountedString* temp_string = new base::RefCountedString();
449 temp_string->data() = test_data.image_32;
450 bitmap_result.bitmap_data = temp_string;
451 bitmap_results.push_back(bitmap_result);
453 if (!test_data.image_64.empty()) {
454 chrome::FaviconBitmapResult bitmap_result;
455 bitmap_result.icon_url = test_data.icon_url;
456 bitmap_result.pixel_size.set_width(64);
457 bitmap_result.pixel_size.set_height(64);
458 base::RefCountedString* temp_string = new base::RefCountedString();
459 temp_string->data() = test_data.image_64;
460 bitmap_result.bitmap_data = temp_string;
461 bitmap_results.push_back(bitmap_result);
463 cache()->OnFaviconDataAvailable(test_data.page_url, bitmap_results);
466 void SyncFaviconCacheTest::TriggerSyncFaviconReceived(
467 const GURL& page_url,
468 const GURL& icon_url,
469 const std::string& icon_bytes,
470 int64 last_visit_time_ms) {
471 cache()->OnReceivedSyncFavicon(page_url,
472 icon_url,
473 icon_bytes,
474 last_visit_time_ms);
475 message_loop_.RunUntilIdle();
478 // A freshly constructed cache should be empty.
479 TEST_F(SyncFaviconCacheTest, Empty) {
480 EXPECT_EQ(0U, GetFaviconCount());
483 TEST_F(SyncFaviconCacheTest, ReceiveSyncFavicon) {
484 std::string page_url = "http://www.google.com";
485 std::string fav_url = "http://www.google.com/favicon.ico";
486 std::string bytes = "bytes";
487 EXPECT_EQ(0U, GetFaviconCount());
488 TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes, 0);
489 EXPECT_EQ(1U, GetFaviconCount());
490 EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
493 TEST_F(SyncFaviconCacheTest, ReceiveEmptySyncFavicon) {
494 std::string page_url = "http://www.google.com";
495 std::string fav_url = "http://www.google.com/favicon.ico";
496 std::string bytes = "bytes";
497 EXPECT_EQ(0U, GetFaviconCount());
498 TriggerSyncFaviconReceived(GURL(page_url),
499 GURL(fav_url),
500 std::string(),
502 EXPECT_EQ(0U, GetFaviconCount());
503 EXPECT_FALSE(ExpectFaviconEquals(page_url, std::string()));
505 // Then receive the actual favicon.
506 TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes, 0);
507 EXPECT_EQ(1U, GetFaviconCount());
508 EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
511 TEST_F(SyncFaviconCacheTest, ReceiveUpdatedSyncFavicon) {
512 std::string page_url = "http://www.google.com";
513 std::string fav_url = "http://www.google.com/favicon.ico";
514 std::string bytes = "bytes";
515 std::string bytes2 = "bytes2";
516 EXPECT_EQ(0U, GetFaviconCount());
517 TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes, 0);
518 EXPECT_EQ(1U, GetFaviconCount());
519 EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
521 // The cache should not update existing favicons from tab sync favicons
522 // (which can be reassociated several times).
523 TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes2, 0);
524 EXPECT_EQ(1U, GetFaviconCount());
525 EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
526 EXPECT_FALSE(ExpectFaviconEquals(page_url, bytes2));
529 TEST_F(SyncFaviconCacheTest, MultipleMappings) {
530 std::string page_url = "http://www.google.com";
531 std::string page2_url = "http://bla.google.com";
532 std::string fav_url = "http://www.google.com/favicon.ico";
533 std::string bytes = "bytes";
534 EXPECT_EQ(0U, GetFaviconCount());
535 TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes, 0);
536 EXPECT_EQ(1U, GetFaviconCount());
537 EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
539 // Map another page to the same favicon. They should share the same data.
540 TriggerSyncFaviconReceived(GURL(page2_url), GURL(fav_url), bytes, 0);
541 EXPECT_EQ(1U, GetFaviconCount());
542 EXPECT_TRUE(ExpectFaviconEquals(page2_url, bytes));
545 TEST_F(SyncFaviconCacheTest, SyncEmpty) {
546 syncer::SyncMergeResult merge_result =
547 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
548 syncer::SyncDataList(),
549 CreateAndPassProcessor(),
550 CreateAndPassSyncErrorFactory());
552 EXPECT_EQ(0U, cache()->GetAllSyncData(syncer::FAVICON_IMAGES).size());
553 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
554 EXPECT_EQ(0, merge_result.num_items_added());
555 EXPECT_EQ(0, merge_result.num_items_modified());
556 EXPECT_EQ(0, merge_result.num_items_deleted());
557 EXPECT_EQ(0, merge_result.num_items_before_association());
558 EXPECT_EQ(0, merge_result.num_items_after_association());
560 merge_result =
561 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
562 syncer::SyncDataList(),
563 CreateAndPassProcessor(),
564 CreateAndPassSyncErrorFactory());
566 EXPECT_EQ(0U, cache()->GetAllSyncData(syncer::FAVICON_TRACKING).size());
567 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
568 EXPECT_EQ(0, merge_result.num_items_added());
569 EXPECT_EQ(0, merge_result.num_items_modified());
570 EXPECT_EQ(0, merge_result.num_items_deleted());
571 EXPECT_EQ(0, merge_result.num_items_before_association());
572 EXPECT_EQ(0, merge_result.num_items_after_association());
575 // Setting up sync with existing local favicons should push those favicons into
576 // sync.
577 TEST_F(SyncFaviconCacheTest, SyncExistingLocal) {
578 std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
579 std::vector<int> expected_icons;
580 for (int i = 0; i < kFaviconBatchSize; ++i) {
581 TestFaviconData favicon = BuildFaviconData(i);
582 TriggerSyncFaviconReceived(favicon.page_url,
583 favicon.icon_url,
584 favicon.image_16,
586 expected_change_types.push_back(syncer::SyncChange::ACTION_ADD);
587 expected_icons.push_back(i);
590 syncer::SyncMergeResult merge_result =
591 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
592 syncer::SyncDataList(),
593 CreateAndPassProcessor(),
594 CreateAndPassSyncErrorFactory());
595 EXPECT_EQ((unsigned long)kFaviconBatchSize,
596 cache()->GetAllSyncData(syncer::FAVICON_IMAGES).size());
597 syncer::SyncChangeList change_list = processor()->GetAndResetChangeList();
598 EXPECT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES,
599 expected_change_types,
600 expected_icons,
601 change_list));
602 EXPECT_EQ(0, merge_result.num_items_added());
603 EXPECT_EQ(0, merge_result.num_items_modified());
604 EXPECT_EQ(0, merge_result.num_items_deleted());
605 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
606 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
608 merge_result =
609 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
610 syncer::SyncDataList(),
611 CreateAndPassProcessor(),
612 CreateAndPassSyncErrorFactory());
613 EXPECT_EQ((unsigned long)kFaviconBatchSize,
614 cache()->GetAllSyncData(syncer::FAVICON_TRACKING).size());
615 change_list = processor()->GetAndResetChangeList();
616 EXPECT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING,
617 expected_change_types,
618 expected_icons,
619 change_list));
620 EXPECT_EQ(0, merge_result.num_items_added());
621 EXPECT_EQ(0, merge_result.num_items_modified());
622 EXPECT_EQ(0, merge_result.num_items_deleted());
623 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
624 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
627 // Setting up sync with existing sync data should load that data into the local
628 // cache.
629 TEST_F(SyncFaviconCacheTest, SyncExistingRemote) {
630 syncer::SyncDataList initial_image_data, initial_tracking_data;
631 std::vector<int> expected_icons;
632 for (int i = 0; i < kFaviconBatchSize; ++i) {
633 expected_icons.push_back(i);
634 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
635 FillImageSpecifics(BuildFaviconData(i),
636 image_specifics.mutable_favicon_image());
637 initial_image_data.push_back(
638 syncer::SyncData::CreateRemoteData(1,
639 image_specifics,
640 base::Time()));
641 FillTrackingSpecifics(BuildFaviconData(i),
642 tracking_specifics.mutable_favicon_tracking());
643 initial_tracking_data.push_back(
644 syncer::SyncData::CreateRemoteData(1,
645 tracking_specifics,
646 base::Time()));
649 syncer::SyncMergeResult merge_result =
650 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
651 initial_image_data,
652 CreateAndPassProcessor(),
653 CreateAndPassSyncErrorFactory());
654 EXPECT_EQ((unsigned long)kFaviconBatchSize,
655 cache()->GetAllSyncData(syncer::FAVICON_IMAGES).size());
656 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
657 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_added());
658 EXPECT_EQ(0, merge_result.num_items_modified());
659 EXPECT_EQ(0, merge_result.num_items_deleted());
660 EXPECT_EQ(0, merge_result.num_items_before_association());
661 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
663 merge_result =
664 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
665 initial_tracking_data,
666 CreateAndPassProcessor(),
667 CreateAndPassSyncErrorFactory());
668 EXPECT_EQ((unsigned long)kFaviconBatchSize,
669 cache()->GetAllSyncData(syncer::FAVICON_TRACKING).size());
670 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
671 EXPECT_EQ(0, merge_result.num_items_added());
672 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
673 EXPECT_EQ(0, merge_result.num_items_deleted());
674 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
675 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
677 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
680 // Setting up sync with local data and sync data should merge the two image
681 // sets, with remote data having priority in case both exist.
682 TEST_F(SyncFaviconCacheTest, SyncMergesImages) {
683 // First go through and add local 16p favicons.
684 for (int i = 0; i < kFaviconBatchSize; ++i) {
685 TestFaviconData favicon = BuildFaviconData(i);
686 TriggerSyncFaviconReceived(favicon.page_url,
687 favicon.icon_url,
688 favicon.image_16,
692 // Then go through and create the initial sync data, which does not have 16p
693 // favicons for the first half, and has custom 16p favicons for the second.
694 std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
695 std::vector<int> expected_icons;
696 std::vector<TestFaviconData> expected_data;
697 syncer::SyncDataList initial_image_data, initial_tracking_data;
698 for (int i = 0; i < kFaviconBatchSize; ++i) {
699 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
700 TestFaviconData test_data = BuildFaviconData(i);
701 if (i < kFaviconBatchSize/2) {
702 test_data.image_16 = std::string();
703 expected_icons.push_back(i);
704 expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
705 } else {
706 test_data.image_16 += "custom";
707 expected_data.push_back(test_data);
709 FillImageSpecifics(test_data,
710 image_specifics.mutable_favicon_image());
712 initial_image_data.push_back(
713 syncer::SyncData::CreateRemoteData(1,
714 image_specifics,
715 base::Time()));
716 FillTrackingSpecifics(test_data,
717 tracking_specifics.mutable_favicon_tracking());
718 initial_tracking_data.push_back(
719 syncer::SyncData::CreateRemoteData(1,
720 tracking_specifics,
721 base::Time()));
724 syncer::SyncMergeResult merge_result =
725 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
726 initial_image_data,
727 CreateAndPassProcessor(),
728 CreateAndPassSyncErrorFactory());
729 EXPECT_EQ((unsigned long)kFaviconBatchSize,
730 cache()->GetAllSyncData(syncer::FAVICON_IMAGES).size());
731 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
732 EXPECT_EQ((unsigned long)kFaviconBatchSize/2, changes.size());
733 EXPECT_EQ(0, merge_result.num_items_added());
734 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
735 EXPECT_EQ(0, merge_result.num_items_deleted());
736 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
737 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
739 merge_result =
740 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
741 initial_tracking_data,
742 CreateAndPassProcessor(),
743 CreateAndPassSyncErrorFactory());
744 EXPECT_EQ((unsigned long)kFaviconBatchSize,
745 cache()->GetAllSyncData(syncer::FAVICON_TRACKING).size());
746 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
747 EXPECT_EQ(0, merge_result.num_items_added());
748 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
749 EXPECT_EQ(0, merge_result.num_items_deleted());
750 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
751 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
753 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
754 ASSERT_TRUE(VerifyLocalCustomIcons(expected_data));
755 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES,
756 expected_change_types,
757 expected_icons,
758 changes));
761 // Setting up sync with local data and sync data should merge the two tracking
762 // sets, such that the visit time is the most recent.
763 TEST_F(SyncFaviconCacheTest, SyncMergesTracking) {
764 // First go through and add local 16p favicons.
765 for (int i = 0; i < kFaviconBatchSize; ++i) {
766 TestFaviconData favicon = BuildFaviconData(i);
767 TriggerSyncFaviconReceived(favicon.page_url,
768 favicon.icon_url,
769 favicon.image_16,
773 // Then go through and create the initial sync data, which for the first half
774 // the local has a newer visit, and for the second the remote does.
775 std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
776 std::vector<int> expected_icons;
777 std::vector<TestFaviconData> expected_data;
778 syncer::SyncDataList initial_image_data, initial_tracking_data;
779 for (int i = 0; i < kFaviconBatchSize; ++i) {
780 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
781 TestFaviconData test_data = BuildFaviconData(i);
782 if (i < kFaviconBatchSize/2) {
783 test_data.last_visit_time = i-1;
784 expected_icons.push_back(i);
785 expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
786 } else {
787 test_data.last_visit_time = i+1;
788 expected_data.push_back(test_data);
790 FillImageSpecifics(test_data,
791 image_specifics.mutable_favicon_image());
793 initial_image_data.push_back(
794 syncer::SyncData::CreateRemoteData(1,
795 image_specifics,
796 base::Time()));
797 FillTrackingSpecifics(test_data,
798 tracking_specifics.mutable_favicon_tracking());
799 initial_tracking_data.push_back(
800 syncer::SyncData::CreateRemoteData(1,
801 tracking_specifics,
802 base::Time()));
805 syncer::SyncMergeResult merge_result =
806 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
807 initial_image_data,
808 CreateAndPassProcessor(),
809 CreateAndPassSyncErrorFactory());
810 EXPECT_EQ((unsigned long)kFaviconBatchSize,
811 cache()->GetAllSyncData(syncer::FAVICON_IMAGES).size());
812 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
813 EXPECT_EQ(0, merge_result.num_items_added());
814 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
815 EXPECT_EQ(0, merge_result.num_items_deleted());
816 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
817 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
819 merge_result =
820 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
821 initial_tracking_data,
822 CreateAndPassProcessor(),
823 CreateAndPassSyncErrorFactory());
824 EXPECT_EQ((unsigned long)kFaviconBatchSize,
825 cache()->GetAllSyncData(syncer::FAVICON_TRACKING).size());
826 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
827 EXPECT_EQ((unsigned long)kFaviconBatchSize/2, changes.size());
828 EXPECT_EQ(0, merge_result.num_items_added());
829 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
830 EXPECT_EQ(0, merge_result.num_items_deleted());
831 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
832 EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
834 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
835 ASSERT_TRUE(VerifyLocalCustomIcons(expected_data));
836 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING,
837 expected_change_types,
838 expected_icons,
839 changes));
842 // Receiving old icons (missing image data) should result in pushing the new
843 // merged icons back to the remote syncer.
844 TEST_F(SyncFaviconCacheTest, ReceiveStaleImages) {
845 syncer::SyncDataList initial_image_data, initial_tracking_data;
846 syncer::SyncChangeList stale_changes;
847 std::vector<int> expected_icons;
848 std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
849 for (int i = 0; i < kFaviconBatchSize; ++i) {
850 expected_icons.push_back(i);
851 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
852 FillImageSpecifics(BuildFaviconData(i),
853 image_specifics.mutable_favicon_image());
854 initial_image_data.push_back(
855 syncer::SyncData::CreateRemoteData(1,
856 image_specifics,
857 base::Time()));
858 expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
859 image_specifics.mutable_favicon_image()->clear_favicon_web();
860 stale_changes.push_back(
861 syncer::SyncChange(
862 FROM_HERE,
863 syncer::SyncChange::ACTION_UPDATE,
864 syncer::SyncData::CreateRemoteData(1,
865 image_specifics,
866 base::Time())));
867 FillTrackingSpecifics(BuildFaviconData(i),
868 tracking_specifics.mutable_favicon_tracking());
869 initial_tracking_data.push_back(
870 syncer::SyncData::CreateRemoteData(1,
871 tracking_specifics,
872 base::Time()));
875 SetUpInitialSync(initial_image_data, initial_tracking_data);
877 // Now receive the same icons as an update, but with missing image data.
878 cache()->ProcessSyncChanges(FROM_HERE, stale_changes);
879 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
880 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
881 ASSERT_EQ((unsigned long)kFaviconBatchSize, changes.size());
882 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES,
883 expected_change_types,
884 expected_icons,
885 changes));
888 // New icons should be added locally without pushing anything back to the
889 // remote syncer.
890 TEST_F(SyncFaviconCacheTest, ReceiveNewImages) {
891 syncer::SyncDataList initial_image_data, initial_tracking_data;
892 syncer::SyncChangeList new_changes;
893 std::vector<int> expected_icons;
894 for (int i = 0; i < kFaviconBatchSize; ++i) {
895 expected_icons.push_back(i);
896 TestFaviconData test_data = BuildFaviconData(i);
897 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
898 FillImageSpecifics(test_data,
899 image_specifics.mutable_favicon_image());
900 new_changes.push_back(
901 syncer::SyncChange(
902 FROM_HERE,
903 syncer::SyncChange::ACTION_UPDATE,
904 syncer::SyncData::CreateRemoteData(1,
905 image_specifics,
906 base::Time())));
907 image_specifics.mutable_favicon_image()->mutable_favicon_web()->
908 mutable_favicon()->append("old");
909 initial_image_data.push_back(
910 syncer::SyncData::CreateRemoteData(1,
911 image_specifics,
912 base::Time()));
913 FillTrackingSpecifics(BuildFaviconData(i),
914 tracking_specifics.mutable_favicon_tracking());
915 initial_tracking_data.push_back(
916 syncer::SyncData::CreateRemoteData(1,
917 tracking_specifics,
918 base::Time()));
921 SetUpInitialSync(initial_image_data, initial_tracking_data);
923 // Now receive the new icons as an update.
924 cache()->ProcessSyncChanges(FROM_HERE, new_changes);
925 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
926 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
929 // Recieving the same icons as the local data should have no effect.
930 TEST_F(SyncFaviconCacheTest, ReceiveSameImages) {
931 syncer::SyncDataList initial_image_data, initial_tracking_data;
932 syncer::SyncChangeList same_changes;
933 std::vector<int> expected_icons;
934 for (int i = 0; i < kFaviconBatchSize; ++i) {
935 expected_icons.push_back(i);
936 TestFaviconData test_data = BuildFaviconData(i);
937 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
938 FillImageSpecifics(test_data,
939 image_specifics.mutable_favicon_image());
940 same_changes.push_back(
941 syncer::SyncChange(
942 FROM_HERE,
943 syncer::SyncChange::ACTION_UPDATE,
944 syncer::SyncData::CreateRemoteData(1,
945 image_specifics,
946 base::Time())));
947 initial_image_data.push_back(
948 syncer::SyncData::CreateRemoteData(1,
949 image_specifics,
950 base::Time()));
951 FillTrackingSpecifics(BuildFaviconData(i),
952 tracking_specifics.mutable_favicon_tracking());
953 initial_tracking_data.push_back(
954 syncer::SyncData::CreateRemoteData(1,
955 tracking_specifics,
956 base::Time()));
959 SetUpInitialSync(initial_image_data, initial_tracking_data);
961 // Now receive the new icons as an update.
962 cache()->ProcessSyncChanges(FROM_HERE, same_changes);
963 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
964 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
967 // Receiving stale tracking (old visit times) should result in pushing back
968 // the newer visit times to the remote syncer.
969 TEST_F(SyncFaviconCacheTest, ReceiveStaleTracking) {
970 syncer::SyncDataList initial_image_data, initial_tracking_data;
971 syncer::SyncChangeList stale_changes;
972 std::vector<int> expected_icons;
973 std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
974 for (int i = 0; i < kFaviconBatchSize; ++i) {
975 expected_icons.push_back(i);
976 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
977 FillImageSpecifics(BuildFaviconData(i),
978 image_specifics.mutable_favicon_image());
979 initial_image_data.push_back(
980 syncer::SyncData::CreateRemoteData(1,
981 image_specifics,
982 base::Time()));
983 expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
984 FillTrackingSpecifics(BuildFaviconData(i),
985 tracking_specifics.mutable_favicon_tracking());
986 initial_tracking_data.push_back(
987 syncer::SyncData::CreateRemoteData(1,
988 tracking_specifics,
989 base::Time()));
990 tracking_specifics.mutable_favicon_tracking()->set_last_visit_time_ms(-1);
991 stale_changes.push_back(
992 syncer::SyncChange(
993 FROM_HERE,
994 syncer::SyncChange::ACTION_UPDATE,
995 syncer::SyncData::CreateRemoteData(1,
996 tracking_specifics,
997 base::Time())));
1000 SetUpInitialSync(initial_image_data, initial_tracking_data);
1002 // Now receive the same icons as an update, but with missing image data.
1003 cache()->ProcessSyncChanges(FROM_HERE, stale_changes);
1004 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1005 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
1006 ASSERT_EQ((unsigned long)kFaviconBatchSize, changes.size());
1007 ASSERT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING,
1008 expected_change_types,
1009 expected_icons,
1010 changes));
1013 // New tracking information should be added locally without pushing anything
1014 // back to the remote syncer.
1015 TEST_F(SyncFaviconCacheTest, ReceiveNewTracking) {
1016 syncer::SyncDataList initial_image_data, initial_tracking_data;
1017 syncer::SyncChangeList new_changes;
1018 std::vector<int> expected_icons;
1019 // We start from one here so that we don't have to deal with a -1 visit time.
1020 for (int i = 1; i <= kFaviconBatchSize; ++i) {
1021 expected_icons.push_back(i);
1022 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1023 FillImageSpecifics(BuildFaviconData(i),
1024 image_specifics.mutable_favicon_image());
1025 initial_image_data.push_back(
1026 syncer::SyncData::CreateRemoteData(1,
1027 image_specifics,
1028 base::Time()));
1029 FillTrackingSpecifics(BuildFaviconData(i),
1030 tracking_specifics.mutable_favicon_tracking());
1031 new_changes.push_back(
1032 syncer::SyncChange(
1033 FROM_HERE,
1034 syncer::SyncChange::ACTION_UPDATE,
1035 syncer::SyncData::CreateRemoteData(1,
1036 tracking_specifics,
1037 base::Time())));
1038 tracking_specifics.mutable_favicon_tracking()->set_last_visit_time_ms(i-1);
1039 initial_tracking_data.push_back(
1040 syncer::SyncData::CreateRemoteData(1,
1041 tracking_specifics,
1042 base::Time()));
1045 SetUpInitialSync(initial_image_data, initial_tracking_data);
1047 // Now receive the new icons as an update.
1048 cache()->ProcessSyncChanges(FROM_HERE, new_changes);
1049 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1050 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
1053 // Receiving the same tracking information as the local data should have no
1054 // effect.
1055 TEST_F(SyncFaviconCacheTest, ReceiveSameTracking) {
1056 syncer::SyncDataList initial_image_data, initial_tracking_data;
1057 syncer::SyncChangeList same_changes;
1058 std::vector<int> expected_icons;
1059 for (int i = 0; i < kFaviconBatchSize; ++i) {
1060 expected_icons.push_back(i);
1061 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1062 FillImageSpecifics(BuildFaviconData(i),
1063 image_specifics.mutable_favicon_image());
1064 initial_image_data.push_back(
1065 syncer::SyncData::CreateRemoteData(1,
1066 image_specifics,
1067 base::Time()));
1068 FillTrackingSpecifics(BuildFaviconData(i),
1069 tracking_specifics.mutable_favicon_tracking());
1070 initial_tracking_data.push_back(
1071 syncer::SyncData::CreateRemoteData(1,
1072 tracking_specifics,
1073 base::Time()));
1074 same_changes.push_back(
1075 syncer::SyncChange(
1076 FROM_HERE,
1077 syncer::SyncChange::ACTION_UPDATE,
1078 syncer::SyncData::CreateRemoteData(1,
1079 tracking_specifics,
1080 base::Time())));
1083 SetUpInitialSync(initial_image_data, initial_tracking_data);
1085 // Now receive the new icons as an update.
1086 cache()->ProcessSyncChanges(FROM_HERE, same_changes);
1087 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1088 ASSERT_TRUE(VerifyLocalIcons(expected_icons));
1091 // Verify we can delete favicons after setting up sync.
1092 TEST_F(SyncFaviconCacheTest, DeleteFavicons) {
1093 syncer::SyncDataList initial_image_data, initial_tracking_data;
1094 syncer::SyncChangeList tracking_deletions, image_deletions;
1095 for (int i = 0; i < kFaviconBatchSize; ++i) {
1096 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1097 FillImageSpecifics(BuildFaviconData(i),
1098 image_specifics.mutable_favicon_image());
1099 initial_image_data.push_back(
1100 syncer::SyncData::CreateRemoteData(1,
1101 image_specifics,
1102 base::Time()));
1103 FillTrackingSpecifics(BuildFaviconData(i),
1104 tracking_specifics.mutable_favicon_tracking());
1105 initial_tracking_data.push_back(
1106 syncer::SyncData::CreateRemoteData(1,
1107 tracking_specifics,
1108 base::Time()));
1109 tracking_deletions.push_back(
1110 syncer::SyncChange(
1111 FROM_HERE,
1112 syncer::SyncChange::ACTION_DELETE,
1113 syncer::SyncData::CreateRemoteData(1,
1114 tracking_specifics,
1115 base::Time())));
1116 image_deletions.push_back(
1117 syncer::SyncChange(
1118 FROM_HERE,
1119 syncer::SyncChange::ACTION_DELETE,
1120 syncer::SyncData::CreateRemoteData(1,
1121 image_specifics,
1122 base::Time())));
1125 SetUpInitialSync(initial_image_data, initial_tracking_data);
1127 // Now receive the tracking deletions. Since we'll still have orphan data,
1128 // the favicon count should remain the same.
1129 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1130 cache()->ProcessSyncChanges(FROM_HERE, tracking_deletions);
1131 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1132 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1134 // Once the image deletions arrive, the favicon count should be 0 again.
1135 cache()->ProcessSyncChanges(FROM_HERE, image_deletions);
1136 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1137 EXPECT_EQ(0U, GetFaviconCount());
1140 // Ensure that MergeDataAndStartSyncing enforces the sync favicon limit by
1141 // dropping local icons.
1142 TEST_F(SyncFaviconCacheTest, ExpireOnMergeData) {
1143 std::vector<int> expected_icons;
1144 syncer::SyncDataList initial_image_data, initial_tracking_data;
1146 // Set up sync so it has the maximum number of favicons, while the local has
1147 // the same amount of different favicons.
1148 for (int i = 0; i < kMaxSyncFavicons; ++i) {
1149 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1150 FillImageSpecifics(BuildFaviconData(i),
1151 image_specifics.mutable_favicon_image());
1152 initial_image_data.push_back(
1153 syncer::SyncData::CreateRemoteData(1,
1154 image_specifics,
1155 base::Time()));
1156 FillTrackingSpecifics(BuildFaviconData(i),
1157 tracking_specifics.mutable_favicon_tracking());
1158 initial_tracking_data.push_back(
1159 syncer::SyncData::CreateRemoteData(1,
1160 tracking_specifics,
1161 base::Time()));
1162 expected_icons.push_back(i);
1164 TestFaviconData favicon = BuildFaviconData(i+kMaxSyncFavicons);
1165 TriggerSyncFaviconReceived(favicon.page_url,
1166 favicon.icon_url,
1167 favicon.image_16,
1168 i+kMaxSyncFavicons);
1171 EXPECT_FALSE(VerifyLocalIcons(expected_icons));
1173 syncer::SyncMergeResult merge_result =
1174 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
1175 initial_image_data,
1176 CreateAndPassProcessor(),
1177 CreateAndPassSyncErrorFactory());
1178 EXPECT_EQ((unsigned long)kMaxSyncFavicons,
1179 cache()->GetAllSyncData(syncer::FAVICON_IMAGES).size());
1180 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1181 EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_added());
1182 EXPECT_EQ(0, merge_result.num_items_modified());
1183 EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_deleted());
1184 EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_before_association());
1185 EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_after_association());
1187 merge_result =
1188 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
1189 initial_tracking_data,
1190 CreateAndPassProcessor(),
1191 CreateAndPassSyncErrorFactory());
1192 EXPECT_EQ((unsigned long)kMaxSyncFavicons,
1193 cache()->GetAllSyncData(syncer::FAVICON_TRACKING).size());
1194 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1195 EXPECT_EQ(0, merge_result.num_items_added());
1196 EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_modified());
1197 EXPECT_EQ(0, merge_result.num_items_deleted());
1198 EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_before_association());
1199 EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_after_association());
1201 EXPECT_TRUE(VerifyLocalIcons(expected_icons));
1204 // Receiving sync additions (via ProcessSyncChanges) should not trigger
1205 // expirations.
1206 TEST_F(SyncFaviconCacheTest, NoExpireOnProcessSyncChanges) {
1207 syncer::SyncDataList initial_image_data, initial_tracking_data;
1208 syncer::SyncChangeList image_changes, tracking_changes;
1209 std::vector<int> expected_icons;
1210 for (int i = 0; i < kMaxSyncFavicons; ++i) {
1211 expected_icons.push_back(i);
1212 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1213 FillImageSpecifics(BuildFaviconData(i),
1214 image_specifics.mutable_favicon_image());
1215 initial_image_data.push_back(
1216 syncer::SyncData::CreateRemoteData(1,
1217 image_specifics,
1218 base::Time()));
1219 FillTrackingSpecifics(BuildFaviconData(i),
1220 tracking_specifics.mutable_favicon_tracking());
1221 initial_tracking_data.push_back(
1222 syncer::SyncData::CreateRemoteData(1,
1223 tracking_specifics,
1224 base::Time()));
1225 // Set up new tracking specifics for the icons received at change time.
1226 expected_icons.push_back(i + kMaxSyncFavicons);
1227 FillImageSpecifics(BuildFaviconData(i + kMaxSyncFavicons),
1228 image_specifics.mutable_favicon_image());
1229 image_changes.push_back(
1230 syncer::SyncChange(
1231 FROM_HERE,
1232 syncer::SyncChange::ACTION_ADD,
1233 syncer::SyncData::CreateRemoteData(1,
1234 image_specifics,
1235 base::Time())));
1236 FillTrackingSpecifics(BuildFaviconData(i + kMaxSyncFavicons),
1237 tracking_specifics.mutable_favicon_tracking());
1238 tracking_changes.push_back(
1239 syncer::SyncChange(
1240 FROM_HERE,
1241 syncer::SyncChange::ACTION_ADD,
1242 syncer::SyncData::CreateRemoteData(1,
1243 tracking_specifics,
1244 base::Time())));
1247 SetUpInitialSync(initial_image_data, initial_tracking_data);
1249 // Now receive the new icons as an update.
1250 EXPECT_EQ((unsigned long)kMaxSyncFavicons, GetFaviconCount());
1251 cache()->ProcessSyncChanges(FROM_HERE, image_changes);
1252 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1253 cache()->ProcessSyncChanges(FROM_HERE, tracking_changes);
1254 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1255 EXPECT_TRUE(VerifyLocalIcons(expected_icons));
1256 EXPECT_GT(GetFaviconCount(), (unsigned long)kMaxSyncFavicons);
1259 // Test that visiting a new page triggers a favicon load and a sync addition.
1260 TEST_F(SyncFaviconCacheTest, AddOnFaviconVisited) {
1261 EXPECT_EQ(0U, GetFaviconCount());
1262 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1263 std::vector<int> expected_icons;
1265 for (int i = 0; i < kFaviconBatchSize; ++i) {
1266 expected_icons.push_back(i);
1267 TestFaviconData test_data = BuildFaviconData(i);
1268 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1271 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetTaskCount());
1273 for (int i = 0; i < kFaviconBatchSize; ++i) {
1274 TestFaviconData test_data = BuildFaviconData(i);
1275 OnCustomFaviconDataAvailable(test_data);
1277 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1278 ASSERT_EQ(2U, changes.size());
1279 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
1280 EXPECT_EQ(syncer::FAVICON_IMAGES, changes[0].sync_data().GetDataType());
1281 EXPECT_TRUE(
1282 CompareFaviconDataToSpecifics(test_data,
1283 changes[0].sync_data().GetSpecifics()));
1284 EXPECT_EQ(syncer::FAVICON_TRACKING, changes[1].sync_data().GetDataType());
1285 // Just verify the favicon url for the tracking specifics and that the
1286 // timestamp is non-null.
1287 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[1].change_type());
1288 EXPECT_EQ(test_data.icon_url.spec(),
1289 changes[1].sync_data().GetSpecifics().favicon_tracking().
1290 favicon_url());
1291 EXPECT_NE(changes[1].sync_data().GetSpecifics().favicon_tracking().
1292 last_visit_time_ms(), 0);
1295 EXPECT_EQ(0U, GetTaskCount());
1296 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1299 // Test that visiting a known page does not trigger a favicon load and just
1300 // updates the sync tracking info.
1301 TEST_F(SyncFaviconCacheTest, UpdateOnFaviconVisited) {
1302 EXPECT_EQ(0U, GetFaviconCount());
1303 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1304 std::vector<int> expected_icons;
1306 // Add the favicons.
1307 for (int i = 0; i < kFaviconBatchSize; ++i) {
1308 expected_icons.push_back(i);
1309 TestFaviconData test_data = BuildFaviconData(i);
1310 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1311 OnCustomFaviconDataAvailable(test_data);
1313 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1315 // Visit the favicons again.
1316 EXPECT_EQ(0U, GetTaskCount());
1317 for (int i = 0; i < kFaviconBatchSize; ++i) {
1318 TestFaviconData test_data = BuildFaviconData(i);
1319 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1321 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1322 ASSERT_EQ(1U, changes.size());
1323 // Just verify the favicon url for the tracking specifics and that the
1324 // timestamp is non-null.
1325 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1326 EXPECT_EQ(test_data.icon_url.spec(),
1327 changes[0].sync_data().GetSpecifics().favicon_tracking().
1328 favicon_url());
1329 EXPECT_NE(changes[0].sync_data().GetSpecifics().favicon_tracking().
1330 last_visit_time_ms(), 0);
1332 EXPECT_EQ(0U, GetTaskCount());
1333 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1336 // Ensure we properly expire old synced favicons as new ones are updated.
1337 TEST_F(SyncFaviconCacheTest, ExpireOnFaviconVisited) {
1338 EXPECT_EQ(0U, GetFaviconCount());
1339 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1340 std::vector<int> expected_icons;
1342 // Add the initial favicons.
1343 for (int i = 0; i < kMaxSyncFavicons; ++i) {
1344 expected_icons.push_back(i);
1345 TestFaviconData test_data = BuildFaviconData(i);
1346 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1347 OnCustomFaviconDataAvailable(test_data);
1349 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1351 // Visit some new favicons, triggering expirations of the old favicons.
1352 EXPECT_EQ(0U, GetTaskCount());
1353 for (int i = 0; i < kFaviconBatchSize; ++i) {
1354 TestFaviconData old_favicon = BuildFaviconData(i);
1355 TestFaviconData test_data = BuildFaviconData(i + kMaxSyncFavicons);
1356 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1357 OnCustomFaviconDataAvailable(test_data);
1359 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1360 ASSERT_EQ(4U, changes.size());
1361 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
1362 EXPECT_TRUE(
1363 CompareFaviconDataToSpecifics(test_data,
1364 changes[0].sync_data().GetSpecifics()));
1365 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, changes[1].change_type());
1366 EXPECT_EQ(old_favicon.icon_url.spec(), changes[1].sync_data().GetTag());
1368 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[2].change_type());
1369 EXPECT_EQ(test_data.icon_url.spec(),
1370 changes[2].sync_data().GetSpecifics().favicon_tracking().
1371 favicon_url());
1372 EXPECT_NE(changes[2].sync_data().GetSpecifics().favicon_tracking().
1373 last_visit_time_ms(), 0);
1374 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, changes[3].change_type());
1375 EXPECT_EQ(old_favicon.icon_url.spec(), changes[3].sync_data().GetTag());
1378 EXPECT_EQ(0U, GetTaskCount());
1379 EXPECT_EQ((unsigned long)kMaxSyncFavicons, GetFaviconCount());
1382 // A full history clear notification should result in all synced favicons being
1383 // deleted.
1384 TEST_F(SyncFaviconCacheTest, HistoryFullClear) {
1385 syncer::SyncDataList initial_image_data, initial_tracking_data;
1386 std::vector<int> expected_icons;
1387 std::vector<syncer::SyncChange::SyncChangeType> expected_deletions;
1388 for (int i = 0; i < kFaviconBatchSize; ++i) {
1389 expected_icons.push_back(i);
1390 expected_deletions.push_back(syncer::SyncChange::ACTION_DELETE);
1391 TestFaviconData test_data = BuildFaviconData(i);
1392 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1393 FillImageSpecifics(test_data,
1394 image_specifics.mutable_favicon_image());
1395 initial_image_data.push_back(
1396 syncer::SyncData::CreateRemoteData(1,
1397 image_specifics,
1398 base::Time()));
1399 FillTrackingSpecifics(BuildFaviconData(i),
1400 tracking_specifics.mutable_favicon_tracking());
1401 initial_tracking_data.push_back(
1402 syncer::SyncData::CreateRemoteData(1,
1403 tracking_specifics,
1404 base::Time()));
1407 SetUpInitialSync(initial_image_data, initial_tracking_data);
1408 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1409 EXPECT_TRUE(changes.empty());
1411 history::URLsDeletedDetails deletions;
1412 deletions.all_history = true;
1413 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1414 content::NotificationService::current()->Notify(
1415 chrome::NOTIFICATION_HISTORY_URLS_DELETED,
1416 content::Source<Profile>(NULL),
1417 content::Details<history::URLsDeletedDetails>(&deletions));
1418 EXPECT_EQ(0U, GetFaviconCount());
1419 changes = processor()->GetAndResetChangeList();
1420 ASSERT_EQ(changes.size(), (unsigned long)kFaviconBatchSize*2);
1421 syncer::SyncChangeList changes_1, changes_2;
1422 for (int i = 0; i < kFaviconBatchSize; ++i) {
1423 changes_1.push_back(changes[i]);
1424 changes_2.push_back(changes[i + kFaviconBatchSize]);
1426 VerifyChanges(syncer::FAVICON_IMAGES,
1427 expected_deletions,
1428 expected_icons,
1429 changes_1);
1430 VerifyChanges(syncer::FAVICON_TRACKING,
1431 expected_deletions,
1432 expected_icons,
1433 changes_2);
1436 // A partial history clear notification should result in the expired favicons
1437 // also being deleted from sync.
1438 TEST_F(SyncFaviconCacheTest, HistorySubsetClear) {
1439 syncer::SyncDataList initial_image_data, initial_tracking_data;
1440 std::vector<int> expected_icons;
1441 std::vector<syncer::SyncChange::SyncChangeType> expected_deletions;
1442 history::URLsDeletedDetails deletions;
1443 for (int i = 0; i < kFaviconBatchSize; ++i) {
1444 TestFaviconData test_data = BuildFaviconData(i);
1445 if (i < kFaviconBatchSize/2) {
1446 expected_icons.push_back(i);
1447 expected_deletions.push_back(syncer::SyncChange::ACTION_DELETE);
1448 deletions.favicon_urls.insert(test_data.icon_url);
1450 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1451 FillImageSpecifics(test_data,
1452 image_specifics.mutable_favicon_image());
1453 initial_image_data.push_back(
1454 syncer::SyncData::CreateRemoteData(1,
1455 image_specifics,
1456 base::Time()));
1457 FillTrackingSpecifics(BuildFaviconData(i),
1458 tracking_specifics.mutable_favicon_tracking());
1459 initial_tracking_data.push_back(
1460 syncer::SyncData::CreateRemoteData(1,
1461 tracking_specifics,
1462 base::Time()));
1465 SetUpInitialSync(initial_image_data, initial_tracking_data);
1466 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1467 EXPECT_TRUE(changes.empty());
1469 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1470 content::NotificationService::current()->Notify(
1471 chrome::NOTIFICATION_HISTORY_URLS_DELETED,
1472 content::Source<Profile>(NULL),
1473 content::Details<history::URLsDeletedDetails>(&deletions));
1474 EXPECT_EQ((unsigned long)kFaviconBatchSize/2, GetFaviconCount());
1475 changes = processor()->GetAndResetChangeList();
1476 ASSERT_EQ(changes.size(), (unsigned long)kFaviconBatchSize);
1477 syncer::SyncChangeList changes_1, changes_2;
1478 for (size_t i = 0; i < kFaviconBatchSize/2; ++i) {
1479 changes_1.push_back(changes[i]);
1480 changes_2.push_back(changes[i + kFaviconBatchSize/2]);
1482 VerifyChanges(syncer::FAVICON_IMAGES,
1483 expected_deletions,
1484 expected_icons,
1485 changes_1);
1486 VerifyChanges(syncer::FAVICON_TRACKING,
1487 expected_deletions,
1488 expected_icons,
1489 changes_2);
1492 // Any favicon urls with the "data" scheme should be ignored.
1493 TEST_F(SyncFaviconCacheTest, IgnoreDataScheme) {
1494 EXPECT_EQ(0U, GetFaviconCount());
1495 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1496 std::vector<int> expected_icons;
1498 for (int i = 0; i < kFaviconBatchSize; ++i) {
1499 TestFaviconData test_data = BuildFaviconData(i);
1500 cache()->OnFaviconVisited(test_data.page_url, GURL());
1503 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetTaskCount());
1505 for (int i = 0; i < kFaviconBatchSize; ++i) {
1506 TestFaviconData test_data = BuildFaviconData(i);
1507 test_data.icon_url = GURL("data:image/png;base64;blabla");
1508 EXPECT_TRUE(test_data.icon_url.is_valid());
1509 OnCustomFaviconDataAvailable(test_data);
1512 EXPECT_EQ(0U, GetTaskCount());
1513 EXPECT_EQ(0U, GetFaviconCount());
1514 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1515 EXPECT_TRUE(changes.empty());
1518 // When visiting a page we've already loaded the favicon for, don't attempt to
1519 // reload the favicon, just update the visit time using the cached icon url.
1520 TEST_F(SyncFaviconCacheTest, ReuseCachedIconUrl) {
1521 EXPECT_EQ(0U, GetFaviconCount());
1522 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1523 std::vector<int> expected_icons;
1525 for (int i = 0; i < kFaviconBatchSize; ++i) {
1526 expected_icons.push_back(i);
1527 TestFaviconData test_data = BuildFaviconData(i);
1528 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1531 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetTaskCount());
1533 for (int i = 0; i < kFaviconBatchSize; ++i) {
1534 TestFaviconData test_data = BuildFaviconData(i);
1535 OnCustomFaviconDataAvailable(test_data);
1537 processor()->GetAndResetChangeList();
1538 EXPECT_EQ(0U, GetTaskCount());
1539 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1541 for (int i = 0; i < kFaviconBatchSize; ++i) {
1542 TestFaviconData test_data = BuildFaviconData(i);
1543 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1544 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1545 ASSERT_EQ(1U, changes.size());
1546 // Just verify the favicon url for the tracking specifics and that the
1547 // timestamp is non-null.
1548 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1549 EXPECT_EQ(test_data.icon_url.spec(),
1550 changes[0].sync_data().GetSpecifics().favicon_tracking().
1551 favicon_url());
1552 EXPECT_NE(changes[0].sync_data().GetSpecifics().favicon_tracking().
1553 last_visit_time_ms(), 0);
1555 EXPECT_EQ(0U, GetTaskCount());
1558 // If we wind up with orphan image/tracking nodes, then receive an update
1559 // for those favicons, we should lazily create the missing nodes.
1560 TEST_F(SyncFaviconCacheTest, UpdatedOrphans) {
1561 EXPECT_EQ(0U, GetFaviconCount());
1562 SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1564 syncer::SyncChangeList initial_image_changes;
1565 syncer::SyncChangeList initial_tracking_changes;
1566 for (int i = 0; i < kFaviconBatchSize; ++i) {
1567 TestFaviconData test_data = BuildFaviconData(i);
1568 // Even favicons have image data but no tracking data. Odd favicons have
1569 // tracking data but no image data.
1570 if (i % 2 == 0) {
1571 sync_pb::EntitySpecifics image_specifics;
1572 FillImageSpecifics(BuildFaviconData(i),
1573 image_specifics.mutable_favicon_image());
1574 initial_image_changes.push_back(
1575 syncer::SyncChange(FROM_HERE,
1576 syncer::SyncChange::ACTION_ADD,
1577 syncer::SyncData::CreateRemoteData(
1578 1, image_specifics, base::Time())));
1579 } else {
1580 sync_pb::EntitySpecifics tracking_specifics;
1581 FillTrackingSpecifics(BuildFaviconData(i),
1582 tracking_specifics.mutable_favicon_tracking());
1583 initial_tracking_changes.push_back(
1584 syncer::SyncChange(FROM_HERE,
1585 syncer::SyncChange::ACTION_ADD,
1586 syncer::SyncData::CreateRemoteData(
1587 1, tracking_specifics, base::Time())));
1591 cache()->ProcessSyncChanges(FROM_HERE, initial_image_changes);
1592 cache()->ProcessSyncChanges(FROM_HERE, initial_tracking_changes);
1593 EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1594 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1596 for (int i = 0; i < kFaviconBatchSize/2; ++i) {
1597 TestFaviconData test_data = BuildFaviconData(i);
1598 cache()->OnFaviconVisited(test_data.page_url, GURL());
1599 EXPECT_EQ(1U, GetTaskCount());
1600 OnCustomFaviconDataAvailable(test_data);
1601 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1603 // Even favicons had image data, so should now receive new tracking data
1604 // and updated image data (we allow one update after the initial add).
1605 // Odd favicons had tracking so should now receive new image data and
1606 // updated tracking data.
1607 if (i % 2 == 0) {
1608 ASSERT_EQ(2U, changes.size());
1609 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1610 EXPECT_TRUE(
1611 CompareFaviconDataToSpecifics(test_data,
1612 changes[0].sync_data().GetSpecifics()));
1613 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[1].change_type());
1614 EXPECT_EQ(test_data.icon_url.spec(),
1615 changes[1].sync_data().GetSpecifics().favicon_tracking().
1616 favicon_url());
1617 EXPECT_NE(changes[1].sync_data().GetSpecifics().favicon_tracking().
1618 last_visit_time_ms(), 0);
1619 } else {
1620 ASSERT_EQ(2U, changes.size());
1621 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
1622 EXPECT_TRUE(
1623 CompareFaviconDataToSpecifics(test_data,
1624 changes[0].sync_data().GetSpecifics()));
1625 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[1].change_type());
1626 EXPECT_EQ(test_data.icon_url.spec(),
1627 changes[1].sync_data().GetSpecifics().favicon_tracking().
1628 favicon_url());
1629 EXPECT_NE(changes[1].sync_data().GetSpecifics().favicon_tracking().
1630 last_visit_time_ms(), 0);
1634 EXPECT_EQ(0U, GetTaskCount());
1635 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1638 // Verify that orphaned favicon images don't result in creating invalid
1639 // favicon tracking data.
1640 TEST_F(SyncFaviconCacheTest, PartialAssociationInfo) {
1641 syncer::SyncDataList initial_image_data, initial_tracking_data;
1642 for (int i = 0; i < kFaviconBatchSize; ++i) {
1643 sync_pb::EntitySpecifics image_specifics;
1644 FillImageSpecifics(BuildFaviconData(i),
1645 image_specifics.mutable_favicon_image());
1646 initial_image_data.push_back(
1647 syncer::SyncData::CreateRemoteData(1,
1648 image_specifics,
1649 base::Time()));
1650 image_specifics.mutable_favicon_image()->clear_favicon_web();
1653 SetUpInitialSync(initial_image_data, initial_tracking_data);
1654 syncer::SyncChangeList change_list = processor()->GetAndResetChangeList();
1655 EXPECT_TRUE(change_list.empty());
1656 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1659 // Tests that we don't choke if a favicon visit node with a null visit time is
1660 // present (see crbug.com/258196) and an update is made.
1661 TEST_F(SyncFaviconCacheTest, NullFaviconVisitTime) {
1662 EXPECT_EQ(0U, GetFaviconCount());
1664 syncer::SyncDataList initial_image_data, initial_tracking_data;
1665 std::vector<int> expected_icons;
1666 for (int i = 0; i < kFaviconBatchSize; ++i) {
1667 expected_icons.push_back(i);
1668 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1669 FillImageSpecifics(BuildFaviconData(i),
1670 image_specifics.mutable_favicon_image());
1671 initial_image_data.push_back(
1672 syncer::SyncData::CreateRemoteData(1,
1673 image_specifics,
1674 base::Time()));
1675 FillTrackingSpecifics(BuildFaviconData(i),
1676 tracking_specifics.mutable_favicon_tracking());
1677 tracking_specifics.mutable_favicon_tracking()->set_last_visit_time_ms(
1678 syncer::TimeToProtoTime(base::Time()));
1679 initial_tracking_data.push_back(
1680 syncer::SyncData::CreateRemoteData(1,
1681 tracking_specifics,
1682 base::Time()));
1685 cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
1686 initial_image_data,
1687 CreateAndPassProcessor(),
1688 CreateAndPassSyncErrorFactory());
1689 ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
1690 cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
1691 initial_tracking_data,
1692 CreateAndPassProcessor(),
1693 CreateAndPassSyncErrorFactory());
1694 ASSERT_EQ((unsigned long)kFaviconBatchSize,
1695 processor()->GetAndResetChangeList().size());
1696 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1698 // Visit the favicons again.
1699 EXPECT_EQ(0U, GetTaskCount());
1700 for (int i = 0; i < kFaviconBatchSize; ++i) {
1701 TestFaviconData test_data = BuildFaviconData(i);
1702 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1704 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1705 ASSERT_EQ(1U, changes.size());
1706 // Just verify the favicon url for the tracking specifics and that the
1707 // timestamp is non-null.
1708 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1709 EXPECT_EQ(test_data.icon_url.spec(),
1710 changes[0].sync_data().GetSpecifics().favicon_tracking().
1711 favicon_url());
1712 EXPECT_NE(changes[0].sync_data().GetSpecifics().favicon_tracking().
1713 last_visit_time_ms(), 0);
1715 EXPECT_EQ(0U, GetTaskCount());
1716 EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount());
1719 // If another synced client has a clock skewed towards the future, it's possible
1720 // that favicons added locally will be expired as they are added. Ensure this
1721 // doesn't crash (see crbug.com/306150).
1722 TEST_F(SyncFaviconCacheTest, VisitFaviconClockSkew) {
1723 EXPECT_EQ(0U, GetFaviconCount());
1724 const int kClockSkew = 20; // 20 minutes in the future.
1726 // Set up sync with kMaxSyncFavicons starting kClockSkew minutes in the
1727 // future.
1728 syncer::SyncDataList initial_image_data, initial_tracking_data;
1729 for (int i = 0; i < kMaxSyncFavicons; ++i) {
1730 sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1731 TestFaviconData test_data = BuildFaviconData(i);
1732 test_data.last_visit_time =
1733 syncer::TimeToProtoTime(
1734 base::Time::Now() + base::TimeDelta::FromMinutes(kClockSkew));
1735 FillImageSpecifics(test_data,
1736 image_specifics.mutable_favicon_image());
1737 initial_image_data.push_back(
1738 syncer::SyncData::CreateRemoteData(1,
1739 image_specifics,
1740 base::Time()));
1741 FillTrackingSpecifics(test_data,
1742 tracking_specifics.mutable_favicon_tracking());
1743 initial_tracking_data.push_back(
1744 syncer::SyncData::CreateRemoteData(1,
1745 tracking_specifics,
1746 base::Time()));
1748 SetUpInitialSync(initial_image_data, initial_tracking_data);
1750 // Visit some new favicons with local time, which will be expired as they
1751 // are added.
1752 EXPECT_EQ(0U, GetTaskCount());
1753 for (int i = 0; i < kClockSkew; ++i) {
1754 TestFaviconData test_data = BuildFaviconData(i + kMaxSyncFavicons);
1755 cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1756 OnCustomFaviconDataAvailable(test_data);
1758 // The changes will be an add followed by a delete for both the image and
1759 // tracking info.
1760 syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1761 ASSERT_EQ(changes.size(), 4U);
1762 ASSERT_EQ(changes[0].change_type(), syncer::SyncChange::ACTION_ADD);
1763 ASSERT_EQ(changes[0].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1764 ASSERT_EQ(changes[1].change_type(), syncer::SyncChange::ACTION_DELETE);
1765 ASSERT_EQ(changes[1].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1766 ASSERT_EQ(changes[2].change_type(), syncer::SyncChange::ACTION_ADD);
1767 ASSERT_EQ(changes[2].sync_data().GetDataType(), syncer::FAVICON_TRACKING);
1768 ASSERT_EQ(changes[3].change_type(), syncer::SyncChange::ACTION_DELETE);
1769 ASSERT_EQ(changes[3].sync_data().GetDataType(), syncer::FAVICON_TRACKING);
1771 EXPECT_EQ(0U, GetTaskCount());
1772 EXPECT_EQ((unsigned long)kMaxSyncFavicons, GetFaviconCount());
1775 } // namespace browser_sync