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