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