blob: fdb5e5d5f8015aba114621e48197f31f1dbe69a2 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/base64.h"
#include "base/run_loop.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_hints_manager.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/optimization_guide/optimization_guide_top_host_provider.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/optimization_guide/command_line_top_host_provider.h"
#include "components/optimization_guide/optimization_guide_enums.h"
#include "components/optimization_guide/optimization_guide_features.h"
#include "components/optimization_guide/optimization_guide_prefs.h"
#include "components/optimization_guide/optimization_guide_store.h"
#include "components/optimization_guide/optimization_guide_switches.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "components/optimization_guide/test_hints_component_creator.h"
#include "components/prefs/pref_service.h"
#include "components/previews/core/previews_switches.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/hashing.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/base/escape.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source.h"
namespace {
// Fetch and calculate the total number of samples from all the bins for
// |histogram_name|. Note: from some browertests run, there might be two
// profiles created, and this will return the total sample count across
// profiles.
int GetTotalHistogramSamples(const base::HistogramTester& histogram_tester,
const std::string& histogram_name) {
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples(histogram_name);
int total = 0;
for (const auto& bucket : buckets)
total += bucket.count;
return total;
}
// Retries fetching |histogram_name| until it contains at least |count| samples.
int RetryForHistogramUntilCountReached(
const base::HistogramTester& histogram_tester,
const std::string& histogram_name,
int count) {
int total = 0;
while (true) {
base::ThreadPoolInstance::Get()->FlushForTesting();
base::RunLoop().RunUntilIdle();
total = GetTotalHistogramSamples(histogram_tester, histogram_name);
if (total >= count)
return total;
}
}
// A WebContentsObserver that asks whether an optimization type can be applied.
class OptimizationGuideConsumerWebContentsObserver
: public content::WebContentsObserver {
public:
OptimizationGuideConsumerWebContentsObserver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {}
~OptimizationGuideConsumerWebContentsObserver() override = default;
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override {
if (callback_) {
OptimizationGuideKeyedService* service =
OptimizationGuideKeyedServiceFactory::GetForProfile(
Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
service->CanApplyOptimizationAsync(navigation_handle,
optimization_guide::proto::NOSCRIPT,
std::move(callback_));
}
}
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override {
OptimizationGuideKeyedService* service =
OptimizationGuideKeyedServiceFactory::GetForProfile(
Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
last_can_apply_optimization_decision_ = service->CanApplyOptimization(
navigation_handle->GetURL(), optimization_guide::proto::NOSCRIPT,
/*optimization_metadata=*/nullptr);
}
// Returns the last optimization guide decision that was returned by the
// OptimizationGuideKeyedService's CanApplyOptimization() method.
optimization_guide::OptimizationGuideDecision
last_can_apply_optimization_decision() {
return last_can_apply_optimization_decision_;
}
void set_callback(
optimization_guide::OptimizationGuideDecisionCallback callback) {
callback_ = std::move(callback);
}
private:
optimization_guide::OptimizationGuideDecision
last_can_apply_optimization_decision_ =
optimization_guide::OptimizationGuideDecision::kUnknown;
optimization_guide::OptimizationGuideDecisionCallback callback_;
};
} // namespace
class OptimizationGuideKeyedServiceDisabledBrowserTest
: public InProcessBrowserTest {
public:
OptimizationGuideKeyedServiceDisabledBrowserTest() {
feature_list_.InitWithFeatures(
{}, {optimization_guide::features::kOptimizationHints});
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceDisabledBrowserTest,
KeyedServiceEnabledButOptimizationHintsDisabled) {
EXPECT_EQ(nullptr, OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile()));
}
class OptimizationGuideKeyedServiceBrowserTest
: public OptimizationGuideKeyedServiceDisabledBrowserTest {
public:
OptimizationGuideKeyedServiceBrowserTest() {
scoped_feature_list_.InitWithFeatures(
{optimization_guide::features::kOptimizationHints}, {});
}
~OptimizationGuideKeyedServiceBrowserTest() override = default;
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitch(optimization_guide::switches::kPurgeHintsStore);
}
void SetUpOnMainThread() override {
OptimizationGuideKeyedServiceDisabledBrowserTest::SetUpOnMainThread();
https_server_.reset(
new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
https_server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir());
https_server_->RegisterRequestHandler(base::BindRepeating(
&OptimizationGuideKeyedServiceBrowserTest::HandleRequest,
base::Unretained(this)));
ASSERT_TRUE(https_server_->Start());
url_with_hints_ = https_server_->GetURL("/simple.html");
url_that_redirects_ =
https_server_->GetURL("/redirect?" + url_with_hints_.spec());
url_that_redirects_to_no_hints_ =
https_server_->GetURL("/redirect?https://nohints.com/");
SetEffectiveConnectionType(
net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
}
void TearDownOnMainThread() override {
EXPECT_TRUE(https_server_->ShutdownAndWaitUntilComplete());
OptimizationGuideKeyedServiceDisabledBrowserTest::TearDownOnMainThread();
}
void RegisterWithKeyedService() {
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->RegisterOptimizationTargets(
{optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD});
// Set up an OptimizationGuideKeyedService consumer.
consumer_.reset(new OptimizationGuideConsumerWebContentsObserver(
browser()->tab_strip_model()->GetActiveWebContents()));
}
optimization_guide::TopHostProvider* top_host_provider() {
auto* optimization_guide_keyed_service =
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile());
return optimization_guide_keyed_service->GetTopHostProvider();
}
optimization_guide::PredictionManager* prediction_manager() {
auto* optimization_guide_keyed_service =
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile());
return optimization_guide_keyed_service->GetPredictionManager();
}
void PushHintsComponentAndWaitForCompletion() {
base::RunLoop run_loop;
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->GetHintsManager()
->ListenForNextUpdateForTesting(run_loop.QuitClosure());
const optimization_guide::HintsComponentInfo& component_info =
test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
optimization_guide::proto::NOSCRIPT, {url_with_hints_.host()},
"simple.html");
g_browser_process->optimization_guide_service()->MaybeUpdateHintsComponent(
component_info);
run_loop.Run();
}
// Sets the effective connection type that the Network Quality Tracker will
// report.
void SetEffectiveConnectionType(
net::EffectiveConnectionType effective_connection_type) {
g_browser_process->network_quality_tracker()
->ReportEffectiveConnectionTypeForTesting(effective_connection_type);
}
// Sets the callback on the consumer of the OptimizationGuideKeyedService. If
// set, this will call the async version of CanApplyOptimization.
void SetCallbackOnConsumer(
optimization_guide::OptimizationGuideDecisionCallback callback) {
ASSERT_TRUE(consumer_);
consumer_->set_callback(std::move(callback));
}
// Returns whether the synthetic trial |trial_name| has been logged and is in
// the |trial_group| for the trial.
bool IsInSyntheticTrialGroup(const std::string& trial_name,
const std::string& trial_group) {
std::vector<std::string> synthetic_trials;
variations::GetSyntheticTrialGroupIdsAsString(&synthetic_trials);
std::string expected_entry =
base::StringPrintf("%x-%x", variations::HashName(trial_name),
variations::HashName(trial_group));
return std::find(synthetic_trials.begin(), synthetic_trials.end(),
expected_entry) != synthetic_trials.end();
}
// Returns the last decision from the CanApplyOptimization() method seen by
// the consumer of the OptimizationGuideKeyedService.
optimization_guide::OptimizationGuideDecision
last_can_apply_optimization_decision() {
return consumer_->last_can_apply_optimization_decision();
}
GURL url_with_hints() { return url_with_hints_; }
GURL url_that_redirects_to_hints() { return url_that_redirects_; }
GURL url_that_redirects_to_no_hints() {
return url_that_redirects_to_no_hints_;
}
base::HistogramTester* histogram_tester() { return &histogram_tester_; }
private:
std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
const net::test_server::HttpRequest& request) {
if (request.GetURL().spec().find("redirect") == std::string::npos) {
return std::unique_ptr<net::test_server::HttpResponse>();
}
GURL request_url = request.GetURL();
std::string dest =
net::UnescapeBinaryURLComponent(request_url.query_piece());
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_FOUND);
http_response->AddCustomHeader("Location", dest);
return http_response;
}
std::unique_ptr<net::EmbeddedTestServer> https_server_;
GURL url_with_hints_;
GURL url_that_redirects_;
GURL url_that_redirects_to_no_hints_;
base::test::ScopedFeatureList scoped_feature_list_;
optimization_guide::testing::TestHintsComponentCreator
test_hints_component_creator_;
std::unique_ptr<OptimizationGuideConsumerWebContentsObserver> consumer_;
// Histogram tester used specifically to capture metrics that are recorded
// during browser initialization.
base::HistogramTester histogram_tester_;
DISALLOW_COPY_AND_ASSIGN(OptimizationGuideKeyedServiceBrowserTest);
};
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
TopHostProviderNotSetIfNotAllowed) {
ASSERT_FALSE(top_host_provider());
// ChromeOS has multiple profiles and optimization guide currently does not
// run on non-Android.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
histogram_tester()->ExpectUniqueSample(
"OptimizationGuide.RemoteFetchingEnabled", false, 1);
EXPECT_TRUE(IsInSyntheticTrialGroup(
"SyntheticOptimizationGuideRemoteFetching", "Disabled"));
#endif
}
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageWithHintsButNoRegistrationDoesNotAttemptToLoadHint) {
PushHintsComponentAndWaitForCompletion();
ukm::TestAutoSetUkmRecorder ukm_recorder;
base::HistogramTester histogram_tester;
ui_test_utils::NavigateToURL(browser(), url_with_hints());
histogram_tester.ExpectTotalCount("OptimizationGuide.LoadedHint.Result", 0);
// Navigate away so UKM get recorded.
ui_test_utils::NavigateToURL(browser(), url_with_hints());
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(0u, entries.size());
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageWithAsyncCallbackReturnsAnswerRedirect) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
SetCallbackOnConsumer(base::BindOnce(
[](base::RunLoop* run_loop,
optimization_guide::OptimizationGuideDecision decision,
const optimization_guide::OptimizationMetadata& metadata) {
EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kFalse,
decision);
run_loop->Quit();
},
run_loop.get()));
ui_test_utils::NavigateToURL(browser(), url_that_redirects_to_no_hints());
run_loop->Run();
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageWithAsyncCallbackReturnsAnswer) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
SetCallbackOnConsumer(base::BindOnce(
[](base::RunLoop* run_loop,
optimization_guide::OptimizationGuideDecision decision,
const optimization_guide::OptimizationMetadata& metadata) {
EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kTrue,
decision);
run_loop->Quit();
},
run_loop.get()));
ui_test_utils::NavigateToURL(browser(), url_with_hints());
run_loop->Run();
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageWithAsyncCallbackReturnsAnswerEventually) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
SetCallbackOnConsumer(base::BindOnce(
[](base::RunLoop* run_loop,
optimization_guide::OptimizationGuideDecision decision,
const optimization_guide::OptimizationMetadata& metadata) {
EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kFalse,
decision);
run_loop->Quit();
},
run_loop.get()));
ui_test_utils::NavigateToURL(browser(), GURL("https://nohints.com/"));
run_loop->Run();
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageWithHintsLoadsHint) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
ukm::TestAutoSetUkmRecorder ukm_recorder;
base::HistogramTester histogram_tester;
ui_test_utils::NavigateToURL(browser(), url_with_hints());
EXPECT_GT(RetryForHistogramUntilCountReached(
histogram_tester, "OptimizationGuide.LoadedHint.Result", 1),
0);
// There is a hint that matches this URL, so there should be an attempt to
// load a hint that succeeds.
histogram_tester.ExpectUniqueSample("OptimizationGuide.LoadedHint.Result",
true, 1);
// We had a hint and it was loaded.
EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kTrue,
last_can_apply_optimization_decision());
// Navigate away so metrics get recorded.
ui_test_utils::NavigateToURL(browser(), url_with_hints());
// Expect that UKM is recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry,
ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName));
// NOSCRIPT = 1, so bit mask is 10, which equals 2.
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName,
2);
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
RecordsMetricsWhenTabHidden) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
ukm::TestAutoSetUkmRecorder ukm_recorder;
base::HistogramTester histogram_tester;
ui_test_utils::NavigateToURL(browser(), url_with_hints());
EXPECT_GT(RetryForHistogramUntilCountReached(
histogram_tester, "OptimizationGuide.LoadedHint.Result", 1),
0);
// There is a hint that matches this URL, so there should be an attempt to
// load a hint that succeeds.
histogram_tester.ExpectUniqueSample("OptimizationGuide.LoadedHint.Result",
true, 1);
// We had a hint and it was loaded.
EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kTrue,
last_can_apply_optimization_decision());
// Make sure metrics get recorded when tab is hidden.
browser()->tab_strip_model()->GetActiveWebContents()->WasHidden();
// Expect that the optimization guide UKM is recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry,
ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName));
// NOSCRIPT = 1, so bit mask is 10, which equals 2.
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName,
2);
}
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageThatRedirectsToUrlWithHintsShouldAttemptTwoLoads) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
ukm::TestAutoSetUkmRecorder ukm_recorder;
base::HistogramTester histogram_tester;
ui_test_utils::NavigateToURL(browser(), url_that_redirects_to_hints());
EXPECT_EQ(RetryForHistogramUntilCountReached(
histogram_tester, "OptimizationGuide.LoadedHint.Result", 2),
2);
// Should attempt and succeed to load a hint once for the initial navigation
// and redirect.
histogram_tester.ExpectBucketCount("OptimizationGuide.LoadedHint.Result",
true, 2);
// Hint is still applicable so we expect it to be allowed to be applied.
EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kTrue,
last_can_apply_optimization_decision());
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageWithoutHint) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
ukm::TestAutoSetUkmRecorder ukm_recorder;
base::HistogramTester histogram_tester;
ui_test_utils::NavigateToURL(browser(), GURL("https://nohints.com/"));
EXPECT_EQ(RetryForHistogramUntilCountReached(
histogram_tester, "OptimizationGuide.LoadedHint.Result", 1),
1);
// There were no hints that match this URL, but there should still be an
// attempt to load a hint but still fail.
histogram_tester.ExpectUniqueSample("OptimizationGuide.LoadedHint.Result",
false, 1);
EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kFalse,
last_can_apply_optimization_decision());
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.NoScript",
static_cast<int>(
optimization_guide::OptimizationTypeDecision::kNoHintAvailable),
1);
}
class OptimizationGuideKeyedServiceDataSaverUserWithInfobarShownTest
: public OptimizationGuideKeyedServiceBrowserTest {
public:
OptimizationGuideKeyedServiceDataSaverUserWithInfobarShownTest() = default;
~OptimizationGuideKeyedServiceDataSaverUserWithInfobarShownTest() override =
default;
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(
optimization_guide::features::kRemoteOptimizationGuideFetching);
OptimizationGuideKeyedServiceBrowserTest::SetUp();
}
void TearDown() override {
OptimizationGuideKeyedServiceBrowserTest::TearDown();
scoped_feature_list_.Reset();
}
void SetUpOnMainThread() override {
OptimizationGuideKeyedServiceBrowserTest::SetUpOnMainThread();
SeedSiteEngagementService();
// Set the blacklist state to initialized so the sites in the engagement
// service will be used and not blacklisted on the first GetTopHosts
// request.
InitializeTopHostBlacklist();
}
void SetUpCommandLine(base::CommandLine* cmd) override {
OptimizationGuideKeyedServiceBrowserTest::SetUpCommandLine(cmd);
cmd->AppendSwitch("enable-spdy-proxy-auth");
// Add switch to avoid having to see the infobar in the test.
cmd->AppendSwitch(previews::switches::kDoNotRequireLitePageRedirectInfoBar);
// Add switch to avoid racing navigations in the test.
cmd->AppendSwitch(optimization_guide::switches::
kDisableFetchingHintsAtNavigationStartForTesting);
}
private:
// Seeds the Site Engagement Service with two HTTP and two HTTPS sites for the
// current profile.
void SeedSiteEngagementService() {
auto* service = site_engagement::SiteEngagementService::Get(
Profile::FromBrowserContext(browser()
->tab_strip_model()
->GetActiveWebContents()
->GetBrowserContext()));
GURL https_url1("https://myfavoritesite.com/");
service->AddPointsForTesting(https_url1, 15);
GURL https_url2("https://myotherfavoritesite.com/");
service->AddPointsForTesting(https_url2, 3);
}
void InitializeTopHostBlacklist() {
Profile::FromBrowserContext(browser()
->tab_strip_model()
->GetActiveWebContents()
->GetBrowserContext())
->GetPrefs()
->SetInteger(
optimization_guide::prefs::kHintsFetcherTopHostBlacklistState,
static_cast<int>(
optimization_guide::prefs::HintsFetcherTopHostBlacklistState::
kInitialized));
}
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServiceDataSaverUserWithInfobarShownTest,
TopHostProviderIsSentDown) {
ASSERT_TRUE(top_host_provider());
std::vector<std::string> top_hosts = top_host_provider()->GetTopHosts();
EXPECT_EQ(2ul, top_hosts.size());
EXPECT_EQ("myfavoritesite.com", top_hosts[0]);
EXPECT_EQ("myotherfavoritesite.com", top_hosts[1]);
// ChromeOS has multiple profiles and optimization guide currently does not
// run on non-Android.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
histogram_tester()->ExpectUniqueSample(
"OptimizationGuide.RemoteFetchingEnabled", true, 1);
EXPECT_TRUE(IsInSyntheticTrialGroup(
"SyntheticOptimizationGuideRemoteFetching", "Enabled"));
#endif
}
// TODO(crbug/1158343): Re-enable when flake is fixed.
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServiceDataSaverUserWithInfobarShownTest,
DISABLED_IncognitoCanStillReadFromComponentHints) {
// Instantiate off the record Optimization Guide Service.
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile()->GetPrimaryOTRProfile())
->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
// Wait until initialization logic finishes running and component pushed to
// both incognito and regular browsers.
PushHintsComponentAndWaitForCompletion();
base::RunLoop().RunUntilIdle();
// Set up incognito browser and incognito OptimizationGuideKeyedService
// consumer.
Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
auto otr_consumer =
std::make_unique<OptimizationGuideConsumerWebContentsObserver>(
otr_browser->tab_strip_model()->GetActiveWebContents());
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
otr_consumer->set_callback(base::BindOnce(
[](base::RunLoop* run_loop,
optimization_guide::OptimizationGuideDecision decision,
const optimization_guide::OptimizationMetadata& metadata) {
// Should still get decision in incognito.
EXPECT_EQ(decision,
optimization_guide::OptimizationGuideDecision::kTrue);
run_loop->Quit();
},
run_loop.get()));
// Navigate to a URL that has a hint from a component.
ui_test_utils::NavigateToURL(otr_browser, url_with_hints());
run_loop->Run();
}
class OptimizationGuideKeyedServiceCommandLineOverridesTest
: public OptimizationGuideKeyedServiceDataSaverUserWithInfobarShownTest {
public:
OptimizationGuideKeyedServiceCommandLineOverridesTest() = default;
~OptimizationGuideKeyedServiceCommandLineOverridesTest() override = default;
void SetUpCommandLine(base::CommandLine* cmd) override {
OptimizationGuideKeyedServiceDataSaverUserWithInfobarShownTest::
SetUpCommandLine(cmd);
cmd->AppendSwitchASCII(optimization_guide::switches::kFetchHintsOverride,
"whatever.com,somehost.com");
}
};
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceCommandLineOverridesTest,
TopHostProviderIsSentDown) {
ASSERT_TRUE(top_host_provider());
std::vector<std::string> top_hosts = top_host_provider()->GetTopHosts();
EXPECT_EQ(2ul, top_hosts.size());
EXPECT_EQ("whatever.com", top_hosts[0]);
EXPECT_EQ("somehost.com", top_hosts[1]);
// ChromeOS has multiple profiles and optimization guide currently does not
// run on non-Android.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
histogram_tester()->ExpectUniqueSample(
"OptimizationGuide.RemoteFetchingEnabled", true, 1);
EXPECT_TRUE(IsInSyntheticTrialGroup(
"SyntheticOptimizationGuideRemoteFetching", "Enabled"));
#endif
}