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