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