1 // Copyright 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.
4 
5 #include "components/sync_sessions/favicon_cache.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/run_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/test/task_environment.h"
15 #include "base/time/time.h"
16 #include "components/favicon/core/test/mock_favicon_service.h"
17 #include "components/sync/model/sync_change_processor_wrapper_for_test.h"
18 #include "components/sync/model/sync_error_factory_mock.h"
19 #include "components/sync/model/time.h"
20 #include "components/sync/protocol/favicon_image_specifics.pb.h"
21 #include "components/sync/protocol/favicon_tracking_specifics.pb.h"
22 #include "components/sync/protocol/sync.pb.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace sync_sessions {
27 
28 namespace {
29 
30 using testing::_;
31 
32 // Total number of favicons to use in sync test batches.
33 const int kFaviconBatchSize = 10;
34 
35 // Maximum number of favicons to sync.
36 const int kMaxSyncFavicons = kFaviconBatchSize*2;
37 
38 // TestChangeProcessor --------------------------------------------------------
39 
40 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
41 // back up to Sync.
42 class TestChangeProcessor : public syncer::SyncChangeProcessor {
43  public:
44   TestChangeProcessor();
45   ~TestChangeProcessor() override;
46 
47   // Store a copy of all the changes passed in so we can examine them later.
48   syncer::SyncError ProcessSyncChanges(
49       const base::Location& from_here,
50       const syncer::SyncChangeList& change_list) override;
51 
GetAllSyncData(syncer::ModelType type) const52   syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override {
53     return syncer::SyncDataList();
54   }
55 
contains_guid(const std::string & guid) const56   bool contains_guid(const std::string& guid) const {
57     return change_map_.count(guid) != 0;
58   }
59 
change_for_guid(const std::string & guid) const60   syncer::SyncChange change_for_guid(const std::string& guid) const {
61     DCHECK(contains_guid(guid));
62     return change_map_.find(guid)->second;
63   }
64 
65   // Returns the last change list received, and resets the internal list.
GetAndResetChangeList()66   syncer::SyncChangeList GetAndResetChangeList() {
67     syncer::SyncChangeList list;
68     list.swap(change_list_);
69     return list;
70   }
71 
set_erroneous(bool erroneous)72   void set_erroneous(bool erroneous) { erroneous_ = erroneous; }
73 
74  private:
75   // Track the changes received in ProcessSyncChanges.
76   std::map<std::string, syncer::SyncChange> change_map_;
77   syncer::SyncChangeList change_list_;
78   bool erroneous_;
79 
80   DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
81 };
82 
TestChangeProcessor()83 TestChangeProcessor::TestChangeProcessor() : erroneous_(false) {
84 }
85 
~TestChangeProcessor()86 TestChangeProcessor::~TestChangeProcessor() {
87 }
88 
ProcessSyncChanges(const base::Location & from_here,const syncer::SyncChangeList & change_list)89 syncer::SyncError TestChangeProcessor::ProcessSyncChanges(
90     const base::Location& from_here,
91     const syncer::SyncChangeList& change_list) {
92   if (erroneous_) {
93     return syncer::SyncError(
94         FROM_HERE,
95         syncer::SyncError::DATATYPE_ERROR,
96         "Some error.",
97         change_list[0].sync_data().GetDataType());
98   }
99 
100   change_list_.insert(change_list_.end(),
101                       change_list.begin(),
102                       change_list.end());
103   change_map_.erase(change_map_.begin(), change_map_.end());
104   for (auto iter = change_list.begin(); iter != change_list.end(); ++iter) {
105     change_map_[iter->sync_data().GetTitle()] = *iter;
106   }
107   return syncer::SyncError();
108 }
109 
110 // TestFaviconData ------------------------------------------------------------
111 struct TestFaviconData {
TestFaviconDatasync_sessions::__anon7159b2430111::TestFaviconData112   TestFaviconData() : is_bookmarked(false) {}
113   GURL page_url;
114   GURL icon_url;
115   std::string image_16;
116   std::string image_32;
117   std::string image_64;
118   base::Time last_visit_time;
119   bool is_bookmarked;
120 };
121 
BuildFaviconData(int index)122 TestFaviconData BuildFaviconData(int index) {
123   TestFaviconData data;
124   data.page_url = GURL(base::StringPrintf("http://bla.com/%.2i.html", index));
125   data.icon_url = GURL(base::StringPrintf("http://bla.com/%.2i.ico", index));
126   data.image_16 = base::StringPrintf("16 %i", index);
127   // TODO(zea): enable this once the cache supports writing them.
128   // data.image_32 = base::StringPrintf("32 %i", index);
129   // data.image_64 = base::StringPrintf("64 %i", index);
130   data.last_visit_time = syncer::ProtoTimeToTime(index);
131   return data;
132 }
133 
FillImageSpecifics(const TestFaviconData & test_data,sync_pb::FaviconImageSpecifics * image_specifics)134 void FillImageSpecifics(
135     const TestFaviconData& test_data,
136     sync_pb::FaviconImageSpecifics* image_specifics) {
137   image_specifics->set_favicon_url(test_data.icon_url.spec());
138   if (!test_data.image_16.empty()) {
139     image_specifics->mutable_favicon_web()->set_height(16);
140     image_specifics->mutable_favicon_web()->set_width(16);
141     image_specifics->mutable_favicon_web()->set_favicon(test_data.image_16);
142   }
143   if (!test_data.image_32.empty()) {
144     image_specifics->mutable_favicon_web_32()->set_height(32);
145     image_specifics->mutable_favicon_web_32()->set_width(32);
146     image_specifics->mutable_favicon_web_32()->set_favicon(test_data.image_32);
147   }
148   if (!test_data.image_64.empty()) {
149     image_specifics->mutable_favicon_touch_64()->set_height(64);
150     image_specifics->mutable_favicon_touch_64()->set_width(64);
151     image_specifics->mutable_favicon_touch_64()->
152         set_favicon(test_data.image_64);
153   }
154 }
155 
FillTrackingSpecifics(const TestFaviconData & test_data,sync_pb::FaviconTrackingSpecifics * tracking_specifics)156 void FillTrackingSpecifics(
157     const TestFaviconData& test_data,
158     sync_pb::FaviconTrackingSpecifics* tracking_specifics) {
159   tracking_specifics->set_favicon_url(test_data.icon_url.spec());
160   tracking_specifics->set_last_visit_time_ms(
161       syncer::TimeToProtoTime(test_data.last_visit_time));
162   tracking_specifics->set_is_bookmarked(test_data.is_bookmarked);
163 }
164 
CompareFaviconDataToSpecifics(const TestFaviconData & test_data,const sync_pb::EntitySpecifics & specifics)165 testing::AssertionResult CompareFaviconDataToSpecifics(
166     const TestFaviconData& test_data,
167     const sync_pb::EntitySpecifics& specifics) {
168   if (specifics.has_favicon_image()) {
169     sync_pb::FaviconImageSpecifics image_specifics = specifics.favicon_image();
170     if (image_specifics.favicon_url() != test_data.icon_url.spec())
171       return testing::AssertionFailure() << "Image icon url doesn't match.";
172     if (!test_data.image_16.empty()) {
173       if (image_specifics.favicon_web().favicon() != test_data.image_16 ||
174           image_specifics.favicon_web().height() != 16 ||
175           image_specifics.favicon_web().width() != 16) {
176         return testing::AssertionFailure() << "16p image data doesn't match.";
177       }
178     } else if (image_specifics.has_favicon_web()) {
179       return testing::AssertionFailure() << "Missing 16p favicon.";
180     }
181     if (!test_data.image_32.empty()) {
182       if (image_specifics.favicon_web_32().favicon() != test_data.image_32 ||
183           image_specifics.favicon_web().height() != 32 ||
184           image_specifics.favicon_web().width() != 32) {
185         return testing::AssertionFailure() << "32p image data doesn't match.";
186       }
187     } else if (image_specifics.has_favicon_web_32()) {
188       return testing::AssertionFailure() << "Missing 32p favicon.";
189     }
190     if (!test_data.image_64.empty()) {
191       if (image_specifics.favicon_touch_64().favicon() != test_data.image_64 ||
192           image_specifics.favicon_web().height() != 64 ||
193           image_specifics.favicon_web().width() != 64) {
194         return testing::AssertionFailure() << "64p image data doesn't match.";
195       }
196     } else if (image_specifics.has_favicon_touch_64()) {
197       return testing::AssertionFailure() << "Missing 64p favicon.";
198     }
199   } else {
200     sync_pb::FaviconTrackingSpecifics tracking_specifics =
201         specifics.favicon_tracking();
202     if (tracking_specifics.favicon_url() != test_data.icon_url.spec())
203       return testing::AssertionFailure() << "Tracking icon url doesn't match.";
204     if (tracking_specifics.last_visit_time_ms() !=
205         syncer::TimeToProtoTime(test_data.last_visit_time)) {
206       return testing::AssertionFailure() << "Visit time doesn't match.";
207     }
208     if (tracking_specifics.is_bookmarked() != test_data.is_bookmarked)
209       return testing::AssertionFailure() << "Bookmark status doesn't match.";
210   }
211   return testing::AssertionSuccess();
212 }
213 
VerifyChanges(syncer::ModelType expected_model_type,const std::vector<syncer::SyncChange::SyncChangeType> & expected_change_types,const std::vector<int> & expected_icons,const syncer::SyncChangeList & change_list)214 testing::AssertionResult VerifyChanges(
215     syncer::ModelType expected_model_type,
216     const std::vector<syncer::SyncChange::SyncChangeType>&
217         expected_change_types,
218     const std::vector<int>& expected_icons,
219     const syncer::SyncChangeList& change_list) {
220   DCHECK_EQ(expected_change_types.size(), expected_icons.size());
221   if (change_list.size() != expected_icons.size())
222     return testing::AssertionFailure() << "Change list size doesn't match.";
223   for (size_t i = 0; i < expected_icons.size(); ++i) {
224     TestFaviconData data = BuildFaviconData(expected_icons[i]);
225     if (change_list[i].sync_data().GetDataType() != expected_model_type)
226       return testing::AssertionFailure() << "Change datatype doesn't match.";
227     if (change_list[i].change_type() != expected_change_types[i])
228       return testing::AssertionFailure() << "Change type doesn't match.";
229     if (change_list[i].change_type() == syncer::SyncChange::ACTION_DELETE) {
230       if (syncer::SyncDataLocal(change_list[i].sync_data()).GetTag() !=
231           data.icon_url.spec())
232         return testing::AssertionFailure() << "Deletion url does not match.";
233     } else {
234       testing::AssertionResult compare_result =
235           CompareFaviconDataToSpecifics(
236               data,
237               change_list[i].sync_data().GetSpecifics());
238       if (!compare_result)
239         return compare_result;
240     }
241   }
242   return testing::AssertionSuccess();
243 }
244 
245 // Helper to extract the favicon id embedded in the tag of a sync
246 // change.
GetFaviconId(const syncer::SyncChange change)247 int GetFaviconId(const syncer::SyncChange change) {
248   std::string tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
249   const std::string kPrefix = "http://bla.com/";
250   const std::string kSuffix = ".ico";
251   if (!base::StartsWith(tag, kPrefix, base::CompareCase::SENSITIVE))
252     return -1;
253   std::string temp = tag.substr(kPrefix.length());
254   if (temp.rfind(kSuffix) <= 0)
255     return -1;
256   temp = temp.substr(0, temp.rfind(kSuffix));
257   int result = -1;
258   if (!base::StringToInt(temp, &result))
259     return -1;
260   return result;
261 }
262 
263 }  // namespace
264 
265 class SyncFaviconCacheTest : public testing::Test {
266  public:
267   SyncFaviconCacheTest();
~SyncFaviconCacheTest()268   ~SyncFaviconCacheTest() override {}
269 
270   void SetUpInitialSync(const syncer::SyncDataList& initial_image_data,
271                         const syncer::SyncDataList& initial_tracking_data);
272 
273   size_t GetFaviconCount() const;
274   size_t GetTaskCount() const;
275 
276   testing::AssertionResult ExpectFaviconEquals(
277         const std::string& page_url,
278         const std::string& bytes) const;
279   testing::AssertionResult VerifyLocalIcons(
280       const std::vector<int>& expected_icons);
281   testing::AssertionResult VerifyLocalCustomIcons(
282       const std::vector<TestFaviconData>& expected_icons);
283 
284   std::unique_ptr<syncer::SyncChangeProcessor> CreateAndPassProcessor();
285   std::unique_ptr<syncer::SyncErrorFactory> CreateAndPassSyncErrorFactory();
286 
cache()287   FaviconCache* cache() { return &cache_; }
processor()288   TestChangeProcessor* processor() { return sync_processor_.get(); }
289 
290   // Populates the local cache of favicons in FaviconService with the data
291   // described in |test_data|.
292   void PopulateFaviconService(const TestFaviconData& test_data);
293 
294   // Helper method to run the message loop after invoking
295   // OnReceivedSyncFavicon, which posts an internal task.
296   void TriggerSyncFaviconReceived(
297       const GURL& page_url,
298       const GURL& icon_url,
299       const std::string& icon_bytes,
300       base::Time last_visit_time = base::Time::Now());
301 
RunUntilIdle()302   void RunUntilIdle() { task_environment_.RunUntilIdle(); }
303 
304  private:
305   base::test::SingleThreadTaskEnvironment task_environment_;
306   testing::NiceMock<favicon::MockFaviconService> mock_favicon_service_;
307   FaviconCache cache_;
308 
309   // Our dummy ChangeProcessor used to inspect changes pushed to Sync.
310   std::unique_ptr<TestChangeProcessor> sync_processor_;
311   std::unique_ptr<syncer::SyncChangeProcessorWrapperForTest>
312       sync_processor_wrapper_;
313 };
314 
SyncFaviconCacheTest()315 SyncFaviconCacheTest::SyncFaviconCacheTest()
316     : task_environment_(
317           base::test::SingleThreadTaskEnvironment::MainThreadType::UI),
318       cache_(&mock_favicon_service_, nullptr, kMaxSyncFavicons),
319       sync_processor_(new TestChangeProcessor),
320       sync_processor_wrapper_(new syncer::SyncChangeProcessorWrapperForTest(
321           sync_processor_.get())) {}
322 
SetUpInitialSync(const syncer::SyncDataList & initial_image_data,const syncer::SyncDataList & initial_tracking_data)323 void SyncFaviconCacheTest::SetUpInitialSync(
324     const syncer::SyncDataList& initial_image_data,
325     const syncer::SyncDataList& initial_tracking_data) {
326   cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
327                                     initial_image_data,
328                                     CreateAndPassProcessor(),
329                                     CreateAndPassSyncErrorFactory());
330   ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
331   cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
332                                     initial_tracking_data,
333                                     CreateAndPassProcessor(),
334                                     CreateAndPassSyncErrorFactory());
335   ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
336 }
337 
GetFaviconCount() const338 size_t SyncFaviconCacheTest::GetFaviconCount() const {
339   return cache_.NumFaviconsForTest();
340 }
341 
GetTaskCount() const342 size_t SyncFaviconCacheTest::GetTaskCount() const {
343   return cache_.NumTasksForTest();
344 }
345 
ExpectFaviconEquals(const std::string & page_url,const std::string & bytes) const346 testing::AssertionResult SyncFaviconCacheTest::ExpectFaviconEquals(
347     const std::string& page_url,
348     const std::string& bytes) const {
349   GURL gurl(page_url);
350   favicon_base::FaviconRawBitmapResult favicon =
351       cache_.GetSyncedFaviconForPageURL(gurl);
352   if (!favicon.is_valid())
353     return testing::AssertionFailure() << "Favicon is missing.";
354   if (favicon.bitmap_data->size() != bytes.size())
355     return testing::AssertionFailure() << "Favicon sizes don't match.";
356   for (size_t i = 0; i < favicon.bitmap_data->size(); ++i) {
357     if (bytes[i] != *(favicon.bitmap_data->front() + i))
358       return testing::AssertionFailure() << "Favicon data doesn't match.";
359   }
360   return testing::AssertionSuccess();
361 }
362 
VerifyLocalIcons(const std::vector<int> & expected_icons)363 testing::AssertionResult SyncFaviconCacheTest::VerifyLocalIcons(
364     const std::vector<int>& expected_icons) {
365   std::vector<TestFaviconData> expected_custom_icons;
366   for (size_t i = 0; i < expected_icons.size(); ++i) {
367     expected_custom_icons.push_back(BuildFaviconData(expected_icons[i]));
368   }
369   return VerifyLocalCustomIcons(expected_custom_icons);
370 }
371 
372 
VerifyLocalCustomIcons(const std::vector<TestFaviconData> & expected_custom_icons)373 testing::AssertionResult SyncFaviconCacheTest::VerifyLocalCustomIcons(
374     const std::vector<TestFaviconData>& expected_custom_icons) {
375   syncer::SyncDataList image_data_list =
376       cache()->GetAllSyncDataForTesting(syncer::FAVICON_IMAGES);
377   syncer::SyncDataList tracking_data_list =
378       cache()->GetAllSyncDataForTesting(syncer::FAVICON_TRACKING);
379   if (expected_custom_icons.size() > image_data_list.size() ||
380       expected_custom_icons.size() > tracking_data_list.size())
381     return testing::AssertionFailure() << "Number of icons doesn't match.";
382   for (size_t i = 0; i < expected_custom_icons.size(); ++i) {
383     const TestFaviconData& test_data = expected_custom_icons[i];
384     // Find the test data in the data lists. Assume that both lists have the
385     // same ordering, which may not match the |expected_custom_icons| ordering.
386     bool found_match = false;
387     for (size_t j = 0; j < image_data_list.size(); ++j) {
388       if (image_data_list[j].GetTitle() != test_data.icon_url.spec())
389         continue;
390       found_match = true;
391       const sync_pb::FaviconImageSpecifics& image_specifics =
392           image_data_list[j].GetSpecifics().favicon_image();
393       sync_pb::FaviconImageSpecifics expected_image_specifics;
394       FillImageSpecifics(test_data, &expected_image_specifics);
395       if (image_specifics.SerializeAsString() !=
396           expected_image_specifics.SerializeAsString()) {
397         return testing::AssertionFailure() << "Image data doesn't match.";
398       }
399       const sync_pb::FaviconTrackingSpecifics& tracking_specifics =
400           tracking_data_list[j].GetSpecifics().favicon_tracking();
401       sync_pb::FaviconTrackingSpecifics expected_tracking_specifics;
402       FillTrackingSpecifics(test_data, &expected_tracking_specifics);
403       if (tracking_specifics.SerializeAsString() !=
404           expected_tracking_specifics.SerializeAsString()) {
405         return testing::AssertionFailure() << "Tracking data doesn't match.";
406       }
407     }
408     if (!found_match)
409       return testing::AssertionFailure() << "Could not find favicon.";
410   }
411   return testing::AssertionSuccess();
412 }
413 
414 std::unique_ptr<syncer::SyncChangeProcessor>
CreateAndPassProcessor()415 SyncFaviconCacheTest::CreateAndPassProcessor() {
416   return std::make_unique<syncer::SyncChangeProcessorWrapperForTest>(
417       sync_processor_.get());
418 }
419 
420 std::unique_ptr<syncer::SyncErrorFactory>
CreateAndPassSyncErrorFactory()421 SyncFaviconCacheTest::CreateAndPassSyncErrorFactory() {
422   return std::make_unique<syncer::SyncErrorFactoryMock>();
423 }
424 
PopulateFaviconService(const TestFaviconData & test_data)425 void SyncFaviconCacheTest::PopulateFaviconService(
426     const TestFaviconData& test_data) {
427   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
428   if (!test_data.image_16.empty()) {
429     favicon_base::FaviconRawBitmapResult bitmap_result;
430     bitmap_result.icon_url = test_data.icon_url;
431     bitmap_result.pixel_size.set_width(16);
432     bitmap_result.pixel_size.set_height(16);
433     base::RefCountedString* temp_string = new base::RefCountedString();
434     temp_string->data() = test_data.image_16;
435     bitmap_result.bitmap_data = temp_string;
436     bitmap_results.push_back(bitmap_result);
437   }
438   if (!test_data.image_32.empty()) {
439     favicon_base::FaviconRawBitmapResult bitmap_result;
440     bitmap_result.icon_url = test_data.icon_url;
441     bitmap_result.pixel_size.set_width(32);
442     bitmap_result.pixel_size.set_height(32);
443     base::RefCountedString* temp_string = new base::RefCountedString();
444     temp_string->data() = test_data.image_32;
445     bitmap_result.bitmap_data = temp_string;
446     bitmap_results.push_back(bitmap_result);
447   }
448   if (!test_data.image_64.empty()) {
449     favicon_base::FaviconRawBitmapResult bitmap_result;
450     bitmap_result.icon_url = test_data.icon_url;
451     bitmap_result.pixel_size.set_width(64);
452     bitmap_result.pixel_size.set_height(64);
453     base::RefCountedString* temp_string = new base::RefCountedString();
454     temp_string->data() = test_data.image_64;
455     bitmap_result.bitmap_data = temp_string;
456     bitmap_results.push_back(bitmap_result);
457   }
458 
459   ON_CALL(mock_favicon_service_,
460           GetFaviconForPageURL(test_data.page_url, _, _, _, _))
461       .WillByDefault([=](auto, auto, auto,
462                          favicon_base::FaviconResultsCallback callback,
463                          base::CancelableTaskTracker* tracker) {
464         return tracker->PostTask(
465             base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
466             base::BindOnce(std::move(callback), bitmap_results));
467       });
468 }
469 
TriggerSyncFaviconReceived(const GURL & page_url,const GURL & icon_url,const std::string & icon_bytes,base::Time last_visit_time)470 void SyncFaviconCacheTest::TriggerSyncFaviconReceived(
471     const GURL& page_url,
472     const GURL& icon_url,
473     const std::string& icon_bytes,
474     base::Time last_visit_time) {
475   if (!icon_bytes.empty()) {
476     scoped_refptr<base::RefCountedString> temp_string(
477         new base::RefCountedString());
478     temp_string->data() = icon_bytes;
479 
480     std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
481     bitmap_results.push_back(favicon_base::FaviconRawBitmapResult());
482     bitmap_results.back().icon_url = icon_url;
483     bitmap_results.back().bitmap_data = temp_string;
484     bitmap_results.back().pixel_size = gfx::Size(16, 16);
485 
486     ON_CALL(mock_favicon_service_, GetFaviconForPageURL(page_url, _, _, _, _))
487         .WillByDefault([=](auto, auto, auto,
488                            favicon_base::FaviconResultsCallback callback,
489                            base::CancelableTaskTracker* tracker) {
490           return tracker->PostTask(
491               base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
492               base::BindOnce(std::move(callback), bitmap_results));
493         });
494 
495     // Mimic the icon itself having been cached long time ago.
496     cache()->OnPageFaviconUpdated(page_url, base::Time::UnixEpoch());
497     // Wait until the FaviconService replies with the result above.
498     RunUntilIdle();
499   }
500 
501   // Feed in the mapping.
502   sync_pb::SessionTab tab;
503   sync_pb::TabNavigation* navigation = tab.add_navigation();
504   navigation->set_virtual_url(page_url.spec());
505   navigation->set_favicon_url(icon_url.spec());
506   cache()->UpdateMappingsFromForeignTab(tab, last_visit_time);
507 }
508 
509 // A freshly constructed cache should be empty.
TEST_F(SyncFaviconCacheTest,Empty)510 TEST_F(SyncFaviconCacheTest, Empty) {
511   EXPECT_EQ(0U, GetFaviconCount());
512 }
513 
TEST_F(SyncFaviconCacheTest,ReceiveSyncFavicon)514 TEST_F(SyncFaviconCacheTest, ReceiveSyncFavicon) {
515   std::string page_url = "http://www.google.com";
516   std::string fav_url = "http://www.google.com/favicon.ico";
517   std::string bytes = "bytes";
518   const base::Time visit_time = base::Time::Now();
519   EXPECT_EQ(0U, GetFaviconCount());
520   TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes, visit_time);
521   EXPECT_EQ(1U, GetFaviconCount());
522   EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
523   EXPECT_EQ(visit_time, cache()->GetLastVisitTimeForTest(GURL(fav_url)));
524 }
525 
TEST_F(SyncFaviconCacheTest,ReceiveEmptySyncFavicon)526 TEST_F(SyncFaviconCacheTest, ReceiveEmptySyncFavicon) {
527   std::string page_url = "http://www.google.com";
528   std::string fav_url = "http://www.google.com/favicon.ico";
529   std::string bytes = "bytes";
530   EXPECT_EQ(0U, GetFaviconCount());
531   TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), std::string());
532   EXPECT_EQ(0U, GetFaviconCount());
533   EXPECT_FALSE(ExpectFaviconEquals(page_url, std::string()));
534 
535   // Then receive the actual favicon.
536   TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes);
537   EXPECT_EQ(1U, GetFaviconCount());
538   EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
539 }
540 
TEST_F(SyncFaviconCacheTest,ReceiveUpdatedSyncFavicon)541 TEST_F(SyncFaviconCacheTest, ReceiveUpdatedSyncFavicon) {
542   std::string page_url = "http://www.google.com";
543   std::string fav_url = "http://www.google.com/favicon.ico";
544   std::string bytes = "bytes";
545   std::string bytes2 = "bytes2";
546   EXPECT_EQ(0U, GetFaviconCount());
547   TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes);
548   EXPECT_EQ(1U, GetFaviconCount());
549   EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
550 
551   // The cache should not update existing favicons from tab sync favicons
552   // (which can be reassociated several times).
553   TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes2);
554   EXPECT_EQ(1U, GetFaviconCount());
555   EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
556   EXPECT_FALSE(ExpectFaviconEquals(page_url, bytes2));
557 }
558 
TEST_F(SyncFaviconCacheTest,MultipleMappings)559 TEST_F(SyncFaviconCacheTest, MultipleMappings) {
560   std::string page_url = "http://www.google.com";
561   std::string page2_url = "http://bla.google.com";
562   std::string fav_url = "http://www.google.com/favicon.ico";
563   std::string bytes = "bytes";
564   EXPECT_EQ(0U, GetFaviconCount());
565   TriggerSyncFaviconReceived(GURL(page_url), GURL(fav_url), bytes);
566   EXPECT_EQ(1U, GetFaviconCount());
567   EXPECT_TRUE(ExpectFaviconEquals(page_url, bytes));
568 
569   // Map another page to the same favicon. They should share the same data.
570   TriggerSyncFaviconReceived(GURL(page2_url), GURL(fav_url), bytes);
571   EXPECT_EQ(1U, GetFaviconCount());
572   EXPECT_TRUE(ExpectFaviconEquals(page2_url, bytes));
573 }
574 
TEST_F(SyncFaviconCacheTest,SyncEmpty)575 TEST_F(SyncFaviconCacheTest, SyncEmpty) {
576   syncer::SyncMergeResult merge_result =
577       cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
578                                         syncer::SyncDataList(),
579                                         CreateAndPassProcessor(),
580                                         CreateAndPassSyncErrorFactory());
581 
582   EXPECT_EQ(0U,
583             cache()->GetAllSyncDataForTesting(syncer::FAVICON_IMAGES).size());
584   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
585   EXPECT_EQ(0, merge_result.num_items_added());
586   EXPECT_EQ(0, merge_result.num_items_modified());
587   EXPECT_EQ(0, merge_result.num_items_deleted());
588   EXPECT_EQ(0, merge_result.num_items_before_association());
589   EXPECT_EQ(0, merge_result.num_items_after_association());
590 
591   merge_result =
592       cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
593                                         syncer::SyncDataList(),
594                                         CreateAndPassProcessor(),
595                                         CreateAndPassSyncErrorFactory());
596 
597   EXPECT_EQ(0U,
598             cache()->GetAllSyncDataForTesting(syncer::FAVICON_TRACKING).size());
599   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
600   EXPECT_EQ(0, merge_result.num_items_added());
601   EXPECT_EQ(0, merge_result.num_items_modified());
602   EXPECT_EQ(0, merge_result.num_items_deleted());
603   EXPECT_EQ(0, merge_result.num_items_before_association());
604   EXPECT_EQ(0, merge_result.num_items_after_association());
605 }
606 
607 // Setting up sync with existing local favicons should push those favicons into
608 // sync.
TEST_F(SyncFaviconCacheTest,SyncExistingLocal)609 TEST_F(SyncFaviconCacheTest, SyncExistingLocal) {
610   std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
611   std::vector<int> expected_icons;
612   for (int i = 0; i < kFaviconBatchSize; ++i) {
613     TestFaviconData favicon = BuildFaviconData(i);
614     TriggerSyncFaviconReceived(favicon.page_url, favicon.icon_url,
615                                favicon.image_16, syncer::ProtoTimeToTime(i));
616     expected_change_types.push_back(syncer::SyncChange::ACTION_ADD);
617     expected_icons.push_back(i);
618   }
619 
620   syncer::SyncMergeResult merge_result =
621       cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
622                                         syncer::SyncDataList(),
623                                         CreateAndPassProcessor(),
624                                         CreateAndPassSyncErrorFactory());
625   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
626             cache()->GetAllSyncDataForTesting(syncer::FAVICON_IMAGES).size());
627   syncer::SyncChangeList change_list = processor()->GetAndResetChangeList();
628   EXPECT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES,
629                             expected_change_types,
630                             expected_icons,
631                             change_list));
632   EXPECT_EQ(0, merge_result.num_items_added());
633   EXPECT_EQ(0, merge_result.num_items_modified());
634   EXPECT_EQ(0, merge_result.num_items_deleted());
635   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
636   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
637 
638   merge_result =
639       cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
640                                         syncer::SyncDataList(),
641                                         CreateAndPassProcessor(),
642                                         CreateAndPassSyncErrorFactory());
643   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
644             cache()->GetAllSyncDataForTesting(syncer::FAVICON_TRACKING).size());
645   change_list = processor()->GetAndResetChangeList();
646   EXPECT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING,
647                             expected_change_types,
648                             expected_icons,
649                             change_list));
650   EXPECT_EQ(0, merge_result.num_items_added());
651   EXPECT_EQ(0, merge_result.num_items_modified());
652   EXPECT_EQ(0, merge_result.num_items_deleted());
653   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
654   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
655 }
656 
657 // Setting up sync with existing sync data should load that data into the local
658 // cache.
TEST_F(SyncFaviconCacheTest,SyncExistingRemote)659 TEST_F(SyncFaviconCacheTest, SyncExistingRemote) {
660   syncer::SyncDataList initial_image_data, initial_tracking_data;
661   std::vector<int> expected_icons;
662   for (int i = 0; i < kFaviconBatchSize; ++i) {
663     expected_icons.push_back(i);
664     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
665     FillImageSpecifics(BuildFaviconData(i),
666                        image_specifics.mutable_favicon_image());
667     initial_image_data.push_back(
668         syncer::SyncData::CreateRemoteData(1, image_specifics));
669     FillTrackingSpecifics(BuildFaviconData(i),
670                           tracking_specifics.mutable_favicon_tracking());
671     initial_tracking_data.push_back(
672         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
673   }
674 
675   syncer::SyncMergeResult merge_result =
676       cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
677                                         initial_image_data,
678                                         CreateAndPassProcessor(),
679                                         CreateAndPassSyncErrorFactory());
680   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
681             cache()->GetAllSyncDataForTesting(syncer::FAVICON_IMAGES).size());
682   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
683   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_added());
684   EXPECT_EQ(0, merge_result.num_items_modified());
685   EXPECT_EQ(0, merge_result.num_items_deleted());
686   EXPECT_EQ(0, merge_result.num_items_before_association());
687   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
688 
689   merge_result =
690       cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
691                                         initial_tracking_data,
692                                         CreateAndPassProcessor(),
693                                         CreateAndPassSyncErrorFactory());
694   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
695             cache()->GetAllSyncDataForTesting(syncer::FAVICON_TRACKING).size());
696   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
697   EXPECT_EQ(0, merge_result.num_items_added());
698   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
699   EXPECT_EQ(0, merge_result.num_items_deleted());
700   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
701   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
702 
703   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
704 }
705 
706 // Setting up sync with local data and sync data should merge the two image
707 // sets, with remote data having priority in case both exist.
TEST_F(SyncFaviconCacheTest,SyncMergesImages)708 TEST_F(SyncFaviconCacheTest, SyncMergesImages) {
709   // First go through and add local 16p favicons.
710   for (int i = 0; i < kFaviconBatchSize; ++i) {
711     TestFaviconData favicon = BuildFaviconData(i);
712     TriggerSyncFaviconReceived(favicon.page_url, favicon.icon_url,
713                                favicon.image_16, syncer::ProtoTimeToTime(i));
714   }
715 
716   // Then go through and create the initial sync data, which does not have 16p
717   // favicons for the first half, and has custom 16p favicons for the second.
718   std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
719   std::vector<int> expected_icons;
720   std::vector<TestFaviconData> expected_data;
721   syncer::SyncDataList initial_image_data, initial_tracking_data;
722   for (int i = 0; i < kFaviconBatchSize; ++i) {
723     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
724     TestFaviconData test_data = BuildFaviconData(i);
725     if (i < kFaviconBatchSize/2) {
726       test_data.image_16 = std::string();
727       expected_icons.push_back(i);
728       expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
729     } else {
730       test_data.image_16 += "custom";
731       expected_data.push_back(test_data);
732     }
733     FillImageSpecifics(test_data,
734                        image_specifics.mutable_favicon_image());
735 
736     initial_image_data.push_back(
737         syncer::SyncData::CreateRemoteData(1, image_specifics));
738     FillTrackingSpecifics(test_data,
739                           tracking_specifics.mutable_favicon_tracking());
740     initial_tracking_data.push_back(
741         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
742   }
743 
744   syncer::SyncMergeResult merge_result =
745       cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
746                                         initial_image_data,
747                                         CreateAndPassProcessor(),
748                                         CreateAndPassSyncErrorFactory());
749   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
750             cache()->GetAllSyncDataForTesting(syncer::FAVICON_IMAGES).size());
751   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
752   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize)/2, changes.size());
753   EXPECT_EQ(0, merge_result.num_items_added());
754   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
755   EXPECT_EQ(0, merge_result.num_items_deleted());
756   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
757   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
758 
759   merge_result =
760       cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
761                                         initial_tracking_data,
762                                         CreateAndPassProcessor(),
763                                         CreateAndPassSyncErrorFactory());
764   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
765             cache()->GetAllSyncDataForTesting(syncer::FAVICON_TRACKING).size());
766   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
767   EXPECT_EQ(0, merge_result.num_items_added());
768   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
769   EXPECT_EQ(0, merge_result.num_items_deleted());
770   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
771   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
772 
773   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
774   ASSERT_TRUE(VerifyLocalCustomIcons(expected_data));
775   ASSERT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES,
776                             expected_change_types,
777                             expected_icons,
778                             changes));
779 }
780 
781 // Setting up sync with local data and sync data should merge the two tracking
782 // sets, such that the visit time is the most recent.
TEST_F(SyncFaviconCacheTest,SyncMergesTracking)783 TEST_F(SyncFaviconCacheTest, SyncMergesTracking) {
784   // First go through and add local 16p favicons.
785   for (int i = 0; i < kFaviconBatchSize; ++i) {
786     TestFaviconData favicon = BuildFaviconData(i);
787     TriggerSyncFaviconReceived(favicon.page_url, favicon.icon_url,
788                                favicon.image_16, syncer::ProtoTimeToTime(i));
789   }
790 
791   // Then go through and create the initial sync data, which for the first half
792   // the local has a newer visit, and for the second the remote does.
793   std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
794   std::vector<int> expected_icons;
795   std::vector<TestFaviconData> expected_data;
796   syncer::SyncDataList initial_image_data, initial_tracking_data;
797   for (int i = 0; i < kFaviconBatchSize; ++i) {
798     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
799     TestFaviconData test_data = BuildFaviconData(i);
800     if (i < kFaviconBatchSize/2) {
801       test_data.last_visit_time = syncer::ProtoTimeToTime(i - 1);
802       expected_icons.push_back(i);
803       expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
804     } else {
805       test_data.last_visit_time = syncer::ProtoTimeToTime(i + 1);
806       expected_data.push_back(test_data);
807     }
808     FillImageSpecifics(test_data,
809                        image_specifics.mutable_favicon_image());
810 
811     initial_image_data.push_back(
812         syncer::SyncData::CreateRemoteData(1, image_specifics));
813     FillTrackingSpecifics(test_data,
814                           tracking_specifics.mutable_favicon_tracking());
815     initial_tracking_data.push_back(
816         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
817   }
818 
819   syncer::SyncMergeResult merge_result =
820       cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
821                                         initial_image_data,
822                                         CreateAndPassProcessor(),
823                                         CreateAndPassSyncErrorFactory());
824   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
825             cache()->GetAllSyncDataForTesting(syncer::FAVICON_IMAGES).size());
826   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
827   EXPECT_EQ(0, merge_result.num_items_added());
828   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
829   EXPECT_EQ(0, merge_result.num_items_deleted());
830   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
831   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
832 
833   merge_result =
834       cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
835                                         initial_tracking_data,
836                                         CreateAndPassProcessor(),
837                                         CreateAndPassSyncErrorFactory());
838   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize),
839             cache()->GetAllSyncDataForTesting(syncer::FAVICON_TRACKING).size());
840   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
841   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize)/2, changes.size());
842   EXPECT_EQ(0, merge_result.num_items_added());
843   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_modified());
844   EXPECT_EQ(0, merge_result.num_items_deleted());
845   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_before_association());
846   EXPECT_EQ(kFaviconBatchSize, merge_result.num_items_after_association());
847 
848   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
849   ASSERT_TRUE(VerifyLocalCustomIcons(expected_data));
850   ASSERT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING,
851                             expected_change_types,
852                             expected_icons,
853                             changes));
854 }
855 
856 // Receiving old icons (missing image data) should result in pushing the new
857 // merged icons back to the remote syncer.
TEST_F(SyncFaviconCacheTest,ReceiveStaleImages)858 TEST_F(SyncFaviconCacheTest, ReceiveStaleImages) {
859   syncer::SyncDataList initial_image_data, initial_tracking_data;
860   syncer::SyncChangeList stale_changes;
861   std::vector<int> expected_icons;
862   std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
863   for (int i = 0; i < kFaviconBatchSize; ++i) {
864     expected_icons.push_back(i);
865     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
866     FillImageSpecifics(BuildFaviconData(i),
867                        image_specifics.mutable_favicon_image());
868     initial_image_data.push_back(
869         syncer::SyncData::CreateRemoteData(1, image_specifics));
870     expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
871     image_specifics.mutable_favicon_image()->clear_favicon_web();
872     stale_changes.push_back(syncer::SyncChange(
873         FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
874         syncer::SyncData::CreateRemoteData(1, image_specifics)));
875     FillTrackingSpecifics(BuildFaviconData(i),
876                           tracking_specifics.mutable_favicon_tracking());
877     initial_tracking_data.push_back(
878         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
879   }
880 
881   SetUpInitialSync(initial_image_data, initial_tracking_data);
882 
883   // Now receive the same icons as an update, but with missing image data.
884   cache()->ProcessSyncChanges(FROM_HERE, stale_changes);
885   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
886   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
887   ASSERT_EQ(static_cast<size_t>(kFaviconBatchSize), changes.size());
888   ASSERT_TRUE(VerifyChanges(syncer::FAVICON_IMAGES,
889                             expected_change_types,
890                             expected_icons,
891                             changes));
892 }
893 
894 // New icons should be added locally without pushing anything back to the
895 // remote syncer.
TEST_F(SyncFaviconCacheTest,ReceiveNewImages)896 TEST_F(SyncFaviconCacheTest, ReceiveNewImages) {
897   syncer::SyncDataList initial_image_data, initial_tracking_data;
898   syncer::SyncChangeList new_changes;
899   std::vector<int> expected_icons;
900   for (int i = 0; i < kFaviconBatchSize; ++i) {
901     expected_icons.push_back(i);
902     TestFaviconData test_data = BuildFaviconData(i);
903     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
904     FillImageSpecifics(test_data,
905                        image_specifics.mutable_favicon_image());
906     new_changes.push_back(syncer::SyncChange(
907         FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
908         syncer::SyncData::CreateRemoteData(1, image_specifics)));
909     image_specifics.mutable_favicon_image()
910         ->mutable_favicon_web()
911         ->mutable_favicon()
912         ->append("old");
913     initial_image_data.push_back(
914         syncer::SyncData::CreateRemoteData(1, image_specifics));
915     FillTrackingSpecifics(BuildFaviconData(i),
916                           tracking_specifics.mutable_favicon_tracking());
917     initial_tracking_data.push_back(
918         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
919   }
920 
921   SetUpInitialSync(initial_image_data, initial_tracking_data);
922 
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));
927 }
928 
929 // Recieving the same icons as the local data should have no effect.
TEST_F(SyncFaviconCacheTest,ReceiveSameImages)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(syncer::SyncChange(
941         FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
942         syncer::SyncData::CreateRemoteData(1, image_specifics)));
943     initial_image_data.push_back(
944         syncer::SyncData::CreateRemoteData(1, image_specifics));
945     FillTrackingSpecifics(BuildFaviconData(i),
946                           tracking_specifics.mutable_favicon_tracking());
947     initial_tracking_data.push_back(
948         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
949   }
950 
951   SetUpInitialSync(initial_image_data, initial_tracking_data);
952 
953   // Now receive the new icons as an update.
954   cache()->ProcessSyncChanges(FROM_HERE, same_changes);
955   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
956   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
957 }
958 
959 // Receiving stale tracking (old visit times) should result in pushing back
960 // the newer visit times to the remote syncer.
TEST_F(SyncFaviconCacheTest,ReceiveStaleTracking)961 TEST_F(SyncFaviconCacheTest, ReceiveStaleTracking) {
962   syncer::SyncDataList initial_image_data, initial_tracking_data;
963   syncer::SyncChangeList stale_changes;
964   std::vector<int> expected_icons;
965   std::vector<syncer::SyncChange::SyncChangeType> expected_change_types;
966   for (int i = 0; i < kFaviconBatchSize; ++i) {
967     expected_icons.push_back(i);
968     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
969     FillImageSpecifics(BuildFaviconData(i),
970                        image_specifics.mutable_favicon_image());
971     initial_image_data.push_back(
972         syncer::SyncData::CreateRemoteData(1, image_specifics));
973     expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE);
974     FillTrackingSpecifics(BuildFaviconData(i),
975                           tracking_specifics.mutable_favicon_tracking());
976     initial_tracking_data.push_back(
977         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
978     tracking_specifics.mutable_favicon_tracking()->set_last_visit_time_ms(-1);
979     stale_changes.push_back(syncer::SyncChange(
980         FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
981         syncer::SyncData::CreateRemoteData(1, tracking_specifics)));
982   }
983 
984   SetUpInitialSync(initial_image_data, initial_tracking_data);
985 
986   // Now receive the same icons as an update, but with missing image data.
987   cache()->ProcessSyncChanges(FROM_HERE, stale_changes);
988   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
989   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
990   ASSERT_EQ(static_cast<size_t>(kFaviconBatchSize), changes.size());
991   ASSERT_TRUE(VerifyChanges(syncer::FAVICON_TRACKING,
992                             expected_change_types,
993                             expected_icons,
994                             changes));
995 }
996 
997 // New tracking information should be added locally without pushing anything
998 // back to the remote syncer.
TEST_F(SyncFaviconCacheTest,ReceiveNewTracking)999 TEST_F(SyncFaviconCacheTest, ReceiveNewTracking) {
1000   syncer::SyncDataList initial_image_data, initial_tracking_data;
1001   syncer::SyncChangeList new_changes;
1002   std::vector<int> expected_icons;
1003   // We start from one here so that we don't have to deal with a -1 visit time.
1004   for (int i = 1; i <= kFaviconBatchSize; ++i) {
1005     expected_icons.push_back(i);
1006     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1007     FillImageSpecifics(BuildFaviconData(i),
1008                        image_specifics.mutable_favicon_image());
1009     initial_image_data.push_back(
1010         syncer::SyncData::CreateRemoteData(1, image_specifics));
1011     FillTrackingSpecifics(BuildFaviconData(i),
1012                           tracking_specifics.mutable_favicon_tracking());
1013     new_changes.push_back(syncer::SyncChange(
1014         FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
1015         syncer::SyncData::CreateRemoteData(1, tracking_specifics)));
1016     tracking_specifics.mutable_favicon_tracking()->set_last_visit_time_ms(i-1);
1017     initial_tracking_data.push_back(
1018         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1019   }
1020 
1021   SetUpInitialSync(initial_image_data, initial_tracking_data);
1022 
1023   // Now receive the new icons as an update.
1024   cache()->ProcessSyncChanges(FROM_HERE, new_changes);
1025   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1026   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
1027 }
1028 
1029 // Receiving the same tracking information as the local data should have no
1030 // effect.
TEST_F(SyncFaviconCacheTest,ReceiveSameTracking)1031 TEST_F(SyncFaviconCacheTest, ReceiveSameTracking) {
1032   syncer::SyncDataList initial_image_data, initial_tracking_data;
1033   syncer::SyncChangeList same_changes;
1034   std::vector<int> expected_icons;
1035   for (int i = 0; i < kFaviconBatchSize; ++i) {
1036     expected_icons.push_back(i);
1037     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1038     FillImageSpecifics(BuildFaviconData(i),
1039                        image_specifics.mutable_favicon_image());
1040     initial_image_data.push_back(
1041         syncer::SyncData::CreateRemoteData(1, image_specifics));
1042     FillTrackingSpecifics(BuildFaviconData(i),
1043                           tracking_specifics.mutable_favicon_tracking());
1044     initial_tracking_data.push_back(
1045         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1046     same_changes.push_back(syncer::SyncChange(
1047         FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
1048         syncer::SyncData::CreateRemoteData(1, tracking_specifics)));
1049   }
1050 
1051   SetUpInitialSync(initial_image_data, initial_tracking_data);
1052 
1053   // Now receive the new icons as an update.
1054   cache()->ProcessSyncChanges(FROM_HERE, same_changes);
1055   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1056   ASSERT_TRUE(VerifyLocalIcons(expected_icons));
1057 }
1058 
1059 // Verify we can delete favicons after setting up sync.
TEST_F(SyncFaviconCacheTest,DeleteFavicons)1060 TEST_F(SyncFaviconCacheTest, DeleteFavicons) {
1061   syncer::SyncDataList initial_image_data, initial_tracking_data;
1062   syncer::SyncChangeList tracking_deletions, image_deletions;
1063   for (int i = 0; i < kFaviconBatchSize; ++i) {
1064     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1065     FillImageSpecifics(BuildFaviconData(i),
1066                        image_specifics.mutable_favicon_image());
1067     initial_image_data.push_back(
1068         syncer::SyncData::CreateRemoteData(1, image_specifics));
1069     FillTrackingSpecifics(BuildFaviconData(i),
1070                           tracking_specifics.mutable_favicon_tracking());
1071     initial_tracking_data.push_back(
1072         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1073     tracking_deletions.push_back(syncer::SyncChange(
1074         FROM_HERE, syncer::SyncChange::ACTION_DELETE,
1075         syncer::SyncData::CreateRemoteData(1, tracking_specifics)));
1076     image_deletions.push_back(syncer::SyncChange(
1077         FROM_HERE, syncer::SyncChange::ACTION_DELETE,
1078         syncer::SyncData::CreateRemoteData(1, image_specifics)));
1079   }
1080 
1081   SetUpInitialSync(initial_image_data, initial_tracking_data);
1082 
1083   // Now receive the tracking deletions. Since we'll still have orphan data,
1084   // the favicon count should remain the same.
1085   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1086   cache()->ProcessSyncChanges(FROM_HERE, tracking_deletions);
1087   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1088   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1089 
1090   // Once the image deletions arrive, the favicon count should be 0 again.
1091   cache()->ProcessSyncChanges(FROM_HERE, image_deletions);
1092   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1093   EXPECT_EQ(0U, GetFaviconCount());
1094 }
1095 
1096 // Ensure that MergeDataAndStartSyncing enforces the sync favicon limit by
1097 // dropping local icons.
TEST_F(SyncFaviconCacheTest,ExpireOnMergeData)1098 TEST_F(SyncFaviconCacheTest, ExpireOnMergeData) {
1099   std::vector<int> expected_icons;
1100   syncer::SyncDataList initial_image_data, initial_tracking_data;
1101 
1102   // Set up sync so it has the maximum number of favicons, while the local has
1103   // the same amount of different favicons.
1104   for (int i = 0; i < kMaxSyncFavicons; ++i) {
1105     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1106     FillImageSpecifics(BuildFaviconData(i),
1107                        image_specifics.mutable_favicon_image());
1108     initial_image_data.push_back(
1109         syncer::SyncData::CreateRemoteData(1, image_specifics));
1110     FillTrackingSpecifics(BuildFaviconData(i),
1111                           tracking_specifics.mutable_favicon_tracking());
1112     initial_tracking_data.push_back(
1113         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1114     expected_icons.push_back(i);
1115 
1116     TestFaviconData favicon = BuildFaviconData(i+kMaxSyncFavicons);
1117     TriggerSyncFaviconReceived(favicon.page_url, favicon.icon_url,
1118                                favicon.image_16,
1119                                syncer::ProtoTimeToTime(i + kMaxSyncFavicons));
1120   }
1121 
1122   EXPECT_FALSE(VerifyLocalIcons(expected_icons));
1123 
1124   // Drops image part of the unsynced icons.
1125   syncer::SyncMergeResult merge_result =
1126       cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
1127                                         initial_image_data,
1128                                         CreateAndPassProcessor(),
1129                                         CreateAndPassSyncErrorFactory());
1130   EXPECT_EQ(static_cast<size_t>(kMaxSyncFavicons)*2,
1131             GetFaviconCount());  // Still have tracking.
1132   EXPECT_EQ(static_cast<size_t>(kMaxSyncFavicons),
1133             cache()->GetAllSyncDataForTesting(syncer::FAVICON_IMAGES).size());
1134   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1135   EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_added());
1136   EXPECT_EQ(0, merge_result.num_items_modified());
1137   EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_deleted());
1138   EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_before_association());
1139   EXPECT_EQ(kMaxSyncFavicons * 2, merge_result.num_items_after_association());
1140 
1141   // Drops tracking part of the unsynced icons.
1142   merge_result =
1143       cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
1144                                         initial_tracking_data,
1145                                         CreateAndPassProcessor(),
1146                                         CreateAndPassSyncErrorFactory());
1147   EXPECT_EQ(static_cast<size_t>(kMaxSyncFavicons),
1148             cache()->GetAllSyncDataForTesting(syncer::FAVICON_TRACKING).size());
1149   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1150   EXPECT_EQ(0, merge_result.num_items_added());
1151   EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_modified());
1152   EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_deleted());
1153   EXPECT_EQ(kMaxSyncFavicons * 2, merge_result.num_items_before_association());
1154   EXPECT_EQ(kMaxSyncFavicons, merge_result.num_items_after_association());
1155 
1156   EXPECT_TRUE(VerifyLocalIcons(expected_icons));
1157 }
1158 
1159 // Receiving sync additions (via ProcessSyncChanges) should not trigger
1160 // expirations.
TEST_F(SyncFaviconCacheTest,NoExpireOnProcessSyncChanges)1161 TEST_F(SyncFaviconCacheTest, NoExpireOnProcessSyncChanges) {
1162   syncer::SyncDataList initial_image_data, initial_tracking_data;
1163   syncer::SyncChangeList image_changes, tracking_changes;
1164   std::vector<int> expected_icons;
1165   for (int i = 0; i < kMaxSyncFavicons; ++i) {
1166     expected_icons.push_back(i);
1167     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1168     FillImageSpecifics(BuildFaviconData(i),
1169                        image_specifics.mutable_favicon_image());
1170     initial_image_data.push_back(
1171         syncer::SyncData::CreateRemoteData(1, image_specifics));
1172     FillTrackingSpecifics(BuildFaviconData(i),
1173                           tracking_specifics.mutable_favicon_tracking());
1174     initial_tracking_data.push_back(
1175         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1176     // Set up new tracking specifics for the icons received at change time.
1177     expected_icons.push_back(i + kMaxSyncFavicons);
1178     FillImageSpecifics(BuildFaviconData(i + kMaxSyncFavicons),
1179                        image_specifics.mutable_favicon_image());
1180     image_changes.push_back(syncer::SyncChange(
1181         FROM_HERE, syncer::SyncChange::ACTION_ADD,
1182         syncer::SyncData::CreateRemoteData(1, image_specifics)));
1183     FillTrackingSpecifics(BuildFaviconData(i + kMaxSyncFavicons),
1184                           tracking_specifics.mutable_favicon_tracking());
1185     tracking_changes.push_back(syncer::SyncChange(
1186         FROM_HERE, syncer::SyncChange::ACTION_ADD,
1187         syncer::SyncData::CreateRemoteData(1, tracking_specifics)));
1188   }
1189 
1190   SetUpInitialSync(initial_image_data, initial_tracking_data);
1191 
1192   // Now receive the new icons as an update.
1193   EXPECT_EQ(static_cast<size_t>(kMaxSyncFavicons), GetFaviconCount());
1194   cache()->ProcessSyncChanges(FROM_HERE, image_changes);
1195   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1196   cache()->ProcessSyncChanges(FROM_HERE, tracking_changes);
1197   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1198   EXPECT_TRUE(VerifyLocalIcons(expected_icons));
1199   EXPECT_LT(static_cast<size_t>(kMaxSyncFavicons), GetFaviconCount());
1200 }
1201 
1202 // Test that visiting a new page triggers a favicon load and a sync addition.
TEST_F(SyncFaviconCacheTest,AddOnFaviconVisited)1203 TEST_F(SyncFaviconCacheTest, AddOnFaviconVisited) {
1204   EXPECT_EQ(0U, GetFaviconCount());
1205   SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1206   std::vector<int> expected_icons;
1207 
1208   for (int i = 0; i < kFaviconBatchSize; ++i) {
1209     PopulateFaviconService(BuildFaviconData(i));
1210     expected_icons.push_back(i);
1211     TestFaviconData test_data = BuildFaviconData(i);
1212     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1213   }
1214 
1215   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetTaskCount());
1216   // Wait until the FaviconService replies with the results populated above.
1217   RunUntilIdle();
1218   EXPECT_EQ(0U, GetTaskCount());
1219   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1220   ASSERT_EQ(2U * kFaviconBatchSize, changes.size());
1221 
1222   for (int i = 0; i < kFaviconBatchSize; ++i) {
1223     TestFaviconData test_data = BuildFaviconData(i);
1224     const syncer::SyncChange& change1 = changes[i * 2];
1225     const syncer::SyncChange& change2 = changes[i * 2 + 1];
1226 
1227     EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change1.change_type());
1228     EXPECT_EQ(syncer::FAVICON_IMAGES, change1.sync_data().GetDataType());
1229     EXPECT_TRUE(CompareFaviconDataToSpecifics(
1230         test_data, change1.sync_data().GetSpecifics()));
1231     EXPECT_EQ(syncer::FAVICON_TRACKING, change2.sync_data().GetDataType());
1232     // Just verify the favicon url for the tracking specifics and that the
1233     // timestamp is non-null.
1234     EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change2.change_type());
1235     EXPECT_EQ(
1236         test_data.icon_url.spec(),
1237         change2.sync_data().GetSpecifics().favicon_tracking().favicon_url());
1238     EXPECT_NE(change2.sync_data()
1239                   .GetSpecifics()
1240                   .favicon_tracking()
1241                   .last_visit_time_ms(),
1242               0);
1243   }
1244 
1245   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1246 }
1247 
1248 // Test that visiting a known page does not trigger a favicon load and just
1249 // updates the sync tracking info.
TEST_F(SyncFaviconCacheTest,UpdateOnFaviconVisited)1250 TEST_F(SyncFaviconCacheTest, UpdateOnFaviconVisited) {
1251   EXPECT_EQ(0U, GetFaviconCount());
1252   SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1253   std::vector<int> expected_icons;
1254 
1255   // Add the favicons.
1256   for (int i = 0; i < kFaviconBatchSize; ++i) {
1257     expected_icons.push_back(i);
1258     TestFaviconData test_data = BuildFaviconData(i);
1259     PopulateFaviconService(test_data);
1260     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1261   }
1262 
1263   // Wait until the FaviconService replies with the results populated above.
1264   RunUntilIdle();
1265   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1266 
1267   // Visit the favicons again.
1268   EXPECT_EQ(0U, GetTaskCount());
1269   for (int i = 0; i < kFaviconBatchSize; ++i) {
1270     TestFaviconData test_data = BuildFaviconData(i);
1271     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1272     // Wait until the FaviconService replies with the results populated earlier.
1273     RunUntilIdle();
1274 
1275     syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1276     ASSERT_EQ(1U, changes.size());
1277     // Just verify the favicon url for the tracking specifics and that the
1278     // timestamp is non-null.
1279     EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1280     EXPECT_EQ(test_data.icon_url.spec(),
1281               changes[0].sync_data().GetSpecifics().favicon_tracking().
1282                   favicon_url());
1283     EXPECT_NE(changes[0].sync_data().GetSpecifics().favicon_tracking().
1284                   last_visit_time_ms(), 0);
1285   }
1286   EXPECT_EQ(0U, GetTaskCount());
1287   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1288 }
1289 
1290 // Ensure we properly expire old synced favicons as new ones are updated.
TEST_F(SyncFaviconCacheTest,ExpireOnFaviconVisited)1291 TEST_F(SyncFaviconCacheTest, ExpireOnFaviconVisited) {
1292   EXPECT_EQ(0U, GetFaviconCount());
1293   SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1294   std::vector<int> expected_icons;
1295 
1296   // Add the initial favicons.
1297   for (int i = 0; i < kMaxSyncFavicons; ++i) {
1298     expected_icons.push_back(i);
1299     TestFaviconData test_data = BuildFaviconData(i);
1300     PopulateFaviconService(test_data);
1301     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1302   }
1303 
1304   // Wait until the FaviconService replies with the results populated above.
1305   RunUntilIdle();
1306   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1307 
1308   // Visit some new favicons, triggering expirations of the old favicons.
1309   EXPECT_EQ(0U, GetTaskCount());
1310   for (int i = 0; i < kFaviconBatchSize; ++i) {
1311     TestFaviconData old_favicon = BuildFaviconData(i);
1312     TestFaviconData test_data = BuildFaviconData(i + kMaxSyncFavicons);
1313     PopulateFaviconService(test_data);
1314     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1315     // Wait until the FaviconService replies with the results populated above.
1316     RunUntilIdle();
1317 
1318     syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1319     ASSERT_EQ(4U, changes.size());
1320     EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
1321     EXPECT_TRUE(
1322         CompareFaviconDataToSpecifics(test_data,
1323                                       changes[0].sync_data().GetSpecifics()));
1324     EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, changes[1].change_type());
1325     EXPECT_EQ(old_favicon.icon_url.spec(),
1326               syncer::SyncDataLocal(changes[1].sync_data()).GetTag());
1327 
1328     EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[2].change_type());
1329     EXPECT_EQ(test_data.icon_url.spec(),
1330               changes[2].sync_data().GetSpecifics().favicon_tracking().
1331                   favicon_url());
1332     EXPECT_NE(changes[2].sync_data().GetSpecifics().favicon_tracking().
1333                   last_visit_time_ms(), 0);
1334     EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, changes[3].change_type());
1335     EXPECT_EQ(old_favicon.icon_url.spec(),
1336               syncer::SyncDataLocal(changes[3].sync_data()).GetTag());
1337   }
1338 
1339   EXPECT_EQ(0U, GetTaskCount());
1340   EXPECT_EQ(static_cast<size_t>(kMaxSyncFavicons), GetFaviconCount());
1341 }
1342 
1343 // A full history clear notification should result in all synced favicons being
1344 // deleted.
TEST_F(SyncFaviconCacheTest,HistoryFullClear)1345 TEST_F(SyncFaviconCacheTest, HistoryFullClear) {
1346   syncer::SyncDataList initial_image_data, initial_tracking_data;
1347   std::vector<int> expected_icons;
1348   std::vector<syncer::SyncChange::SyncChangeType> expected_deletions;
1349   for (int i = 0; i < kFaviconBatchSize; ++i) {
1350     expected_icons.push_back(i);
1351     expected_deletions.push_back(syncer::SyncChange::ACTION_DELETE);
1352     TestFaviconData test_data = BuildFaviconData(i);
1353     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1354     FillImageSpecifics(test_data,
1355                        image_specifics.mutable_favicon_image());
1356     initial_image_data.push_back(
1357         syncer::SyncData::CreateRemoteData(1, image_specifics));
1358     FillTrackingSpecifics(BuildFaviconData(i),
1359                           tracking_specifics.mutable_favicon_tracking());
1360     initial_tracking_data.push_back(
1361         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1362   }
1363 
1364   SetUpInitialSync(initial_image_data, initial_tracking_data);
1365   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1366   EXPECT_TRUE(changes.empty());
1367 
1368   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1369   cache()->OnURLsDeleted(nullptr, history::DeletionInfo::ForAllHistory());
1370   EXPECT_EQ(0U, GetFaviconCount());
1371   changes = processor()->GetAndResetChangeList();
1372   ASSERT_EQ(changes.size(), static_cast<size_t>(kFaviconBatchSize)*2);
1373   syncer::SyncChangeList changes_1, changes_2;
1374   for (int i = 0; i < kFaviconBatchSize; ++i) {
1375     changes_1.push_back(changes[i]);
1376     changes_2.push_back(changes[i + kFaviconBatchSize]);
1377   }
1378   VerifyChanges(syncer::FAVICON_IMAGES,
1379                 expected_deletions,
1380                 expected_icons,
1381                 changes_1);
1382   VerifyChanges(syncer::FAVICON_TRACKING,
1383                 expected_deletions,
1384                 expected_icons,
1385                 changes_2);
1386 }
1387 
1388 // A partial history clear notification should result in the expired favicons
1389 // also being deleted from sync.
TEST_F(SyncFaviconCacheTest,HistorySubsetClear)1390 TEST_F(SyncFaviconCacheTest, HistorySubsetClear) {
1391   syncer::SyncDataList initial_image_data, initial_tracking_data;
1392   std::vector<int> expected_icons;
1393   std::vector<syncer::SyncChange::SyncChangeType> expected_deletions;
1394   std::set<GURL> favicon_urls_to_delete;
1395   for (int i = 0; i < kFaviconBatchSize; ++i) {
1396     TestFaviconData test_data = BuildFaviconData(i);
1397     if (i < kFaviconBatchSize/2) {
1398       expected_icons.push_back(i);
1399       expected_deletions.push_back(syncer::SyncChange::ACTION_DELETE);
1400       favicon_urls_to_delete.insert(test_data.icon_url);
1401     }
1402     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1403     FillImageSpecifics(test_data,
1404                        image_specifics.mutable_favicon_image());
1405     initial_image_data.push_back(
1406         syncer::SyncData::CreateRemoteData(1, image_specifics));
1407     FillTrackingSpecifics(BuildFaviconData(i),
1408                           tracking_specifics.mutable_favicon_tracking());
1409     initial_tracking_data.push_back(
1410         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1411   }
1412 
1413   SetUpInitialSync(initial_image_data, initial_tracking_data);
1414   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1415   EXPECT_TRUE(changes.empty());
1416 
1417   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1418   cache()->OnURLsDeleted(
1419       nullptr, history::DeletionInfo::ForUrls(history::URLRows(),
1420                                               favicon_urls_to_delete));
1421   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize)/2, GetFaviconCount());
1422   changes = processor()->GetAndResetChangeList();
1423   ASSERT_EQ(changes.size(), static_cast<size_t>(kFaviconBatchSize));
1424   syncer::SyncChangeList changes_1, changes_2;
1425   for (size_t i = 0; i < kFaviconBatchSize/2; ++i) {
1426     changes_1.push_back(changes[i]);
1427     changes_2.push_back(changes[i + kFaviconBatchSize/2]);
1428   }
1429   VerifyChanges(syncer::FAVICON_IMAGES,
1430                 expected_deletions,
1431                 expected_icons,
1432                 changes_1);
1433   VerifyChanges(syncer::FAVICON_TRACKING,
1434                 expected_deletions,
1435                 expected_icons,
1436                 changes_2);
1437 }
1438 
1439 // Any favicon urls with the "data" scheme should be ignored.
TEST_F(SyncFaviconCacheTest,IgnoreDataScheme)1440 TEST_F(SyncFaviconCacheTest, IgnoreDataScheme) {
1441   EXPECT_EQ(0U, GetFaviconCount());
1442   SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1443   std::vector<int> expected_icons;
1444 
1445   for (int i = 0; i < kFaviconBatchSize; ++i) {
1446     TestFaviconData test_data = BuildFaviconData(i);
1447     test_data.icon_url = GURL("data:image/png;base64;blabla");
1448     EXPECT_TRUE(test_data.icon_url.is_valid());
1449     PopulateFaviconService(test_data);
1450     cache()->OnFaviconVisited(test_data.page_url, GURL());
1451   }
1452 
1453   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetTaskCount());
1454   // Wait until the FaviconService replies with the results populated above.
1455   RunUntilIdle();
1456 
1457   EXPECT_EQ(0U, GetTaskCount());
1458   EXPECT_EQ(0U, GetFaviconCount());
1459   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1460   EXPECT_TRUE(changes.empty());
1461 }
1462 
1463 // When visiting a page we've already loaded the favicon for, don't attempt to
1464 // reload the favicon, just update the visit time using the cached icon url.
TEST_F(SyncFaviconCacheTest,ReuseCachedIconUrl)1465 TEST_F(SyncFaviconCacheTest, ReuseCachedIconUrl) {
1466   EXPECT_EQ(0U, GetFaviconCount());
1467   SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1468   std::vector<int> expected_icons;
1469 
1470   for (int i = 0; i < kFaviconBatchSize; ++i) {
1471     expected_icons.push_back(i);
1472     TestFaviconData test_data = BuildFaviconData(i);
1473     PopulateFaviconService(test_data);
1474     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1475   }
1476 
1477   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetTaskCount());
1478   // Wait until the FaviconService replies with the results populated above.
1479   RunUntilIdle();
1480 
1481   processor()->GetAndResetChangeList();
1482   EXPECT_EQ(0U, GetTaskCount());
1483   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1484 
1485   for (int i = 0; i < kFaviconBatchSize; ++i) {
1486     TestFaviconData test_data = BuildFaviconData(i);
1487     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1488     // Wait until the FaviconService replies with the results populated earlier.
1489     RunUntilIdle();
1490     syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1491     ASSERT_EQ(1U, changes.size());
1492     // Just verify the favicon url for the tracking specifics and that the
1493     // timestamp is non-null.
1494     EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1495     EXPECT_EQ(test_data.icon_url.spec(),
1496               changes[0].sync_data().GetSpecifics().favicon_tracking().
1497                   favicon_url());
1498     EXPECT_NE(changes[0].sync_data().GetSpecifics().favicon_tracking().
1499                   last_visit_time_ms(), 0);
1500   }
1501   EXPECT_EQ(0U, GetTaskCount());
1502 }
1503 
1504 // If we wind up with orphan image/tracking nodes, then receive an update
1505 // for those favicons, we should lazily create the missing nodes.
TEST_F(SyncFaviconCacheTest,UpdatedOrphans)1506 TEST_F(SyncFaviconCacheTest, UpdatedOrphans) {
1507   EXPECT_EQ(0U, GetFaviconCount());
1508   SetUpInitialSync(syncer::SyncDataList(), syncer::SyncDataList());
1509 
1510   syncer::SyncChangeList initial_image_changes;
1511   syncer::SyncChangeList initial_tracking_changes;
1512   for (int i = 0; i < kFaviconBatchSize; ++i) {
1513     TestFaviconData test_data = BuildFaviconData(i);
1514     // Even favicons have image data but no tracking data. Odd favicons have
1515     // tracking data but no image data.
1516     if (i % 2 == 0) {
1517       sync_pb::EntitySpecifics image_specifics;
1518       FillImageSpecifics(BuildFaviconData(i),
1519                          image_specifics.mutable_favicon_image());
1520       initial_image_changes.push_back(syncer::SyncChange(
1521           FROM_HERE, syncer::SyncChange::ACTION_ADD,
1522           syncer::SyncData::CreateRemoteData(1, image_specifics)));
1523     } else {
1524       sync_pb::EntitySpecifics tracking_specifics;
1525       FillTrackingSpecifics(BuildFaviconData(i),
1526                             tracking_specifics.mutable_favicon_tracking());
1527       initial_tracking_changes.push_back(syncer::SyncChange(
1528           FROM_HERE, syncer::SyncChange::ACTION_ADD,
1529           syncer::SyncData::CreateRemoteData(1, tracking_specifics)));
1530     }
1531   }
1532 
1533   cache()->ProcessSyncChanges(FROM_HERE, initial_image_changes);
1534   cache()->ProcessSyncChanges(FROM_HERE, initial_tracking_changes);
1535   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1536   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1537 
1538   for (int i = 0; i < kFaviconBatchSize/2; ++i) {
1539     TestFaviconData test_data = BuildFaviconData(i);
1540     PopulateFaviconService(test_data);
1541     cache()->OnFaviconVisited(test_data.page_url, GURL());
1542     EXPECT_EQ(1U, GetTaskCount());
1543     // Wait until the FaviconService replies with the results populated above.
1544     RunUntilIdle();
1545     EXPECT_EQ(0U, GetTaskCount());
1546     syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1547 
1548     // Even favicons had image data, so should now receive new tracking data
1549     // and updated image data (we allow one update after the initial add).
1550     // Odd favicons had tracking so should now receive new image data and
1551     // updated tracking data.
1552     if (i % 2 == 0) {
1553       ASSERT_EQ(2U, changes.size());
1554       EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1555       EXPECT_TRUE(
1556           CompareFaviconDataToSpecifics(test_data,
1557                                         changes[0].sync_data().GetSpecifics()));
1558       EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[1].change_type());
1559       EXPECT_EQ(test_data.icon_url.spec(),
1560                 changes[1].sync_data().GetSpecifics().favicon_tracking().
1561                     favicon_url());
1562       EXPECT_NE(changes[1].sync_data().GetSpecifics().favicon_tracking().
1563                     last_visit_time_ms(), 0);
1564     } else {
1565       ASSERT_EQ(2U, changes.size());
1566       EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
1567       EXPECT_TRUE(
1568           CompareFaviconDataToSpecifics(test_data,
1569                                         changes[0].sync_data().GetSpecifics()));
1570       EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[1].change_type());
1571       EXPECT_EQ(test_data.icon_url.spec(),
1572                 changes[1].sync_data().GetSpecifics().favicon_tracking().
1573                     favicon_url());
1574       EXPECT_NE(changes[1].sync_data().GetSpecifics().favicon_tracking().
1575                     last_visit_time_ms(), 0);
1576     }
1577   }
1578 
1579   EXPECT_EQ(0U, GetTaskCount());
1580   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1581 }
1582 
1583 // Verify that orphaned favicon images don't result in creating invalid
1584 // favicon tracking data.
TEST_F(SyncFaviconCacheTest,PartialAssociationInfo)1585 TEST_F(SyncFaviconCacheTest, PartialAssociationInfo) {
1586   syncer::SyncDataList initial_image_data, initial_tracking_data;
1587   for (int i = 0; i < kFaviconBatchSize; ++i) {
1588     sync_pb::EntitySpecifics image_specifics;
1589     FillImageSpecifics(BuildFaviconData(i),
1590                        image_specifics.mutable_favicon_image());
1591     initial_image_data.push_back(
1592         syncer::SyncData::CreateRemoteData(1, image_specifics));
1593     image_specifics.mutable_favicon_image()->clear_favicon_web();
1594   }
1595 
1596   SetUpInitialSync(initial_image_data, initial_tracking_data);
1597   syncer::SyncChangeList change_list = processor()->GetAndResetChangeList();
1598   EXPECT_TRUE(change_list.empty());
1599   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1600 }
1601 
1602 // Tests that we don't choke if a favicon visit node with a null visit time is
1603 // present (see crbug.com/258196) and an update is made.
TEST_F(SyncFaviconCacheTest,NullFaviconVisitTime)1604 TEST_F(SyncFaviconCacheTest, NullFaviconVisitTime) {
1605   EXPECT_EQ(0U, GetFaviconCount());
1606 
1607   syncer::SyncDataList initial_image_data, initial_tracking_data;
1608   std::vector<int> expected_icons;
1609   for (int i = 0; i < kFaviconBatchSize; ++i) {
1610     expected_icons.push_back(i);
1611     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1612     FillImageSpecifics(BuildFaviconData(i),
1613                        image_specifics.mutable_favicon_image());
1614     initial_image_data.push_back(
1615         syncer::SyncData::CreateRemoteData(1, image_specifics));
1616     FillTrackingSpecifics(BuildFaviconData(i),
1617                           tracking_specifics.mutable_favicon_tracking());
1618     tracking_specifics.mutable_favicon_tracking()->set_last_visit_time_ms(
1619         syncer::TimeToProtoTime(base::Time()));
1620     initial_tracking_data.push_back(
1621         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1622   }
1623 
1624   cache()->MergeDataAndStartSyncing(syncer::FAVICON_IMAGES,
1625                                     initial_image_data,
1626                                     CreateAndPassProcessor(),
1627                                     CreateAndPassSyncErrorFactory());
1628   ASSERT_EQ(0U, processor()->GetAndResetChangeList().size());
1629   cache()->MergeDataAndStartSyncing(syncer::FAVICON_TRACKING,
1630                                     initial_tracking_data,
1631                                     CreateAndPassProcessor(),
1632                                     CreateAndPassSyncErrorFactory());
1633   ASSERT_EQ(static_cast<size_t>(kFaviconBatchSize),
1634             processor()->GetAndResetChangeList().size());
1635   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1636 
1637   // Visit the favicons again.
1638   EXPECT_EQ(0U, GetTaskCount());
1639   for (int i = 0; i < kFaviconBatchSize; ++i) {
1640     TestFaviconData test_data = BuildFaviconData(i);
1641     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1642     // Wait until the FaviconService replies with the results populated earlier.
1643     RunUntilIdle();
1644 
1645     syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1646     ASSERT_EQ(1U, changes.size());
1647     // Just verify the favicon url for the tracking specifics and that the
1648     // timestamp is non-null.
1649     EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
1650     EXPECT_EQ(test_data.icon_url.spec(),
1651               changes[0].sync_data().GetSpecifics().favicon_tracking().
1652                   favicon_url());
1653     EXPECT_NE(changes[0].sync_data().GetSpecifics().favicon_tracking().
1654                   last_visit_time_ms(), 0);
1655   }
1656   EXPECT_EQ(0U, GetTaskCount());
1657   EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
1658 }
1659 
1660 // If another synced client has a clock skewed towards the future, it's possible
1661 // that favicons added locally will be expired as they are added. Ensure this
1662 // doesn't crash (see crbug.com/306150).
TEST_F(SyncFaviconCacheTest,VisitFaviconClockSkew)1663 TEST_F(SyncFaviconCacheTest, VisitFaviconClockSkew) {
1664   EXPECT_EQ(0U, GetFaviconCount());
1665   const int kClockSkew = 20;  // 20 minutes in the future.
1666 
1667   // Set up sync with kMaxSyncFavicons starting kClockSkew minutes in the
1668   // future.
1669   syncer::SyncDataList initial_image_data, initial_tracking_data;
1670   for (int i = 0; i < kMaxSyncFavicons; ++i) {
1671     sync_pb::EntitySpecifics image_specifics, tracking_specifics;
1672     TestFaviconData test_data = BuildFaviconData(i);
1673     test_data.last_visit_time =
1674         base::Time::Now() + base::TimeDelta::FromMinutes(kClockSkew);
1675     FillImageSpecifics(test_data,
1676                        image_specifics.mutable_favicon_image());
1677     initial_image_data.push_back(
1678         syncer::SyncData::CreateRemoteData(1, image_specifics));
1679     FillTrackingSpecifics(test_data,
1680                           tracking_specifics.mutable_favicon_tracking());
1681     initial_tracking_data.push_back(
1682         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1683   }
1684   SetUpInitialSync(initial_image_data, initial_tracking_data);
1685 
1686   // Visit some new favicons with local time, which will be expired as they
1687   // are added.
1688   EXPECT_EQ(0U, GetTaskCount());
1689   for (int i = 0; i < kClockSkew; ++i) {
1690     TestFaviconData test_data = BuildFaviconData(i + kMaxSyncFavicons);
1691     PopulateFaviconService(test_data);
1692     cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1693     // Wait until the FaviconService replies with the results populated above.
1694     RunUntilIdle();
1695 
1696     // The changes will be an add followed by a delete for both the image and
1697     // tracking info.
1698     syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1699     ASSERT_EQ(changes.size(), 4U);
1700     ASSERT_EQ(changes[0].change_type(), syncer::SyncChange::ACTION_ADD);
1701     ASSERT_EQ(changes[0].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1702     ASSERT_EQ(changes[1].change_type(), syncer::SyncChange::ACTION_DELETE);
1703     ASSERT_EQ(changes[1].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1704     ASSERT_EQ(changes[2].change_type(), syncer::SyncChange::ACTION_ADD);
1705     ASSERT_EQ(changes[2].sync_data().GetDataType(), syncer::FAVICON_TRACKING);
1706     ASSERT_EQ(changes[3].change_type(), syncer::SyncChange::ACTION_DELETE);
1707     ASSERT_EQ(changes[3].sync_data().GetDataType(), syncer::FAVICON_TRACKING);
1708   }
1709   EXPECT_EQ(0U, GetTaskCount());
1710   EXPECT_EQ(static_cast<size_t>(kMaxSyncFavicons), GetFaviconCount());
1711 }
1712 
1713 // Simulate a case where the set of tracking info and image info doesn't match,
1714 // and there is more tracking info than the max. A local update should correctly
1715 // determine whether to update/add an image/tracking entity.
TEST_F(SyncFaviconCacheTest,MixedThreshold)1716 TEST_F(SyncFaviconCacheTest, MixedThreshold) {
1717   // First go through and add local favicons.
1718   for (int i = kMaxSyncFavicons; i < kMaxSyncFavicons + 5; ++i) {
1719     TestFaviconData favicon = BuildFaviconData(i);
1720     TriggerSyncFaviconReceived(favicon.page_url,
1721                                favicon.icon_url,
1722                                favicon.image_16,
1723                                favicon.last_visit_time);
1724   }
1725 
1726   syncer::SyncDataList initial_image_data, initial_tracking_data;
1727   // Then sync with enough favicons such that the tracking info is over the max
1728   // after merge completes.
1729   for (int i = 0; i < kMaxSyncFavicons; ++i) {
1730     sync_pb::EntitySpecifics image_specifics;
1731     // Push the images forward by 5, to match the unsynced favicons.
1732     FillImageSpecifics(BuildFaviconData(i + 5),
1733                        image_specifics.mutable_favicon_image());
1734     initial_image_data.push_back(
1735         syncer::SyncData::CreateRemoteData(1, image_specifics));
1736 
1737     sync_pb::EntitySpecifics tracking_specifics;
1738     FillTrackingSpecifics(BuildFaviconData(i),
1739                           tracking_specifics.mutable_favicon_tracking());
1740     initial_tracking_data.push_back(
1741         syncer::SyncData::CreateRemoteData(1, tracking_specifics));
1742   }
1743   SetUpInitialSync(initial_image_data, initial_tracking_data);
1744 
1745   // The local unsynced tracking info should be dropped, but not deleted.
1746   EXPECT_EQ(0U, processor()->GetAndResetChangeList().size());
1747 
1748   // Because the image and tracking data don't overlap, the total number of
1749   // favicons is still over the limit.
1750   EXPECT_EQ(static_cast<size_t>(kMaxSyncFavicons)+5, GetFaviconCount());
1751 
1752   // Trigger a tracking change for one of the favicons whose tracking info
1753   // was dropped, resulting in a tracking add and expiration of the orphaned
1754   // images.
1755   TestFaviconData test_data = BuildFaviconData(kMaxSyncFavicons);
1756   cache()->OnFaviconVisited(test_data.page_url, test_data.icon_url);
1757 
1758   syncer::SyncChangeList changes = processor()->GetAndResetChangeList();
1759   // 1 image update, 5 image deletions, 1 tracking deletion.
1760   ASSERT_EQ(6U, changes.size());
1761   // Expire image for favicon[kMaxSyncFavicons + 1].
1762   EXPECT_EQ(changes[0].change_type(), syncer::SyncChange::ACTION_DELETE);
1763   EXPECT_EQ(changes[0].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1764   EXPECT_EQ(kMaxSyncFavicons + 1, GetFaviconId(changes[0]));
1765   // Expire image for favicon[kMaxSyncFavicons + 2].
1766   EXPECT_EQ(changes[1].change_type(), syncer::SyncChange::ACTION_DELETE);
1767   EXPECT_EQ(changes[1].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1768   EXPECT_EQ(kMaxSyncFavicons + 2, GetFaviconId(changes[1]));
1769   // Expire image for favicon[kMaxSyncFavicons + 3].
1770   EXPECT_EQ(changes[2].change_type(), syncer::SyncChange::ACTION_DELETE);
1771   EXPECT_EQ(changes[2].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1772   EXPECT_EQ(kMaxSyncFavicons + 3, GetFaviconId(changes[2]));
1773   // Expire image for favicon[kMaxSyncFavicons + 4].
1774   EXPECT_EQ(changes[3].change_type(), syncer::SyncChange::ACTION_DELETE);
1775   EXPECT_EQ(changes[3].sync_data().GetDataType(), syncer::FAVICON_IMAGES);
1776   EXPECT_EQ(kMaxSyncFavicons + 4, GetFaviconId(changes[3]));
1777   // Update tracking for favicon[kMaxSyncFavicons].
1778   EXPECT_EQ(changes[4].change_type(), syncer::SyncChange::ACTION_ADD);
1779   EXPECT_EQ(changes[4].sync_data().GetDataType(), syncer::FAVICON_TRACKING);
1780   EXPECT_EQ(kMaxSyncFavicons, GetFaviconId(changes[4]));
1781   // Expire tracking for favicon[0].
1782   EXPECT_EQ(changes[5].change_type(), syncer::SyncChange::ACTION_DELETE);
1783   EXPECT_EQ(changes[5].sync_data().GetDataType(), syncer::FAVICON_TRACKING);
1784   EXPECT_EQ(0, GetFaviconId(changes[5]));
1785 }
1786 
1787 }  // namespace sync_sessions
1788