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