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 24 namespace browser_sync { 25 26 namespace { 27 28 // Total number of favicons to use in sync test batches. 29 const int kFaviconBatchSize = 10; 30 31 // Maximum number of favicons to sync. 32 const int kMaxSyncFavicons = kFaviconBatchSize*2; 33 34 // TestChangeProcessor -------------------------------------------------------- 35 36 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed 37 // back up to Sync. 38 class 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 80 TestChangeProcessor::TestChangeProcessor() : erroneous_(false) { 81 } 82 83 TestChangeProcessor::~TestChangeProcessor() { 84 } 85 86 syncer::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 ------------------------------------------------------------ 109 struct 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 120 TestFaviconData 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 132 void 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 154 void 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 162 testing::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 209 testing::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. 242 int 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 260 class 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 304 SyncFaviconCacheTest::SyncFaviconCacheTest() 305 : cache_(NULL, kMaxSyncFavicons), 306 sync_processor_(new TestChangeProcessor), 307 sync_processor_wrapper_(new syncer::SyncChangeProcessorWrapperForTest( 308 sync_processor_.get())) {} 309 310 void 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 325 size_t SyncFaviconCacheTest::GetFaviconCount() const { 326 return cache_.NumFaviconsForTest(); 327 } 328 329 size_t SyncFaviconCacheTest::GetTaskCount() const { 330 return cache_.NumTasksForTest(); 331 } 332 333 testing::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 349 testing::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 359 testing::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 400 scoped_ptr<syncer::SyncChangeProcessor> 401 SyncFaviconCacheTest::CreateAndPassProcessor() { 402 return scoped_ptr<syncer::SyncChangeProcessor>( 403 new syncer::SyncChangeProcessorWrapperForTest(sync_processor_.get())); 404 } 405 406 scoped_ptr<syncer::SyncErrorFactory> SyncFaviconCacheTest:: 407 CreateAndPassSyncErrorFactory() { 408 return scoped_ptr<syncer::SyncErrorFactory>( 409 new syncer::SyncErrorFactoryMock()); 410 } 411 412 void 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 448 void 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. 461 TEST_F(SyncFaviconCacheTest, Empty) { 462 EXPECT_EQ(0U, GetFaviconCount()); 463 } 464 465 TEST_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 475 TEST_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 493 TEST_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 511 TEST_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 527 TEST_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. 559 TEST_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. 611 TEST_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. 668 TEST_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. 753 TEST_F(SyncFaviconCacheTest, SyncMergesTracking) { 754 // First go through and add local 16p favicons. 755 for (int i = 0; i < kFaviconBatchSize; ++i) { 756 TestFaviconData favicon = BuildFaviconData(i); 757 TriggerSyncFaviconReceived(favicon.page_url, 758 favicon.icon_url, 759 favicon.image_16, 760 i); 761 } 762 763 // Then go through and create the initial sync data, which for the first half 764 // the local has a newer visit, and for the second the remote does. 765 std::vector<syncer::SyncChange::SyncChangeType> expected_change_types; 766 std::vector<int> expected_icons; 767 std::vector<TestFaviconData> expected_data; 768 syncer::SyncDataList initial_image_data, initial_tracking_data; 769 for (int i = 0; i < kFaviconBatchSize; ++i) { 770 sync_pb::EntitySpecifics image_specifics, tracking_specifics; 771 TestFaviconData test_data = BuildFaviconData(i); 772 if (i < kFaviconBatchSize/2) { 773 test_data.last_visit_time = i-1; 774 expected_icons.push_back(i); 775 expected_change_types.push_back(syncer::SyncChange::ACTION_UPDATE); 776 } else { 777 test_data.last_visit_time = i+1; 778 expected_data.push_back(test_data); 779 } 780 FillImageSpecifics(test_data, 781 image_specifics.mutable_favicon_image()); 782 783 initial_image_data.push_back(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. 838 TEST_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. 890 TEST_F(SyncFaviconCacheTest, ReceiveNewImages) { 891 syncer::SyncDataList initial_image_data, initial_tracking_data; 892 syncer::SyncChangeList new_changes; 893 std::vector<int> expected_icons; 894 for (int i = 0; i < kFaviconBatchSize; ++i) { 895 expected_icons.push_back(i); 896 TestFaviconData test_data = BuildFaviconData(i); 897 sync_pb::EntitySpecifics image_specifics, tracking_specifics; 898 FillImageSpecifics(test_data, 899 image_specifics.mutable_favicon_image()); 900 new_changes.push_back(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. 938 TEST_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. 983 TEST_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. 1035 TEST_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. 1081 TEST_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. 1124 TEST_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. 1182 TEST_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. 1254 TEST_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. 1316 TEST_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. 1357 TEST_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. 1393 TEST_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. 1442 TEST_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. 1500 TEST_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. 1559 TEST_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. 1586 TEST_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. 1626 TEST_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. 1714 TEST_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. 1737 TEST_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). 1802 TEST_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. 1862 TEST_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