[NTP][RQ] Removes the NTP Most Visited Repeatable Queries code
We are no longer pursuing this feature in its current form. See:
http://shortn/_19XwyxO97k
Keeps ntp_features::kNtpRepeatableQueries feature around for use in a
follow-up experiment to show organic repeatable queries in NTP MV tiles.
Fixed: 1177139, 1170500
, 1163629
Change-Id: I3916df9a1296096ecfb7874700ab60275d828ce7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2910964
Commit-Queue: Moe Ahmadi <mahmadi@chromium.org>
Reviewed-by: Mark Pearson <mpearson@chromium.org>
Reviewed-by: Nicolas Ouellet-Payeur <nicolaso@chromium.org>
Reviewed-by: Tibor Goldschwendt <tiborg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#886317}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
cacb35c4da
commit
bf8038bb47
chrome/browser
components
ntp_tiles
omnibox
browser
search
ios/chrome/browser
testing/variations
tools
metrics
histograms
histograms_xml
traffic_annotation
summary
@ -3974,8 +3974,6 @@ static_library("browser") {
|
||||
"search/promos/promo_service_factory.cc",
|
||||
"search/promos/promo_service_factory.h",
|
||||
"search/promos/promo_service_observer.h",
|
||||
"search/repeatable_queries/repeatable_queries_service_factory.cc",
|
||||
"search/repeatable_queries/repeatable_queries_service_factory.h",
|
||||
"search/search_engine_base_url_tracker.cc",
|
||||
"search/search_engine_base_url_tracker.h",
|
||||
"search/search_suggest/search_suggest_data.cc",
|
||||
|
@ -1512,19 +1512,6 @@ const FeatureEntry::FeatureVariation kNtpDriveModuleVariations[] = {
|
||||
{"- Managed Users Only", kNtpDriveModuleManagedUsersOnly,
|
||||
base::size(kNtpDriveModuleManagedUsersOnly), nullptr},
|
||||
};
|
||||
|
||||
const FeatureEntry::FeatureParam kNtpRepeatableQueriesInsertPositionStart[] = {
|
||||
{ntp_features::kNtpRepeatableQueriesInsertPositionParam, "start"}};
|
||||
const FeatureEntry::FeatureParam kNtpRepeatableQueriesInsertPositionEnd[] = {
|
||||
{ntp_features::kNtpRepeatableQueriesInsertPositionParam, "end"}};
|
||||
const FeatureEntry::FeatureVariation kNtpRepeatableQueriesVariations[] = {
|
||||
{"- Start", kNtpRepeatableQueriesInsertPositionStart,
|
||||
base::size(kNtpRepeatableQueriesInsertPositionStart),
|
||||
"t3317864" /* variation_id */},
|
||||
{"- End", kNtpRepeatableQueriesInsertPositionEnd,
|
||||
base::size(kNtpRepeatableQueriesInsertPositionEnd),
|
||||
"t3317864" /* variation_id */},
|
||||
};
|
||||
#endif // !defined(OS_ANDROID)
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
@ -4618,9 +4605,7 @@ const FeatureEntry kFeatureEntries[] = {
|
||||
|
||||
{"ntp-repeatable-queries", flag_descriptions::kNtpRepeatableQueriesName,
|
||||
flag_descriptions::kNtpRepeatableQueriesDescription, kOsDesktop,
|
||||
FEATURE_WITH_PARAMS_VALUE_TYPE(ntp_features::kNtpRepeatableQueries,
|
||||
kNtpRepeatableQueriesVariations,
|
||||
"NtpRepeatableQueries")},
|
||||
FEATURE_VALUE_TYPE(ntp_features::kNtpRepeatableQueries)},
|
||||
|
||||
{"ntp-modules", flag_descriptions::kNtpModulesName,
|
||||
flag_descriptions::kNtpModulesDescription, kOsDesktop,
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "chrome/browser/ntp_tiles/chrome_custom_links_manager_factory.h"
|
||||
#include "chrome/browser/ntp_tiles/chrome_popular_sites_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/search/repeatable_queries/repeatable_queries_service_factory.h"
|
||||
#include "chrome/browser/search/suggestions/suggestions_service_factory.h"
|
||||
#include "chrome/common/buildflags.h"
|
||||
#include "components/history/core/browser/top_sites.h"
|
||||
@ -120,11 +119,6 @@ ChromeMostVisitedSitesFactory::NewForProfile(Profile* profile) {
|
||||
|
||||
auto most_visited_sites = std::make_unique<ntp_tiles::MostVisitedSites>(
|
||||
profile->GetPrefs(), TopSitesFactory::GetForProfile(profile),
|
||||
#if defined(OS_ANDROID)
|
||||
nullptr,
|
||||
#else
|
||||
RepeatableQueriesServiceFactory::GetForProfile(profile),
|
||||
#endif
|
||||
SuggestionsServiceFactory::GetForProfile(profile),
|
||||
#if defined(OS_ANDROID)
|
||||
ChromePopularSitesFactory::NewForProfile(profile),
|
||||
|
@ -10,74 +10,6 @@
|
||||
|
||||
namespace ntp_features {
|
||||
|
||||
TEST(NTPFeaturesTest, LocalHistoryRepeatableQueriesAgeThresholdDays) {
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
|
||||
// The default value can be overridden.
|
||||
scoped_feature_list_.InitWithFeaturesAndParameters(
|
||||
{{kNtpRepeatableQueries,
|
||||
{{kNtpRepeatableQueriesAgeThresholdDaysParam, "7"}}}},
|
||||
{});
|
||||
base::Time age_threshold = GetLocalHistoryRepeatableQueriesAgeThreshold();
|
||||
EXPECT_EQ(7, base::TimeDelta(base::Time::Now() - age_threshold).InDays());
|
||||
|
||||
// If the age threshold is not parsable to an unsigned integer, the default
|
||||
// value is used.
|
||||
scoped_feature_list_.Reset();
|
||||
scoped_feature_list_.InitWithFeaturesAndParameters(
|
||||
{{kNtpRepeatableQueries,
|
||||
{{kNtpRepeatableQueriesAgeThresholdDaysParam, "j"}}}},
|
||||
{});
|
||||
age_threshold = GetLocalHistoryRepeatableQueriesAgeThreshold();
|
||||
EXPECT_EQ(180, base::TimeDelta(base::Time::Now() - age_threshold).InDays());
|
||||
}
|
||||
|
||||
TEST(NTPFeaturesTest, LocalHistoryRepeatableQueriesRecencyDecayUnit) {
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
|
||||
// The default value can be overridden.
|
||||
scoped_feature_list_.InitWithFeaturesAndParameters(
|
||||
{{kNtpRepeatableQueries,
|
||||
{{kNtpRepeatableQueriesRecencyHalfLifeSecondsParam,
|
||||
"86400" /* One day */}}}},
|
||||
{});
|
||||
int recency_decay = GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds();
|
||||
EXPECT_EQ(86400, recency_decay);
|
||||
|
||||
// If the recency decay unit is not parsable to an unsigned integer, the
|
||||
// default value is used.
|
||||
scoped_feature_list_.Reset();
|
||||
scoped_feature_list_.InitWithFeaturesAndParameters(
|
||||
{{kNtpRepeatableQueries,
|
||||
{{kNtpRepeatableQueriesRecencyHalfLifeSecondsParam, "j"}}}},
|
||||
{});
|
||||
recency_decay = GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds();
|
||||
EXPECT_EQ(604800 /* One week */, recency_decay);
|
||||
}
|
||||
|
||||
TEST(NTPFeaturesTest, LocalHistoryRepeatableQueriesFrequencyExponent) {
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
|
||||
// The default value can be overridden.
|
||||
scoped_feature_list_.InitWithFeaturesAndParameters(
|
||||
{{kNtpRepeatableQueries,
|
||||
{{kNtpRepeatableQueriesFrequencyExponentParam, "1.5"}}}},
|
||||
{});
|
||||
double frequency_exponent =
|
||||
GetLocalHistoryRepeatableQueriesFrequencyExponent();
|
||||
EXPECT_EQ(1.5, frequency_exponent);
|
||||
|
||||
// If the recency decay unit is not parsable to an unsigned integer, the
|
||||
// default value is used.
|
||||
scoped_feature_list_.Reset();
|
||||
scoped_feature_list_.InitWithFeaturesAndParameters(
|
||||
{{kNtpRepeatableQueries,
|
||||
{{kNtpRepeatableQueriesFrequencyExponentParam, "j"}}}},
|
||||
{});
|
||||
frequency_exponent = GetLocalHistoryRepeatableQueriesFrequencyExponent();
|
||||
EXPECT_EQ(2, frequency_exponent);
|
||||
}
|
||||
|
||||
TEST(NTPFeaturesTest, ModulesLoadTimeout) {
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
|
||||
|
@ -1,62 +0,0 @@
|
||||
// Copyright 2020 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/search/repeatable_queries/repeatable_queries_service_factory.h"
|
||||
|
||||
#include "base/feature_list.h"
|
||||
#include "chrome/browser/content_settings/cookie_settings_factory.h"
|
||||
#include "chrome/browser/history/history_service_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/search_engines/template_url_service_factory.h"
|
||||
#include "chrome/browser/signin/identity_manager_factory.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "components/keyed_service/content/browser_context_dependency_manager.h"
|
||||
#include "components/omnibox/common/omnibox_features.h"
|
||||
#include "components/search/ntp_features.h"
|
||||
#include "components/search/repeatable_queries/repeatable_queries_service.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
|
||||
// static
|
||||
RepeatableQueriesService* RepeatableQueriesServiceFactory::GetForProfile(
|
||||
Profile* profile) {
|
||||
return static_cast<RepeatableQueriesService*>(
|
||||
GetInstance()->GetServiceForBrowserContext(profile, true));
|
||||
}
|
||||
|
||||
// static
|
||||
RepeatableQueriesServiceFactory*
|
||||
RepeatableQueriesServiceFactory::GetInstance() {
|
||||
return base::Singleton<RepeatableQueriesServiceFactory>::get();
|
||||
}
|
||||
|
||||
RepeatableQueriesServiceFactory::RepeatableQueriesServiceFactory()
|
||||
: BrowserContextKeyedServiceFactory(
|
||||
"RepeatableQueriesService",
|
||||
BrowserContextDependencyManager::GetInstance()) {
|
||||
DependsOn(CookieSettingsFactory::GetInstance());
|
||||
DependsOn(IdentityManagerFactory::GetInstance());
|
||||
}
|
||||
|
||||
RepeatableQueriesServiceFactory::~RepeatableQueriesServiceFactory() = default;
|
||||
|
||||
KeyedService* RepeatableQueriesServiceFactory::BuildServiceInstanceFor(
|
||||
content::BrowserContext* context) const {
|
||||
if (!base::FeatureList::IsEnabled(ntp_features::kNtpRepeatableQueries))
|
||||
return nullptr;
|
||||
|
||||
Profile* profile = Profile::FromBrowserContext(context);
|
||||
signin::IdentityManager* identity_manager =
|
||||
IdentityManagerFactory::GetForProfile(profile);
|
||||
history::HistoryService* history_service =
|
||||
HistoryServiceFactory::GetForProfile(profile,
|
||||
ServiceAccessType::EXPLICIT_ACCESS);
|
||||
TemplateURLService* template_url_service =
|
||||
TemplateURLServiceFactory::GetForProfile(profile);
|
||||
auto url_loader_factory = context->GetDefaultStoragePartition()
|
||||
->GetURLLoaderFactoryForBrowserProcess();
|
||||
return new RepeatableQueriesService(identity_manager, history_service,
|
||||
template_url_service, url_loader_factory,
|
||||
GURL(chrome::kChromeUINewTabURL));
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef CHROME_BROWSER_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_FACTORY_H_
|
||||
#define CHROME_BROWSER_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_FACTORY_H_
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
|
||||
|
||||
class RepeatableQueriesService;
|
||||
class Profile;
|
||||
|
||||
class RepeatableQueriesServiceFactory
|
||||
: public BrowserContextKeyedServiceFactory {
|
||||
public:
|
||||
// Returns the RepeatableQueriesService for |profile|.
|
||||
static RepeatableQueriesService* GetForProfile(Profile* profile);
|
||||
|
||||
static RepeatableQueriesServiceFactory* GetInstance();
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<RepeatableQueriesServiceFactory>;
|
||||
|
||||
RepeatableQueriesServiceFactory();
|
||||
~RepeatableQueriesServiceFactory() override;
|
||||
|
||||
// Overridden from BrowserContextKeyedServiceFactory:
|
||||
KeyedService* BuildServiceInstanceFor(
|
||||
content::BrowserContext* profile) const override;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RepeatableQueriesServiceFactory);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_FACTORY_H_
|
@ -92,7 +92,6 @@ bool ChromeNTPTilesInternalsMessageHandlerClient::DoesSourceExist(
|
||||
return false;
|
||||
#endif
|
||||
case ntp_tiles::TileSource::CUSTOM_LINKS:
|
||||
case ntp_tiles::TileSource::REPEATABLE_QUERIES_SERVICE:
|
||||
#if defined(OS_ANDROID)
|
||||
return false;
|
||||
#else
|
||||
|
@ -29,7 +29,6 @@ const char kHistogramAllowlistName[] = "allowlist";
|
||||
const char kHistogramHomepageName[] = "homepage";
|
||||
const char kHistogramCustomLinksName[] = "custom_links";
|
||||
const char kHistogramExploreName[] = "explore";
|
||||
const char kHistogramRepeatableQueryName[] = "repeatable_query";
|
||||
|
||||
// Suffixes for the various icon types.
|
||||
const char kTileTypeSuffixIconColor[] = "IconsColor";
|
||||
@ -60,8 +59,6 @@ std::string GetSourceHistogramName(TileSource source) {
|
||||
return kHistogramCustomLinksName;
|
||||
case TileSource::EXPLORE:
|
||||
return kHistogramExploreName;
|
||||
case TileSource::REPEATABLE_QUERIES_SERVICE:
|
||||
return kHistogramRepeatableQueryName;
|
||||
}
|
||||
NOTREACHED();
|
||||
return std::string();
|
||||
|
@ -120,7 +120,6 @@ std::u16string GenerateShortTitle(const std::u16string& title) {
|
||||
MostVisitedSites::MostVisitedSites(
|
||||
PrefService* prefs,
|
||||
scoped_refptr<history::TopSites> top_sites,
|
||||
RepeatableQueriesService* repeatable_queries,
|
||||
SuggestionsService* suggestions,
|
||||
std::unique_ptr<PopularSites> popular_sites,
|
||||
std::unique_ptr<CustomLinksManager> custom_links,
|
||||
@ -128,7 +127,6 @@ MostVisitedSites::MostVisitedSites(
|
||||
std::unique_ptr<MostVisitedSitesSupervisor> supervisor)
|
||||
: prefs_(prefs),
|
||||
top_sites_(top_sites),
|
||||
repeatable_queries_(repeatable_queries),
|
||||
suggestions_service_(suggestions),
|
||||
popular_sites_(std::move(popular_sites)),
|
||||
custom_links_(std::move(custom_links)),
|
||||
@ -181,8 +179,6 @@ bool MostVisitedSites::DoesSourceExist(TileSource source) const {
|
||||
return custom_links_ != nullptr;
|
||||
case TileSource::EXPLORE:
|
||||
return explore_sites_client_ != nullptr;
|
||||
case TileSource::REPEATABLE_QUERIES_SERVICE:
|
||||
return false;
|
||||
}
|
||||
NOTREACHED();
|
||||
return false;
|
||||
@ -220,10 +216,6 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
|
||||
top_sites_observation_.Observe(top_sites_.get());
|
||||
}
|
||||
|
||||
if (repeatable_queries_) {
|
||||
repeatable_queries_observation_.Observe(repeatable_queries_);
|
||||
}
|
||||
|
||||
if (custom_links_) {
|
||||
custom_links_subscription_ =
|
||||
custom_links_->RegisterCallbackForOnChanged(base::BindRepeating(
|
||||
@ -250,10 +242,6 @@ void MostVisitedSites::Refresh() {
|
||||
top_sites_->SyncWithHistory();
|
||||
}
|
||||
|
||||
if (repeatable_queries_) {
|
||||
repeatable_queries_->Refresh();
|
||||
}
|
||||
|
||||
suggestions_service_->FetchSuggestionsData();
|
||||
}
|
||||
|
||||
@ -403,12 +391,6 @@ void MostVisitedSites::AddOrRemoveBlockedUrl(const GURL& url, bool add_url) {
|
||||
base::UserMetricsAction("Suggestions.Site.RemovalUndone"));
|
||||
}
|
||||
|
||||
if (repeatable_queries_) {
|
||||
// Restoring repeatable queries is not supported as deletion is permanent.
|
||||
if (add_url)
|
||||
repeatable_queries_->DeleteQueryWithDestinationURL(url);
|
||||
}
|
||||
|
||||
if (top_sites_) {
|
||||
if (add_url)
|
||||
top_sites_->AddBlockedUrl(url);
|
||||
@ -501,37 +483,7 @@ void MostVisitedSites::OnMostVisitedURLsAvailable(
|
||||
}
|
||||
|
||||
mv_source_ = TileSource::TOP_SITES;
|
||||
InitiateNotificationForNewTiles(InsertRepeatableQueryTiles(std::move(tiles)));
|
||||
}
|
||||
|
||||
NTPTilesVector MostVisitedSites::InsertRepeatableQueryTiles(
|
||||
NTPTilesVector tiles) {
|
||||
if (!repeatable_queries_)
|
||||
return tiles;
|
||||
|
||||
const std::vector<RepeatableQuery>& repeatable_queries =
|
||||
repeatable_queries_->repeatable_queries();
|
||||
|
||||
// Make room for the repeatable query tiles, if necessary.
|
||||
int num_overflow_tiles =
|
||||
tiles.size() + repeatable_queries.size() - GetMaxNumSites();
|
||||
if (num_overflow_tiles > 0)
|
||||
tiles.resize(tiles.size() - num_overflow_tiles);
|
||||
|
||||
auto insert_position = (ntp_features::GetRepeatableQueriesInsertPosition() ==
|
||||
ntp_features::RepeatableQueriesInsertPosition::kStart)
|
||||
? tiles.begin()
|
||||
: tiles.end();
|
||||
for (const auto& repeatable_query : repeatable_queries) {
|
||||
NTPTile tile;
|
||||
tile.title = repeatable_query.query;
|
||||
tile.url = repeatable_query.destination_url;
|
||||
tile.source = TileSource::REPEATABLE_QUERIES_SERVICE;
|
||||
|
||||
auto inserted_position = tiles.insert(insert_position, tile);
|
||||
insert_position = inserted_position + 1;
|
||||
}
|
||||
return tiles;
|
||||
InitiateNotificationForNewTiles(std::move(tiles));
|
||||
}
|
||||
|
||||
void MostVisitedSites::OnSuggestionsProfileChanged(
|
||||
@ -938,21 +890,6 @@ void MostVisitedSites::TopSitesChanged(TopSites* top_sites,
|
||||
}
|
||||
}
|
||||
|
||||
void MostVisitedSites::OnRepeatableQueriesUpdated() {
|
||||
// Repeatable Queries are shown along with the most visited URLs only.
|
||||
// Simulate a change to the most visited urls. This will result in
|
||||
// MostVisitedSites::OnMostVisitedURLsAvailable to be called synchronously or
|
||||
// asynchronously depending on whether the most visited URLs are cached.
|
||||
if (top_sites_) {
|
||||
TopSitesChanged(top_sites_.get(), ChangeReason::MOST_VISITED);
|
||||
}
|
||||
}
|
||||
|
||||
void MostVisitedSites::OnRepeatableQueriesServiceShuttingDown() {
|
||||
DCHECK(repeatable_queries_observation_.IsObserving());
|
||||
repeatable_queries_observation_.Reset();
|
||||
}
|
||||
|
||||
bool MostVisitedSites::ShouldAddHomeTile() const {
|
||||
return GetMaxNumSites() > 0u &&
|
||||
homepage_client_ && // No platform-specific implementation - no tile.
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include "components/ntp_tiles/popular_sites.h"
|
||||
#include "components/ntp_tiles/section_type.h"
|
||||
#include "components/ntp_tiles/tile_source.h"
|
||||
#include "components/search/repeatable_queries/repeatable_queries_service.h"
|
||||
#include "components/search/repeatable_queries/repeatable_queries_service_observer.h"
|
||||
#include "components/suggestions/proto/suggestions.pb.h"
|
||||
#include "components/suggestions/suggestions_service.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
@ -84,8 +82,7 @@ class MostVisitedSitesSupervisor {
|
||||
|
||||
// Tracks the list of most visited sites.
|
||||
class MostVisitedSites : public history::TopSitesObserver,
|
||||
public MostVisitedSitesSupervisor::Observer,
|
||||
public RepeatableQueriesServiceObserver {
|
||||
public MostVisitedSitesSupervisor::Observer {
|
||||
public:
|
||||
// The observer to be notified when the list of most visited sites changes.
|
||||
class Observer {
|
||||
@ -126,7 +123,6 @@ class MostVisitedSites : public history::TopSitesObserver,
|
||||
// optional and if null, the associated features will be disabled.
|
||||
MostVisitedSites(PrefService* prefs,
|
||||
scoped_refptr<history::TopSites> top_sites,
|
||||
RepeatableQueriesService* repeatable_queries,
|
||||
suggestions::SuggestionsService* suggestions,
|
||||
std::unique_ptr<PopularSites> popular_sites,
|
||||
std::unique_ptr<CustomLinksManager> custom_links,
|
||||
@ -266,8 +262,6 @@ class MostVisitedSites : public history::TopSitesObserver,
|
||||
void OnMostVisitedURLsAvailable(
|
||||
const history::MostVisitedURLList& visited_list);
|
||||
|
||||
NTPTilesVector InsertRepeatableQueryTiles(NTPTilesVector tiles);
|
||||
|
||||
// Callback for when an update is reported by the SuggestionsService.
|
||||
void OnSuggestionsProfileChanged(
|
||||
const suggestions::SuggestionsProfile& suggestions_profile);
|
||||
@ -349,13 +343,8 @@ class MostVisitedSites : public history::TopSitesObserver,
|
||||
void TopSitesChanged(history::TopSites* top_sites,
|
||||
ChangeReason change_reason) override;
|
||||
|
||||
// RepeatableQueriesServiceObserver implementation.
|
||||
void OnRepeatableQueriesUpdated() override;
|
||||
void OnRepeatableQueriesServiceShuttingDown() override;
|
||||
|
||||
PrefService* prefs_;
|
||||
scoped_refptr<history::TopSites> top_sites_;
|
||||
RepeatableQueriesService* repeatable_queries_;
|
||||
suggestions::SuggestionsService* suggestions_service_;
|
||||
std::unique_ptr<PopularSites> const popular_sites_;
|
||||
std::unique_ptr<CustomLinksManager> const custom_links_;
|
||||
@ -382,10 +371,6 @@ class MostVisitedSites : public history::TopSitesObserver,
|
||||
base::ScopedObservation<history::TopSites, history::TopSitesObserver>
|
||||
top_sites_observation_{this};
|
||||
|
||||
base::ScopedObservation<RepeatableQueriesService,
|
||||
RepeatableQueriesServiceObserver>
|
||||
repeatable_queries_observation_{this};
|
||||
|
||||
base::CallbackListSubscription custom_links_subscription_;
|
||||
|
||||
// The main source of personal tiles - either TOP_SITES or SUGGESTIONS_SEVICE.
|
||||
|
@ -472,9 +472,9 @@ class MostVisitedSitesTest
|
||||
EXPECT_CALL(*icon_cacher, StartFetchMostLikely(_, _)).Times(AtLeast(0));
|
||||
|
||||
most_visited_sites_ = std::make_unique<MostVisitedSites>(
|
||||
&pref_service_, mock_top_sites_, /*repeatable_queries=*/nullptr,
|
||||
&mock_suggestions_service_, popular_sites_factory_.New(),
|
||||
std::move(mock_custom_links), std::move(icon_cacher),
|
||||
&pref_service_, mock_top_sites_, &mock_suggestions_service_,
|
||||
popular_sites_factory_.New(), std::move(mock_custom_links),
|
||||
std::move(icon_cacher),
|
||||
/*supervisor=*/nullptr);
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,8 @@ enum class TileSource {
|
||||
HOMEPAGE,
|
||||
// Tile comes from explore sites list.
|
||||
EXPLORE,
|
||||
// Tile comes from the repeatable queries service, based on search history.
|
||||
REPEATABLE_QUERIES_SERVICE,
|
||||
|
||||
LAST = REPEATABLE_QUERIES_SERVICE
|
||||
LAST = EXPLORE
|
||||
};
|
||||
|
||||
} // namespace ntp_tiles
|
||||
|
@ -152,7 +152,6 @@ class InMemoryURLIndex : public KeyedService,
|
||||
friend class history::HQPPerfTestOnePopularURL;
|
||||
friend class InMemoryURLIndexTest;
|
||||
friend class InMemoryURLIndexCacheTest;
|
||||
friend class RepeatableQueriesServiceTest;
|
||||
FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, ExpireRow);
|
||||
FRIEND_TEST_ALL_PREFIXES(LimitedInMemoryURLIndexTest, Initialization);
|
||||
|
||||
|
@ -6,9 +6,6 @@ static_library("search") {
|
||||
sources = [
|
||||
"ntp_features.cc",
|
||||
"ntp_features.h",
|
||||
"repeatable_queries/repeatable_queries_service.cc",
|
||||
"repeatable_queries/repeatable_queries_service.h",
|
||||
"repeatable_queries/repeatable_queries_service_observer.h",
|
||||
"search.cc",
|
||||
"search.h",
|
||||
"search_provider_observer.cc",
|
||||
@ -34,10 +31,7 @@ static_library("search") {
|
||||
source_set("unit_tests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"repeatable_queries/repeatable_queries_service_unittest.cc",
|
||||
"search_unittest.cc",
|
||||
]
|
||||
sources = [ "search_unittest.cc" ]
|
||||
if (is_android) {
|
||||
sources += [ "search_android_unittest.cc" ]
|
||||
}
|
||||
|
@ -95,15 +95,6 @@ const base::Feature kNtpChromeCartModule{"NtpChromeCartModule",
|
||||
const base::Feature kNtpDriveModule{"NtpDriveModule",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT};
|
||||
|
||||
const char kNtpRepeatableQueriesAgeThresholdDaysParam[] =
|
||||
"NtpRepeatableQueriesAgeThresholdDays";
|
||||
const char kNtpRepeatableQueriesRecencyHalfLifeSecondsParam[] =
|
||||
"NtpRepeatableQueriesRecencyHalfLifeSeconds";
|
||||
const char kNtpRepeatableQueriesFrequencyExponentParam[] =
|
||||
"NtpRepeatableQueriesFrequencyExponent";
|
||||
const char kNtpRepeatableQueriesInsertPositionParam[] =
|
||||
"NtpRepeatableQueriesInsertPosition";
|
||||
|
||||
const char kNtpModulesLoadTimeoutMillisecondsParam[] =
|
||||
"NtpModulesLoadTimeoutMillisecondsParam";
|
||||
const char kNtpStatefulTasksModuleDataParam[] =
|
||||
@ -117,60 +108,6 @@ const char kNtpDriveModuleDataParam[] = "NtpDriveModuleDataParam";
|
||||
const char kNtpDriveModuleManagedUsersOnlyParam[] =
|
||||
"NtpDriveModuleManagedUsersOnlyParam";
|
||||
|
||||
base::Time GetLocalHistoryRepeatableQueriesAgeThreshold() {
|
||||
const base::TimeDelta kLocalHistoryRepeatableQueriesAgeThreshold =
|
||||
base::TimeDelta::FromDays(180); // Six months.
|
||||
std::string param_value = base::GetFieldTrialParamValueByFeature(
|
||||
kNtpRepeatableQueries, kNtpRepeatableQueriesAgeThresholdDaysParam);
|
||||
|
||||
// If the field trial param is not found or cannot be parsed to an unsigned
|
||||
// integer, return the default value.
|
||||
unsigned int param_value_as_int = 0;
|
||||
if (!base::StringToUint(param_value, ¶m_value_as_int)) {
|
||||
return base::Time::Now() - kLocalHistoryRepeatableQueriesAgeThreshold;
|
||||
}
|
||||
|
||||
return (base::Time::Now() - base::TimeDelta::FromDays(param_value_as_int));
|
||||
}
|
||||
|
||||
int GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds() {
|
||||
const base::TimeDelta kLocalHistoryRepeatableQueriesRecencyHalfLife =
|
||||
base::TimeDelta::FromDays(7); // One week.
|
||||
std::string param_value = base::GetFieldTrialParamValueByFeature(
|
||||
kNtpRepeatableQueries, kNtpRepeatableQueriesRecencyHalfLifeSecondsParam);
|
||||
|
||||
// If the field trial param is not found or cannot be parsed to an unsigned
|
||||
// integer, return the default value.
|
||||
unsigned int param_value_as_int = 0;
|
||||
if (!base::StringToUint(param_value, ¶m_value_as_int)) {
|
||||
return kLocalHistoryRepeatableQueriesRecencyHalfLife.InSeconds();
|
||||
}
|
||||
|
||||
return param_value_as_int;
|
||||
}
|
||||
|
||||
double GetLocalHistoryRepeatableQueriesFrequencyExponent() {
|
||||
const double kLocalHistoryRepeatableQueriesFrequencyExponent = 2.0;
|
||||
std::string param_value = base::GetFieldTrialParamValueByFeature(
|
||||
kNtpRepeatableQueries, kNtpRepeatableQueriesFrequencyExponentParam);
|
||||
|
||||
// If the field trial param is not found or cannot be parsed to an unsigned
|
||||
// integer, return the default value.
|
||||
double param_value_as_double = 0;
|
||||
if (!base::StringToDouble(param_value, ¶m_value_as_double)) {
|
||||
return kLocalHistoryRepeatableQueriesFrequencyExponent;
|
||||
}
|
||||
|
||||
return param_value_as_double;
|
||||
}
|
||||
|
||||
RepeatableQueriesInsertPosition GetRepeatableQueriesInsertPosition() {
|
||||
std::string param_value = base::GetFieldTrialParamValueByFeature(
|
||||
kNtpRepeatableQueries, kNtpRepeatableQueriesInsertPositionParam);
|
||||
return param_value == "end" ? RepeatableQueriesInsertPosition::kEnd
|
||||
: RepeatableQueriesInsertPosition::kStart;
|
||||
}
|
||||
|
||||
base::TimeDelta GetModulesLoadTimeout() {
|
||||
std::string param_value = base::GetFieldTrialParamValueByFeature(
|
||||
kModules, kNtpModulesLoadTimeoutMillisecondsParam);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "base/feature_list.h"
|
||||
|
||||
namespace base {
|
||||
class Time;
|
||||
class TimeDelta;
|
||||
} // namespace base
|
||||
|
||||
namespace ntp_features {
|
||||
@ -38,28 +38,6 @@ extern const base::Feature kDisableSearchSuggestChips;
|
||||
|
||||
extern const base::Feature kNtpHandleMostVisitedNavigationExplicitly;
|
||||
|
||||
// Parameter name determining the age threshold in days for local history
|
||||
// repeatable queries.
|
||||
// The value of this parameter should be parsable as an unsigned integer.
|
||||
extern const char kNtpRepeatableQueriesAgeThresholdDaysParam[];
|
||||
// Parameter name determining the number of seconds until the recency component
|
||||
// of the frecency score for local history repeatable queries decays to half.
|
||||
// The value of this parameter should be parsable as an unsigned integer.
|
||||
extern const char kNtpRepeatableQueriesRecencyHalfLifeSecondsParam[];
|
||||
// Parameter name determining the factor by which the frequency component of the
|
||||
// frecency score for local history repeatable queries is exponentiated.
|
||||
// The value of this parameter should be parsable as a double.
|
||||
extern const char kNtpRepeatableQueriesFrequencyExponentParam[];
|
||||
// Parameter name determining the position, with respect to the MV tiles, in
|
||||
// which the repeatable queries should be inserted.
|
||||
extern const char kNtpRepeatableQueriesInsertPositionParam[];
|
||||
// The available positions, with respect to the MV tiles, in which the
|
||||
// repeatable queries can be inserted.
|
||||
enum class RepeatableQueriesInsertPosition {
|
||||
kStart = 0, // At the start of MV tiles.
|
||||
kEnd, // At the end of MV tiles.
|
||||
};
|
||||
|
||||
// Parameter determining the module load timeout.
|
||||
extern const char kNtpModulesLoadTimeoutMillisecondsParam[];
|
||||
// Parameter determining the type of stateful data to request.
|
||||
@ -75,18 +53,6 @@ extern const char kNtpDriveModuleDataParam[];
|
||||
// Parameter for enabling the Drive module for managed users only.
|
||||
extern const char kNtpDriveModuleManagedUsersOnlyParam[];
|
||||
|
||||
// Returns the age threshold for local history repeatable queries.
|
||||
base::Time GetLocalHistoryRepeatableQueriesAgeThreshold();
|
||||
// Returns the number of seconds until the recency component of the frecency
|
||||
// score for local history repeatable queries decays to half.
|
||||
int GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds();
|
||||
// Returns the factor by which the frequency component of the frecency score for
|
||||
// local history repeatable queries is exponentiated.
|
||||
double GetLocalHistoryRepeatableQueriesFrequencyExponent();
|
||||
// Returns the position, with respect to the MV tiles, in which the repeatable
|
||||
// queries should be inserted.
|
||||
RepeatableQueriesInsertPosition GetRepeatableQueriesInsertPosition();
|
||||
|
||||
// Returns the timeout after which the load of a module should be aborted.
|
||||
base::TimeDelta GetModulesLoadTimeout();
|
||||
} // namespace ntp_features
|
||||
|
@ -1,529 +0,0 @@
|
||||
// Copyright 2020 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 "components/search/repeatable_queries/repeatable_queries_service.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/callback_helpers.h"
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/json/json_writer.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/scoped_observation.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/task/task_traits.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/values.h"
|
||||
#include "components/history/core/browser/history_service.h"
|
||||
#include "components/history/core/browser/history_types.h"
|
||||
#include "components/history/core/browser/keyword_search_term.h"
|
||||
#include "components/history/core/browser/url_database.h"
|
||||
#include "components/search/ntp_features.h"
|
||||
#include "components/search/search_provider_observer.h"
|
||||
#include "components/search_engines/template_url_service.h"
|
||||
#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
|
||||
#include "components/signin/public/identity_manager/identity_manager.h"
|
||||
#include "components/variations/net/variations_http_headers.h"
|
||||
#include "net/http/http_status_code.h"
|
||||
#include "net/traffic_annotation/network_traffic_annotation.h"
|
||||
#include "services/network/public/cpp/resource_request.h"
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "services/network/public/cpp/simple_url_loader.h"
|
||||
|
||||
namespace {
|
||||
const char kXSSIResponsePreamble[] = ")]}'";
|
||||
const size_t kMaxQueries = 2;
|
||||
|
||||
bool JsonToRepeatableQueriesData(const base::Value& root_value,
|
||||
std::vector<RepeatableQuery>* data) {
|
||||
// 1st element is the query. 2nd element is the list of results.
|
||||
std::u16string query;
|
||||
const base::ListValue* root_list = nullptr;
|
||||
const base::ListValue* results_list = nullptr;
|
||||
if (!root_value.GetAsList(&root_list) || !root_list->GetString(0, &query) ||
|
||||
!query.empty() || !root_list->GetList(1, &results_list))
|
||||
return false;
|
||||
|
||||
// Ignore the 3rd and 4th elements. 5th element is the key-value pairs from
|
||||
// the Suggest server containing the deletion URLs.
|
||||
const base::DictionaryValue* extras = nullptr;
|
||||
const base::ListValue* suggestion_details = nullptr;
|
||||
if (!root_list->GetDictionary(4, &extras) ||
|
||||
!extras->GetList("google:suggestdetail", &suggestion_details) ||
|
||||
suggestion_details->GetSize() != results_list->GetSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::u16string suggestion;
|
||||
for (size_t index = 0; results_list->GetString(index, &suggestion); ++index) {
|
||||
RepeatableQuery result;
|
||||
result.query = base::CollapseWhitespace(suggestion, false);
|
||||
if (result.query.empty())
|
||||
continue;
|
||||
|
||||
const base::DictionaryValue* suggestion_detail = nullptr;
|
||||
if (suggestion_details->GetDictionary(index, &suggestion_detail)) {
|
||||
suggestion_detail->GetString("du", &result.deletion_url);
|
||||
}
|
||||
data->push_back(result);
|
||||
}
|
||||
|
||||
return !data->empty();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
const char RepeatableQueriesService::kExtractedCountHistogram[] =
|
||||
"NewTabPage.RepeatableQueries.ExtractedCount";
|
||||
const char RepeatableQueriesService::kExtractionDurationHistogram[] =
|
||||
"NewTabPage.RepeatableQueries.ExtractionDuration";
|
||||
|
||||
class RepeatableQueriesService::SigninObserver
|
||||
: public signin::IdentityManager::Observer {
|
||||
public:
|
||||
SigninObserver(signin::IdentityManager* identity_manager,
|
||||
base::RepeatingClosure callback)
|
||||
: identity_manager_(identity_manager), callback_(std::move(callback)) {
|
||||
if (identity_manager_) {
|
||||
identity_manager_observation_.Observe(identity_manager_);
|
||||
}
|
||||
}
|
||||
~SigninObserver() override = default;
|
||||
|
||||
bool IsSignedIn() {
|
||||
return identity_manager_ ? !identity_manager_->GetAccountsInCookieJar()
|
||||
.signed_in_accounts.empty()
|
||||
: false;
|
||||
}
|
||||
|
||||
private:
|
||||
// IdentityManager::Observer implementation.
|
||||
void OnAccountsInCookieUpdated(
|
||||
const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
|
||||
const GoogleServiceAuthError& error) override {
|
||||
callback_.Run();
|
||||
}
|
||||
|
||||
base::ScopedObservation<signin::IdentityManager,
|
||||
signin::IdentityManager::Observer>
|
||||
identity_manager_observation_{this};
|
||||
// May be nullptr in tests.
|
||||
signin::IdentityManager* const identity_manager_;
|
||||
base::RepeatingClosure callback_;
|
||||
};
|
||||
|
||||
RepeatableQueriesService::RepeatableQueriesService(
|
||||
signin::IdentityManager* identity_manager,
|
||||
history::HistoryService* history_service,
|
||||
TemplateURLService* template_url_service,
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
|
||||
const GURL& request_initiator_url)
|
||||
: history_service_(history_service),
|
||||
template_url_service_(template_url_service),
|
||||
url_loader_factory_(url_loader_factory),
|
||||
request_initiator_url_(request_initiator_url),
|
||||
signin_observer_(std::make_unique<SigninObserver>(
|
||||
identity_manager,
|
||||
base::BindRepeating(&RepeatableQueriesService::SigninStatusChanged,
|
||||
base::Unretained(this)))),
|
||||
search_provider_observer_(std::make_unique<SearchProviderObserver>(
|
||||
template_url_service,
|
||||
base::BindRepeating(&RepeatableQueriesService::SearchProviderChanged,
|
||||
base::Unretained(this)))),
|
||||
deletion_task_runner_(base::ThreadPool::CreateSequencedTaskRunner({})) {
|
||||
DCHECK(history_service_);
|
||||
DCHECK(template_url_service_);
|
||||
DCHECK(url_loader_factory_);
|
||||
}
|
||||
|
||||
RepeatableQueriesService::~RepeatableQueriesService() = default;
|
||||
|
||||
void RepeatableQueriesService::Shutdown() {
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnRepeatableQueriesServiceShuttingDown();
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<RepeatableQuery>&
|
||||
RepeatableQueriesService::repeatable_queries() const {
|
||||
return repeatable_queries_;
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::Refresh() {
|
||||
if (!search_provider_observer()->is_google()) {
|
||||
NotifyObservers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (signin_observer()->IsSignedIn()) {
|
||||
GetRepeatableQueriesFromServer();
|
||||
} else {
|
||||
GetRepeatableQueriesFromURLDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::DeleteQueryWithDestinationURL(const GURL& url) {
|
||||
auto it = std::find_if(repeatable_queries_.begin(), repeatable_queries_.end(),
|
||||
[&url](const auto& repeatable_query) {
|
||||
return repeatable_query.destination_url == url;
|
||||
});
|
||||
|
||||
// Return if no repeatable query with a matching destination URL exists.
|
||||
if (it == repeatable_queries_.end()) {
|
||||
// Still notify observers of the deletion attempt.
|
||||
NotifyObservers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (it->deletion_url.empty()) {
|
||||
DeleteRepeatableQueryFromURLDatabase(it->query);
|
||||
} else {
|
||||
DeleteRepeatableQueryFromServer(it->deletion_url);
|
||||
}
|
||||
|
||||
// Delete all the Google search URLs for the given query from history.
|
||||
const TemplateURL* default_provider =
|
||||
template_url_service_->GetDefaultSearchProvider();
|
||||
if (default_provider) {
|
||||
history_service_->DeleteMatchingURLsForKeyword(default_provider->id(),
|
||||
it->query);
|
||||
}
|
||||
|
||||
// Make sure the query is not suggested again.
|
||||
MarkQueryAsDeleted(it->query);
|
||||
|
||||
// Update the repeatable queries and notify the observers.
|
||||
repeatable_queries_.erase(it);
|
||||
NotifyObservers();
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::AddObserver(
|
||||
RepeatableQueriesServiceObserver* observer) {
|
||||
observers_.AddObserver(observer);
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::RemoveObserver(
|
||||
RepeatableQueriesServiceObserver* observer) {
|
||||
observers_.RemoveObserver(observer);
|
||||
}
|
||||
|
||||
RepeatableQueriesService::SigninObserver*
|
||||
RepeatableQueriesService::signin_observer() {
|
||||
return signin_observer_.get();
|
||||
}
|
||||
|
||||
SearchProviderObserver* RepeatableQueriesService::search_provider_observer() {
|
||||
return search_provider_observer_.get();
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::SearchProviderChanged() {
|
||||
// If we have cached data, clear it.
|
||||
repeatable_queries_.clear();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::SigninStatusChanged() {
|
||||
// If we have cached data, clear it.
|
||||
repeatable_queries_.clear();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
GURL RepeatableQueriesService::GetQueryDestinationURL(
|
||||
const std::u16string& query,
|
||||
const TemplateURL* search_provider) {
|
||||
DCHECK(search_provider);
|
||||
|
||||
TemplateURLRef::SearchTermsArgs search_terms_args(query);
|
||||
const TemplateURLRef& search_url_ref = search_provider->url_ref();
|
||||
const SearchTermsData& search_terms_data =
|
||||
template_url_service_->search_terms_data();
|
||||
DCHECK(search_url_ref.SupportsReplacement(search_terms_data));
|
||||
return GURL(
|
||||
search_url_ref.ReplaceSearchTerms(search_terms_args, search_terms_data));
|
||||
}
|
||||
|
||||
GURL RepeatableQueriesService::GetQueryDeletionURL(
|
||||
const std::string& deletion_url) {
|
||||
const auto* default_provider =
|
||||
template_url_service_->GetDefaultSearchProvider();
|
||||
if (!default_provider)
|
||||
return GURL();
|
||||
const SearchTermsData& search_terms_data =
|
||||
template_url_service_->search_terms_data();
|
||||
GURL request_url = default_provider->GenerateSearchURL(search_terms_data);
|
||||
return request_url.GetOrigin().Resolve(deletion_url);
|
||||
}
|
||||
|
||||
GURL RepeatableQueriesService::GetRequestURL() {
|
||||
TemplateURLRef::SearchTermsArgs search_terms_args;
|
||||
search_terms_args.request_source = TemplateURLRef::NON_SEARCHBOX_NTP;
|
||||
const TemplateURLRef& suggestion_url_ref =
|
||||
template_url_service_->GetDefaultSearchProvider()->suggestions_url_ref();
|
||||
const SearchTermsData& search_terms_data =
|
||||
template_url_service_->search_terms_data();
|
||||
DCHECK(suggestion_url_ref.SupportsReplacement(search_terms_data));
|
||||
return GURL(suggestion_url_ref.ReplaceSearchTerms(search_terms_args,
|
||||
search_terms_data));
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::FlushForTesting(base::OnceClosure flushed) {
|
||||
deletion_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
|
||||
std::move(flushed));
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::GetRepeatableQueriesFromServer() {
|
||||
net::NetworkTrafficAnnotationTag traffic_annotation =
|
||||
net::DefineNetworkTrafficAnnotation("repeatable_queries_service", R"(
|
||||
semantics {
|
||||
sender: "Repeatable Queries Service"
|
||||
description:
|
||||
"Downloads search queries to be shown on the Most Visited "
|
||||
"section of New Tab Page to signed-in users based on their "
|
||||
"previous search history."
|
||||
trigger:
|
||||
"Displaying the new tab page, if Google is the "
|
||||
"configured search provider, and the user is signed in."
|
||||
data: "Google credentials if user is signed in."
|
||||
destination: GOOGLE_OWNED_SERVICE
|
||||
}
|
||||
policy {
|
||||
cookies_allowed: YES
|
||||
cookies_store: "user"
|
||||
setting:
|
||||
"Users can control this feature by selecting a non-Google default "
|
||||
"search engine in Chrome settings under 'Search Engine', or by "
|
||||
"signing out of the browser on the New Tab Page. Users can opt "
|
||||
"out of this feature by switching to custom shortcuts."
|
||||
chrome_policy {
|
||||
DefaultSearchProviderEnabled {
|
||||
policy_options {mode: MANDATORY}
|
||||
DefaultSearchProviderEnabled: false
|
||||
}
|
||||
BrowserSignin {
|
||||
policy_options {mode: MANDATORY}
|
||||
BrowserSignin: 0
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
auto resource_request = std::make_unique<network::ResourceRequest>();
|
||||
const GURL& request_url = GetRequestURL();
|
||||
variations::AppendVariationsHeaderUnknownSignedIn(
|
||||
request_url, variations::InIncognito::kNo, resource_request.get());
|
||||
resource_request->url = request_url;
|
||||
resource_request->request_initiator =
|
||||
url::Origin::Create(request_initiator_url_);
|
||||
|
||||
loaders_.push_back(network::SimpleURLLoader::Create(
|
||||
std::move(resource_request), traffic_annotation));
|
||||
loaders_.back()->DownloadToString(
|
||||
url_loader_factory_.get(),
|
||||
base::BindOnce(&RepeatableQueriesService::RepeatableQueriesResponseLoaded,
|
||||
weak_ptr_factory_.GetWeakPtr(), loaders_.back().get()),
|
||||
network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::RepeatableQueriesResponseLoaded(
|
||||
network::SimpleURLLoader* loader,
|
||||
std::unique_ptr<std::string> response) {
|
||||
auto net_error = loader->NetError();
|
||||
base::EraseIf(loaders_, [loader](const auto& loader_ptr) {
|
||||
return loader == loader_ptr.get();
|
||||
});
|
||||
|
||||
if (net_error != net::OK || !response) {
|
||||
// In the case of network errors, keep the cached data, if any, but still
|
||||
// notify observers of the finished load attempt.
|
||||
NotifyObservers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (base::StartsWith(*response, kXSSIResponsePreamble,
|
||||
base::CompareCase::SENSITIVE)) {
|
||||
*response = response->substr(strlen(kXSSIResponsePreamble));
|
||||
}
|
||||
|
||||
data_decoder::DataDecoder::ParseJsonIsolated(
|
||||
*response,
|
||||
base::BindOnce(&RepeatableQueriesService::RepeatableQueriesParsed,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::RepeatableQueriesParsed(
|
||||
data_decoder::DataDecoder::ValueOrError result) {
|
||||
const TemplateURL* default_provider =
|
||||
template_url_service_->GetDefaultSearchProvider();
|
||||
if (!default_provider)
|
||||
return;
|
||||
|
||||
repeatable_queries_.clear();
|
||||
|
||||
std::vector<RepeatableQuery> queries;
|
||||
if (result.value && JsonToRepeatableQueriesData(*result.value, &queries)) {
|
||||
for (auto& query : queries) {
|
||||
if (IsQueryDeleted(query.query))
|
||||
continue;
|
||||
query.destination_url =
|
||||
GetQueryDestinationURL(query.query, default_provider);
|
||||
repeatable_queries_.push_back(query);
|
||||
if (repeatable_queries_.size() >= kMaxQueries)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NotifyObservers();
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::GetRepeatableQueriesFromURLDatabase() {
|
||||
const TemplateURL* default_provider =
|
||||
template_url_service_->GetDefaultSearchProvider();
|
||||
if (!default_provider)
|
||||
return;
|
||||
|
||||
repeatable_queries_.clear();
|
||||
|
||||
// Fail if the in-memory URLDatabase is not available.
|
||||
history::URLDatabase* url_db = history_service_->InMemoryDatabase();
|
||||
if (!url_db)
|
||||
return;
|
||||
|
||||
const base::TimeTicks db_query_time = base::TimeTicks::Now();
|
||||
auto results = url_db->GetMostRecentNormalizedKeywordSearchTerms(
|
||||
template_url_service_->GetDefaultSearchProvider()->id(),
|
||||
ntp_features::GetLocalHistoryRepeatableQueriesAgeThreshold());
|
||||
|
||||
const base::Time now = base::Time::Now();
|
||||
const int kRecencyDecayUnitSec =
|
||||
ntp_features::GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds();
|
||||
const double kFrequencyExponent =
|
||||
ntp_features::GetLocalHistoryRepeatableQueriesFrequencyExponent();
|
||||
auto CompareByFrecency = [&](const auto& a, const auto& b) {
|
||||
return a.GetFrecency(now, kRecencyDecayUnitSec, kFrequencyExponent) >
|
||||
b.GetFrecency(now, kRecencyDecayUnitSec, kFrequencyExponent);
|
||||
};
|
||||
std::sort(results.begin(), results.end(), CompareByFrecency);
|
||||
|
||||
for (const auto& result : results) {
|
||||
RepeatableQuery repeatable_query;
|
||||
repeatable_query.query = result.normalized_term;
|
||||
if (IsQueryDeleted(repeatable_query.query))
|
||||
continue;
|
||||
repeatable_query.destination_url =
|
||||
GetQueryDestinationURL(repeatable_query.query, default_provider);
|
||||
repeatable_queries_.push_back(repeatable_query);
|
||||
if (repeatable_queries_.size() >= kMaxQueries)
|
||||
break;
|
||||
}
|
||||
|
||||
base::UmaHistogramTimes(kExtractionDurationHistogram,
|
||||
base::TimeTicks::Now() - db_query_time);
|
||||
base::UmaHistogramCounts10000(kExtractedCountHistogram, results.size());
|
||||
|
||||
NotifyObservers();
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::DeleteRepeatableQueryFromServer(
|
||||
const std::string& deletion_url) {
|
||||
net::NetworkTrafficAnnotationTag traffic_annotation =
|
||||
net::DefineNetworkTrafficAnnotation("repeatable_queries_deletion", R"(
|
||||
semantics {
|
||||
sender: "Repeatable Queries Service"
|
||||
description:
|
||||
"When users attempt to delete a server-provided repeatable search "
|
||||
"query from the Most Visited section of New Tab Page, Chrome sends "
|
||||
"a request to the server requesting deletion of that suggestion."
|
||||
trigger:
|
||||
"User attempts to delete a server-provided repeatable search "
|
||||
"query for which the server provided a custom deletion URL from "
|
||||
"the Most Visited section of New Tab Page, if Google is the "
|
||||
"configured search provider, and the user is signed in."
|
||||
data: "Google credentials if user is signed in."
|
||||
destination: GOOGLE_OWNED_SERVICE
|
||||
}
|
||||
policy {
|
||||
cookies_allowed: YES
|
||||
cookies_store: "user"
|
||||
setting:
|
||||
"Users can control this feature by selecting a non-Google default "
|
||||
"search engine in Chrome settings under 'Search Engine', or by "
|
||||
"signing out of the browser on the New Tab Page. Users can opt "
|
||||
"out of this feature by switching to custom shortcuts."
|
||||
chrome_policy {
|
||||
DefaultSearchProviderEnabled {
|
||||
policy_options {mode: MANDATORY}
|
||||
DefaultSearchProviderEnabled: false
|
||||
}
|
||||
BrowserSignin {
|
||||
policy_options {mode: MANDATORY}
|
||||
BrowserSignin: 0
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
GURL request_url = GetQueryDeletionURL(deletion_url);
|
||||
if (!request_url.is_valid())
|
||||
return;
|
||||
|
||||
auto deletion_request = std::make_unique<network::ResourceRequest>();
|
||||
variations::AppendVariationsHeaderUnknownSignedIn(
|
||||
request_url, variations::InIncognito::kNo, deletion_request.get());
|
||||
deletion_request->url = request_url;
|
||||
deletion_request->request_initiator =
|
||||
url::Origin::Create(request_initiator_url_);
|
||||
|
||||
loaders_.push_back(network::SimpleURLLoader::Create(
|
||||
std::move(deletion_request), traffic_annotation));
|
||||
loaders_.back()->DownloadToString(
|
||||
url_loader_factory_.get(),
|
||||
base::BindOnce(&RepeatableQueriesService::DeletionResponseLoaded,
|
||||
weak_ptr_factory_.GetWeakPtr(), loaders_.back().get()),
|
||||
network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::DeletionResponseLoaded(
|
||||
network::SimpleURLLoader* loader,
|
||||
std::unique_ptr<std::string> response) {
|
||||
base::EraseIf(loaders_, [loader](const auto& loader_ptr) {
|
||||
return loader == loader_ptr.get();
|
||||
});
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::DeleteRepeatableQueryFromURLDatabase(
|
||||
const std::u16string& query) {
|
||||
deletion_task_runner_->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(
|
||||
&RepeatableQueriesService::DeleteRepeatableQueryFromURLDatabaseTask,
|
||||
weak_ptr_factory_.GetWeakPtr(), query,
|
||||
history_service_->InMemoryDatabase()));
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::DeleteRepeatableQueryFromURLDatabaseTask(
|
||||
const std::u16string& query,
|
||||
history::URLDatabase* url_db) {
|
||||
// Fail if the in-memory URLDatabase is not available.
|
||||
if (!url_db)
|
||||
return;
|
||||
|
||||
// Delete all the search terms matching the repeatable query suggestion from
|
||||
// the in-memory URLDatabase.
|
||||
url_db->DeleteKeywordSearchTermForNormalizedTerm(
|
||||
template_url_service_->GetDefaultSearchProvider()->id(), query);
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::NotifyObservers() {
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnRepeatableQueriesUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
bool RepeatableQueriesService::IsQueryDeleted(const std::u16string& query) {
|
||||
return base::Contains(deleted_repeatable_queries_, query);
|
||||
}
|
||||
|
||||
void RepeatableQueriesService::MarkQueryAsDeleted(const std::u16string& query) {
|
||||
deleted_repeatable_queries_.insert(query);
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_H_
|
||||
#define COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
#include "components/search/repeatable_queries/repeatable_queries_service_observer.h"
|
||||
#include "services/data_decoder/public/cpp/data_decoder.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
class SearchProviderObserver;
|
||||
class TemplateURLService;
|
||||
class TemplateURL;
|
||||
|
||||
namespace base {
|
||||
class SequencedTaskRunner;
|
||||
} // namespace base
|
||||
|
||||
namespace history {
|
||||
class HistoryService;
|
||||
class URLDatabase;
|
||||
} // namespace history
|
||||
|
||||
namespace network {
|
||||
class SimpleURLLoader;
|
||||
class SharedURLLoaderFactory;
|
||||
} // namespace network
|
||||
|
||||
namespace signin {
|
||||
class IdentityManager;
|
||||
} // namespace signin
|
||||
|
||||
// Represents a repeatable query suggestion.
|
||||
class RepeatableQuery {
|
||||
public:
|
||||
RepeatableQuery() = default;
|
||||
~RepeatableQuery() = default;
|
||||
|
||||
bool operator==(const RepeatableQuery& other) const {
|
||||
return query == other.query && destination_url == other.destination_url &&
|
||||
deletion_url == other.deletion_url;
|
||||
}
|
||||
bool operator!=(const RepeatableQuery& other) const {
|
||||
return !(this == &other);
|
||||
}
|
||||
|
||||
// Repeatable query suggestion.
|
||||
std::u16string query;
|
||||
|
||||
// The URL to navigate to when the suggestion is selected.
|
||||
GURL destination_url;
|
||||
|
||||
// The relative endpoint used for deleting the query suggestion on the server.
|
||||
// Populated for server provided queries only.
|
||||
std::string deletion_url;
|
||||
};
|
||||
|
||||
// Provides repeatable query suggestions to be shown in the NTP Most Visited
|
||||
// tiles when Google is the default search provider. The repeatable queries are
|
||||
// requested from the server for signed-in users and extracted from the
|
||||
// in-memory URLDatabase for unauthenticated users.
|
||||
class RepeatableQueriesService : public KeyedService {
|
||||
public:
|
||||
RepeatableQueriesService(
|
||||
signin::IdentityManager* identity_manager,
|
||||
history::HistoryService* history_service,
|
||||
TemplateURLService* template_url_service,
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
|
||||
const GURL& request_initiator_url);
|
||||
~RepeatableQueriesService() override;
|
||||
RepeatableQueriesService(const RepeatableQueriesService&) = delete;
|
||||
RepeatableQueriesService& operator=(const RepeatableQueriesService&) = delete;
|
||||
|
||||
// Histograms recorded by this class.
|
||||
static const char kExtractedCountHistogram[];
|
||||
static const char kExtractionDurationHistogram[];
|
||||
|
||||
// KeyedService:
|
||||
void Shutdown() override;
|
||||
|
||||
// Returns the currently cached repeatable query suggestions, if any.
|
||||
const std::vector<RepeatableQuery>& repeatable_queries() const;
|
||||
|
||||
// If Google is the default search provider, asynchronously requests
|
||||
// repeatable query suggestions from the server for signed-in users and
|
||||
// synchronously extracts them from the in-memory URLDatabase for
|
||||
// unauthenticated users. Regardless of success, observers are notified via
|
||||
// RepeatableQueriesServiceObserver::OnRepeatableQueriesUpdated.
|
||||
void Refresh();
|
||||
|
||||
// Deletes the records of the repeatable query suggestion with the given
|
||||
// destination URL on the server as well as on the device, whichever is
|
||||
// applicable. Prevents the suggestion from being offered again by
|
||||
// blocklisting it. Updates the current set of suggestions and notifies the
|
||||
// observers.
|
||||
void DeleteQueryWithDestinationURL(const GURL& url);
|
||||
|
||||
// Add/remove observers.
|
||||
void AddObserver(RepeatableQueriesServiceObserver* observer);
|
||||
void RemoveObserver(RepeatableQueriesServiceObserver* observer);
|
||||
|
||||
protected:
|
||||
class SigninObserver;
|
||||
|
||||
virtual SigninObserver* signin_observer();
|
||||
virtual SearchProviderObserver* search_provider_observer();
|
||||
|
||||
// Called when the default search provider changes.
|
||||
void SearchProviderChanged();
|
||||
|
||||
// Called when the signin status changes.
|
||||
void SigninStatusChanged();
|
||||
|
||||
// Returns the server destination URL for |query| with |search_provider|.
|
||||
// |search_provider| may not be nullptr.
|
||||
GURL GetQueryDestinationURL(const std::u16string& query,
|
||||
const TemplateURL* search_provider);
|
||||
|
||||
// Returns the resolved deletion URL for the given relative deletion URL.
|
||||
GURL GetQueryDeletionURL(const std::string& deletion_url);
|
||||
|
||||
// Returns the server request URL.
|
||||
GURL GetRequestURL();
|
||||
|
||||
void FlushForTesting(base::OnceClosure flushed);
|
||||
|
||||
private:
|
||||
// Requests repeatable queries from the server. Called for signed-in users.
|
||||
void GetRepeatableQueriesFromServer();
|
||||
void RepeatableQueriesResponseLoaded(network::SimpleURLLoader* loader,
|
||||
std::unique_ptr<std::string> response);
|
||||
void RepeatableQueriesParsed(data_decoder::DataDecoder::ValueOrError result);
|
||||
|
||||
// Queries the in-memory URLDatabase for the repeatable queries submitted
|
||||
// to the default search provider. Called for unauthenticated users.
|
||||
void GetRepeatableQueriesFromURLDatabase();
|
||||
|
||||
// Deletes |query| from the in-memory URLDatabase.
|
||||
void DeleteRepeatableQueryFromURLDatabase(const std::u16string& query);
|
||||
void DeleteRepeatableQueryFromURLDatabaseTask(const std::u16string& query,
|
||||
history::URLDatabase* url_db);
|
||||
|
||||
// Deletes the query with |deletion_url| from the server.
|
||||
void DeleteRepeatableQueryFromServer(const std::string& deletion_url);
|
||||
void DeletionResponseLoaded(network::SimpleURLLoader* loader,
|
||||
std::unique_ptr<std::string> response);
|
||||
|
||||
void NotifyObservers();
|
||||
|
||||
bool IsQueryDeleted(const std::u16string& query);
|
||||
void MarkQueryAsDeleted(const std::u16string& query);
|
||||
|
||||
history::HistoryService* history_service_;
|
||||
|
||||
TemplateURLService* template_url_service_;
|
||||
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
|
||||
|
||||
const GURL request_initiator_url_;
|
||||
|
||||
std::unique_ptr<SigninObserver> signin_observer_;
|
||||
|
||||
std::unique_ptr<SearchProviderObserver> search_provider_observer_;
|
||||
|
||||
base::ObserverList<RepeatableQueriesServiceObserver, true> observers_;
|
||||
|
||||
std::vector<RepeatableQuery> repeatable_queries_;
|
||||
|
||||
// Used to ensure the deleted repeatable queries won't be suggested again.
|
||||
// This does not need to be persisted across sessions as the queries do get
|
||||
// deleted on the server as well as on the device, whichever is applicable.
|
||||
std::set<std::u16string> deleted_repeatable_queries_;
|
||||
|
||||
std::vector<std::unique_ptr<network::SimpleURLLoader>> loaders_;
|
||||
|
||||
// The TaskRunner to which in-memory URLDatabase deletion tasks are posted.
|
||||
scoped_refptr<base::SequencedTaskRunner> deletion_task_runner_;
|
||||
|
||||
base::WeakPtrFactory<RepeatableQueriesService> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
#endif // COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_H_
|
@ -1,23 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_OBSERVER_H_
|
||||
#define COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_OBSERVER_H_
|
||||
|
||||
// Observer class for the RepeatableQueriesService.
|
||||
class RepeatableQueriesServiceObserver : public base::CheckedObserver {
|
||||
public:
|
||||
// Called after a Refresh() call on the service, either directly or as a
|
||||
// result of default search provider or signin status change. Note that this
|
||||
// is called after each Refresh(), even if the network request failed, or if
|
||||
// it didn't result in an actual change to the cached data. Observers can get
|
||||
// the repeatable queries via RepeatableQueriesService::repeatable_queries().
|
||||
virtual void OnRepeatableQueriesUpdated() = 0;
|
||||
|
||||
// Called when the service is shutting down allowing the observers to
|
||||
// unregister themselves and clear references to the service.
|
||||
virtual void OnRepeatableQueriesServiceShuttingDown() {}
|
||||
};
|
||||
|
||||
#endif // COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_OBSERVER_H_
|
@ -1,702 +0,0 @@
|
||||
// Copyright 2020 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 "components/search/repeatable_queries/repeatable_queries_service.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_helpers.h"
|
||||
#include "base/cancelable_callback.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/bookmarks/browser/bookmark_model.h"
|
||||
#include "components/bookmarks/test/test_bookmark_client.h"
|
||||
#include "components/history/core/browser/history_service.h"
|
||||
#include "components/history/core/browser/url_database.h"
|
||||
#include "components/history/core/test/history_service_test_util.h"
|
||||
#include "components/omnibox/browser/in_memory_url_index.h"
|
||||
#include "components/omnibox/browser/in_memory_url_index_test_util.h"
|
||||
#include "components/search/search.h"
|
||||
#include "components/search/search_provider_observer.h"
|
||||
#include "components/search_engines/search_engines_test_util.h"
|
||||
#include "components/search_engines/template_url_service.h"
|
||||
#include "components/signin/public/base/test_signin_client.h"
|
||||
#include "components/signin/public/identity_manager/identity_test_environment.h"
|
||||
#include "components/signin/public/identity_manager/identity_test_utils.h"
|
||||
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
using base::Time;
|
||||
using base::TimeDelta;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GoodServerResponse() {
|
||||
return R"()]}'
|
||||
[
|
||||
"",
|
||||
[
|
||||
"server query 1",
|
||||
"server query 2",
|
||||
"server query 3"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
{
|
||||
"google:suggestdetail":[
|
||||
{
|
||||
"du":"/delete?server+query+1"
|
||||
},
|
||||
{
|
||||
"du":"/delete?server+query+2"
|
||||
},
|
||||
{
|
||||
"du":"/delete?server+query+3"
|
||||
}
|
||||
]
|
||||
}
|
||||
])";
|
||||
}
|
||||
|
||||
std::string BadServerResponse1() {
|
||||
return R"()]}'
|
||||
[
|
||||
"",
|
||||
[
|
||||
"server query 1",
|
||||
"server query 2",
|
||||
"server query 3"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
{
|
||||
}
|
||||
])";
|
||||
}
|
||||
|
||||
std::string BadServerResponse2() {
|
||||
return R"()]}'
|
||||
[
|
||||
"",
|
||||
[
|
||||
"server query 1",
|
||||
"server query 2",
|
||||
"server query 3"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
{
|
||||
"google:suggestdetail":[
|
||||
{
|
||||
"du":"/delete?server+query+1"
|
||||
},
|
||||
{
|
||||
"du":"/delete?server+query+2"
|
||||
},
|
||||
]
|
||||
}
|
||||
])";
|
||||
}
|
||||
|
||||
// Used to populate the URLDatabase.
|
||||
struct TestURLData {
|
||||
const TemplateURL* search_provider;
|
||||
std::string search_terms;
|
||||
int age_in_seconds;
|
||||
int visit_count = 1;
|
||||
std::string title = "";
|
||||
int typed_count = 1;
|
||||
bool hidden = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class MockSearchProviderObserver : public SearchProviderObserver {
|
||||
public:
|
||||
MockSearchProviderObserver()
|
||||
: SearchProviderObserver(/*template_url_service=*/nullptr,
|
||||
base::DoNothing::Repeatedly()) {}
|
||||
~MockSearchProviderObserver() override = default;
|
||||
|
||||
MOCK_METHOD0(is_google, bool());
|
||||
};
|
||||
|
||||
class TestRepeatableQueriesService : public RepeatableQueriesService {
|
||||
public:
|
||||
TestRepeatableQueriesService(
|
||||
signin::IdentityManager* identity_manager,
|
||||
history::HistoryService* history_service,
|
||||
TemplateURLService* template_url_service,
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
|
||||
const GURL& request_initiator_url)
|
||||
: RepeatableQueriesService(identity_manager,
|
||||
history_service,
|
||||
template_url_service,
|
||||
std::move(url_loader_factory),
|
||||
request_initiator_url) {}
|
||||
~TestRepeatableQueriesService() override = default;
|
||||
|
||||
MockSearchProviderObserver* search_provider_observer() override {
|
||||
return &search_provider_observer_;
|
||||
}
|
||||
|
||||
void SearchProviderChanged() {
|
||||
RepeatableQueriesService::SearchProviderChanged();
|
||||
}
|
||||
|
||||
void SigninStatusChanged() {
|
||||
RepeatableQueriesService::SigninStatusChanged();
|
||||
}
|
||||
|
||||
void FlushForTesting(base::OnceClosure flushed) {
|
||||
RepeatableQueriesService::FlushForTesting(std::move(flushed));
|
||||
}
|
||||
|
||||
GURL GetQueryDestinationURL(const std::u16string& query,
|
||||
const TemplateURL* search_provider) {
|
||||
return RepeatableQueriesService::GetQueryDestinationURL(query,
|
||||
search_provider);
|
||||
}
|
||||
|
||||
GURL GetQueryDeletionURL(const std::string& deletion_url) {
|
||||
return RepeatableQueriesService::GetQueryDeletionURL(deletion_url);
|
||||
}
|
||||
|
||||
GURL GetRequestURL() { return RepeatableQueriesService::GetRequestURL(); }
|
||||
|
||||
testing::NiceMock<MockSearchProviderObserver> search_provider_observer_;
|
||||
};
|
||||
|
||||
class RepeatableQueriesServiceTest : public ::testing::Test,
|
||||
public RepeatableQueriesServiceObserver {
|
||||
public:
|
||||
RepeatableQueriesServiceTest() = default;
|
||||
~RepeatableQueriesServiceTest() override = default;
|
||||
|
||||
void SetUp() override {
|
||||
bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
|
||||
|
||||
CHECK(history_dir_.CreateUniqueTempDir());
|
||||
history_service_ = history::CreateHistoryService(
|
||||
history_dir_.GetPath(), /*create_history_db=*/true);
|
||||
|
||||
in_memory_url_index_ = std::make_unique<InMemoryURLIndex>(
|
||||
bookmark_model_.get(), history_service_.get(), nullptr,
|
||||
history_dir_.GetPath(), SchemeSet());
|
||||
in_memory_url_index_->Init();
|
||||
|
||||
template_url_service_ = std::make_unique<TemplateURLService>(nullptr, 0);
|
||||
|
||||
// Add the fallback default search provider to the TemplateURLService so
|
||||
// that it gets a valid unique identifier. Make the newly added provider the
|
||||
// user selected default search provider.
|
||||
TemplateURL* default_provider = template_url_service_->Add(
|
||||
std::make_unique<TemplateURL>(default_search_provider()->data()));
|
||||
template_url_service_->SetUserSelectedDefaultSearchProvider(
|
||||
default_provider);
|
||||
// Verify that Google is the default search provider.
|
||||
EXPECT_TRUE(
|
||||
search::DefaultSearchProviderIsGoogle(template_url_service_.get()));
|
||||
|
||||
identity_env_ = std::make_unique<signin::IdentityTestEnvironment>(
|
||||
&test_url_loader_factory_);
|
||||
identity_env_->MakePrimaryAccountAvailable("example@gmail.com");
|
||||
identity_env_->SetAutomaticIssueOfAccessTokens(true);
|
||||
|
||||
service_ = std::make_unique<TestRepeatableQueriesService>(
|
||||
identity_env_->identity_manager(), history_service_.get(),
|
||||
template_url_service_.get(),
|
||||
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
|
||||
&test_url_loader_factory_),
|
||||
GURL());
|
||||
EXPECT_TRUE(service_->repeatable_queries().empty());
|
||||
service_->AddObserver(this);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// RepeatableQueriesService must be explicitly shut down so that its
|
||||
// observers can unregister.
|
||||
service_->Shutdown();
|
||||
// InMemoryURLIndex must be explicitly shut down or it will DCHECK() in
|
||||
// its destructor.
|
||||
in_memory_url_index_->Shutdown();
|
||||
|
||||
WaitForRepeatableQueriesService();
|
||||
WaitForHistoryService();
|
||||
WaitForInMemoryURLIndex();
|
||||
}
|
||||
|
||||
const TemplateURL* default_search_provider() {
|
||||
return template_url_service_->GetDefaultSearchProvider();
|
||||
}
|
||||
|
||||
network::TestURLLoaderFactory* test_url_loader_factory() {
|
||||
return &test_url_loader_factory_;
|
||||
}
|
||||
|
||||
TestRepeatableQueriesService* service() { return service_.get(); }
|
||||
|
||||
void set_service_is_done(bool is_done) { service_is_done_ = is_done; }
|
||||
|
||||
void SignIn() {
|
||||
AccountInfo account_info =
|
||||
identity_env_->MakeAccountAvailable("test@email.com");
|
||||
identity_env_->SetCookieAccounts({{account_info.email, account_info.gaia}});
|
||||
}
|
||||
|
||||
void SignOut() { identity_env_->SetCookieAccounts({}); }
|
||||
|
||||
GURL GetQueryDestinationURL(const std::string& query) {
|
||||
return service_->GetQueryDestinationURL(base::ASCIIToUTF16(query),
|
||||
default_search_provider());
|
||||
}
|
||||
|
||||
void RefreshAndMaybeWaitForService() {
|
||||
service_is_done_ = false;
|
||||
service_->Refresh();
|
||||
MaybeWaitForService();
|
||||
}
|
||||
|
||||
void MaybeWaitForService() {
|
||||
if (!service_is_done_) {
|
||||
service_run_loop_ = std::make_unique<base::RunLoop>();
|
||||
// Quits in OnRepeatableQueriesUpdated when the service is done.
|
||||
service_run_loop_->Run();
|
||||
}
|
||||
}
|
||||
|
||||
// Fills the URLDatabase with search URLs created using the provided data.
|
||||
void FillURLDatabase(const std::vector<TestURLData>& url_data_list) {
|
||||
const Time now = Time::Now();
|
||||
for (const auto& entry : url_data_list) {
|
||||
TemplateURLRef::SearchTermsArgs search_terms_args(
|
||||
base::UTF8ToUTF16(entry.search_terms));
|
||||
const auto& search_terms_data =
|
||||
template_url_service_->search_terms_data();
|
||||
std::string search_url =
|
||||
entry.search_provider->url_ref().ReplaceSearchTerms(
|
||||
search_terms_args, search_terms_data);
|
||||
history_service_->AddPageWithDetails(
|
||||
GURL(search_url), base::UTF8ToUTF16(entry.title), entry.visit_count,
|
||||
entry.typed_count, now - TimeDelta::FromSeconds(entry.age_in_seconds),
|
||||
entry.hidden, history::SOURCE_BROWSED);
|
||||
history_service_->SetKeywordSearchTermsForURL(
|
||||
GURL(search_url), entry.search_provider->id(),
|
||||
base::UTF8ToUTF16(entry.search_terms));
|
||||
WaitForHistoryService();
|
||||
}
|
||||
}
|
||||
|
||||
// Waits for RepeatableQueriesService's async operations.
|
||||
void WaitForRepeatableQueriesService() {
|
||||
base::RunLoop run_loop;
|
||||
service_->FlushForTesting(run_loop.QuitClosure());
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
// Waits for history::HistoryService's async operations.
|
||||
void WaitForHistoryService() {
|
||||
history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
|
||||
}
|
||||
|
||||
// Waits for InMemoryURLIndex's async operations.
|
||||
void WaitForInMemoryURLIndex() {
|
||||
BlockUntilInMemoryURLIndexIsRefreshed(in_memory_url_index_.get());
|
||||
}
|
||||
|
||||
private:
|
||||
base::test::TaskEnvironment task_environment_;
|
||||
std::unique_ptr<base::RunLoop> service_run_loop_;
|
||||
std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
|
||||
std::unique_ptr<history::HistoryService> history_service_;
|
||||
std::unique_ptr<InMemoryURLIndex> in_memory_url_index_;
|
||||
base::ScopedTempDir history_dir_;
|
||||
std::unique_ptr<TemplateURLService> template_url_service_;
|
||||
data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
|
||||
network::TestURLLoaderFactory test_url_loader_factory_;
|
||||
std::unique_ptr<signin::IdentityTestEnvironment> identity_env_;
|
||||
std::unique_ptr<TestRepeatableQueriesService> service_;
|
||||
bool service_is_done_ = false;
|
||||
|
||||
// RepeatableQueriesServiceObserver
|
||||
void OnRepeatableQueriesUpdated() override;
|
||||
void OnRepeatableQueriesServiceShuttingDown() override;
|
||||
};
|
||||
|
||||
void RepeatableQueriesServiceTest::OnRepeatableQueriesUpdated() {
|
||||
service_is_done_ = true;
|
||||
if (service_run_loop_) {
|
||||
service_run_loop_->Quit();
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatableQueriesServiceTest::OnRepeatableQueriesServiceShuttingDown() {
|
||||
service_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1177139) Re-enable test
|
||||
TEST_F(RepeatableQueriesServiceTest, DISABLED_SignedIn) {
|
||||
SignIn();
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
GoodServerResponse());
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillOnce(testing::Return(true));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
// The first two server suggestions are kept as repeatable queries.
|
||||
std::vector<RepeatableQuery> expected_server_queries{
|
||||
{u"server query 1", GetQueryDestinationURL("server query 1"),
|
||||
"/delete?server+query+1"},
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1170500) Test fails also on other platforms
|
||||
TEST_F(RepeatableQueriesServiceTest, DISABLED_SignedIn_BadResponse) {
|
||||
SignIn();
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
GoodServerResponse());
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_server_queries{
|
||||
{u"server query 1", GetQueryDestinationURL("server query 1"),
|
||||
"/delete?server+query+1"},
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
BadServerResponse1());
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
// Cached data is cleared.
|
||||
EXPECT_TRUE(service()->repeatable_queries().empty());
|
||||
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
BadServerResponse2());
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
// Cached data is still empty.
|
||||
EXPECT_TRUE(service()->repeatable_queries().empty());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1170500) Test fails also on other platforms
|
||||
TEST_F(RepeatableQueriesServiceTest, DISABLED_SignedIn_ErrorResponse) {
|
||||
SignIn();
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
GoodServerResponse());
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_server_queries{
|
||||
{u"server query 1", GetQueryDestinationURL("server query 1"),
|
||||
"/delete?server+query+1"},
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
|
||||
test_url_loader_factory()->AddResponse(
|
||||
service()->GetRequestURL(), network::mojom::URLResponseHead::New(),
|
||||
std::string(), network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
// Cached data is kept.
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1158533): This test is disabled because it has been failing
|
||||
// intermittently on all platforms.
|
||||
TEST_F(RepeatableQueriesServiceTest,
|
||||
DISABLED_SignedIn_DefaultSearchProviderChanged) {
|
||||
SignIn();
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
GoodServerResponse());
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillOnce(testing::Return(true))
|
||||
.WillOnce(testing::Return(false));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_server_queries{
|
||||
{u"server query 1", GetQueryDestinationURL("server query 1"),
|
||||
"/delete?server+query+1"},
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
|
||||
set_service_is_done(false);
|
||||
// Simulate DSP change. Requests a refresh.
|
||||
service()->SearchProviderChanged();
|
||||
MaybeWaitForService();
|
||||
// Cached data is cleared.
|
||||
EXPECT_TRUE(service()->repeatable_queries().empty());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1170500) Test fails also on other platforms
|
||||
TEST_F(RepeatableQueriesServiceTest, DISABLED_SignedIn_SigninStatusChanged) {
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
SignIn();
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
GoodServerResponse());
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_server_queries{
|
||||
{u"server query 1", GetQueryDestinationURL("server query 1"),
|
||||
"/delete?server+query+1"},
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
|
||||
int original_query_age =
|
||||
history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
|
||||
FillURLDatabase({
|
||||
// Issued far enough from the original query; won't be ignored:
|
||||
{default_search_provider(), "more recent local query",
|
||||
/*age_in_seconds=*/0},
|
||||
// Issued far enough from the original query; won't be ignored:
|
||||
{default_search_provider(), "less recent local query",
|
||||
/*age_in_seconds=*/1},
|
||||
{default_search_provider(), "less recent local query",
|
||||
/*age_in_seconds=*/original_query_age},
|
||||
{default_search_provider(), "more recent local query",
|
||||
/*age_in_seconds=*/original_query_age},
|
||||
});
|
||||
|
||||
set_service_is_done(false);
|
||||
SignOut(); // Requests a refresh.
|
||||
MaybeWaitForService();
|
||||
// Cached data is updated to local results.
|
||||
std::vector<RepeatableQuery> expected_local_queries{
|
||||
{u"more recent local query",
|
||||
GetQueryDestinationURL("more recent local query"), ""},
|
||||
{u"less recent local query",
|
||||
GetQueryDestinationURL("less recent local query"), ""}};
|
||||
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
|
||||
|
||||
histogram_tester.ExpectTotalCount(
|
||||
RepeatableQueriesService::kExtractionDurationHistogram, 1);
|
||||
histogram_tester.ExpectTotalCount(
|
||||
RepeatableQueriesService::kExtractedCountHistogram, 1);
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
RepeatableQueriesService::kExtractedCountHistogram, 2, 1);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1170500) Test fails also on other platforms
|
||||
TEST_F(RepeatableQueriesServiceTest, DISABLED_SignedIn_Deletion) {
|
||||
SignIn();
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
GoodServerResponse());
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_server_queries{
|
||||
{u"server query 1", GetQueryDestinationURL("server query 1"),
|
||||
"/delete?server+query+1"},
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
|
||||
// Try to delete a query suggestion not provided by the service.
|
||||
set_service_is_done(false);
|
||||
service()->DeleteQueryWithDestinationURL(GetQueryDestinationURL("blah"));
|
||||
// No request to delete the suggestion was sent.
|
||||
EXPECT_TRUE(test_url_loader_factory()->pending_requests()->empty());
|
||||
MaybeWaitForService();
|
||||
// Suggestions should not change.
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
|
||||
// Delete the query suggestion provided by the service.
|
||||
set_service_is_done(false);
|
||||
service()->DeleteQueryWithDestinationURL(
|
||||
GetQueryDestinationURL("server query 1"));
|
||||
// A request to delete the suggestion was sent.
|
||||
EXPECT_EQ(1u, test_url_loader_factory()->pending_requests()->size());
|
||||
EXPECT_EQ(test_url_loader_factory()->GetPendingRequest(0)->request.url,
|
||||
service()->GetQueryDeletionURL("/delete?server+query+1"));
|
||||
MaybeWaitForService();
|
||||
expected_server_queries = {{u"server query 2",
|
||||
GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
// The deleted suggestion is not offered anymore.
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
|
||||
expected_server_queries = {
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"},
|
||||
{u"server query 3", GetQueryDestinationURL("server query 3"),
|
||||
"/delete?server+query+3"}};
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
// The deleted suggestion will not be offered again.
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS simulators
|
||||
// TODO(crbug.com/1170500) Test fails also on other platforms
|
||||
TEST_F(RepeatableQueriesServiceTest,
|
||||
DISABLED_SignedOut_DefaultSearchProviderChanged) {
|
||||
int original_query_age =
|
||||
history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
|
||||
FillURLDatabase({
|
||||
// Issued far enough from the original query; won't be ignored:
|
||||
{default_search_provider(), "more recent local query",
|
||||
/*age_in_seconds=*/0},
|
||||
// Issued far enough from the original query; won't be ignored:
|
||||
{default_search_provider(), "less recent local query",
|
||||
/*age_in_seconds=*/1},
|
||||
{default_search_provider(), "less recent local query",
|
||||
/*age_in_seconds=*/original_query_age},
|
||||
{default_search_provider(), "more recent local query",
|
||||
/*age_in_seconds=*/original_query_age},
|
||||
});
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillOnce(testing::Return(true))
|
||||
.WillOnce(testing::Return(false));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_local_queries{
|
||||
{u"more recent local query",
|
||||
GetQueryDestinationURL("more recent local query"), ""},
|
||||
{u"less recent local query",
|
||||
GetQueryDestinationURL("less recent local query"), ""}};
|
||||
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
|
||||
|
||||
set_service_is_done(false);
|
||||
// Simulate DSP change. Requests a refresh.
|
||||
service()->SearchProviderChanged();
|
||||
MaybeWaitForService();
|
||||
// Cached data is cleared.
|
||||
EXPECT_TRUE(service()->repeatable_queries().empty());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1170500) Test fails also on other platforms
|
||||
TEST_F(RepeatableQueriesServiceTest, DISABLED_SignedOut_SigninStatusChanged) {
|
||||
int original_query_age =
|
||||
history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
|
||||
FillURLDatabase({
|
||||
// Issued far enough from the original query; won't be ignored:
|
||||
{default_search_provider(), "more recent local query",
|
||||
/*age_in_seconds=*/0},
|
||||
// Issued far enough from the original query; won't be ignored:
|
||||
{default_search_provider(), "less recent local query",
|
||||
/*age_in_seconds=*/1},
|
||||
{default_search_provider(), "less recent local query",
|
||||
/*age_in_seconds=*/original_query_age},
|
||||
{default_search_provider(), "more recent local query",
|
||||
/*age_in_seconds=*/original_query_age},
|
||||
});
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_local_queries{
|
||||
{u"more recent local query",
|
||||
GetQueryDestinationURL("more recent local query"), ""},
|
||||
{u"less recent local query",
|
||||
GetQueryDestinationURL("less recent local query"), ""}};
|
||||
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
|
||||
|
||||
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
|
||||
GoodServerResponse());
|
||||
|
||||
set_service_is_done(false);
|
||||
SignIn(); // Requests a refresh.
|
||||
MaybeWaitForService();
|
||||
// Cached data is updated to server results.
|
||||
std::vector<RepeatableQuery> expected_server_queries{
|
||||
{u"server query 1", GetQueryDestinationURL("server query 1"),
|
||||
"/delete?server+query+1"},
|
||||
{u"server query 2", GetQueryDestinationURL("server query 2"),
|
||||
"/delete?server+query+2"}};
|
||||
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1151909) Test fails on iOS
|
||||
// TODO(crbug.com/1170500) Test fails also on other platforms
|
||||
TEST_F(RepeatableQueriesServiceTest, DISABLED_SignedOut_Deletion) {
|
||||
FillURLDatabase({{default_search_provider(), "local query 1",
|
||||
/*age_in_seconds=*/1},
|
||||
{default_search_provider(), "local query 2",
|
||||
/*age_in_seconds=*/2},
|
||||
{default_search_provider(), "local query 3",
|
||||
/*age_in_seconds=*/3}});
|
||||
|
||||
EXPECT_CALL(*service()->search_provider_observer(), is_google())
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
std::vector<RepeatableQuery> expected_local_queries{
|
||||
{u"local query 1", GetQueryDestinationURL("local query 1"), ""},
|
||||
{u"local query 2", GetQueryDestinationURL("local query 2"), ""}};
|
||||
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
|
||||
|
||||
// Try to delete a query suggestion not provided by the service.
|
||||
set_service_is_done(false);
|
||||
service()->DeleteQueryWithDestinationURL(GetQueryDestinationURL("blah"));
|
||||
MaybeWaitForService();
|
||||
// Suggestions should not change.
|
||||
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
|
||||
|
||||
// Delete the query suggestion provided by the service.
|
||||
set_service_is_done(false);
|
||||
service()->DeleteQueryWithDestinationURL(
|
||||
GetQueryDestinationURL("local query 1"));
|
||||
MaybeWaitForService();
|
||||
expected_local_queries = {
|
||||
{u"local query 2", GetQueryDestinationURL("local query 2"), ""}};
|
||||
// The deleted suggestion is not offered anymore.
|
||||
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
|
||||
|
||||
// Make sure there is no pending deletion task.
|
||||
WaitForRepeatableQueriesService();
|
||||
|
||||
// Request a refresh.
|
||||
RefreshAndMaybeWaitForService();
|
||||
expected_local_queries = {
|
||||
{u"local query 2", GetQueryDestinationURL("local query 2"), ""},
|
||||
{u"local query 3", GetQueryDestinationURL("local query 3"), ""}};
|
||||
// The deleted suggestion will not be offered again.
|
||||
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
|
||||
}
|
@ -25,7 +25,6 @@ IOSMostVisitedSitesFactory::NewForBrowserState(
|
||||
return std::make_unique<ntp_tiles::MostVisitedSites>(
|
||||
browser_state->GetPrefs(),
|
||||
ios::TopSitesFactory::GetForBrowserState(browser_state),
|
||||
/*repeatable_queries=*/nullptr,
|
||||
suggestions::SuggestionsServiceFactory::GetForBrowserState(browser_state),
|
||||
IOSPopularSitesFactory::NewForBrowserState(browser_state),
|
||||
/*custom_links=*/nullptr,
|
||||
|
@ -76,7 +76,6 @@ bool IOSNTPTilesInternalsMessageHandlerBridge::DoesSourceExist(
|
||||
case ntp_tiles::TileSource::CUSTOM_LINKS:
|
||||
case ntp_tiles::TileSource::ALLOWLIST:
|
||||
case ntp_tiles::TileSource::EXPLORE:
|
||||
case ntp_tiles::TileSource::REPEATABLE_QUERIES_SERVICE:
|
||||
return false;
|
||||
}
|
||||
NOTREACHED();
|
||||
|
@ -5040,31 +5040,6 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"NtpRepeatableQueriesDesktop": [
|
||||
{
|
||||
"platforms": [
|
||||
"chromeos",
|
||||
"chromeos_lacros",
|
||||
"linux",
|
||||
"mac",
|
||||
"windows"
|
||||
],
|
||||
"experiments": [
|
||||
{
|
||||
"name": "Enabled",
|
||||
"params": {
|
||||
"NtpRepeatableQueriesAgeThresholdDays": "180",
|
||||
"NtpRepeatableQueriesFrequencyExponent": "2",
|
||||
"NtpRepeatableQueriesInsertPosition": "start",
|
||||
"NtpRepeatableQueriesRecencyHalfLifeSeconds": "604800"
|
||||
},
|
||||
"enable_features": [
|
||||
"NtpRepeatableQueries"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"NtpWebUIDesktop": [
|
||||
{
|
||||
"platforms": [
|
||||
|
@ -11620,7 +11620,11 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
|
||||
<suffix name="popular_baked_in" label="Baked-in, popular suggestions."/>
|
||||
<suffix name="popular_fetched"
|
||||
label="Non-personalized, popular suggestions (fetched from the server)."/>
|
||||
<suffix name="repeatable_query" label="Repeatable Query suggestion."/>
|
||||
<suffix name="repeatable_query" label="Repeatable Query suggestion.">
|
||||
<obsolete>
|
||||
Removed in 05 2021.
|
||||
</obsolete>
|
||||
</suffix>
|
||||
<suffix name="search_page" label="Google Search page">
|
||||
<obsolete>
|
||||
Used for experiment but was never launched, as of 2019-07.
|
||||
|
@ -1325,6 +1325,9 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
|
||||
|
||||
<histogram name="NewTabPage.RepeatableQueries.ExtractedCount" units="count"
|
||||
expires_after="2021-10-25">
|
||||
<obsolete>
|
||||
Removed in 05 2021.
|
||||
</obsolete>
|
||||
<owner>mahmadi@chromium.org</owner>
|
||||
<owner>chrome-desktop-ntp@google.com</owner>
|
||||
<summary>
|
||||
@ -1337,6 +1340,9 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
|
||||
|
||||
<histogram name="NewTabPage.RepeatableQueries.ExtractionDuration" units="ms"
|
||||
expires_after="2021-10-25">
|
||||
<obsolete>
|
||||
Removed in 05 2021.
|
||||
</obsolete>
|
||||
<owner>mahmadi@chromium.org</owner>
|
||||
<owner>chrome-desktop-ntp@google.com</owner>
|
||||
<summary>
|
||||
|
@ -285,8 +285,6 @@ Refer to README.md for content description and update process.
|
||||
<item id="remoting_telemetry_log_writer" added_in_milestone="86" hash_code="107268760" type="0" content_hash_code="81741595" os_list="linux,windows" file_path="remoting/base/telemetry_log_writer.cc"/>
|
||||
<item id="render_view_context_menu" added_in_milestone="62" hash_code="25844439" type="0" content_hash_code="69471170" os_list="linux,windows" file_path="chrome/browser/renderer_context_menu/render_view_context_menu.cc"/>
|
||||
<item id="renderer_initiated_download" added_in_milestone="62" hash_code="116443055" type="0" content_hash_code="37846436" os_list="linux,windows" file_path="content/browser/renderer_host/render_frame_host_impl.cc"/>
|
||||
<item id="repeatable_queries_deletion" added_in_milestone="88" hash_code="59980744" type="0" content_hash_code="9022058" os_list="linux,windows" file_path="components/search/repeatable_queries/repeatable_queries_service.cc"/>
|
||||
<item id="repeatable_queries_service" added_in_milestone="88" hash_code="5394442" type="0" content_hash_code="115294794" os_list="linux,windows" file_path="components/search/repeatable_queries/repeatable_queries_service.cc"/>
|
||||
<item id="reporting" added_in_milestone="62" hash_code="109891200" type="0" content_hash_code="125758928" os_list="linux,windows" file_path="net/reporting/reporting_uploader.cc"/>
|
||||
<item id="resource_dispatcher_host" added_in_milestone="62" hash_code="81157007" type="0" deprecated="2019-07-30" content_hash_code="35725167" file_path=""/>
|
||||
<item id="resource_prefetch" added_in_milestone="62" hash_code="110815970" type="0" deprecated="2018-02-28" content_hash_code="39251261" file_path=""/>
|
||||
|
@ -409,8 +409,6 @@ hidden="true" so that these annotations don't show up in the document.
|
||||
<traffic_annotation unique_id="popular_sites_fetch"/>
|
||||
<traffic_annotation unique_id="search_suggest_service"/>
|
||||
<traffic_annotation unique_id="remote_suggestions_provider"/>
|
||||
<traffic_annotation unique_id="repeatable_queries_deletion"/>
|
||||
<traffic_annotation unique_id="repeatable_queries_service"/>
|
||||
<traffic_annotation unique_id="promo_service"/>
|
||||
<traffic_annotation unique_id="task_module_service"/>
|
||||
</sender>
|
||||
|
Reference in New Issue
Block a user