blob: a9f5abf5cef14eff795aedf5b73a5d493ae6104c [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include <memory>
#include "base/base64.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/strings/escape.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/run_until.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/optimization_guide/browser_test_util.h"
#include "chrome/browser/optimization_guide/chrome_hints_manager.h"
#include "chrome/browser/optimization_guide/chrome_model_quality_logs_uploader_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/profile_waiter.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
#include "components/optimization_guide/core/command_line_top_host_provider.h"
#include "components/optimization_guide/core/feature_registry/mqls_feature_registry.h"
#include "components/optimization_guide/core/model_execution/feature_keys.h"
#include "components/optimization_guide/core/model_execution/model_execution_features.h"
#include "components/optimization_guide/core/model_execution/model_execution_features_controller.h"
#include "components/optimization_guide/core/model_execution/model_execution_prefs.h"
#include "components/optimization_guide/core/model_execution/on_device_model_component.h"
#include "components/optimization_guide/core/optimization_guide_enums.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_prefs.h"
#include "components/optimization_guide/core/optimization_guide_store.h"
#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/optimization_guide/core/optimization_guide_test_util.h"
#include "components/optimization_guide/core/optimization_hints_component_update_listener.h"
#include "components/optimization_guide/core/test_hints_component_creator.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "components/optimization_guide/proto/model_quality_service.pb.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/hashing.h"
#include "components/variations/service/variations_service.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.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"
#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/on_device_model/public/cpp/features.h"
namespace optimization_guide {
using model_execution::prefs::ModelExecutionEnterprisePolicyValue;
using ::testing::ElementsAre;
namespace {
using proto::OptimizationType;
class ScopedSetMetricsConsent {
public:
// Enables or disables metrics consent based off of |consent|.
explicit ScopedSetMetricsConsent(bool consent) : consent_(consent) {
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
&consent_);
}
ScopedSetMetricsConsent(const ScopedSetMetricsConsent&) = delete;
ScopedSetMetricsConsent& operator=(const ScopedSetMetricsConsent&) = delete;
~ScopedSetMetricsConsent() {
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
nullptr);
}
private:
const bool consent_;
};
// 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->CanApplyOptimization(navigation_handle->GetURL(),
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(), proto::NOSCRIPT,
/*optimization_metadata=*/nullptr);
}
// Returns the last optimization guide decision that was returned by the
// OptimizationGuideKeyedService's CanApplyOptimization() method.
OptimizationGuideDecision last_can_apply_optimization_decision() {
return last_can_apply_optimization_decision_;
}
void set_callback(OptimizationGuideDecisionCallback callback) {
callback_ = std::move(callback);
}
private:
OptimizationGuideDecision last_can_apply_optimization_decision_ =
OptimizationGuideDecision::kUnknown;
OptimizationGuideDecisionCallback callback_;
};
// A WebContentsObserver that specifically calls the new API that automatically
// decided whether to use the sync or async api in the background.
class OptimizationGuideNewApiConsumerWebContentsObserver
: public content::WebContentsObserver {
public:
OptimizationGuideNewApiConsumerWebContentsObserver(
content::WebContents* web_contents,
OptimizationGuideDecisionCallback callback)
: content::WebContentsObserver(web_contents),
callback_(std::move(callback)) {}
~OptimizationGuideNewApiConsumerWebContentsObserver() override = default;
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override {
if (callback_) {
OptimizationGuideKeyedService* service =
OptimizationGuideKeyedServiceFactory::GetForProfile(
Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
service->CanApplyOptimization(navigation_handle->GetURL(),
proto::NOSCRIPT, std::move(callback_));
}
}
private:
OptimizationGuideDecisionCallback callback_;
};
} // namespace
class OptimizationGuideKeyedServiceDisabledBrowserTest
: public InProcessBrowserTest {
public:
OptimizationGuideKeyedServiceDisabledBrowserTest() {
feature_list_.InitWithFeatures({}, {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()
: network_connection_tracker_(
network::TestNetworkConnectionTracker::CreateInstance()) {
// Enable visibility of tab organization feature.
scoped_feature_list_.InitWithFeaturesAndParameters(
/*enabled_features=*/
{{features::kOptimizationHints, {}},
{features::kOptimizationGuideModelExecution, {}},
{features::internal::kComposeSettingsVisibility, {}},
{features::internal::kWallpaperSearchSettingsVisibility, {}},
{on_device_model::features::kUseFakeChromeML, {}},
{features::kLogOnDeviceMetricsOnStartup,
{
{"on_device_startup_metric_delay", "0"},
}},
{features::internal::kTabOrganizationSettingsVisibility,
{{"allow_unsigned_user", "true"}}}},
/*disabled_features=*/
{features::internal::kWallpaperSearchGraduated,
features::internal::kComposeGraduated,
features::internal::kTabOrganizationGraduated});
}
OptimizationGuideKeyedServiceBrowserTest(
const OptimizationGuideKeyedServiceBrowserTest&) = delete;
OptimizationGuideKeyedServiceBrowserTest& operator=(
const OptimizationGuideKeyedServiceBrowserTest&) = delete;
~OptimizationGuideKeyedServiceBrowserTest() override = default;
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitch(switches::kPurgeHintsStore);
}
void SetUp() override {
policy_provider_.SetDefaultReturns(
/*is_initialization_complete_return=*/true,
/*is_first_policy_load_complete_return=*/true);
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
&policy_provider_);
InProcessBrowserTest::SetUp();
}
void SetUpBrowserContextKeyedServices(
content::BrowserContext* context) override {
OptimizationGuideKeyedServiceDisabledBrowserTest::
SetUpBrowserContextKeyedServices(context);
IdentityTestEnvironmentProfileAdaptor::
SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
// Note: Behavior for unofficial builds is tested by unit tests.
SetIsOfficialBuildForTesting(true);
}
void SetUpOnMainThread() override {
OptimizationGuideKeyedServiceDisabledBrowserTest::SetUpOnMainThread();
https_server_ = std::make_unique<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/");
SetConnectionType(network::mojom::ConnectionType::CONNECTION_2G);
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
browser()->profile());
}
void TearDownOnMainThread() override {
EXPECT_TRUE(https_server_->ShutdownAndWaitUntilComplete());
OptimizationGuideKeyedServiceDisabledBrowserTest::TearDownOnMainThread();
}
void RegisterWithKeyedService() {
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->RegisterOptimizationTypes({proto::NOSCRIPT});
// Set up an OptimizationGuideKeyedService consumer.
consumer_ = std::make_unique<OptimizationGuideConsumerWebContentsObserver>(
browser()->tab_strip_model()->GetActiveWebContents());
}
void CanApplyOptimizationOnDemand(
const std::vector<GURL>& urls,
const std::vector<proto::OptimizationType>& optimization_types,
OnDemandOptimizationGuideDecisionRepeatingCallback callback) {
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->CanApplyOptimizationOnDemand(urls, optimization_types,
proto::CONTEXT_BATCH_UPDATE_ACTIVE_TABS,
callback);
}
PredictionManager* prediction_manager() {
auto* optimization_guide_keyed_service =
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile());
return optimization_guide_keyed_service->GetPredictionManager();
}
void PushHintsComponentAndWaitForCompletion() {
RetryForHistogramUntilCountReached(
histogram_tester(),
"OptimizationGuide.HintsManager.HintCacheInitialized", 1);
base::RunLoop run_loop;
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->GetHintsManager()
->ListenForNextUpdateForTesting(run_loop.QuitClosure());
const HintsComponentInfo& component_info =
test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
proto::NOSCRIPT, {url_with_hints_.host()}, "simple.html");
OptimizationHintsComponentUpdateListener::GetInstance()
->MaybeUpdateHintsComponent(component_info);
run_loop.Run();
}
// Sets the connection type that the Network Connection Tracker will report.
void SetConnectionType(network::mojom::ConnectionType connection_type) {
network_connection_tracker_->SetConnectionType(connection_type);
}
// Sets the callback on the consumer of the OptimizationGuideKeyedService. If
// set, this will call the async version of CanApplyOptimization.
void SetCallbackOnConsumer(OptimizationGuideDecisionCallback callback) {
ASSERT_TRUE(consumer_);
consumer_->set_callback(std::move(callback));
}
// Returns the last decision from the CanApplyOptimization() method seen by
// the consumer of the OptimizationGuideKeyedService.
OptimizationGuideDecision last_can_apply_optimization_decision() {
return consumer_->last_can_apply_optimization_decision();
}
OptimizationGuideKeyedService* service() {
auto* profile = browser()->profile();
return OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
}
ModelExecutionFeaturesController* model_execution_features_controller() {
return service()->model_execution_features_controller_.get();
}
std::unique_ptr<ModelQualityLogEntry> GetModelQualityLogEntryForCompose() {
auto log_entry = std::make_unique<ModelQualityLogEntry>(
service()->GetModelQualityLogsUploaderService()->GetWeakPtr());
*log_entry->log_ai_data_request()->mutable_compose() =
proto::ComposeLoggingData();
return log_entry;
}
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_; }
void EnableSignIn() {
auto account_info =
identity_test_env_adaptor_->identity_test_env()
->MakePrimaryAccountAvailable("user@gmail.com",
signin::ConsentLevel::kSignin);
AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
mutator.set_can_use_model_execution_features(true);
identity_test_env_adaptor_->identity_test_env()
->UpdateAccountInfoForAccount(account_info);
}
void SignOut() {
identity_test_env_adaptor_->identity_test_env()->ClearPrimaryAccount();
}
bool IsSettingVisible(UserVisibleFeatureKey feature) {
return OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile())
->IsSettingVisible(feature);
}
void SetMetricsConsent(bool consent) {
scoped_metrics_consent_.emplace(consent);
}
void EnableFeature(UserVisibleFeatureKey feature) {
// Sign in must be enabled as a prerequisite for enabling any user-visible
// feature.
EnableSignIn();
auto* prefs = browser()->profile()->GetPrefs();
prefs->SetInteger(prefs::GetSettingEnabledPrefName(feature),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
base::RunLoop().RunUntilIdle();
}
void SetEnterprisePolicy(const std::string& key,
ModelExecutionEnterprisePolicyValue value) {
// Enable logging via the enterprise policy.
policies_.Set(key, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(value)), nullptr);
policy_provider_.UpdateChromePolicy(policies_);
base::RunLoop().RunUntilIdle();
}
void SetIsDogfoodClient(bool is_dogfood_client) {
g_browser_process->variations_service()->SetIsLikelyDogfoodClientForTesting(
is_dogfood_client);
}
void SetIsOfficialBuildForTesting(bool is_official_build) {
OptimizationGuideKeyedService::SetIsOfficialBuildForTesting(
is_official_build);
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
::testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_;
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 nullptr;
}
GURL request_url = request.GetURL();
std::string dest =
base::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_;
std::optional<ScopedSetMetricsConsent> scoped_metrics_consent_;
std::unique_ptr<network::TestNetworkConnectionTracker>
network_connection_tracker_;
// Enterprise policies. Stored as a member variable because each call to
// `UpdateChromePolicy` clears previous updates; so accumulate the policies
// in this `PolicyMap` instead.
policy::PolicyMap policies_;
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_;
// Identity test support.
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
};
// Configures the global VariationsService to treat this client as a likely
// dogfood client, before any keyed services are created.
class DogfoodOptimizationGuideKeyedServiceBrowserTest
: public OptimizationGuideKeyedServiceBrowserTest {
public:
DogfoodOptimizationGuideKeyedServiceBrowserTest() = default;
DogfoodOptimizationGuideKeyedServiceBrowserTest(
const OptimizationGuideKeyedServiceBrowserTest&) = delete;
DogfoodOptimizationGuideKeyedServiceBrowserTest& operator=(
const OptimizationGuideKeyedServiceBrowserTest&) = delete;
~DogfoodOptimizationGuideKeyedServiceBrowserTest() override = default;
void SetUpBrowserContextKeyedServices(
content::BrowserContext* context) override {
OptimizationGuideKeyedServiceBrowserTest::SetUpBrowserContextKeyedServices(
context);
SetIsDogfoodClient(true);
}
};
class OptimizationGuideKeyedServiceStartupLogDisabledBrowserTest
: public OptimizationGuideKeyedServiceBrowserTest {
public:
OptimizationGuideKeyedServiceStartupLogDisabledBrowserTest() {
feature_list_.InitWithFeaturesAndParameters(
{
{features::kOptimizationGuideOnDeviceModel, {}},
},
{features::kLogOnDeviceMetricsOnStartup});
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
RemoteFetchingDisabled) {
// ChromeOS has multiple profiles and optimization guide currently does not
// run on non-Android.
#if !BUILDFLAG(IS_CHROMEOS)
histogram_tester()->ExpectUniqueSample(
"OptimizationGuide.RemoteFetchingEnabled", false, 1);
EXPECT_TRUE(variations::IsInSyntheticTrialGroup(
"SyntheticOptimizationGuideRemoteFetching", "Disabled"));
#endif
}
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, OptimizationGuideDecision decision,
const OptimizationMetadata& metadata) {
EXPECT_EQ(OptimizationGuideDecision::kFalse, decision);
run_loop->Quit();
},
run_loop.get()));
ASSERT_TRUE(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, OptimizationGuideDecision decision,
const OptimizationMetadata& metadata) {
EXPECT_EQ(OptimizationGuideDecision::kTrue, decision);
run_loop->Quit();
},
run_loop.get()));
ASSERT_TRUE(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, OptimizationGuideDecision decision,
const OptimizationMetadata& metadata) {
EXPECT_EQ(OptimizationGuideDecision::kFalse, decision);
run_loop->Quit();
},
run_loop.get()));
ASSERT_TRUE(
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;
ASSERT_TRUE(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(OptimizationGuideDecision::kTrue,
last_can_apply_optimization_decision());
// Navigate away so metrics get recorded.
ASSERT_TRUE(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].get();
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry,
ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName));
const int64_t* entry_metric = ukm_recorder.GetEntryMetric(
entry,
ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName);
EXPECT_TRUE(*entry_metric & (1 << proto::NOSCRIPT));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
RecordsMetricsWhenTabHidden) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
ukm::TestAutoSetUkmRecorder ukm_recorder;
base::HistogramTester histogram_tester;
ASSERT_TRUE(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(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].get();
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry,
ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName));
const int64_t* entry_metric = ukm_recorder.GetEntryMetric(
entry,
ukm::builders::OptimizationGuide::kRegisteredOptimizationTypesName);
EXPECT_TRUE(*entry_metric & (1 << proto::NOSCRIPT));
}
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageThatRedirectsToUrlWithHintsShouldAttemptTwoLoads) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
base::HistogramTester histogram_tester;
ASSERT_TRUE(
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(OptimizationGuideDecision::kTrue,
last_can_apply_optimization_decision());
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
NavigateToPageWithoutHint) {
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
base::HistogramTester histogram_tester;
ASSERT_TRUE(
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(OptimizationGuideDecision::kFalse,
last_can_apply_optimization_decision());
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.NoScript",
static_cast<int>(OptimizationTypeDecision::kNoHintAvailable), 1);
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CheckForBlocklistFilter) {
PushHintsComponentAndWaitForCompletion();
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
{
base::HistogramTester histogram_tester;
// Register an optimization type with an optimization filter.
ogks->RegisterOptimizationTypes({proto::FAST_HOST_HINTS});
// Wait until filter is loaded. This histogram will record twice: once when
// the config is found and once when the filter is created.
RetryForHistogramUntilCountReached(
&histogram_tester,
"OptimizationGuide.OptimizationFilterStatus.FastHostHints", 2);
EXPECT_EQ(
OptimizationGuideDecision::kFalse,
ogks->CanApplyOptimization(GURL("https://blockedhost.com/whatever"),
proto::FAST_HOST_HINTS, nullptr));
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.FastHostHints",
static_cast<int>(
OptimizationTypeDecision::kNotAllowedByOptimizationFilter),
1);
}
// Register another type with optimization filter.
{
base::HistogramTester histogram_tester;
ogks->RegisterOptimizationTypes({proto::LITE_PAGE_REDIRECT});
// Wait until filter is loaded. This histogram will record twice: once when
// the config is found and once when the filter is created.
RetryForHistogramUntilCountReached(
&histogram_tester,
"OptimizationGuide.OptimizationFilterStatus.LitePageRedirect", 2);
// The previously loaded filter should still be loaded and give the same
// result.
EXPECT_EQ(
OptimizationGuideDecision::kFalse,
ogks->CanApplyOptimization(GURL("https://blockedhost.com/whatever"),
proto::FAST_HOST_HINTS, nullptr));
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.FastHostHints",
static_cast<int>(
OptimizationTypeDecision::kNotAllowedByOptimizationFilter),
1);
}
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CanApplyOptimizationOnDemand) {
PushHintsComponentAndWaitForCompletion();
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
ogks->RegisterOptimizationTypes({proto::OptimizationType::NOSCRIPT,
proto::OptimizationType::FAST_HOST_HINTS});
base::HistogramTester histogram_tester;
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url_with_hints()));
RetryForHistogramUntilCountReached(&histogram_tester,
"OptimizationGuide.LoadedHint.Result", 1);
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
base::flat_set<GURL> received_callbacks;
CanApplyOptimizationOnDemand(
{url_with_hints(), GURL("https://blockedhost.com/whatever")},
{proto::OptimizationType::NOSCRIPT,
proto::OptimizationType::FAST_HOST_HINTS},
base::BindRepeating(
[](base::RunLoop* run_loop, base::flat_set<GURL>* received_callbacks,
const GURL& url,
const base::flat_map<proto::OptimizationType,
OptimizationGuideDecisionWithMetadata>&
decisions) {
received_callbacks->insert(url);
// Expect one decision per requested type.
EXPECT_EQ(decisions.size(), 2u);
if (received_callbacks->size() == 2) {
run_loop->Quit();
}
},
run_loop.get(), &received_callbacks));
run_loop->Run();
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CanApplyOptimizationNewAPI) {
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
ogks->RegisterOptimizationTypes({proto::OptimizationType::NOSCRIPT});
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
// Before the hints or navigation are initiated, we should get a negative
// response.
ogks->CanApplyOptimization(
url_with_hints(), proto::OptimizationType::NOSCRIPT,
base::BindOnce(
[](base::RunLoop* run_loop, OptimizationGuideDecision decision,
const OptimizationMetadata& metadata) {
EXPECT_EQ(decision, OptimizationGuideDecision::kFalse);
run_loop->Quit();
},
run_loop.get()));
run_loop->Run();
// Now attach a WebContentsObserver to make a request while a navigation is
// in progress.
run_loop = std::make_unique<base::RunLoop>();
OptimizationGuideNewApiConsumerWebContentsObserver observer(
browser()->tab_strip_model()->GetActiveWebContents(),
base::BindOnce(
[](base::RunLoop* run_loop, OptimizationGuideDecision decision,
const OptimizationMetadata& metadata) {
EXPECT_EQ(OptimizationGuideDecision::kTrue, decision);
run_loop->Quit();
},
run_loop.get()));
PushHintsComponentAndWaitForCompletion();
RegisterWithKeyedService();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url_with_hints()));
run_loop->Run();
// After the navigation has finished, we should still be able to query and
// get the correct response.
run_loop = std::make_unique<base::RunLoop>();
ogks->CanApplyOptimization(
url_with_hints(), proto::OptimizationType::NOSCRIPT,
base::BindOnce(
[](base::RunLoop* run_loop, OptimizationGuideDecision decision,
const OptimizationMetadata& metadata) {
EXPECT_EQ(decision, OptimizationGuideDecision::kTrue);
run_loop->Quit();
},
run_loop.get()));
run_loop->Run();
}
class TestSettingsEnabledObserver : public SettingsEnabledObserver {
public:
explicit TestSettingsEnabledObserver(UserVisibleFeatureKey feature)
: SettingsEnabledObserver(feature) {}
void OnChangeInFeatureCurrentlyEnabledState(bool is_now_enabled) override {
count_feature_enabled_state_changes_++;
is_currently_enabled_ = is_now_enabled;
}
int count_feature_enabled_state_changes_ = 0;
bool is_currently_enabled_ = false;
};
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
SettingsVisibilitySignedOutVsSignedIn) {
// User is not signed-in.
EXPECT_FALSE(IsSettingVisible(UserVisibleFeatureKey::kWallpaperSearch));
// Visibility of tab organizer is allowed for unsigned users.
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kTabOrganization));
// Visibility of this feature is enabled via finch but the feature is still
// not visible.
EXPECT_FALSE(IsSettingVisible(UserVisibleFeatureKey::kCompose));
// kCompose should now be visible after
// sign-in.
EnableSignIn();
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kTabOrganization));
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kCompose));
#if !BUILDFLAG(IS_CHROMEOS)
// SignOut not supported on ChromeOS.
SignOut();
// Tab Organizer is visible to unsigned users.
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kTabOrganization));
EXPECT_FALSE(IsSettingVisible(UserVisibleFeatureKey::kCompose));
#endif
}
// Verifies that Model Execution Features Controller is available for incognito
// profiles and the visibility of settings is correct.
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
SettingsVisibilityUpdatedCorrectly) {
EnableSignIn();
// Visibility of wallpaper search is enabled on ToT.
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kWallpaperSearch));
// Visibility of tab organizer is enabled via finch.
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kTabOrganization));
// Visibility of compose is enabled via finch.
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kCompose));
auto* prefs = browser()->profile()->GetPrefs();
prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
// Restarting the browser should cause wallpaper setting to be visible since
// the feature is enabled.
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kTabOrganization));
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kCompose));
prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kDisabled));
// Restarting the browser should cause wallpaper setting to still be visible
// since the feature is still enabled.
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kTabOrganization));
EXPECT_TRUE(IsSettingVisible(UserVisibleFeatureKey::kCompose));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
SettingsOptInRevokedAfterSignOut) {
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
EnableSignIn();
TestSettingsEnabledObserver wallpaper_search_observer(
UserVisibleFeatureKey::kWallpaperSearch);
TestSettingsEnabledObserver compose_observer(UserVisibleFeatureKey::kCompose);
ogks->AddModelExecutionSettingsEnabledObserver(&wallpaper_search_observer);
ogks->AddModelExecutionSettingsEnabledObserver(&compose_observer);
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kTabOrganization));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kCompose));
auto* prefs = browser()->profile()->GetPrefs();
prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
EXPECT_EQ(1, wallpaper_search_observer.count_feature_enabled_state_changes_);
EXPECT_TRUE(wallpaper_search_observer.is_currently_enabled_);
EXPECT_EQ(0, compose_observer.count_feature_enabled_state_changes_);
EXPECT_TRUE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kTabOrganization));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kCompose));
#if !BUILDFLAG(IS_CHROMEOS)
// SignOut not supported on ChromeOS.
SignOut();
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kTabOrganization));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kCompose));
EXPECT_EQ(2, wallpaper_search_observer.count_feature_enabled_state_changes_);
EXPECT_FALSE(wallpaper_search_observer.is_currently_enabled_);
#endif
}
// Verifies that Model Execution Features Controller is available for incognito
// profiles and the setting opt-in toggle and pref is updated correctly.
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
SettingsOptInUpdatedCorrectly) {
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
EnableSignIn();
TestSettingsEnabledObserver wallpaper_search_observer(
UserVisibleFeatureKey::kWallpaperSearch);
TestSettingsEnabledObserver compose_observer(UserVisibleFeatureKey::kCompose);
ogks->AddModelExecutionSettingsEnabledObserver(&wallpaper_search_observer);
ogks->AddModelExecutionSettingsEnabledObserver(&compose_observer);
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kTabOrganization));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kCompose));
auto* prefs = browser()->profile()->GetPrefs();
prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
EXPECT_EQ(1, wallpaper_search_observer.count_feature_enabled_state_changes_);
EXPECT_TRUE(wallpaper_search_observer.is_currently_enabled_);
EXPECT_EQ(0, compose_observer.count_feature_enabled_state_changes_);
EXPECT_TRUE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kTabOrganization));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kCompose));
prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kDisabled));
EXPECT_EQ(2, wallpaper_search_observer.count_feature_enabled_state_changes_);
EXPECT_FALSE(wallpaper_search_observer.is_currently_enabled_);
EXPECT_EQ(0, compose_observer.count_feature_enabled_state_changes_);
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kTabOrganization));
EXPECT_FALSE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kCompose));
}
// Verifies that Model Execution Features Controller returns null for incognito
// profiles.
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
SettingsVisibilityIncognito) {
EnableSignIn();
// Set up incognito browser and incognito OptimizationGuideKeyedService
// consumer.
Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
EXPECT_TRUE(otr_browser);
// Instantiate off the record Optimization Guide Service.
OptimizationGuideKeyedService* otr_ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile()->GetPrimaryOTRProfile(
/*create_if_needed=*/true));
auto* prefs = browser()->profile()->GetPrefs();
prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
EXPECT_FALSE(otr_ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
}
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServiceStartupLogDisabledBrowserTest,
PerformanceClassOnlyComputedOnce) {
constexpr auto kKey = optimization_guide::ModelBasedCapabilityKey::kCompose;
auto* service =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
base::RunLoop loop1;
base::RunLoop loop2;
base::RunLoop loop3;
// Call multiple times, should only get performance class once.
service->GetOnDeviceModelEligibilityAsync(
kKey,
/*capabilities=*/{},
base::IgnoreArgs<optimization_guide::OnDeviceModelEligibilityReason>(
loop1.QuitClosure()));
service->GetOnDeviceModelEligibilityAsync(
kKey,
/*capabilities=*/{},
base::IgnoreArgs<optimization_guide::OnDeviceModelEligibilityReason>(
loop2.QuitClosure()));
service->GetOnDeviceModelEligibilityAsync(
kKey,
/*capabilities=*/{},
base::IgnoreArgs<optimization_guide::OnDeviceModelEligibilityReason>(
loop3.QuitClosure()));
loop1.Run();
histogram_tester()->ExpectTotalCount(
"OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", 1);
loop2.Run();
loop3.Run();
histogram_tester()->ExpectTotalCount(
"OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", 1);
// Call again after waiting, should not get performance class again..
base::RunLoop loop4;
service->GetOnDeviceModelEligibilityAsync(
kKey,
/*capabilities=*/{},
base::IgnoreArgs<optimization_guide::OnDeviceModelEligibilityReason>(
loop4.QuitClosure()));
loop4.Run();
histogram_tester()->ExpectTotalCount(
"OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", 1);
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
LogOnDeviceMetricsAfterStart) {
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
OnDeviceModelComponentStateManager* on_device_component_state_manager =
OnDeviceModelComponentStateManager::GetInstanceForTesting();
ASSERT_TRUE(on_device_component_state_manager);
EXPECT_TRUE(base::test::RunUntil([&]() {
return histogram_tester()
->GetAllSamples(
"OptimizationGuide.ModelExecution."
"OnDeviceModelPerformanceClass")
.size() > 0;
}));
histogram_tester()->ExpectTotalCount(
"OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", 1);
}
// Creating multiple profiles isn't supported easily on ChromeOS and android.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
LogOnDeviceMetricsSingleTimeForMultipleProfiles) {
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
OnDeviceModelComponentStateManager* on_device_component_state_manager =
OnDeviceModelComponentStateManager::GetInstanceForTesting();
ASSERT_TRUE(on_device_component_state_manager);
// Add a second profile which should not log performance class.
ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath path = profile_manager->GenerateNextProfileDirectoryPath();
ProfileWaiter profile_waiter;
profile_manager->CreateProfileAsync(path, {});
profile_waiter.WaitForProfileAdded();
EXPECT_TRUE(base::test::RunUntil([&]() {
return histogram_tester()
->GetAllSamples(
"OptimizationGuide.ModelExecution."
"OnDeviceModelPerformanceClass")
.size() > 0;
}));
// Make sure all tasks have finished running.
content::RunAllTasksUntilIdle();
histogram_tester()->ExpectTotalCount(
"OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", 1);
}
#endif
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
// CreateGuestBrowser() is not supported for Android or ChromeOS out of the box.
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
GuestProfileUniqueKeyedService) {
Browser* guest_browser = CreateGuestBrowser();
OptimizationGuideKeyedService* guest_ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(
guest_browser->profile());
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
EXPECT_TRUE(guest_ogks);
EXPECT_TRUE(ogks);
EXPECT_NE(guest_ogks, ogks);
auto* prefs = browser()->profile()->GetPrefs();
auto* guest_prefs = guest_browser->profile()->GetPrefs();
EnableSignIn();
prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
guest_prefs->SetInteger(
prefs::GetSettingEnabledPrefName(UserVisibleFeatureKey::kWallpaperSearch),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
EXPECT_TRUE(ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_FALSE(guest_ogks->ShouldFeatureBeCurrentlyEnabledForUser(
UserVisibleFeatureKey::kWallpaperSearch));
}
#endif
// Test the visibility of features with `kOptimizationGuideModelExecution`
// enabled or disabled.
class OptimizationGuideKeyedServiceBrowserWithModelExecutionFeatureDisabledTest
: public ::testing::WithParamInterface<bool>,
public OptimizationGuideKeyedServiceBrowserTest {
public:
OptimizationGuideKeyedServiceBrowserWithModelExecutionFeatureDisabledTest()
: OptimizationGuideKeyedServiceBrowserTest() {
// Enable visibility of tab organization feature.
scoped_feature_list_.Reset();
if (ShouldFeatureBeEnabled()) {
scoped_feature_list_.InitWithFeatures(
{features::kOptimizationHints,
// Enabled.
features::kOptimizationGuideModelExecution,
features::internal::kTabOrganizationSettingsVisibility},
{features::internal::kTabOrganizationGraduated});
} else {
scoped_feature_list_.InitWithFeatures(
{features::kOptimizationHints,
features::internal::kTabOrganizationSettingsVisibility},
// Disabled.
{features::kOptimizationGuideModelExecution,
features::internal::kTabOrganizationGraduated});
}
}
bool ShouldFeatureBeEnabled() const { return GetParam(); }
};
INSTANTIATE_TEST_SUITE_P(
All,
OptimizationGuideKeyedServiceBrowserWithModelExecutionFeatureDisabledTest,
::testing::Bool());
IN_PROC_BROWSER_TEST_P(
OptimizationGuideKeyedServiceBrowserWithModelExecutionFeatureDisabledTest,
SettingsNotVisible) {
EnableSignIn();
EXPECT_EQ(ShouldFeatureBeEnabled(),
IsSettingVisible(UserVisibleFeatureKey::kWallpaperSearch));
EXPECT_EQ(ShouldFeatureBeEnabled(),
IsSettingVisible(UserVisibleFeatureKey::kTabOrganization));
}
class OptimizationGuideKeyedServicePermissionsCheckDisabledTest
: public OptimizationGuideKeyedServiceBrowserTest {
public:
OptimizationGuideKeyedServicePermissionsCheckDisabledTest() = default;
~OptimizationGuideKeyedServicePermissionsCheckDisabledTest() override =
default;
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(
features::kRemoteOptimizationGuideFetching);
OptimizationGuideKeyedServiceBrowserTest::SetUp();
}
void TearDown() override {
OptimizationGuideKeyedServiceBrowserTest::TearDown();
scoped_feature_list_.Reset();
}
void SetUpCommandLine(base::CommandLine* cmd) override {
OptimizationGuideKeyedServiceBrowserTest::SetUpCommandLine(cmd);
cmd->AppendSwitch(switches::kDisableCheckingUserPermissionsForTesting);
// Add switch to avoid racing navigations in the test.
cmd->AppendSwitch(
switches::kDisableFetchingHintsAtNavigationStartForTesting);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServicePermissionsCheckDisabledTest,
RemoteFetchingAllowed) {
// ChromeOS has multiple profiles and optimization guide currently does not
// run on non-Android.
#if !BUILDFLAG(IS_CHROMEOS)
histogram_tester()->ExpectUniqueSample(
"OptimizationGuide.RemoteFetchingEnabled", true, 1);
EXPECT_TRUE(variations::IsInSyntheticTrialGroup(
"SyntheticOptimizationGuideRemoteFetching", "Enabled"));
#endif
}
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServicePermissionsCheckDisabledTest,
IncognitoCanStillReadFromComponentHints) {
// Wait until initialization logic finishes running and component pushed to
// both incognito and regular browsers.
PushHintsComponentAndWaitForCompletion();
// Set up incognito browser and incognito OptimizationGuideKeyedService
// consumer.
Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
// Instantiate off the record Optimization Guide Service.
OptimizationGuideKeyedService* otr_ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile()->GetPrimaryOTRProfile(
/*create_if_needed=*/true));
otr_ogks->RegisterOptimizationTypes({proto::NOSCRIPT});
// Navigate to a URL that has a hint from a component and wait for that hint
// to have loaded.
base::HistogramTester histogram_tester;
ASSERT_TRUE(ui_test_utils::NavigateToURL(otr_browser, url_with_hints()));
RetryForHistogramUntilCountReached(&histogram_tester,
"OptimizationGuide.LoadedHint.Result", 1);
EXPECT_EQ(OptimizationGuideDecision::kTrue,
otr_ogks->CanApplyOptimization(url_with_hints(), proto::NOSCRIPT,
nullptr));
}
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServicePermissionsCheckDisabledTest,
IncognitoStillProcessesBloomFilter) {
PushHintsComponentAndWaitForCompletion();
CreateIncognitoBrowser(browser()->profile());
// Instantiate off the record Optimization Guide Service.
OptimizationGuideKeyedService* otr_ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile()->GetPrimaryOTRProfile(
/*create_if_needed=*/true));
base::HistogramTester histogram_tester;
// Register an optimization type with an optimization filter.
otr_ogks->RegisterOptimizationTypes({proto::FAST_HOST_HINTS});
// Wait until filter is loaded. This histogram will record twice: once when
// the config is found and once when the filter is created.
RetryForHistogramUntilCountReached(
&histogram_tester,
"OptimizationGuide.OptimizationFilterStatus.FastHostHints", 2);
EXPECT_EQ(
OptimizationGuideDecision::kFalse,
otr_ogks->CanApplyOptimization(GURL("https://blockedhost.com/whatever"),
proto::FAST_HOST_HINTS, nullptr));
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.FastHostHints",
static_cast<int>(
OptimizationTypeDecision::kNotAllowedByOptimizationFilter),
1);
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CheckUploadWithMetricsConsent) {
// Enable metrics consent.
SetMetricsConsent(true);
ASSERT_TRUE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
// Attempt to upload a new quality log.
ModelQualityLogEntry::Upload(GetModelQualityLogEntryForCompose());
// Upload shouldn't be blocked by metrics consent.
histogram_tester()->ExpectBucketCount(
"OptimizationGuide.ModelQualityLogsUploaderService.UploadStatus.Compose",
ModelQualityLogsUploadStatus::kMetricsReportingDisabled, 0);
// Disable metrics consent.
SetMetricsConsent(false);
ASSERT_FALSE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
// Attempt to upload a new quality log.
ModelQualityLogEntry::Upload(GetModelQualityLogEntryForCompose());
// Upload should be disabled as there is no metrics consent, so total
// histogram bucket count will be 1.
histogram_tester()->ExpectBucketCount(
"OptimizationGuide.ModelQualityLogsUploaderService.UploadStatus.Compose",
ModelQualityLogsUploadStatus::kMetricsReportingDisabled, 1);
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CheckUploadWithoutMetricsConsent) {
auto* profile = browser()->profile();
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
// Disable metrics consent.
SetMetricsConsent(false);
ASSERT_FALSE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_FALSE(
ogks->GetModelQualityLogsUploaderService()->CanUploadLogs(metadata));
// Upload should be disabled as there is no metrics consent, so total
// histogram bucket count will be 1.
histogram_tester()->ExpectBucketCount(
"OptimizationGuide.ModelQualityLogsUploaderService.UploadStatus.Compose",
ModelQualityLogsUploadStatus::kMetricsReportingDisabled, 1);
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CheckUploadOnDestructionWithoutMetricsConsent) {
// Disable metrics consent.
SetMetricsConsent(false);
ASSERT_FALSE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
// Intercept network requests.
network::TestURLLoaderFactory url_loader_factory;
service()
->GetModelQualityLogsUploaderService()
->SetUrlLoaderFactoryForTesting(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&url_loader_factory));
// Create a new ModelQualityLogEntry for compose.
std::unique_ptr<ModelQualityLogEntry> log_entry =
GetModelQualityLogEntryForCompose();
// Destruct the log entry, this should trigger uploading the logs.
log_entry.reset();
// Upload should be stopped on destruction as there is no metrics consent.
base::RunLoop().RunUntilIdle();
content::RunAllTasksUntilIdle();
EXPECT_EQ(0, url_loader_factory.NumPending());
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CheckUploadWithEnterprisePolicy) {
// Enable metrics consent and sign in.
SetMetricsConsent(true);
EnableSignIn();
auto* profile = browser()->profile();
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
auto compose_feature = UserVisibleFeatureKey::kCompose;
auto* prefs = profile->GetPrefs();
prefs->SetInteger(prefs::GetSettingEnabledPrefName(compose_feature),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
base::RunLoop().RunUntilIdle();
policy::PolicyMap policies;
// Disable logging via the enterprise policy to state kAllowWithoutLogging.
policies.Set(policy::key::kHelpMeWriteSettings,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(
model_execution::prefs::ModelExecutionEnterprisePolicyValue::
kAllowWithoutLogging)),
nullptr);
policy_provider_.UpdateChromePolicy(policies);
base::RunLoop().RunUntilIdle();
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_FALSE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
// Attempt to upload a new quality log.
ModelQualityLogEntry::Upload(GetModelQualityLogEntryForCompose());
// Disable logging via via the enterprise policy to kDisable state.
policies.Set(policy::key::kHelpMeWriteSettings,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(
model_execution::prefs::ModelExecutionEnterprisePolicyValue::
kDisable)),
nullptr);
policy_provider_.UpdateChromePolicy(policies);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
// Attempt to upload a new quality log.
ModelQualityLogEntry::Upload(GetModelQualityLogEntryForCompose());
// Enable logging via via the enterprise policy to state kAllow this shouldn't
// stop upload.
policies.Set(
policy::key::kHelpMeWriteSettings, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(
model_execution::prefs::ModelExecutionEnterprisePolicyValue::kAllow)),
nullptr);
policy_provider_.UpdateChromePolicy(policies);
prefs->SetInteger(prefs::GetSettingEnabledPrefName(compose_feature),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
EXPECT_TRUE(
ogks->GetModelQualityLogsUploaderService()->CanUploadLogs(metadata));
// Attempt to upload a new quality log.
ModelQualityLogEntry::Upload(GetModelQualityLogEntryForCompose());
// Log uploads should have been recorded as disabled twice because of
// enterprise policy.
EXPECT_THAT(
histogram_tester()->GetAllSamples(
"OptimizationGuide.ModelQualityLogsUploaderService.UploadStatus."
"Compose"),
ElementsAre(base::Bucket(
ModelQualityLogsUploadStatus::kDisabledDueToEnterprisePolicy, 2)));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CheckCanUploadLogsWithEnterprisePolicy) {
// Enable metrics consent and sign in.
SetMetricsConsent(true);
EnableSignIn();
auto* profile = browser()->profile();
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
auto compose_feature = UserVisibleFeatureKey::kCompose;
auto* prefs = profile->GetPrefs();
prefs->SetInteger(prefs::GetSettingEnabledPrefName(compose_feature),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
base::RunLoop().RunUntilIdle();
policy::PolicyMap policies;
// Disable logging via via the enterprise policy to state
// kAllowWithoutLogging this should return
// ChromeModelQualityLogsUploaderService::CanUploadLogs to false.
policies.Set(policy::key::kHelpMeWriteSettings,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(
model_execution::prefs::ModelExecutionEnterprisePolicyValue::
kAllowWithoutLogging)),
nullptr);
policy_provider_.UpdateChromePolicy(policies);
base::RunLoop().RunUntilIdle();
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_FALSE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
EXPECT_FALSE(
ogks->GetModelQualityLogsUploaderService()->CanUploadLogs(metadata));
// Disable logging via the enterprise policy to kDisable state this should
// return ChromeModelQualityLogsUploaderService::CanUploadLogs to false.
policies.Set(policy::key::kHelpMeWriteSettings,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(
model_execution::prefs::ModelExecutionEnterprisePolicyValue::
kDisable)),
nullptr);
policy_provider_.UpdateChromePolicy(policies);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
EXPECT_FALSE(
ogks->GetModelQualityLogsUploaderService()->CanUploadLogs(metadata));
// Enable logging via the enterprise policy to state kAllow this shouldn't
// stop upload and should return
// ChromeModelQualityLogsUploaderService::CanUploadLogs to true.
policies.Set(
policy::key::kHelpMeWriteSettings, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(
model_execution::prefs::ModelExecutionEnterprisePolicyValue::kAllow)),
nullptr);
policy_provider_.UpdateChromePolicy(policies);
prefs->SetInteger(prefs::GetSettingEnabledPrefName(compose_feature),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
EXPECT_TRUE(
ogks->GetModelQualityLogsUploaderService()->CanUploadLogs(metadata));
// Log uploads should have been recorded as disabled twice because of
// enterprise policy.
EXPECT_THAT(
histogram_tester()->GetAllSamples(
"OptimizationGuide.ModelQualityLogsUploaderService.UploadStatus."
"Compose"),
ElementsAre(base::Bucket(
ModelQualityLogsUploadStatus::kDisabledDueToEnterprisePolicy, 2)));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
LoggingDisabledByEnterprisePolicy_NonDogfood_NoSwitch) {
auto compose_feature = UserVisibleFeatureKey::kCompose;
EnableFeature(compose_feature);
SetEnterprisePolicy(
policy::key::kHelpMeWriteSettings,
ModelExecutionEnterprisePolicyValue::kAllowWithoutLogging);
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_FALSE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
}
IN_PROC_BROWSER_TEST_F(
OptimizationGuideKeyedServiceBrowserTest,
LoggingDisabledByEnterprisePolicy_NonDogfood_WithSwitch) {
auto compose_feature = UserVisibleFeatureKey::kCompose;
EnableFeature(compose_feature);
SetEnterprisePolicy(
policy::key::kHelpMeWriteSettings,
ModelExecutionEnterprisePolicyValue::kAllowWithoutLogging);
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableModelQualityDogfoodLogging);
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_FALSE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
}
IN_PROC_BROWSER_TEST_F(DogfoodOptimizationGuideKeyedServiceBrowserTest,
LoggingDisabledByEnterprisePolicy_Dogfood_NoSwitch) {
auto compose_feature = UserVisibleFeatureKey::kCompose;
EnableFeature(compose_feature);
SetEnterprisePolicy(
policy::key::kHelpMeWriteSettings,
ModelExecutionEnterprisePolicyValue::kAllowWithoutLogging);
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_FALSE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
}
IN_PROC_BROWSER_TEST_F(DogfoodOptimizationGuideKeyedServiceBrowserTest,
LoggingDisabledByEnterprisePolicy_Dogfood_WithSwitch) {
auto compose_feature = UserVisibleFeatureKey::kCompose;
EnableFeature(compose_feature);
SetEnterprisePolicy(
policy::key::kHelpMeWriteSettings,
ModelExecutionEnterprisePolicyValue::kAllowWithoutLogging);
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableModelQualityDogfoodLogging);
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_TRUE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
FeedbackIsEnabledWhenLoggingIsEnabled) {
auto compose_feature = UserVisibleFeatureKey::kCompose;
EnableFeature(compose_feature);
SetEnterprisePolicy(policy::key::kHelpMeWriteSettings,
ModelExecutionEnterprisePolicyValue::kAllow);
EXPECT_TRUE(service()->ShouldFeatureBeCurrentlyAllowedForFeedback(
proto::LogAiDataRequest::FeatureCase::kCompose));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
FeedbackIsDisabledWhenLoggingIsDisabled_NotDogfood) {
auto compose_feature = UserVisibleFeatureKey::kCompose;
EnableFeature(compose_feature);
SetEnterprisePolicy(
policy::key::kHelpMeWriteSettings,
ModelExecutionEnterprisePolicyValue::kAllowWithoutLogging);
SetIsDogfoodClient(false);
EXPECT_FALSE(service()->ShouldFeatureBeCurrentlyAllowedForFeedback(
proto::LogAiDataRequest::FeatureCase::kCompose));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
FeedbackIsEnabledWhenLoggingIsDisabled_Dogfood) {
auto compose_feature = UserVisibleFeatureKey::kCompose;
EnableFeature(compose_feature);
SetEnterprisePolicy(
policy::key::kHelpMeWriteSettings,
ModelExecutionEnterprisePolicyValue::kAllowWithoutLogging);
SetIsDogfoodClient(true);
EXPECT_TRUE(service()->ShouldFeatureBeCurrentlyAllowedForFeedback(
proto::LogAiDataRequest::FeatureCase::kCompose));
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideKeyedServiceBrowserTest,
CheckModelQualityLogsUploadOnDestruction) {
// Enable metrics consent and sign in.
SetMetricsConsent(true);
EnableSignIn();
auto* profile = browser()->profile();
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
auto compose_feature = UserVisibleFeatureKey::kCompose;
auto* prefs = profile->GetPrefs();
policy::PolicyMap policies;
// Enable logging via via the enterprise policy to state kAllow this shouldn't
// stop upload and should return
// ChromeModelQualityLogsUploaderService::CanUploadLogs to true.
policies.Set(
policy::key::kHelpMeWriteSettings, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(static_cast<int>(
model_execution::prefs::ModelExecutionEnterprisePolicyValue::kAllow)),
nullptr);
policy_provider_.UpdateChromePolicy(policies);
prefs->SetInteger(prefs::GetSettingEnabledPrefName(compose_feature),
static_cast<int>(prefs::FeatureOptInState::kEnabled));
base::RunLoop().RunUntilIdle();
const MqlsFeatureMetadata* metadata =
MqlsFeatureRegistry::GetInstance().GetFeature(
proto::LogAiDataRequest::FeatureCase::kCompose);
EXPECT_TRUE(model_execution_features_controller()
->ShouldFeatureBeCurrentlyAllowedForLogging(metadata));
EXPECT_TRUE(
ogks->GetModelQualityLogsUploaderService()->CanUploadLogs(metadata));
// Intercept network requests.
network::TestURLLoaderFactory url_loader_factory;
service()
->GetModelQualityLogsUploaderService()
->SetUrlLoaderFactoryForTesting(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&url_loader_factory));
// Create a new ModelQualityLogEntry for compose.
std::unique_ptr<ModelQualityLogEntry> log_entry =
GetModelQualityLogEntryForCompose();
// Destruct the log entry, this should upload the logs.
log_entry.reset();
// Logs should be uploaded on destruction.
base::RunLoop().RunUntilIdle();
content::RunAllTasksUntilIdle();
EXPECT_EQ(1, url_loader_factory.NumPending());
}
} // namespace optimization_guide