diff options
Diffstat (limited to 'chrome/browser/sync/glue')
-rw-r--r-- | chrome/browser/sync/glue/favicon_cache.cc | 117 | ||||
-rw-r--r-- | chrome/browser/sync/glue/favicon_cache.h | 28 | ||||
-rw-r--r-- | chrome/browser/sync/glue/favicon_cache_unittest.cc | 126 |
3 files changed, 245 insertions, 26 deletions
diff --git a/chrome/browser/sync/glue/favicon_cache.cc b/chrome/browser/sync/glue/favicon_cache.cc index 244bd54..a1dc8fa 100644 --- a/chrome/browser/sync/glue/favicon_cache.cc +++ b/chrome/browser/sync/glue/favicon_cache.cc @@ -7,7 +7,11 @@ #include "base/metrics/histogram.h" #include "chrome/browser/favicon/favicon_service.h" #include "chrome/browser/favicon/favicon_service_factory.h" +#include "chrome/browser/history/history_notifications.h" #include "chrome/browser/history/history_types.h" +#include "chrome/common/chrome_notification_types.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" #include "sync/api/time.h" #include "sync/protocol/favicon_image_specifics.pb.h" #include "sync/protocol/favicon_tracking_specifics.pb.h" @@ -190,7 +194,11 @@ FaviconCache::FaviconCache(Profile* profile, int max_sync_favicon_limit) : profile_(profile), weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), legacy_delegate_(NULL), - max_sync_favicon_limit_(max_sync_favicon_limit) {} + max_sync_favicon_limit_(max_sync_favicon_limit) { + notification_registrar_.Add(this, + chrome::NOTIFICATION_HISTORY_URLS_DELETED, + content::Source<Profile>(profile_)); +} FaviconCache::~FaviconCache() {} @@ -248,8 +256,7 @@ syncer::SyncMergeResult FaviconCache::MergeDataAndStartSyncing( FaviconMap::iterator favicon_iter = synced_favicons_.find(*iter); DVLOG(1) << "Dropping local favicon " << favicon_iter->second->favicon_url.spec(); - recent_favicons_.erase(favicon_iter->second); - synced_favicons_.erase(favicon_iter); + DropSyncedFavicon(favicon_iter); merge_result.set_num_items_deleted(merge_result.num_items_deleted() + 1); } } @@ -316,8 +323,7 @@ syncer::SyncError FaviconCache::ProcessSyncChanges( continue; } else { DVLOG(1) << "Deleting favicon at " << favicon_url.spec(); - recent_favicons_.erase(favicon_iter->second); - synced_favicons_.erase(favicon_iter); + DropSyncedFavicon(favicon_iter); // TODO(zea): it's possible that we'll receive a deletion for an image, // but not a tracking data, or vice versa, resulting in an orphan // favicon node in one of the types. We should track how often this @@ -489,6 +495,41 @@ void FaviconCache::RemoveLegacyDelegate() { legacy_delegate_ = NULL; } +void FaviconCache::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK_EQ(type, chrome::NOTIFICATION_HISTORY_URLS_DELETED); + + content::Details<history::URLsDeletedDetails> deleted_details(details); + + // We only care about actual user (or sync) deletions. + if (deleted_details->archived) + return; + + if (!deleted_details->all_history) { + DeleteSyncedFavicons(deleted_details->favicon_urls); + return; + } + + // All history was cleared: just delete all favicons. + DVLOG(1) << "History clear detected, deleting all synced favicons."; + syncer::SyncChangeList image_deletions, tracking_deletions; + for (FaviconMap::iterator iter = synced_favicons_.begin(); + iter != synced_favicons_.end();) { + iter = DeleteSyncedFavicon(iter, + &image_deletions, + &tracking_deletions); + } + + if (favicon_images_sync_processor_.get() && + favicon_tracking_sync_processor_.get()) { + favicon_images_sync_processor_->ProcessSyncChanges(FROM_HERE, + image_deletions); + favicon_tracking_sync_processor_->ProcessSyncChanges(FROM_HERE, + tracking_deletions); + } +} + bool FaviconCache::FaviconRecencyFunctor::operator()( const linked_ptr<SyncedFaviconInfo>& lhs, const linked_ptr<SyncedFaviconInfo>& rhs) const { @@ -665,20 +706,9 @@ void FaviconCache::ExpireFaviconsIfNecessary( while (recent_favicons_.size() > max_sync_favicon_limit_) { linked_ptr<SyncedFaviconInfo> candidate = *recent_favicons_.begin(); DVLOG(1) << "Expiring favicon " << candidate->favicon_url.spec(); - recent_favicons_.erase(recent_favicons_.begin()); - synced_favicons_.erase(candidate->favicon_url); - image_changes->push_back( - syncer::SyncChange(FROM_HERE, - syncer::SyncChange::ACTION_DELETE, - syncer::SyncData::CreateLocalDelete( - candidate->favicon_url.spec(), - syncer::FAVICON_IMAGES))); - tracking_changes->push_back( - syncer::SyncChange(FROM_HERE, - syncer::SyncChange::ACTION_DELETE, - syncer::SyncData::CreateLocalDelete( - candidate->favicon_url.spec(), - syncer::FAVICON_TRACKING))); + DeleteSyncedFavicon(synced_favicons_.find(candidate->favicon_url), + image_changes, + tracking_changes); } DCHECK_EQ(recent_favicons_.size(), synced_favicons_.size()); } @@ -830,6 +860,55 @@ syncer::SyncData FaviconCache::CreateSyncDataFromLocalFavicon( return data; } +void FaviconCache::DeleteSyncedFavicons(const std::set<GURL>& favicon_urls) { + syncer::SyncChangeList image_deletions, tracking_deletions; + for (std::set<GURL>::const_iterator iter = favicon_urls.begin(); + iter != favicon_urls.end(); ++iter) { + FaviconMap::iterator favicon_iter = synced_favicons_.find(*iter); + if (favicon_iter == synced_favicons_.end()) + continue; + DeleteSyncedFavicon(favicon_iter, + &image_deletions, + &tracking_deletions); + } + DVLOG(1) << "Deleting " << image_deletions.size() << " synced favicons."; + if (favicon_images_sync_processor_.get() && + favicon_tracking_sync_processor_.get()) { + favicon_images_sync_processor_->ProcessSyncChanges(FROM_HERE, + image_deletions); + favicon_tracking_sync_processor_->ProcessSyncChanges(FROM_HERE, + tracking_deletions); + } +} + +FaviconCache::FaviconMap::iterator FaviconCache::DeleteSyncedFavicon( + FaviconMap::iterator favicon_iter, + syncer::SyncChangeList* image_changes, + syncer::SyncChangeList* tracking_changes) { + linked_ptr<SyncedFaviconInfo> favicon_info = favicon_iter->second; + image_changes->push_back( + syncer::SyncChange(FROM_HERE, + syncer::SyncChange::ACTION_DELETE, + syncer::SyncData::CreateLocalDelete( + favicon_info->favicon_url.spec(), + syncer::FAVICON_IMAGES))); + tracking_changes->push_back( + syncer::SyncChange(FROM_HERE, + syncer::SyncChange::ACTION_DELETE, + syncer::SyncData::CreateLocalDelete( + favicon_info->favicon_url.spec(), + syncer::FAVICON_TRACKING))); + FaviconMap::iterator next = favicon_iter; + next++; + DropSyncedFavicon(favicon_iter); + return next; +} + +void FaviconCache::DropSyncedFavicon(FaviconMap::iterator favicon_iter) { + recent_favicons_.erase(favicon_iter->second); + synced_favicons_.erase(favicon_iter); +} + size_t FaviconCache::NumFaviconsForTest() const { return synced_favicons_.size(); } diff --git a/chrome/browser/sync/glue/favicon_cache.h b/chrome/browser/sync/glue/favicon_cache.h index fdf97ea..b7c8f7c 100644 --- a/chrome/browser/sync/glue/favicon_cache.h +++ b/chrome/browser/sync/glue/favicon_cache.h @@ -18,6 +18,8 @@ #include "chrome/browser/history/history_types.h" #include "chrome/browser/sessions/session_id.h" #include "chrome/common/cancelable_task_tracker.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "googleurl/src/gurl.h" #include "sync/api/sync_change.h" #include "sync/api/sync_error_factory.h" @@ -52,7 +54,8 @@ class FaviconCacheObserver { // Encapsulates the logic for loading and storing synced favicons. // TODO(zea): make this a ProfileKeyedService. -class FaviconCache : public syncer::SyncableService { +class FaviconCache : public syncer::SyncableService, + public content::NotificationObserver { public: FaviconCache(Profile* profile, int max_sync_favicon_limit); virtual ~FaviconCache(); @@ -106,6 +109,11 @@ class FaviconCache : public syncer::SyncableService { void SetLegacyDelegate(FaviconCacheObserver* observer); void RemoveLegacyDelegate(); + // NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + private: friend class SyncFaviconCacheTest; @@ -179,6 +187,21 @@ class FaviconCache : public syncer::SyncableService { syncer::ModelType type, const GURL& favicon_url) const; + // Deletes all synced favicons corresponding with |favicon_urls| and pushes + // the deletions to sync. + void DeleteSyncedFavicons(const std::set<GURL>& favicon_urls); + + // Deletes the favicon pointed to by |favicon_iter| and appends the necessary + // sync deletions to |image_changes| and |tracking_changes|. + // Returns an iterator to the favicon after |favicon_iter|. + FaviconMap::iterator DeleteSyncedFavicon( + FaviconMap::iterator favicon_iter, + syncer::SyncChangeList* image_changes, + syncer::SyncChangeList* tracking_changes); + + // Locally drops the favicon pointed to by |favicon_iter|. + void DropSyncedFavicon(FaviconMap::iterator favicon_iter); + // For testing only. size_t NumFaviconsForTest() const; size_t NumTasksForTest() const; @@ -214,6 +237,9 @@ class FaviconCache : public syncer::SyncableService { scoped_ptr<syncer::SyncChangeProcessor> favicon_images_sync_processor_; scoped_ptr<syncer::SyncChangeProcessor> favicon_tracking_sync_processor_; + // For listening to history deletions. + content::NotificationRegistrar notification_registrar_; + // Maximum number of favicons to sync. 0 means no limit. const size_t max_sync_favicon_limit_; diff --git a/chrome/browser/sync/glue/favicon_cache_unittest.cc b/chrome/browser/sync/glue/favicon_cache_unittest.cc index 9eac341..f7c146b 100644 --- a/chrome/browser/sync/glue/favicon_cache_unittest.cc +++ b/chrome/browser/sync/glue/favicon_cache_unittest.cc @@ -5,6 +5,9 @@ #include "chrome/browser/sync/glue/favicon_cache.h" #include "base/stringprintf.h" +#include "chrome/browser/history/history_notifications.h" +#include "chrome/common/chrome_notification_types.h" +#include "content/public/browser/notification_service.h" #include "sync/api/sync_error_factory_mock.h" #include "sync/protocol/favicon_image_specifics.pb.h" #include "sync/protocol/favicon_tracking_specifics.pb.h" @@ -238,12 +241,17 @@ testing::AssertionResult VerifyChanges( return testing::AssertionFailure() << "Change datatype doesn't match."; if (change_list[i].change_type() != expected_change_types[i]) return testing::AssertionFailure() << "Change type doesn't match."; - testing::AssertionResult compare_result = - CompareFaviconDataToSpecifics( - BuildFaviconData(expected_icons[i]), - change_list[i].sync_data().GetSpecifics()); - if (compare_result.failure_message()) - return compare_result; + if (change_list[i].change_type() == syncer::SyncChange::ACTION_DELETE) { + if (change_list[i].sync_data().GetTag() != data.icon_url.spec()) + return testing::AssertionFailure() << "Deletion url does not match."; + } else { + testing::AssertionResult compare_result = + CompareFaviconDataToSpecifics( + data, + change_list[i].sync_data().GetSpecifics()); + if (!compare_result) + return compare_result; + } } return testing::AssertionSuccess(); } @@ -1281,4 +1289,110 @@ TEST_F(SyncFaviconCacheTest, ExpireOnFaviconVisited) { EXPECT_EQ((unsigned long)kMaxSyncFavicons, GetFaviconCount()); } +// A full history clear notification should result in all synced favicons being +// deleted. +TEST_F(SyncFaviconCacheTest, HistoryFullClear) { + syncer::SyncDataList initial_image_data, initial_tracking_data; + std::vector<int> expected_icons; + std::vector<syncer::SyncChange::SyncChangeType> expected_deletions; + for (int i = 0; i < kFaviconBatchSize; ++i) { + expected_icons.push_back(i); + expected_deletions.push_back(syncer::SyncChange::ACTION_DELETE); + TestFaviconData test_data = BuildFaviconData(i); + sync_pb::EntitySpecifics image_specifics, tracking_specifics; + FillImageSpecifics(test_data, + image_specifics.mutable_favicon_image()); + initial_image_data.push_back( + syncer::SyncData::CreateRemoteData(1, + image_specifics)); + FillTrackingSpecifics(BuildFaviconData(i), + tracking_specifics.mutable_favicon_tracking()); + initial_tracking_data.push_back( + syncer::SyncData::CreateRemoteData(1, + tracking_specifics)); + } + + SetUpInitialSync(initial_image_data, initial_tracking_data); + syncer::SyncChangeList changes = processor()->GetAndResetChangeList(); + EXPECT_TRUE(changes.empty()); + + history::URLsDeletedDetails deletions; + deletions.all_history = true; + EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount()); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_HISTORY_URLS_DELETED, + content::Source<Profile>(NULL), + content::Details<history::URLsDeletedDetails>(&deletions)); + EXPECT_EQ(0U, GetFaviconCount()); + changes = processor()->GetAndResetChangeList(); + ASSERT_EQ(changes.size(), (unsigned long)kFaviconBatchSize*2); + syncer::SyncChangeList changes_1, changes_2; + for (int i = 0; i < kFaviconBatchSize; ++i) { + changes_1.push_back(changes[i]); + changes_2.push_back(changes[i + kFaviconBatchSize]); + } + VerifyChanges(syncer::FAVICON_IMAGES, + expected_deletions, + expected_icons, + changes_1); + VerifyChanges(syncer::FAVICON_TRACKING, + expected_deletions, + expected_icons, + changes_2); +} + +// A partial history clear notification should result in the expired favicons +// also being deleted from sync. +TEST_F(SyncFaviconCacheTest, HistorySubsetClear) { + syncer::SyncDataList initial_image_data, initial_tracking_data; + std::vector<int> expected_icons; + std::vector<syncer::SyncChange::SyncChangeType> expected_deletions; + history::URLsDeletedDetails deletions; + for (int i = 0; i < kFaviconBatchSize; ++i) { + TestFaviconData test_data = BuildFaviconData(i); + if (i < kFaviconBatchSize/2) { + expected_icons.push_back(i); + expected_deletions.push_back(syncer::SyncChange::ACTION_DELETE); + deletions.favicon_urls.insert(test_data.icon_url); + } + sync_pb::EntitySpecifics image_specifics, tracking_specifics; + FillImageSpecifics(test_data, + image_specifics.mutable_favicon_image()); + initial_image_data.push_back( + syncer::SyncData::CreateRemoteData(1, + image_specifics)); + FillTrackingSpecifics(BuildFaviconData(i), + tracking_specifics.mutable_favicon_tracking()); + initial_tracking_data.push_back( + syncer::SyncData::CreateRemoteData(1, + tracking_specifics)); + } + + SetUpInitialSync(initial_image_data, initial_tracking_data); + syncer::SyncChangeList changes = processor()->GetAndResetChangeList(); + EXPECT_TRUE(changes.empty()); + + EXPECT_EQ((unsigned long)kFaviconBatchSize, GetFaviconCount()); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_HISTORY_URLS_DELETED, + content::Source<Profile>(NULL), + content::Details<history::URLsDeletedDetails>(&deletions)); + EXPECT_EQ((unsigned long)kFaviconBatchSize/2, GetFaviconCount()); + changes = processor()->GetAndResetChangeList(); + ASSERT_EQ(changes.size(), (unsigned long)kFaviconBatchSize); + syncer::SyncChangeList changes_1, changes_2; + for (size_t i = 0; i < kFaviconBatchSize/2; ++i) { + changes_1.push_back(changes[i]); + changes_2.push_back(changes[i + kFaviconBatchSize/2]); + } + VerifyChanges(syncer::FAVICON_IMAGES, + expected_deletions, + expected_icons, + changes_1); + VerifyChanges(syncer::FAVICON_TRACKING, + expected_deletions, + expected_icons, + changes_2); +} + } // namespace browser_sync |