| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/previews/previews_top_host_provider_impl.h" |
| |
| #include "base/values.h" |
| #include "chrome/browser/engagement/site_engagement_service.h" |
| #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/optimization_guide/optimization_guide_prefs.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/previews/content/previews_hints_util.h" |
| #include "components/previews/core/previews_experiments.h" |
| #include "content/public/test/mock_navigation_handle.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace previews { |
| |
| // Class to test the TopHostProvider and the HintsFetcherTopHostBlacklist. |
| class PreviewsTopHostProviderImplTest : public ChromeRenderViewHostTestHarness { |
| public: |
| void SetUp() override { |
| ChromeRenderViewHostTestHarness::SetUp(); |
| |
| top_host_provider_ = |
| std::make_unique<PreviewsTopHostProviderImpl>(profile()); |
| service_ = SiteEngagementService::Get(profile()); |
| pref_service_ = profile()->GetPrefs(); |
| } |
| |
| void AddEngagedHosts(size_t num_hosts) { |
| for (size_t i = 1; i <= num_hosts; i++) { |
| AddEngagedHost(GURL(base::StringPrintf("https://domain%zu.com", i)), |
| static_cast<int>(i)); |
| } |
| } |
| |
| void AddEngagedHost(GURL url, int num_points) { |
| service_->AddPointsForTesting(url, num_points); |
| } |
| |
| bool IsHostBlacklisted(const std::string& host) { |
| const base::DictionaryValue* top_host_blacklist = |
| pref_service_->GetDictionary( |
| optimization_guide::prefs::kHintsFetcherTopHostBlacklist); |
| return top_host_blacklist->FindKey(previews::HashHostForDictionary(host)); |
| } |
| |
| void PopulateTopHostBlacklist(size_t num_hosts) { |
| std::unique_ptr<base::DictionaryValue> top_host_filter = |
| pref_service_ |
| ->GetDictionary( |
| optimization_guide::prefs::kHintsFetcherTopHostBlacklist) |
| ->CreateDeepCopy(); |
| |
| for (size_t i = 1; i <= num_hosts; i++) { |
| top_host_filter->SetBoolKey( |
| HashHostForDictionary(base::StringPrintf("domain%zu.com", i)), true); |
| } |
| pref_service_->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist, |
| *top_host_filter); |
| } |
| |
| void AddHostToBlackList(const std::string& host) { |
| std::unique_ptr<base::DictionaryValue> top_host_filter = |
| pref_service_ |
| ->GetDictionary( |
| optimization_guide::prefs::kHintsFetcherTopHostBlacklist) |
| ->CreateDeepCopy(); |
| top_host_filter->SetBoolKey(previews::HashHostForDictionary(host), true); |
| pref_service_->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist, |
| *top_host_filter); |
| } |
| |
| void SimulateUniqueNavigationsToTopHosts(size_t num_hosts) { |
| for (size_t i = 1; i <= num_hosts; i++) { |
| SimulateNavigation(GURL(base::StringPrintf("https://domain%zu.com", i))); |
| } |
| } |
| |
| void SimulateNavigation(GURL url) { |
| std::unique_ptr<content::MockNavigationHandle> test_handle_ = |
| std::make_unique<content::MockNavigationHandle>(url, main_rfh()); |
| PreviewsTopHostProviderImpl::MaybeUpdateTopHostBlacklist( |
| test_handle_.get()); |
| } |
| |
| void RemoveHostsFromBlacklist(size_t num_hosts_navigated) { |
| std::unique_ptr<base::DictionaryValue> top_host_filter = |
| pref_service_ |
| ->GetDictionary( |
| optimization_guide::prefs::kHintsFetcherTopHostBlacklist) |
| ->CreateDeepCopy(); |
| |
| for (size_t i = 1; i <= num_hosts_navigated; i++) { |
| top_host_filter->RemoveKey( |
| HashHostForDictionary(base::StringPrintf("domain%zu.com", i))); |
| } |
| pref_service_->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist, |
| *top_host_filter); |
| } |
| |
| void SetTopHostBlacklistState( |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState |
| blacklist_state) { |
| profile()->GetPrefs()->SetInteger( |
| optimization_guide::prefs::kHintsFetcherTopHostBlacklistState, |
| static_cast<int>(blacklist_state)); |
| } |
| |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState |
| GetCurrentTopHostBlacklistState() { |
| return static_cast< |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState>( |
| pref_service_->GetInteger( |
| optimization_guide::prefs::kHintsFetcherTopHostBlacklistState)); |
| } |
| |
| void TearDown() override { ChromeRenderViewHostTestHarness::TearDown(); } |
| |
| PreviewsTopHostProviderImpl* top_host_provider() { |
| return top_host_provider_.get(); |
| } |
| |
| private: |
| std::unique_ptr<PreviewsTopHostProviderImpl> top_host_provider_; |
| SiteEngagementService* service_; |
| PrefService* pref_service_; |
| }; |
| |
| TEST_F(PreviewsTopHostProviderImplTest, GetTopHostsMaxSites) { |
| SetTopHostBlacklistState(optimization_guide::prefs:: |
| HintsFetcherTopHostBlacklistState::kInitialized); |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 3; |
| AddEngagedHosts(engaged_hosts); |
| |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| |
| EXPECT_EQ(max_top_hosts, hosts.size()); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, |
| GetTopHostsFiltersPrivacyBlackedlistedHosts) { |
| SetTopHostBlacklistState(optimization_guide::prefs:: |
| HintsFetcherTopHostBlacklistState::kInitialized); |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 5; |
| size_t num_hosts_blacklisted = 2; |
| AddEngagedHosts(engaged_hosts); |
| |
| PopulateTopHostBlacklist(num_hosts_blacklisted); |
| |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| |
| EXPECT_EQ(hosts.size(), engaged_hosts - num_hosts_blacklisted); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, GetTopHostsInitializeBlacklistState) { |
| EXPECT_EQ(GetCurrentTopHostBlacklistState(), |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState:: |
| kNotInitialized); |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 5; |
| AddEngagedHosts(engaged_hosts); |
| |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| // On initialization, GetTopHosts should always return zero hosts. |
| EXPECT_EQ(hosts.size(), 0u); |
| EXPECT_EQ(GetCurrentTopHostBlacklistState(), |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState:: |
| kInitialized); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, |
| GetTopHostsBlacklistStateNotInitializedToInitialized) { |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 5; |
| size_t num_hosts_blacklisted = 5; |
| AddEngagedHosts(engaged_hosts); |
| |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), 0u); |
| |
| // Blacklist should now have items removed. |
| size_t num_navigations = 2; |
| RemoveHostsFromBlacklist(num_navigations); |
| |
| hosts = top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), |
| engaged_hosts - (num_hosts_blacklisted - num_navigations)); |
| EXPECT_EQ(GetCurrentTopHostBlacklistState(), |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState:: |
| kInitialized); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, |
| GetTopHostsBlacklistStateNotInitializedToEmpty) { |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 5; |
| size_t num_hosts_blacklisted = 5; |
| AddEngagedHosts(engaged_hosts); |
| |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), 0u); |
| |
| // Blacklist should now have items removed. |
| size_t num_navigations = 5; |
| RemoveHostsFromBlacklist(num_navigations); |
| |
| hosts = top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), |
| engaged_hosts - (num_hosts_blacklisted - num_navigations)); |
| EXPECT_EQ( |
| GetCurrentTopHostBlacklistState(), |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState::kEmpty); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, |
| MaybeUpdateTopHostBlacklistNavigationsOnBlacklist) { |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 5; |
| size_t num_top_hosts = 3; |
| AddEngagedHosts(engaged_hosts); |
| |
| // The blacklist should be populated on the first request. |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), 0u); |
| |
| // Navigate to some engaged hosts to trigger their removal from the top host |
| // blacklist. |
| SimulateUniqueNavigationsToTopHosts(num_top_hosts); |
| |
| hosts = top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), num_top_hosts); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, |
| MaybeUpdateTopHostBlacklistEmptyBlacklist) { |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 5; |
| size_t num_top_hosts = 5; |
| AddEngagedHosts(engaged_hosts); |
| |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), 0u); |
| |
| SimulateUniqueNavigationsToTopHosts(num_top_hosts); |
| |
| EXPECT_EQ( |
| GetCurrentTopHostBlacklistState(), |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState::kEmpty); |
| |
| hosts = top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), num_top_hosts); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, |
| HintsFetcherTopHostBlacklistNonHTTPOrHTTPSHost) { |
| size_t engaged_hosts = 5; |
| size_t max_top_hosts = 5; |
| size_t num_hosts_blacklisted = 5; |
| GURL http_url = GURL("http://anyscheme.com"); |
| GURL file_url = GURL("file://anyscheme.com"); |
| AddEngagedHosts(engaged_hosts); |
| AddEngagedHost(http_url, 5); |
| |
| PopulateTopHostBlacklist(num_hosts_blacklisted); |
| AddHostToBlackList(http_url.host()); |
| |
| SetTopHostBlacklistState(optimization_guide::prefs:: |
| HintsFetcherTopHostBlacklistState::kInitialized); |
| |
| // A Non HTTP/HTTPS navigation should not remove a host from the blacklist. |
| SimulateNavigation(file_url); |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), 0u); |
| // The host, anyscheme.com, should still be on the blacklist. |
| EXPECT_TRUE(IsHostBlacklisted(file_url.host())); |
| |
| // TopHostProviderImpl prevents HTTP hosts from being returned. |
| SimulateNavigation(http_url); |
| hosts = top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), 0u); |
| |
| EXPECT_FALSE(IsHostBlacklisted(http_url.host())); |
| } |
| |
| TEST_F(PreviewsTopHostProviderImplTest, |
| IntializeTopHostBlacklistWithMaxTopSites) { |
| size_t engaged_hosts = |
| previews::params::MaxHintsFetcherTopHostBlacklistSize() + 1; |
| size_t max_top_hosts = |
| previews::params::MaxHintsFetcherTopHostBlacklistSize() + 1; |
| AddEngagedHosts(engaged_hosts); |
| |
| // Blacklist should be populated on the first request. |
| std::vector<std::string> hosts = |
| top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ(hosts.size(), 0u); |
| |
| hosts = top_host_provider()->GetTopHosts(max_top_hosts); |
| EXPECT_EQ( |
| hosts.size(), |
| engaged_hosts - previews::params::MaxHintsFetcherTopHostBlacklistSize()); |
| EXPECT_EQ(GetCurrentTopHostBlacklistState(), |
| optimization_guide::prefs::HintsFetcherTopHostBlacklistState:: |
| kInitialized); |
| |
| // The last host has the most engagement points so it will be blacklisted. The |
| // first host has the lowest engagement score and will not be blacklisted |
| // because it is not in the top MaxHintsFetcherTopHostBlacklistSize engaged |
| // hosts by engagement score. |
| EXPECT_TRUE(IsHostBlacklisted(base::StringPrintf( |
| "domain%zu.com", |
| previews::params::MaxHintsFetcherTopHostBlacklistSize()))); |
| EXPECT_FALSE(IsHostBlacklisted(base::StringPrintf("domain%u.com", 1u))); |
| } |
| |
| } // namespace previews |