blob: a79167f7dc025eb43a325dace5ca245aa3a0593d [file] [log] [blame]
// Copyright 2021 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/privacy_sandbox/privacy_sandbox_service_impl.h"
#include <tuple>
#include "base/containers/to_vector.h"
#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/test/icu_test_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/first_party_sets/first_party_sets_policy_service.h"
#include "chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h"
#include "chrome/browser/policy/policy_test_utils.h"
#include "chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h"
#include "chrome/browser/privacy_sandbox/notice/mocks/mock_notice_service.h"
#include "chrome/browser/privacy_sandbox/notice/notice.mojom.h"
#include "chrome/browser/privacy_sandbox/notice/notice_model.h"
#include "chrome/browser/privacy_sandbox/notice/notice_service_factory.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_countries.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h"
#include "chrome/browser/privacy_sandbox/profile_bucket_metrics.h"
#include "chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/fake_profile_manager.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/browsing_topics/test_util.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/content_settings/core/test/content_settings_mock_provider.h"
#include "components/content_settings/core/test/content_settings_test_utils.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/policy/core/common/mock_policy_service.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/mock_privacy_sandbox_settings.h"
#include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations.h"
#include "components/privacy_sandbox/privacy_sandbox_attestations/scoped_privacy_sandbox_attestations.h"
#include "components/privacy_sandbox/privacy_sandbox_features.h"
#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
#include "components/privacy_sandbox/privacy_sandbox_settings_impl.h"
#include "components/privacy_sandbox/privacy_sandbox_test_util.h"
#include "components/privacy_sandbox/tracking_protection_settings.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/base/user_selectable_type.h"
#include "components/sync/test/test_sync_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/first_party_sets_handler.h"
#include "content/public/browser/interest_group_manager.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_task_environment.h"
#include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_entry_override.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
#include "net/first_party_sets/global_first_party_sets.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "url/origin.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/hats/mock_trust_safety_sentiment_service.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chromeos/ash/components/login/login_state/login_state.h"
#include "chromeos/ash/components/login/login_state/scoped_test_public_session_login_state.h"
#include "chromeos/components/kiosk/kiosk_test_utils.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#endif
namespace {
using ::browsing_topics::Topic;
using ::privacy_sandbox::CanonicalTopic;
using PromptAction = ::PrivacySandboxService::PromptAction;
using PromptSuppressedReason = ::PrivacySandboxService::PromptSuppressedReason;
using PromptType = ::PrivacySandboxService::PromptType;
using PromptTypeCombination = ::PrivacySandboxService::PromptTypeCombination;
using EligibilityLevel = ::privacy_sandbox::EligibilityLevel;
using SurfaceType = ::PrivacySandboxService::SurfaceType;
using NoticeSurfaceType = ::privacy_sandbox::SurfaceType;
using ::testing::Combine;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::NiceMock;
using ::testing::Pair;
using ::testing::ValuesIn;
using Notice = privacy_sandbox::notice::mojom::PrivacySandboxNotice;
using NoticeEvent = privacy_sandbox::notice::mojom::PrivacySandboxNoticeEvent;
using enum privacy_sandbox_test_util::StateKey;
using enum privacy_sandbox_test_util::InputKey;
using enum privacy_sandbox_test_util::OutputKey;
using enum PrivacySandboxService::PromptAction;
using privacy_sandbox_test_util::InputKey;
using privacy_sandbox_test_util::OutputKey;
using privacy_sandbox_test_util::StateKey;
using privacy_sandbox::notice::mojom::PrivacySandboxNoticeEvent;
using privacy_sandbox_test_util::MultipleInputKeys;
using privacy_sandbox_test_util::MultipleOutputKeys;
using privacy_sandbox_test_util::MultipleStateKeys;
using privacy_sandbox_test_util::SiteDataExceptions;
using privacy_sandbox_test_util::TestCase;
using privacy_sandbox_test_util::TestInput;
using privacy_sandbox_test_util::TestOutput;
using privacy_sandbox_test_util::TestState;
const char kFirstPartySetsStateHistogram[] = "Settings.FirstPartySets.State";
const char kDefaultProfileUsername[] = "user@gmail.com";
const char kTestEmail[] = "test@test.com";
const base::Version kRelatedWebsiteSetsVersion("1.2.3");
constexpr int kTestTaxonomyVersion = 1;
class TestPrivacySandboxService
: public privacy_sandbox_test_util::PrivacySandboxServiceTestInterface {
public:
explicit TestPrivacySandboxService(PrivacySandboxService* service)
: service_(service) {}
// PrivacySandboxServiceTestInterface
void TopicsToggleChanged(bool new_value) const override {
service_->TopicsToggleChanged(new_value);
}
void SetTopicAllowed(privacy_sandbox::CanonicalTopic topic,
bool allowed) override {
service_->SetTopicAllowed(topic, allowed);
}
bool TopicsHasActiveConsent() const override {
return service_->TopicsHasActiveConsent();
}
privacy_sandbox::TopicsConsentUpdateSource TopicsConsentLastUpdateSource()
const override {
return service_->TopicsConsentLastUpdateSource();
}
base::Time TopicsConsentLastUpdateTime() const override {
return service_->TopicsConsentLastUpdateTime();
}
std::string TopicsConsentLastUpdateText() const override {
return service_->TopicsConsentLastUpdateText();
}
void ForceChromeBuildForTests(bool force_chrome_build) const override {
service_->ForceChromeBuildForTests(force_chrome_build);
}
int GetRequiredPromptType(int surface_type) const override {
return static_cast<int>(service_->GetRequiredPromptType(
static_cast<SurfaceType>(surface_type)));
}
void PromptActionOccurred(int action, int surface_type) const override {
service_->PromptActionOccurred(static_cast<PromptAction>(action),
static_cast<SurfaceType>(surface_type));
}
private:
raw_ptr<PrivacySandboxService> service_;
};
class TestInterestGroupManager : public content::InterestGroupManager {
public:
void SetInterestGroupDataKeys(
const std::vector<InterestGroupDataKey>& data_keys) {
data_keys_ = data_keys;
}
// content::InterestGroupManager:
void GetAllInterestGroupJoiningOrigins(
base::OnceCallback<void(std::vector<url::Origin>)> callback) override {
NOTREACHED();
}
void GetAllInterestGroupDataKeys(
base::OnceCallback<void(std::vector<InterestGroupDataKey>)> callback)
override {
std::move(callback).Run(data_keys_);
}
void RemoveInterestGroupsByDataKey(InterestGroupDataKey data_key,
base::OnceClosure callback) override {
NOTREACHED();
}
void AddTrustedServerKeysDebugOverride(
TrustedServerAPIType api,
const url::Origin& coordinator,
std::string serialized_keys,
base::OnceCallback<void(std::optional<std::string>)> callback) override {
NOTREACHED();
}
private:
std::vector<InterestGroupDataKey> data_keys_;
};
// Remove any user preference settings for Related Website Set related
// preferences, returning them to their default value.
void ClearRwsUserPrefs(
sync_preferences::TestingPrefServiceSyncable* pref_service) {
pref_service->RemoveUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled);
pref_service->RemoveUserPref(
prefs::kPrivacySandboxRelatedWebsiteSetsDataAccessAllowedInitialized);
}
std::vector<int> GetTopicsSettingsStringIdentifiers(bool did_consent,
bool has_current_topics,
bool has_blocked_topics) {
if (did_consent && !has_blocked_topics) {
return {IDS_SETTINGS_TOPICS_PAGE_TITLE,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_LABEL,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2,
IDS_SETTINGS_TOPICS_PAGE_ACTIVE_TOPICS_HEADING,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_DISABLED,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING_NEW,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_EMPTY_TEXT_V2,
IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL};
} else if (did_consent && has_blocked_topics) {
return {IDS_SETTINGS_TOPICS_PAGE_TITLE,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_LABEL,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2,
IDS_SETTINGS_TOPICS_PAGE_ACTIVE_TOPICS_HEADING,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_DISABLED,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING_NEW,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_NEW,
IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL};
} else if (!did_consent && has_current_topics && has_blocked_topics) {
return {IDS_SETTINGS_TOPICS_PAGE_TITLE,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_LABEL,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2,
IDS_SETTINGS_TOPICS_PAGE_ACTIVE_TOPICS_HEADING,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING_NEW,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_NEW,
IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL};
} else if (!did_consent && has_current_topics && !has_blocked_topics) {
return {IDS_SETTINGS_TOPICS_PAGE_TITLE,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_LABEL,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2,
IDS_SETTINGS_TOPICS_PAGE_ACTIVE_TOPICS_HEADING,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING_NEW,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_EMPTY_TEXT_V2,
IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL};
} else if (!did_consent && !has_current_topics && has_blocked_topics) {
return {IDS_SETTINGS_TOPICS_PAGE_TITLE,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_LABEL,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2,
IDS_SETTINGS_TOPICS_PAGE_ACTIVE_TOPICS_HEADING,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY_TEXT_V2,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING_NEW,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_NEW,
IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL};
} else if (!did_consent && !has_current_topics && !has_blocked_topics) {
return {IDS_SETTINGS_TOPICS_PAGE_TITLE,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_LABEL,
IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2,
IDS_SETTINGS_TOPICS_PAGE_ACTIVE_TOPICS_HEADING,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL,
IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY_TEXT_V2,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING_NEW,
IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_EMPTY_TEXT_V2,
IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL};
}
NOTREACHED() << "Invalid topics settings consent state";
}
std::vector<int> GetTopicsConfirmationStringIdentifiers() {
return {IDS_PRIVACY_SANDBOX_M1_CONSENT_TITLE,
IDS_PRIVACY_SANDBOX_M1_CONSENT_DESCRIPTION_1,
IDS_PRIVACY_SANDBOX_M1_CONSENT_DESCRIPTION_2,
IDS_PRIVACY_SANDBOX_M1_CONSENT_DESCRIPTION_3,
IDS_PRIVACY_SANDBOX_M1_CONSENT_DESCRIPTION_4,
IDS_PRIVACY_SANDBOX_M1_CONSENT_LEARN_MORE_EXPAND_LABEL,
IDS_PRIVACY_SANDBOX_M1_CONSENT_LEARN_MORE_BULLET_1,
IDS_PRIVACY_SANDBOX_M1_CONSENT_LEARN_MORE_BULLET_2,
IDS_PRIVACY_SANDBOX_M1_CONSENT_LEARN_MORE_BULLET_3,
IDS_PRIVACY_SANDBOX_M1_CONSENT_LEARN_MORE_LINK};
}
struct NoticeTestingParameters {
// Inputs
SurfaceType surface_type;
base::test::FeatureRefAndParams feature_flag;
PromptAction shown_type;
PromptAction prompt_action;
// Expected Output
// Represents the correct notice preference name that should be logged
std::string_view notice_name;
};
} // namespace
// A mock implementation of the PrivacySandboxCountries interface for testing.
class MockPrivacySandboxCountries : public PrivacySandboxCountries {
public:
MOCK_METHOD(bool, IsConsentCountry, (), (override));
MOCK_METHOD(bool, IsRestOfWorldCountry, (), (override));
MOCK_METHOD(bool, IsLatestCountryChina, (), (override));
};
class PrivacySandboxServiceTest : public testing::Test {
public:
static constexpr std::string_view kPromptMigrationHistogram =
"PrivacySandbox.Notice.Migration.PromptTypeCombination";
PrivacySandboxServiceTest()
: browser_task_environment_(
base::test::TaskEnvironment::TimeSource::MOCK_TIME),
scoped_attestations_(
privacy_sandbox::PrivacySandboxAttestations::CreateForTesting()) {
CreateDefaultProfile();
first_party_sets_policy_service_ =
std::make_unique<first_party_sets::FirstPartySetsPolicyService>(
profile()->GetOriginalProfile());
}
void SetUp() override {
InitializeFeaturesBeforeStart();
CreateService();
base::RunLoop run_loop;
first_party_sets_policy_service_->WaitForFirstInitCompleteForTesting(
run_loop.QuitClosure());
run_loop.Run();
first_party_sets_policy_service_->ResetForTesting();
}
void TearDown() override {
privacy_sandbox_service_->Shutdown();
privacy_sandbox_service_ = nullptr;
}
virtual void InitializeFeaturesBeforeStart() {}
void CreateDefaultProfile() {
default_profile_manager_ = std::make_unique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal());
ASSERT_TRUE(default_profile_manager_->SetUp());
default_profile_ = default_profile_manager_->CreateTestingProfile(
kDefaultProfileUsername, IdentityTestEnvironmentProfileAdaptor::
GetIdentityTestEnvironmentFactories());
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
default_profile_.get());
identity_test_env_adaptor_->identity_test_env()
->EnableRemovalOfExtendedAccountInfo();
}
void EnableSignIn() {
auto account_info = identity_test_env_adaptor_->identity_test_env()
->MakePrimaryAccountAvailable(
kTestEmail, signin::ConsentLevel::kSignin);
AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
signin::UpdateAccountInfoForAccount(
identity_test_env_adaptor_->identity_test_env()->identity_manager(),
account_info);
mutator.set_can_use_model_execution_features(true);
identity_test_env_adaptor_->identity_test_env()
->UpdateAccountInfoForAccount(account_info);
}
void EnableSignInU18() {
auto account_info = identity_test_env_adaptor_->identity_test_env()
->MakePrimaryAccountAvailable(
kTestEmail, signin::ConsentLevel::kSignin);
AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
mutator.set_can_run_chrome_privacy_sandbox_trials(false);
signin::UpdateAccountInfoForAccount(
identity_test_env_adaptor_->identity_test_env()->identity_manager(),
account_info);
mutator.set_can_use_model_execution_features(true);
identity_test_env_adaptor_->identity_test_env()
->UpdateAccountInfoForAccount(account_info);
}
void EnableSignInOver18() {
auto account_info = identity_test_env_adaptor_->identity_test_env()
->MakePrimaryAccountAvailable(
kTestEmail, signin::ConsentLevel::kSignin);
AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
mutator.set_can_run_chrome_privacy_sandbox_trials(true);
signin::UpdateAccountInfoForAccount(
identity_test_env_adaptor_->identity_test_env()->identity_manager(),
account_info);
mutator.set_can_use_model_execution_features(true);
identity_test_env_adaptor_->identity_test_env()
->UpdateAccountInfoForAccount(account_info);
}
// ChromeOS users cannot sign out, their account preferences can never be
// cleared.
#if !BUILDFLAG(IS_CHROMEOS)
void SignOut() {
identity_test_env_adaptor_->identity_test_env()->ClearPrimaryAccount();
}
#endif // !BUILDFLAG(IS_CHROMEOS)
virtual std::unique_ptr<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
CreateMockDelegate() {
auto mock_delegate = std::make_unique<testing::NiceMock<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>>();
mock_delegate->SetUpIsPrivacySandboxRestrictedResponse(
/*restricted=*/false);
return mock_delegate;
}
signin::IdentityTestEnvironment* identity_test_env() {
return identity_test_env_adaptor_->identity_test_env();
}
void CreateService() {
// `CreateService` is sometimes called twice, or more in a tests.
// Previous instances must be destroyed in the opposite order of their
// construction.
if (privacy_sandbox_service_) {
privacy_sandbox_service_->Shutdown();
privacy_sandbox_service_ = nullptr;
}
auto mock_delegate = CreateMockDelegate();
mock_delegate_ = mock_delegate.get();
mock_privacy_sandbox_countries_ =
std::make_unique<MockPrivacySandboxCountries>();
privacy_sandbox_settings_ =
std::make_unique<privacy_sandbox::PrivacySandboxSettingsImpl>(
std::move(mock_delegate), host_content_settings_map(),
cookie_settings(), tracking_protection_settings(), prefs());
privacy_sandbox_service_ =
PrivacySandboxServiceFactory::GetInstance()
->SetTestingSubclassFactoryAndUse(
profile(),
base::BindOnce(&PrivacySandboxServiceTest::BuildTestService,
base::Unretained(this)));
}
virtual profile_metrics::BrowserProfileType GetProfileType() {
return profile_type_;
}
void SetProfileType(profile_metrics::BrowserProfileType profile_type) {
profile_type_ = profile_type;
}
void RunTestCase(const TestState& test_state,
const TestInput& test_input,
const TestOutput& test_output) {
auto user_provider = std::make_unique<content_settings::MockProvider>();
auto* user_provider_raw = user_provider.get();
auto managed_provider = std::make_unique<content_settings::MockProvider>();
auto* managed_provider_raw = managed_provider.get();
content_settings::TestUtils::OverrideProvider(
host_content_settings_map(), std::move(user_provider),
content_settings::ProviderType::kPrefProvider);
content_settings::TestUtils::OverrideProvider(
host_content_settings_map(), std::move(managed_provider),
content_settings::ProviderType::kPolicyProvider);
auto service_wrapper = TestPrivacySandboxService(privacy_sandbox_service());
privacy_sandbox_test_util::RunTestCase(
browser_task_environment(), prefs(), host_content_settings_map(),
mock_delegate(), mock_browsing_topics_service(),
privacy_sandbox_settings(), &service_wrapper, user_provider_raw,
managed_provider_raw, TestCase(test_state, test_input, test_output));
}
PrefService* local_state() {
return TestingBrowserProcess::GetGlobal()->local_state();
}
TestingProfile* profile() { return default_profile_; }
PrivacySandboxServiceImpl* privacy_sandbox_service() {
return privacy_sandbox_service_.get();
}
privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings() {
return privacy_sandbox_settings_.get();
}
base::test::ScopedFeatureList* feature_list() { return &inner_feature_list_; }
sync_preferences::TestingPrefServiceSyncable* prefs() {
return profile()->GetTestingPrefService();
}
HostContentSettingsMap* host_content_settings_map() {
return HostContentSettingsMapFactory::GetForProfile(profile());
}
content_settings::CookieSettings* cookie_settings() {
return CookieSettingsFactory::GetForProfile(profile()).get();
}
privacy_sandbox::TrackingProtectionSettings* tracking_protection_settings() {
return TrackingProtectionSettingsFactory::GetForProfile(profile());
}
TestInterestGroupManager* test_interest_group_manager() {
return &test_interest_group_manager_;
}
content::BrowsingDataRemover* browsing_data_remover() {
return profile()->GetBrowsingDataRemover();
}
browsing_topics::MockBrowsingTopicsService* mock_browsing_topics_service() {
return &mock_browsing_topics_service_;
}
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate*
mock_delegate() {
return mock_delegate_;
}
first_party_sets::ScopedMockFirstPartySetsHandler&
mock_first_party_sets_handler() {
return mock_first_party_sets_handler_;
}
first_party_sets::FirstPartySetsPolicyService*
first_party_sets_policy_service() {
return first_party_sets_policy_service_.get();
}
MockPrivacySandboxCountries* mock_privacy_sandbox_countries() {
return mock_privacy_sandbox_countries_.get();
}
void MoveToEEA() {
ON_CALL(*mock_privacy_sandbox_countries(), IsConsentCountry())
.WillByDefault(testing::Return(true));
ON_CALL(*mock_privacy_sandbox_countries(), IsRestOfWorldCountry())
.WillByDefault(testing::Return(false));
}
void MoveToROW() {
ON_CALL(*mock_privacy_sandbox_countries(), IsConsentCountry())
.WillByDefault(testing::Return(false));
ON_CALL(*mock_privacy_sandbox_countries(), IsRestOfWorldCountry())
.WillByDefault(testing::Return(true));
}
base::HistogramTester* histogram_tester() { return &histogram_tester_; }
content::BrowserTaskEnvironment* browser_task_environment() {
return &browser_task_environment_;
}
protected:
base::HistogramTester histogram_tester_;
private:
std::unique_ptr<PrivacySandboxServiceImpl> BuildTestService(
content::BrowserContext* context) {
return std::make_unique<PrivacySandboxServiceImpl>(
profile(), privacy_sandbox_settings(), tracking_protection_settings(),
cookie_settings(), profile()->GetPrefs(), test_interest_group_manager(),
GetProfileType(), browsing_data_remover(), host_content_settings_map(),
mock_browsing_topics_service(), first_party_sets_policy_service(),
mock_privacy_sandbox_countries());
}
content::BrowserTaskEnvironment browser_task_environment_;
// In production, ProfileManager is created much earlier than Profile
// creation.
std::unique_ptr<TestingProfileManager> default_profile_manager_;
raw_ptr<TestingProfile> default_profile_;
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
profile_metrics::BrowserProfileType profile_type_ =
profile_metrics::BrowserProfileType::kRegular;
base::test::ScopedFeatureList outer_feature_list_;
base::test::ScopedFeatureList inner_feature_list_;
TestInterestGroupManager test_interest_group_manager_;
browsing_topics::MockBrowsingTopicsService mock_browsing_topics_service_;
first_party_sets::ScopedMockFirstPartySetsHandler
mock_first_party_sets_handler_;
std::unique_ptr<first_party_sets::FirstPartySetsPolicyService>
first_party_sets_policy_service_;
std::unique_ptr<MockPrivacySandboxCountries> mock_privacy_sandbox_countries_;
std::unique_ptr<privacy_sandbox::PrivacySandboxSettings>
privacy_sandbox_settings_;
raw_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
mock_delegate_; // Owned by |privacy_sandbox_settings_|.
privacy_sandbox::ScopedPrivacySandboxAttestations scoped_attestations_;
raw_ptr<PrivacySandboxServiceImpl> privacy_sandbox_service_ = nullptr;
};
// Params correspond to (IsFeatureOn, IsConsentCountry, ExpectedResult).
class PrivacySandboxPrivacyGuideShouldShowAdTopicsTest
: public PrivacySandboxServiceTest,
public testing::WithParamInterface<std::tuple<bool, bool, bool>> {};
TEST_P(PrivacySandboxPrivacyGuideShouldShowAdTopicsTest,
ShownAccordingToConsentCountryAndFeature) {
auto [is_feature_on, is_consent_country, result] = GetParam();
feature_list()->Reset();
if (is_feature_on) {
feature_list()->InitAndEnableFeature(
privacy_sandbox::kPrivacySandboxAdTopicsContentParity);
} else {
feature_list()->InitAndDisableFeature(
privacy_sandbox::kPrivacySandboxAdTopicsContentParity);
}
ON_CALL(*mock_privacy_sandbox_countries(), IsConsentCountry())
.WillByDefault(testing::Return(is_consent_country));
bool should_show_card =
privacy_sandbox_service()
->PrivacySandboxPrivacyGuideShouldShowAdTopicsCard();
ASSERT_EQ(should_show_card, result);
}
INSTANTIATE_TEST_SUITE_P(PrivacySandboxPrivacyGuideShouldShowAdTopicsTest,
PrivacySandboxPrivacyGuideShouldShowAdTopicsTest,
testing::Values(std::tuple(true, true, true),
std::tuple(true, false, false),
std::tuple(false, true, false),
std::tuple(false, false, false)));
class PrivacySandboxShouldUsePrivacyPolicyChinaDomain
: public PrivacySandboxServiceTest {};
TEST_F(PrivacySandboxShouldUsePrivacyPolicyChinaDomain, ShouldUseChinaDomain) {
ON_CALL(*mock_privacy_sandbox_countries(), IsLatestCountryChina())
.WillByDefault(testing::Return(true));
bool should_use_china_domain =
privacy_sandbox_service()->ShouldUsePrivacyPolicyChinaDomain();
ASSERT_EQ(should_use_china_domain, true);
}
TEST_F(PrivacySandboxShouldUsePrivacyPolicyChinaDomain,
ShouldNotUseChinaDomain) {
ON_CALL(*mock_privacy_sandbox_countries(), IsLatestCountryChina())
.WillByDefault(testing::Return(false));
bool should_use_china_domain =
privacy_sandbox_service()->ShouldUsePrivacyPolicyChinaDomain();
ASSERT_EQ(should_use_china_domain, false);
}
TEST_F(PrivacySandboxServiceTest, GetFledgeJoiningEtldPlusOne) {
// Confirm that the set of FLEDGE origins which were top-frame for FLEDGE join
// actions is correctly converted into a list of eTLD+1s.
using FledgeTestCase =
std::pair<std::vector<url::Origin>, std::vector<std::string>>;
// Items which map to the same eTLD+1 should be coalesced into a single entry.
FledgeTestCase test_case_1 = {
{url::Origin::Create(GURL("https://www.example.com")),
url::Origin::Create(GURL("https://example.com:8080")),
url::Origin::Create(GURL("http://www.example.com"))},
{"example.com"}};
// eTLD's should return the host instead, this is relevant for sites which
// are themselves on the PSL, e.g. github.io.
FledgeTestCase test_case_2 = {
{
url::Origin::Create(GURL("https://co.uk")),
url::Origin::Create(GURL("http://co.uk")),
url::Origin::Create(GURL("http://example.co.uk")),
},
{"co.uk", "example.co.uk"}};
// IP addresses should also return the host.
FledgeTestCase test_case_3 = {
{
url::Origin::Create(GURL("https://192.168.1.2")),
url::Origin::Create(GURL("https://192.168.1.2:8080")),
url::Origin::Create(GURL("https://192.168.1.3:8080")),
},
{"192.168.1.2", "192.168.1.3"}};
// Results should be alphabetically ordered.
FledgeTestCase test_case_4 = {{
url::Origin::Create(GURL("https://d.com")),
url::Origin::Create(GURL("https://b.com")),
url::Origin::Create(GURL("https://a.com")),
url::Origin::Create(GURL("https://c.com")),
},
{"a.com", "b.com", "c.com", "d.com"}};
std::vector<FledgeTestCase> test_cases = {test_case_1, test_case_2,
test_case_3, test_case_4};
for (const auto& [origins, expected] : test_cases) {
base::HistogramTester histogram_tester;
test_interest_group_manager()->SetInterestGroupDataKeys(
base::ToVector(origins, [](const auto& origin) {
return content::InterestGroupManager::InterestGroupDataKey{
url::Origin::Create(GURL("https://embedded.com")), origin};
}));
bool callback_called = false;
auto callback = base::BindLambdaForTesting(
[&](std::vector<std::string> items_for_display) {
ASSERT_EQ(items_for_display.size(), expected.size());
for (size_t i = 0; i < items_for_display.size(); i++) {
EXPECT_EQ(expected[i], items_for_display[i]);
}
callback_called = true;
});
privacy_sandbox_service()->GetFledgeJoiningEtldPlusOneForDisplay(callback);
EXPECT_TRUE(callback_called);
histogram_tester.ExpectUniqueSample(
"PrivacySandbox.ProtectedAudience.JoiningTopFrameDisplayed", true,
origins.size());
}
}
TEST_F(PrivacySandboxServiceTest, GetFledgeJoiningEtldPlusOne_InvalidTopFrame) {
// Confirm that when an invalid top frame is received, the appropriate metric
// is recorded, and the returned list is empty.
base::HistogramTester histogram_tester;
auto missing_top_frame = content::InterestGroupManager::InterestGroupDataKey{
url::Origin::Create(GURL("https://embedded.com")), url::Origin()};
test_interest_group_manager()->SetInterestGroupDataKeys({missing_top_frame});
bool callback_called = false;
auto callback = base::BindLambdaForTesting(
[&](std::vector<std::string> items_for_display) {
ASSERT_EQ(items_for_display.size(), 0u);
callback_called = true;
});
privacy_sandbox_service()->GetFledgeJoiningEtldPlusOneForDisplay(callback);
EXPECT_TRUE(callback_called);
histogram_tester.ExpectUniqueSample(
"PrivacySandbox.ProtectedAudience.JoiningTopFrameDisplayed", false, 1);
}
TEST_F(PrivacySandboxServiceTest, GetFledgeBlockedEtldPlusOne) {
// Confirm that blocked FLEDGE top frame eTLD+1's are correctly produced
// for display.
const std::vector<std::string> sites = {"google.com", "example.com",
"google.com.au"};
for (const auto& site : sites) {
privacy_sandbox_settings()->SetFledgeJoiningAllowed(site, false);
}
// Sites should be returned in lexographical order.
auto returned_sites =
privacy_sandbox_service()->GetBlockedFledgeJoiningTopFramesForDisplay();
ASSERT_EQ(returned_sites.size(), 3u);
EXPECT_EQ(returned_sites[0], sites[1]);
EXPECT_EQ(returned_sites[1], sites[0]);
EXPECT_EQ(returned_sites[2], sites[2]);
// Settings a site back to allowed should appropriately remove it from the
// display list.
privacy_sandbox_settings()->SetFledgeJoiningAllowed("google.com", true);
returned_sites =
privacy_sandbox_service()->GetBlockedFledgeJoiningTopFramesForDisplay();
ASSERT_EQ(returned_sites.size(), 2u);
EXPECT_EQ(returned_sites[0], sites[1]);
EXPECT_EQ(returned_sites[1], sites[2]);
}
TEST_F(PrivacySandboxServiceTest, PromptActionsUMAActions) {
base::UserActionTester user_action_tester;
feature_list()->Reset();
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"}});
privacy_sandbox_service()->PromptActionOccurred(kNoticeShown,
SurfaceType::kDesktop);
EXPECT_EQ(
user_action_tester.GetActionCount("Settings.PrivacySandbox.Notice.Shown"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeOpenSettings,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.OpenedSettings"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeAcknowledge,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.Acknowledged"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeDismiss,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.Dismissed"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeClosedNoInteraction,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.ClosedNoInteraction"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeLearnMore,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.LearnMore"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeMoreInfoOpened,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.LearnMoreExpanded"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeMoreInfoClosed,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.LearnMoreClosed"),
1);
privacy_sandbox_service()->PromptActionOccurred(kConsentMoreButtonClicked,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.MoreButtonClicked"),
1);
privacy_sandbox_service()->PromptActionOccurred(kNoticeMoreButtonClicked,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.MoreButtonClicked"),
1);
// Site Suggested Ads & Ads Measurement more info dropdown prompt actions part
// of Ads API UX Enhancements.
privacy_sandbox_service()->PromptActionOccurred(
kNoticeSiteSuggestedAdsMoreInfoOpened, SurfaceType::kDesktop);
EXPECT_EQ(
user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.SiteSuggestedAdsLearnMoreExpanded"),
1);
privacy_sandbox_service()->PromptActionOccurred(
kNoticeSiteSuggestedAdsMoreInfoClosed, SurfaceType::kDesktop);
EXPECT_EQ(
user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.SiteSuggestedAdsLearnMoreClosed"),
1);
privacy_sandbox_service()->PromptActionOccurred(
kNoticeAdsMeasurementMoreInfoOpened, SurfaceType::kDesktop);
EXPECT_EQ(
user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.AdsMeasurementLearnMoreExpanded"),
1);
privacy_sandbox_service()->PromptActionOccurred(
kNoticeAdsMeasurementMoreInfoClosed, SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Notice.AdsMeasurementLearnMoreClosed"),
1);
feature_list()->Reset();
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName, "true"}});
privacy_sandbox_service()->PromptActionOccurred(kConsentShown,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.Shown"),
1);
privacy_sandbox_service()->PromptActionOccurred(kConsentAccepted,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.Accepted"),
1);
privacy_sandbox_service()->PromptActionOccurred(kConsentDeclined,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.Declined"),
1);
privacy_sandbox_service()->PromptActionOccurred(kConsentMoreInfoOpened,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.LearnMoreExpanded"),
1);
privacy_sandbox_service()->PromptActionOccurred(kPrivacyPolicyLinkClicked,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.PrivacyPolicyLinkClicked"),
1);
privacy_sandbox_service()->PromptActionOccurred(kConsentMoreInfoClosed,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.LearnMoreClosed"),
1);
privacy_sandbox_service()->PromptActionOccurred(kConsentClosedNoDecision,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.Consent.ClosedNoInteraction"),
1);
feature_list()->Reset();
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName, "true"},
{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
privacy_sandbox_service()->PromptActionOccurred(kRestrictedNoticeOpenSettings,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.RestrictedNotice.OpenedSettings"),
1);
privacy_sandbox_service()->PromptActionOccurred(kRestrictedNoticeAcknowledge,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.RestrictedNotice.Acknowledged"),
1);
privacy_sandbox_service()->PromptActionOccurred(kRestrictedNoticeShown,
SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.RestrictedNotice.Shown"),
1);
privacy_sandbox_service()->PromptActionOccurred(
kRestrictedNoticeClosedNoInteraction, SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.RestrictedNotice.ClosedNoInteraction"),
1);
privacy_sandbox_service()->PromptActionOccurred(
kRestrictedNoticeMoreButtonClicked, SurfaceType::kDesktop);
EXPECT_EQ(user_action_tester.GetActionCount(
"Settings.PrivacySandbox.RestrictedNotice.MoreButtonClicked"),
1);
}
TEST_F(PrivacySandboxServiceTest, FledgeBlockDeletesData) {
// Allowing FLEDGE joining should not start a removal task.
privacy_sandbox_service()->SetFledgeJoiningAllowed("example.com", true);
EXPECT_EQ(browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
0xffffffffffffffffull); // -1, indicates no last removal task.
// When FLEDGE joining is blocked, a removal task should be started.
privacy_sandbox_service()->SetFledgeJoiningAllowed("example.com", false);
EXPECT_EQ(browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
content::BrowsingDataRemover::DATA_TYPE_INTEREST_GROUPS);
EXPECT_EQ(browsing_data_remover()->GetLastUsedBeginTimeForTesting(),
base::Time::Min());
EXPECT_EQ(browsing_data_remover()->GetLastUsedOriginTypeMaskForTesting(),
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB);
}
TEST_F(PrivacySandboxServiceTest, DisablingTopicsPrefClearsData) {
// Confirm that when the topics preference is disabled, topics data is
// deleted. No browsing data remover tasks are started.
EXPECT_CALL(*mock_browsing_topics_service(), ClearAllTopicsData()).Times(0);
// Enabling should not delete data.
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
constexpr uint64_t kNoRemovalTask = -1ull;
EXPECT_EQ(browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
kNoRemovalTask);
// Disabling should start delete topics data.
EXPECT_CALL(*mock_browsing_topics_service(), ClearAllTopicsData()).Times(1);
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, false);
EXPECT_EQ(browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
kNoRemovalTask);
}
TEST_F(PrivacySandboxServiceTest, DisablingFledgePrefClearsData) {
// Confirm that when the fledge preference is disabled, a browsing data
// remover task is started. Topics data isn't deleted.
EXPECT_CALL(*mock_browsing_topics_service(), ClearAllTopicsData()).Times(0);
// Enabling should not cause a removal task.
prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, true);
constexpr uint64_t kNoRemovalTask = -1ull;
EXPECT_EQ(browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
kNoRemovalTask);
// Disabling should start a task clearing all related information.
prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, false);
EXPECT_EQ(
browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
content::BrowsingDataRemover::DATA_TYPE_INTEREST_GROUPS |
content::BrowsingDataRemover::DATA_TYPE_SHARED_STORAGE |
content::BrowsingDataRemover::DATA_TYPE_INTEREST_GROUPS_INTERNAL);
EXPECT_EQ(browsing_data_remover()->GetLastUsedBeginTimeForTesting(),
base::Time::Min());
EXPECT_EQ(browsing_data_remover()->GetLastUsedOriginTypeMaskForTesting(),
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB);
}
TEST_F(PrivacySandboxServiceTest, DisablingAdMeasurementePrefClearsData) {
// Confirm that when the ad measurement preference is disabled, a browsing
// data remover task is started. Topics data isn't deleted.
EXPECT_CALL(*mock_browsing_topics_service(), ClearAllTopicsData()).Times(0);
// Enabling should not cause a removal task.
prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, true);
constexpr uint64_t kNoRemovalTask = -1ull;
EXPECT_EQ(browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
kNoRemovalTask);
// Disabling should start a task clearing all related information.
prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, false);
EXPECT_EQ(
browsing_data_remover()->GetLastUsedRemovalMaskForTesting(),
content::BrowsingDataRemover::DATA_TYPE_ATTRIBUTION_REPORTING |
content::BrowsingDataRemover::DATA_TYPE_AGGREGATION_SERVICE |
content::BrowsingDataRemover::DATA_TYPE_PRIVATE_AGGREGATION_INTERNAL);
EXPECT_EQ(browsing_data_remover()->GetLastUsedBeginTimeForTesting(),
base::Time::Min());
EXPECT_EQ(browsing_data_remover()->GetLastUsedOriginTypeMaskForTesting(),
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB);
}
TEST_F(PrivacySandboxServiceTest, GetTopTopics) {
// Check that the service correctly de-dupes and orders top topics. Topics
// should be alphabetically ordered.
const privacy_sandbox::CanonicalTopic kFirstTopic =
privacy_sandbox::CanonicalTopic(browsing_topics::Topic(24), // "Blues"
kTestTaxonomyVersion);
const privacy_sandbox::CanonicalTopic kSecondTopic =
privacy_sandbox::CanonicalTopic(
browsing_topics::Topic(23), // "Music & audio"
kTestTaxonomyVersion);
const std::vector<privacy_sandbox::CanonicalTopic> kTopTopics = {
kSecondTopic, kSecondTopic, kFirstTopic};
EXPECT_CALL(*mock_browsing_topics_service(), GetTopTopicsForDisplay())
.WillOnce(testing::Return(kTopTopics));
auto topics = privacy_sandbox_service()->GetCurrentTopTopics();
ASSERT_EQ(topics.size(), 2u);
EXPECT_EQ(topics[0], kFirstTopic);
EXPECT_EQ(topics[1], kSecondTopic);
}
TEST_F(PrivacySandboxServiceTest, GetBlockedTopics) {
// Check that blocked topics are correctly alphabetically sorted and returned.
const privacy_sandbox::CanonicalTopic kFirstTopic =
privacy_sandbox::CanonicalTopic(browsing_topics::Topic(24), // "Blues"
kTestTaxonomyVersion);
const privacy_sandbox::CanonicalTopic kSecondTopic =
privacy_sandbox::CanonicalTopic(
browsing_topics::Topic(23), // "Music & audio"
kTestTaxonomyVersion);
// The PrivacySandboxService assumes that the PrivacySandboxSettings service
// dedupes blocked topics. Check that assumption here.
privacy_sandbox_settings()->SetTopicAllowed(kSecondTopic, false);
privacy_sandbox_settings()->SetTopicAllowed(kSecondTopic, false);
privacy_sandbox_settings()->SetTopicAllowed(kFirstTopic, false);
privacy_sandbox_settings()->SetTopicAllowed(kFirstTopic, false);
auto blocked_topics = privacy_sandbox_service()->GetBlockedTopics();
ASSERT_EQ(blocked_topics.size(), 2u);
EXPECT_EQ(blocked_topics[0], kFirstTopic);
EXPECT_EQ(blocked_topics[1], kSecondTopic);
}
TEST_F(PrivacySandboxServiceTest, GetFirstLevelTopics) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeatureWithParameters(
blink::features::kBrowsingTopicsParameters, {{"taxonomy_version", "2"}});
// Check that blocked topics are correctly alphabetically sorted and returned.
const privacy_sandbox::CanonicalTopic kFirstTopic =
privacy_sandbox::CanonicalTopic(browsing_topics::Topic(1),
kTestTaxonomyVersion);
const privacy_sandbox::CanonicalTopic kLastTopic =
privacy_sandbox::CanonicalTopic(browsing_topics::Topic(332),
kTestTaxonomyVersion);
auto first_level_topics = privacy_sandbox_service()->GetFirstLevelTopics();
ASSERT_EQ(first_level_topics.size(), 22u);
EXPECT_EQ(first_level_topics[0], kFirstTopic);
EXPECT_EQ(first_level_topics[21], kLastTopic);
}
TEST_F(PrivacySandboxServiceTest, GetChildTopicsCurrentlyAssigned) {
const privacy_sandbox::CanonicalTopic kParentTopic =
privacy_sandbox::CanonicalTopic(
browsing_topics::Topic(1), // "Arts & Entertainment"
kTestTaxonomyVersion);
const privacy_sandbox::CanonicalTopic kDirectChildTopic =
privacy_sandbox::CanonicalTopic(
browsing_topics::Topic(23), // "Music & audio"
kTestTaxonomyVersion);
const privacy_sandbox::CanonicalTopic kIndirectChildTopic =
privacy_sandbox::CanonicalTopic(browsing_topics::Topic(29), // "Jazz"
kTestTaxonomyVersion);
const privacy_sandbox::CanonicalTopic kNotChildTopic =
privacy_sandbox::CanonicalTopic(
browsing_topics::Topic(99), // "Hair Care"
kTestTaxonomyVersion);
// No child topic assigned initially.
auto currently_assigned_child_topics =
privacy_sandbox_service()->GetChildTopicsCurrentlyAssigned(kParentTopic);
ASSERT_EQ(0u, currently_assigned_child_topics.size());
// Assign some topics.
const std::vector<privacy_sandbox::CanonicalTopic> kTopTopics = {
kDirectChildTopic, kIndirectChildTopic, kNotChildTopic};
ON_CALL(*mock_browsing_topics_service(), GetTopTopicsForDisplay())
.WillByDefault(testing::Return(kTopTopics));
// Both direct and indirect child should be returned.
currently_assigned_child_topics =
privacy_sandbox_service()->GetChildTopicsCurrentlyAssigned(kParentTopic);
ASSERT_EQ(currently_assigned_child_topics.size(), 2u);
EXPECT_EQ(currently_assigned_child_topics[0], kIndirectChildTopic);
EXPECT_EQ(currently_assigned_child_topics[1], kDirectChildTopic);
}
TEST_F(PrivacySandboxServiceTest, SetTopicAllowed) {
const privacy_sandbox::CanonicalTopic kTestTopic =
privacy_sandbox::CanonicalTopic(browsing_topics::Topic(10),
kTestTaxonomyVersion);
EXPECT_CALL(*mock_browsing_topics_service(), ClearTopic(kTestTopic)).Times(1);
privacy_sandbox_service()->SetTopicAllowed(kTestTopic, false);
EXPECT_FALSE(privacy_sandbox_settings()->IsTopicAllowed(kTestTopic));
testing::Mock::VerifyAndClearExpectations(mock_browsing_topics_service());
EXPECT_CALL(*mock_browsing_topics_service(), ClearTopic(kTestTopic)).Times(0);
privacy_sandbox_service()->SetTopicAllowed(kTestTopic, true);
EXPECT_TRUE(privacy_sandbox_settings()->IsTopicAllowed(kTestTopic));
}
TEST_F(PrivacySandboxServiceTest, TestNoFakeTopics) {
auto* service = privacy_sandbox_service();
EXPECT_THAT(service->GetCurrentTopTopics(), testing::IsEmpty());
EXPECT_THAT(service->GetBlockedTopics(), testing::IsEmpty());
}
TEST_F(PrivacySandboxServiceTest, TestNoFakeTopicsPrefOff) {
// Sample data won't be returned for current topics when the pref is off, only
// the blocked list.
prefs()->SetUserPref(prefs::kPrivacySandboxM1TopicsEnabled,
std::make_unique<base::Value>(false));
feature_list()->InitWithFeaturesAndParameters(
{{privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ShowSampleDataForTesting
.name,
"true"}}}},
{});
CanonicalTopic topic3(Topic(3), kTestTaxonomyVersion);
CanonicalTopic topic4(Topic(4), kTestTaxonomyVersion);
auto* service = privacy_sandbox_service();
EXPECT_THAT(service->GetCurrentTopTopics(), testing::IsEmpty());
EXPECT_THAT(service->GetBlockedTopics(), ElementsAre(topic3, topic4));
}
TEST_F(PrivacySandboxServiceTest, TestFakeTopics) {
std::vector<base::test::FeatureRefAndParams> test_features = {
{privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ShowSampleDataForTesting.name,
"true"}}}};
// Sample data for current topics is only returned when the pref is on.
prefs()->SetUserPref(prefs::kPrivacySandboxM1TopicsEnabled,
std::make_unique<base::Value>(true));
for (const auto& feature : test_features) {
feature_list()->Reset();
feature_list()->InitWithFeaturesAndParameters({feature}, {});
CanonicalTopic topic1(Topic(1), kTestTaxonomyVersion);
CanonicalTopic topic2(Topic(2), kTestTaxonomyVersion);
CanonicalTopic topic3(Topic(3), kTestTaxonomyVersion);
CanonicalTopic topic4(Topic(4), kTestTaxonomyVersion);
// Duplicate a topic to test that it doesn't appear in the results in
// addition to topic4.
CanonicalTopic topic4_duplicate(Topic(4), kTestTaxonomyVersion - 1);
auto* service = privacy_sandbox_service();
EXPECT_THAT(service->GetCurrentTopTopics(), ElementsAre(topic1, topic2));
EXPECT_THAT(service->GetBlockedTopics(), ElementsAre(topic3, topic4));
service->SetTopicAllowed(topic1, false);
EXPECT_THAT(service->GetCurrentTopTopics(), ElementsAre(topic2));
EXPECT_THAT(service->GetBlockedTopics(),
ElementsAre(topic1, topic3, topic4));
service->SetTopicAllowed(topic4, true);
service->SetTopicAllowed(topic4_duplicate, true);
EXPECT_THAT(service->GetCurrentTopTopics(), ElementsAre(topic2, topic4));
EXPECT_THAT(service->GetBlockedTopics(), ElementsAre(topic1, topic3));
service->SetTopicAllowed(topic1, true);
service->SetTopicAllowed(topic4, false);
service->SetTopicAllowed(topic4_duplicate, false);
EXPECT_THAT(service->GetCurrentTopTopics(), ElementsAre(topic1, topic2));
EXPECT_THAT(service->GetBlockedTopics(), ElementsAre(topic3, topic4));
}
}
using PrivacySandboxServiceDeathTest = PrivacySandboxServiceTest;
TEST_F(PrivacySandboxServiceDeathTest, TPSettingsNullExpectDeath) {
ASSERT_DEATH(
{
PrivacySandboxServiceImpl(
profile(), privacy_sandbox_settings(),
/*tracking_protection_settings=*/nullptr, cookie_settings(),
profile()->GetPrefs(), test_interest_group_manager(),
GetProfileType(), browsing_data_remover(),
host_content_settings_map(), mock_browsing_topics_service(),
first_party_sets_policy_service(),
mock_privacy_sandbox_countries());
},
"");
}
TEST_F(PrivacySandboxServiceTest,
RelatedWebsiteSetsNotRelevantMetricAllowedCookies) {
base::HistogramTester histogram_tester;
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
prefs()->SetUserPref(prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kOff)));
cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW);
CreateService();
histogram_tester.ExpectUniqueSample(
kFirstPartySetsStateHistogram,
PrivacySandboxServiceImpl::FirstPartySetsState::kFpsNotRelevant, 1);
}
TEST_F(PrivacySandboxServiceTest,
RelatedWebsiteSetsNotRelevantMetricBlockedCookies) {
base::HistogramTester histogram_tester;
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
CreateService();
histogram_tester.ExpectUniqueSample(
kFirstPartySetsStateHistogram,
PrivacySandboxServiceImpl::FirstPartySetsState::kFpsNotRelevant, 1);
}
TEST_F(PrivacySandboxServiceTest, RelatedWebsiteSetsEnabledMetric) {
base::HistogramTester histogram_tester;
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
CreateService();
histogram_tester.ExpectUniqueSample(
kFirstPartySetsStateHistogram,
PrivacySandboxServiceImpl::FirstPartySetsState::kFpsEnabled, 1);
}
TEST_F(PrivacySandboxServiceTest, RelatedWebsiteSetsDisabledMetric) {
base::HistogramTester histogram_tester;
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(false));
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
CreateService();
histogram_tester.ExpectUniqueSample(
kFirstPartySetsStateHistogram,
PrivacySandboxServiceImpl::FirstPartySetsState::kFpsDisabled, 1);
}
TEST_F(PrivacySandboxServiceTest,
GetRelatedWebsiteSetOwner_SimulatedRwsData_DisabledWhen3pcAllowed) {
GURL associate1_gurl("https://associate1.test");
net::SchemefulSite primary_site(GURL("https://primary.test"));
net::SchemefulSite associate1_site(associate1_gurl);
// Create Global RWS with the following set:
// { primary: "https://primary.test",
// associatedSites: ["https://associate1.test"}
net::GlobalFirstPartySets global_sets(
kRelatedWebsiteSetsVersion,
{
{primary_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}},
{associate1_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}},
},
{});
// Simulate 3PC are allowed while RWS pref is enabled
CreateService();
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kOff)));
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
first_party_sets_policy_service()->InitForTesting();
// We shouldn't get associate1's owner since RWS is disabled.
EXPECT_EQ(
privacy_sandbox_service()->GetRelatedWebsiteSetOwner(associate1_gurl),
std::nullopt);
}
TEST_F(
PrivacySandboxServiceTest,
GetRelatedWebsiteSetOwner_SimulatedRwsData_DisabledWhenAllCookiesBlocked) {
GURL associate1_gurl("https://associate1.test");
net::SchemefulSite primary_site(GURL("https://primary.test"));
net::SchemefulSite associate1_site(associate1_gurl);
// Create Global RWS with the following set:
// { primary: "https://primary.test",
// associatedSites: ["https://associate1.test"}
net::GlobalFirstPartySets global_sets(
kRelatedWebsiteSetsVersion,
{
{primary_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}},
{associate1_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}},
},
{});
// Simulate all cookies are blocked while RWS pref is enabled
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
CreateService();
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
first_party_sets_policy_service()->InitForTesting();
// We shouldn't get associate1's owner since RWS is disabled.
EXPECT_EQ(
privacy_sandbox_service()->GetRelatedWebsiteSetOwner(associate1_gurl),
std::nullopt);
}
TEST_F(PrivacySandboxServiceTest,
GetRelatedWebsiteSetOwner_SimulatedRwsData_DisabledByRwsPref) {
GURL associate1_gurl("https://associate1.test");
net::SchemefulSite primary_site(GURL("https://primary.test"));
net::SchemefulSite associate1_site(associate1_gurl);
// Create Global RWS with the following set:
// { primary: "https://primary.test",
// associatedSites: ["https://associate1.test"}
net::GlobalFirstPartySets global_sets(
kRelatedWebsiteSetsVersion,
{
{primary_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}},
{associate1_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}},
},
{});
// Simulate RWS pref disabled while 3PC are being blocked
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
CreateService();
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(false));
mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
first_party_sets_policy_service()->InitForTesting();
// We shouldn't get associate1's owner since RWS is disabled.
EXPECT_EQ(
privacy_sandbox_service()->GetRelatedWebsiteSetOwner(associate1_gurl),
std::nullopt);
}
TEST_F(PrivacySandboxServiceTest,
SimulatedRwsData_RwsEnabled_WithoutGlobalSets) {
GURL primary_gurl("https://primary.test");
GURL associate1_gurl("https://associate1.test");
GURL associate2_gurl("https://associate2.test");
net::SchemefulSite primary_site(primary_gurl);
net::SchemefulSite associate1_site(associate1_gurl);
net::SchemefulSite associate2_site(associate2_gurl);
// Set up state for the RWS UI: block 3PC and enable the RWS pref.
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
CreateService();
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
// Verify `GetRelatedWebsiteSetOwner` returns empty if RWS is enabled but the
// Global sets are not ready yet.
EXPECT_EQ(
privacy_sandbox_service()->GetRelatedWebsiteSetOwner(associate1_gurl),
std::nullopt);
EXPECT_EQ(
privacy_sandbox_service()->GetRelatedWebsiteSetOwner(associate2_gurl),
std::nullopt);
}
TEST_F(PrivacySandboxServiceTest,
SimulatedRwsData_RwsEnabled_WithGlobalSetsAndProfileSets) {
GURL primary_gurl("https://primary.test");
GURL associate1_gurl("https://associate1.test");
GURL associate2_gurl("https://associate2.test");
net::SchemefulSite primary_site(primary_gurl);
net::SchemefulSite associate1_site(associate1_gurl);
net::SchemefulSite associate2_site(associate2_gurl);
// Set up state for the RWS UI: block 3PC and enable the RWS pref.
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
CreateService();
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
// Simulate that the Global RWS are ready with the following set:
// { primary: "https://primary.test",
// associatedSites: ["https://associate1.test", "https://associate2.test"] }
mock_first_party_sets_handler().SetGlobalSets(net::GlobalFirstPartySets(
kRelatedWebsiteSetsVersion,
{
{primary_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}},
{associate1_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}},
{associate2_site,
{net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}},
},
{}));
// Simulate that associate2 is removed from the Global RWS for
// this profile.
mock_first_party_sets_handler().SetContextConfig(
net::FirstPartySetsContextConfig::Create(
{{net::SchemefulSite(GURL("https://associate2.test")),
net::FirstPartySetEntryOverride()}})
.value());
first_party_sets_policy_service()->InitForTesting();
// Verify that primary owns associate1, but no longer owns associate2.
EXPECT_EQ(privacy_sandbox_service()
->GetRelatedWebsiteSetOwner(associate1_gurl)
.value(),
primary_site);
EXPECT_EQ(
privacy_sandbox_service()->GetRelatedWebsiteSetOwner(associate2_gurl),
std::nullopt);
}
TEST_F(PrivacySandboxServiceTest, RwsPrefInit) {
// Check that the init of the RWS pref occurs correctly.
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
EXPECT_TRUE(
prefs()->GetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled));
EXPECT_FALSE(prefs()->GetBoolean(
prefs::kPrivacySandboxRelatedWebsiteSetsDataAccessAllowedInitialized));
// If the UI is available, the user blocks 3PC, and the pref has not been
// previously init, it should be.
CreateService();
EXPECT_FALSE(
prefs()->GetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled));
EXPECT_TRUE(prefs()->GetBoolean(
prefs::kPrivacySandboxRelatedWebsiteSetsDataAccessAllowedInitialized));
// Once the pref has been init, it should not be re-init, and updated user
// cookie settings should not impact it.
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kOff)));
CreateService();
EXPECT_TRUE(
prefs()->GetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled));
EXPECT_TRUE(prefs()->GetBoolean(
prefs::kPrivacySandboxRelatedWebsiteSetsDataAccessAllowedInitialized));
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
CreateService();
EXPECT_TRUE(
prefs()->GetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled));
EXPECT_TRUE(prefs()->GetBoolean(
prefs::kPrivacySandboxRelatedWebsiteSetsDataAccessAllowedInitialized));
// Blocking all cookies should also init the RWS pref to off.
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kOff)));
cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
CreateService();
EXPECT_FALSE(
prefs()->GetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled));
EXPECT_TRUE(prefs()->GetBoolean(
prefs::kPrivacySandboxRelatedWebsiteSetsDataAccessAllowedInitialized));
}
TEST_F(PrivacySandboxServiceTest, UsesConfiguredRelatedWebsiteSets) {
// Set up state for the RWS UI: block 3PC and enable the RWS pref.
prefs()->SetUserPref(
prefs::kCookieControlsMode,
std::make_unique<base::Value>(static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty)));
CreateService();
ClearRwsUserPrefs(prefs());
prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled,
std::make_unique<base::Value>(true));
// Simulate that the Global RWS are ready with the following
// set:
// { primary: "https://youtube-primary.test",
// associatedSites: ["https://youtube.com"]
// }
net::SchemefulSite youtube_primary_site(GURL("https://youtube-primary.test"));
GURL youtube_gurl("https://youtube.com");
net::SchemefulSite youtube_site(youtube_gurl);
mock_first_party_sets_handler().SetGlobalSets(net::GlobalFirstPartySets(
kRelatedWebsiteSetsVersion,
{
{youtube_primary_site,
{net::FirstPartySetEntry(youtube_primary_site,
net::SiteType::kPrimary)}},
{youtube_site,
{net::FirstPartySetEntry(youtube_primary_site,
net::SiteType::kAssociated)}},
},
{}));
// Simulate that https://google.de is moved into a new RWS for this profile.
mock_first_party_sets_handler().SetContextConfig(
net::FirstPartySetsContextConfig::Create(
{{net::SchemefulSite(GURL("https://google.de")),
net::FirstPartySetEntryOverride(net::FirstPartySetEntry(
net::SchemefulSite(GURL("https://new-primary.test")),
net::SiteType::kAssociated))}})
.value());
first_party_sets_policy_service()->InitForTesting();
EXPECT_EQ(privacy_sandbox_service()->GetRelatedWebsiteSetOwner(youtube_gurl),
youtube_primary_site);
EXPECT_FALSE(privacy_sandbox_service()->IsPartOfManagedRelatedWebsiteSet(
net::SchemefulSite(GURL("https://googlesource.com"))));
EXPECT_TRUE(privacy_sandbox_service()->IsPartOfManagedRelatedWebsiteSet(
net::SchemefulSite(GURL("https://google.de"))));
}
TEST_F(PrivacySandboxServiceTest, TopicsConsentDefault) {
RunTestCase(
TestState{}, TestInput{},
TestOutput{{kTopicsConsentGiven, false},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kDefaultValue},
{kTopicsConsentLastUpdateTime, base::Time()},
{kTopicsConsentStringIdentifiers, std::vector<int>()}});
}
TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_EnableWithBlocked) {
// Note that when testing for enabling topics, there can never have been
// current topics in prod code.
RunTestCase(
TestState{{kActiveTopicsConsent, false},
{kHasCurrentTopics, false},
{kHasBlockedTopics, true},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{
{kTopicsToggleNewValue, true},
},
TestOutput{
{kTopicsConsentGiven, true},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kSettings},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsSettingsStringIdentifiers(/*did_consent=*/true,
/*has_current_topics=*/false,
/*has_blocked_topics=*/true)},
});
}
TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_EnableNoBlocked) {
RunTestCase(
TestState{{kActiveTopicsConsent, false},
{kHasCurrentTopics, false},
{kHasBlockedTopics, false},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{
{kTopicsToggleNewValue, true},
},
TestOutput{
{kTopicsConsentGiven, true},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kSettings},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsSettingsStringIdentifiers(/*did_consent=*/true,
/*has_current_topics=*/false,
/*has_blocked_topics=*/false)},
});
}
TEST_F(PrivacySandboxServiceTest,
TopicsConsentSettings_DisableCurrentAndBlocked) {
RunTestCase(
TestState{{kActiveTopicsConsent, true},
{kHasCurrentTopics, true},
{kHasBlockedTopics, true},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{
{kTopicsToggleNewValue, false},
},
TestOutput{
{kTopicsConsentGiven, false},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kSettings},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsSettingsStringIdentifiers(/*did_consent=*/false,
/*has_current_topics=*/true,
/*has_blocked_topics=*/true)},
});
}
TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_DisableBlockedOnly) {
RunTestCase(
TestState{{kActiveTopicsConsent, true},
{kHasCurrentTopics, false},
{kHasBlockedTopics, true},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{
{kTopicsToggleNewValue, false},
},
TestOutput{
{kTopicsConsentGiven, false},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kSettings},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsSettingsStringIdentifiers(/*did_consent=*/false,
/*has_current_topics=*/false,
/*has_blocked_topics=*/true)},
});
}
TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_DisableCurrentOnly) {
RunTestCase(
TestState{{kActiveTopicsConsent, true},
{kHasCurrentTopics, true},
{kHasBlockedTopics, false},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{
{kTopicsToggleNewValue, false},
},
TestOutput{
{kTopicsConsentGiven, false},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kSettings},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsSettingsStringIdentifiers(/*did_consent=*/false,
/*has_current_topics=*/true,
/*has_blocked_topics=*/false)},
});
}
TEST_F(PrivacySandboxServiceTest,
TopicsConsentSettings_DisableNoCurrentNoBlocked) {
RunTestCase(
TestState{{kActiveTopicsConsent, true},
{kHasCurrentTopics, false},
{kHasBlockedTopics, false},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{
{kTopicsToggleNewValue, false},
},
TestOutput{
{kTopicsConsentGiven, false},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kSettings},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsSettingsStringIdentifiers(/*did_consent=*/false,
/*has_current_topics=*/false,
/*has_blocked_topics=*/false)},
});
}
TEST_F(PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptSuppressed_Explicitly) {
base::HistogramTester histogram_tester;
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
// TODO(crbug.com/385345006): Add support for multi profile testing.
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kRestricted));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToPrivacySandboxRestricted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToPrivacySandboxRestricted),
/*expected_count=*/1);
prefs()->SetInteger(
prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kThirdPartyCookiesBlocked));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueTo3PCBlocked),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueTo3PCBlocked),
/*expected_count=*/1);
prefs()->SetInteger(
prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kTrialsConsentDeclined));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToTrialConsentDeclined),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToTrialConsentDeclined),
/*expected_count=*/1);
prefs()->SetInteger(
prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kTrialsDisabledAfterNotice));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToTrialsDisabledAfterNoticeShown),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToTrialsDisabledAfterNoticeShown),
/*expected_count=*/1);
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kPolicy));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToManagedState),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToManagedState),
/*expected_count=*/1);
prefs()->SetInteger(
prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNoticeShownToGuardian));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeNotShownDueToNoticeShownToGuardian),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeNotShownDueToNoticeShownToGuardian),
/*expected_count=*/1);
}
TEST_F(PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptSuppressed_Implicitly) {
base::HistogramTester histogram_tester;
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
// Ensure prompt not suppressed.
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNone));
// Disable one of the K-APIs.
prefs()->SetManagedPref(prefs::kPrivacySandboxM1TopicsEnabled,
base::Value(false));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToManagedState),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kPromptNotShownDueToManagedState),
/*expected_count=*/1);
}
TEST_F(PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_EEA) {
base::HistogramTester histogram_tester;
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
// Ensure prompt not suppressed.
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNone));
base::test::ScopedFeatureList feature_list_consent_required;
std::map<std::string, std::string> consent_required_feature_param = {
{std::string(
privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName),
"true"},
{std::string(privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName),
"false"}};
feature_list_consent_required.InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
consent_required_feature_param);
// Not consented
prefs()->SetBoolean(prefs::kPrivacySandboxM1ConsentDecisionMade, false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEAConsentPromptWaiting),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEAConsentPromptWaiting),
/*expected_count=*/1);
// Consent decision made and notice acknowledged.
prefs()->SetBoolean(prefs::kPrivacySandboxM1ConsentDecisionMade, true);
prefs()->SetBoolean(prefs::kPrivacySandboxM1EEANoticeAcknowledged, true);
// With topics enabled.
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEAFlowCompletedWithTopicsAccepted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEAFlowCompletedWithTopicsAccepted),
/*expected_count=*/1);
// With topics disabled.
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEAFlowCompletedWithTopicsDeclined),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEAFlowCompletedWithTopicsDeclined),
/*expected_count=*/1);
// Consent decision made but notice was not acknowledged.
prefs()->SetBoolean(prefs::kPrivacySandboxM1EEANoticeAcknowledged, false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEANoticePromptWaiting),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kEEANoticePromptWaiting),
/*expected_count=*/1);
}
TEST_F(PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_ROW) {
base::HistogramTester histogram_tester;
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
// Ensure prompt not suppressed.
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNone));
base::test::ScopedFeatureList feature_list_notice_required;
std::map<std::string, std::string> notice_required_feature_param = {
{std::string(
privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName),
"false"},
{std::string(privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName),
"true"}};
feature_list_notice_required.InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4, notice_required_feature_param);
// Notice flow not completed.
prefs()->SetBoolean(prefs::kPrivacySandboxM1RowNoticeAcknowledged, false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kROWNoticePromptWaiting),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kROWNoticePromptWaiting),
/*expected_count=*/1);
// Notice flow completed.
prefs()->SetBoolean(prefs::kPrivacySandboxM1RowNoticeAcknowledged, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kROWNoticeFlowCompleted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kROWNoticeFlowCompleted),
/*expected_count=*/1);
}
TEST_F(PrivacySandboxServiceTest, RecordPrivacySandbox4StartupMetrics_APIs) {
// Each test for the APIs are scoped below to ensure we start with a clean
// HistogramTester as each call to `RecordPrivacySandbox4StartupMetrics` emits
// histograms for all APIs.
// Topics
{
base::HistogramTester histogram_tester;
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount("Settings.PrivacySandbox.Topics.Enabled",
static_cast<int>(true),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.Topics.EnabledForProfile",
privacy_sandbox::ProfileEnabledState::kPSProfileOneEnabled,
/*expected_count=*/1);
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount("Settings.PrivacySandbox.Topics.Enabled",
static_cast<int>(false),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.Topics.EnabledForProfile",
privacy_sandbox::ProfileEnabledState::kPSProfileOneDisabled,
/*expected_count=*/1);
}
// Fledge
{
base::HistogramTester histogram_tester;
prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount("Settings.PrivacySandbox.Fledge.Enabled",
static_cast<int>(true),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.Fledge.EnabledForProfile",
privacy_sandbox::ProfileEnabledState::kPSProfileOneEnabled,
/*expected_count=*/1);
prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount("Settings.PrivacySandbox.Fledge.Enabled",
static_cast<int>(false),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.Fledge.EnabledForProfile",
privacy_sandbox::ProfileEnabledState::kPSProfileOneDisabled,
/*expected_count=*/1);
}
// Ad measurement
{
base::HistogramTester histogram_tester;
prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.AdMeasurement.Enabled", static_cast<int>(true),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.AdMeasurement.EnabledForProfile",
privacy_sandbox::ProfileEnabledState::kPSProfileOneEnabled,
/*expected_count=*/1);
prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.AdMeasurement.Enabled",
static_cast<int>(false),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
"Settings.PrivacySandbox.AdMeasurement.EnabledForProfile",
privacy_sandbox::ProfileEnabledState::kPSProfileOneDisabled,
/*expected_count=*/1);
}
}
// Test class to verify that non-regular profiles (guest and incognito) emit
// only client-level histograms for privacy sandbox startup metrics.
class PrivacySandbox4StartupMetricsNonRegularProfilesTest
: public PrivacySandboxServiceTest,
public testing::WithParamInterface<
std::tuple<std::string,
std::string,
bool,
profile_metrics::BrowserProfileType>> {};
TEST_P(PrivacySandbox4StartupMetricsNonRegularProfilesTest, APIs) {
auto [feature_name, feature_pref, is_enabled, profile_type] = GetParam();
base::HistogramTester histogram_tester;
profile_metrics::SetBrowserProfileType(profile(), profile_type);
prefs()->SetBoolean(feature_pref, is_enabled);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
// Check that no profile level histograms are emitted.
EXPECT_THAT(
histograms,
testing::Not(testing::AnyOf(base::StrCat(
{"Settings.PrivacySandbox.", feature_name, ".EnabledForProfile"}))));
histogram_tester.ExpectBucketCount(
base::StrCat({"Settings.PrivacySandbox.", feature_name, ".Enabled"}),
static_cast<int>(is_enabled),
/*expected_count=*/1);
}
INSTANTIATE_TEST_SUITE_P(
PrivacySandbox4StartupMetricsNonRegularProfilesTests,
PrivacySandbox4StartupMetricsNonRegularProfilesTest,
::testing::Values(
std::make_tuple("Topics",
prefs::kPrivacySandboxM1TopicsEnabled,
true,
profile_metrics::BrowserProfileType::kGuest),
std::make_tuple("Fledge",
prefs::kPrivacySandboxM1FledgeEnabled,
true,
profile_metrics::BrowserProfileType::kGuest),
std::make_tuple("AdMeasurement",
prefs::kPrivacySandboxM1AdMeasurementEnabled,
true,
profile_metrics::BrowserProfileType::kGuest),
std::make_tuple("Topics",
prefs::kPrivacySandboxM1TopicsEnabled,
true,
profile_metrics::BrowserProfileType::kIncognito),
std::make_tuple("Fledge",
prefs::kPrivacySandboxM1FledgeEnabled,
true,
profile_metrics::BrowserProfileType::kIncognito),
std::make_tuple("AdMeasurement",
prefs::kPrivacySandboxM1AdMeasurementEnabled,
true,
profile_metrics::BrowserProfileType::kIncognito),
std::make_tuple("Topics",
prefs::kPrivacySandboxM1TopicsEnabled,
false,
profile_metrics::BrowserProfileType::kGuest),
std::make_tuple("Fledge",
prefs::kPrivacySandboxM1FledgeEnabled,
false,
profile_metrics::BrowserProfileType::kGuest),
std::make_tuple("AdMeasurement",
prefs::kPrivacySandboxM1AdMeasurementEnabled,
false,
profile_metrics::BrowserProfileType::kGuest),
std::make_tuple("Topics",
prefs::kPrivacySandboxM1TopicsEnabled,
false,
profile_metrics::BrowserProfileType::kIncognito),
std::make_tuple("Fledge",
prefs::kPrivacySandboxM1FledgeEnabled,
false,
profile_metrics::BrowserProfileType::kIncognito),
std::make_tuple("AdMeasurement",
prefs::kPrivacySandboxM1AdMeasurementEnabled,
false,
profile_metrics::BrowserProfileType::kIncognito)));
struct SurfaceMapping {
PrivacySandboxService::SurfaceType input_surface;
NoticeSurfaceType expected_notice_surface;
};
struct NoticeActionData {
base::test::FeatureRefAndParams feature_flag;
PromptAction action_occurred;
Notice expected_notice;
NoticeEvent expected_event;
};
class PrivacySandboxNoticeServiceInteractionTest
: public PrivacySandboxServiceTest,
public testing::WithParamInterface<
std::tuple<SurfaceMapping, NoticeActionData>> {
public:
PrivacySandboxNoticeServiceInteractionTest() {
const auto& core_data = std::get<1>(GetParam());
feature_list_.InitWithFeaturesAndParameters(
/*enabled_features=*/{core_data.feature_flag,
{privacy_sandbox::
kPsDualWritePrefsToNoticeStorage,
{}}},
/*disabled_features=*/{});
}
void SetUp() override {
mock_notice_service_ = static_cast<
privacy_sandbox::MockPrivacySandboxNoticeService*>(
PrivacySandboxNoticeServiceFactory::GetInstance()
->SetTestingFactoryAndUse(
profile(),
base::BindRepeating(
&privacy_sandbox::BuildMockPrivacySandboxNoticeService)));
PrivacySandboxServiceTest::SetUp();
}
void TearDown() override {
PrivacySandboxServiceTest::TearDown();
mock_notice_service_ = nullptr;
}
privacy_sandbox::MockPrivacySandboxNoticeService* mock_notice_service() {
return mock_notice_service_;
}
protected:
base::test::ScopedFeatureList feature_list_;
raw_ptr<privacy_sandbox::MockPrivacySandboxNoticeService>
mock_notice_service_ = nullptr;
};
TEST_P(PrivacySandboxNoticeServiceInteractionTest,
VerifyNoticeServiceEventOccurred) {
const auto& [surface_mapping, core_data] = GetParam();
EXPECT_CALL(*mock_notice_service(),
EventOccurred(Pair(Eq(core_data.expected_notice),
Eq(surface_mapping.expected_notice_surface)),
Eq(core_data.expected_event)))
.Times(1);
privacy_sandbox_service()->PromptActionOccurred(
core_data.action_occurred, surface_mapping.input_surface);
testing::Mock::VerifyAndClearExpectations(mock_notice_service());
}
const std::vector<SurfaceMapping> kSurfaceMappings = {
{.input_surface = SurfaceType::kDesktop,
.expected_notice_surface = NoticeSurfaceType::kDesktopNewTab},
{.input_surface = SurfaceType::kBrApp,
.expected_notice_surface = NoticeSurfaceType::kClankBrApp},
{.input_surface = SurfaceType::kAGACCT,
.expected_notice_surface = NoticeSurfaceType::kClankCustomTab},
};
base::test::FeatureRefAndParams ConsentFeature() {
return {
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName, "true"}}};
}
base::test::FeatureRefAndParams NoticeFeature() {
return {
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"}}};
}
base::test::FeatureRefAndParams RestrictedNoticeFeature() {
return {privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}}};
}
const std::vector<NoticeActionData> kNoticeActionDataList = {
// --- Shown Actions ---
{.feature_flag = ConsentFeature(),
.action_occurred = PromptAction::kConsentShown,
.expected_notice = Notice::kTopicsConsentNotice,
.expected_event = NoticeEvent::kShown},
{.feature_flag = ConsentFeature(),
.action_occurred = PromptAction::kNoticeShown,
.expected_notice = Notice::kProtectedAudienceMeasurementNotice,
.expected_event = NoticeEvent::kShown},
{.feature_flag = NoticeFeature(),
.action_occurred = PromptAction::kNoticeShown,
.expected_notice = Notice::kThreeAdsApisNotice,
.expected_event = NoticeEvent::kShown},
{.feature_flag = RestrictedNoticeFeature(),
.action_occurred = PromptAction::kRestrictedNoticeShown,
.expected_notice = Notice::kMeasurementNotice,
.expected_event = NoticeEvent::kShown},
// --- Consent Actions ---
{.feature_flag = ConsentFeature(),
.action_occurred = PromptAction::kConsentAccepted,
.expected_notice = Notice::kTopicsConsentNotice,
.expected_event = NoticeEvent::kOptIn},
{.feature_flag = ConsentFeature(),
.action_occurred = PromptAction::kConsentDeclined,
.expected_notice = Notice::kTopicsConsentNotice,
.expected_event = NoticeEvent::kOptOut},
// --- Ack Actions ---
{.feature_flag = ConsentFeature(),
.action_occurred = PromptAction::kNoticeAcknowledge,
.expected_notice = Notice::kProtectedAudienceMeasurementNotice,
.expected_event = NoticeEvent::kAck},
{.feature_flag = NoticeFeature(),
.action_occurred = PromptAction::kNoticeAcknowledge,
.expected_notice = Notice::kThreeAdsApisNotice,
.expected_event = NoticeEvent::kAck},
{.feature_flag = RestrictedNoticeFeature(),
.action_occurred = PromptAction::kRestrictedNoticeAcknowledge,
.expected_notice = Notice::kMeasurementNotice,
.expected_event = NoticeEvent::kAck},
// --- Settings Actions ---
{.feature_flag = ConsentFeature(),
.action_occurred = PromptAction::kNoticeOpenSettings,
.expected_notice = Notice::kProtectedAudienceMeasurementNotice,
.expected_event = NoticeEvent::kSettings},
{.feature_flag = NoticeFeature(),
.action_occurred = PromptAction::kNoticeOpenSettings,
.expected_notice = Notice::kThreeAdsApisNotice,
.expected_event = NoticeEvent::kSettings},
{.feature_flag = RestrictedNoticeFeature(),
.action_occurred = PromptAction::kRestrictedNoticeOpenSettings,
.expected_notice = Notice::kMeasurementNotice,
.expected_event = NoticeEvent::kSettings},
};
INSTANTIATE_TEST_SUITE_P(PrivacySandboxNoticeServiceInteractionTest,
PrivacySandboxNoticeServiceInteractionTest,
Combine(ValuesIn(kSurfaceMappings),
ValuesIn(kNoticeActionDataList)));
class PrivacySandboxServiceM1RestrictedNoticeTest
: public PrivacySandboxServiceTest {
public:
void InitializeFeaturesBeforeStart() override {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"},
{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
}
};
TEST_F(PrivacySandboxServiceM1RestrictedNoticeTest,
RestrictedPromptActionsUpdatePrefs) {
// Prompt acknowledge action should update the prefs accordingly.
RunTestCase(TestState{{kM1AdMeasurementEnabledUserPrefValue, false},
{kM1RestrictedNoticePreviouslyAcknowledged, false}},
TestInput{{kPromptAction,
static_cast<int>(kRestrictedNoticeAcknowledge)}},
TestOutput{{kM1AdMeasurementEnabled, true},
{kM1RestrictedNoticeAcknowledged, true}});
// Open settings action should update the prefs accordingly.
RunTestCase(TestState{{kM1AdMeasurementEnabledUserPrefValue, false},
{kM1RestrictedNoticePreviouslyAcknowledged, false}},
TestInput{{kPromptAction,
static_cast<int>(kRestrictedNoticeOpenSettings)}},
TestOutput{{kM1AdMeasurementEnabled, true},
{kM1RestrictedNoticeAcknowledged, true}});
}
class PrivacySandboxServiceM1DelayCreation : public PrivacySandboxServiceTest {
public:
void SetUp() override {
// Prevent service from being created by base class.
}
};
TEST_F(PrivacySandboxServiceM1DelayCreation,
UnrestrictedRemainsEnabledWithConsent) {
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxTopicsConsentGiven, true);
prefs()->SetTime(prefs::kPrivacySandboxTopicsConsentLastUpdateTime,
base::Time::Now());
prefs()->SetInteger(
prefs::kPrivacySandboxTopicsConsentLastUpdateReason,
static_cast<int>(
privacy_sandbox::TopicsConsentUpdateSource::kConfirmation));
prefs()->SetString(prefs::kPrivacySandboxTopicsConsentTextAtLastUpdate,
"foo");
CreateService();
EXPECT_TRUE(prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled));
EXPECT_TRUE(prefs()->GetBoolean(prefs::kPrivacySandboxM1FledgeEnabled));
EXPECT_TRUE(
prefs()->GetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled));
EXPECT_TRUE(prefs()->GetBoolean(prefs::kPrivacySandboxTopicsConsentGiven));
EXPECT_EQ(prefs()->GetTime(prefs::kPrivacySandboxTopicsConsentLastUpdateTime),
base::Time::Now());
EXPECT_EQ(static_cast<privacy_sandbox::TopicsConsentUpdateSource>(
prefs()->GetInteger(
prefs::kPrivacySandboxTopicsConsentLastUpdateReason)),
privacy_sandbox::TopicsConsentUpdateSource::kConfirmation);
EXPECT_EQ(
prefs()->GetString(prefs::kPrivacySandboxTopicsConsentTextAtLastUpdate),
"foo");
}
TEST_F(PrivacySandboxServiceM1DelayCreation,
PromptSuppressReasonClearedWhenRestrictedNoticeEnabled) {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kRestricted));
CreateService();
EXPECT_EQ(prefs()->GetValue(prefs::kPrivacySandboxM1PromptSuppressed),
static_cast<int>(PromptSuppressedReason::kNone));
}
TEST_F(PrivacySandboxServiceM1DelayCreation,
PromptSuppressReasonNotClearedWhenRestrictedNoticeDisabled) {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"false"}});
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kRestricted));
CreateService();
EXPECT_EQ(prefs()->GetValue(prefs::kPrivacySandboxM1PromptSuppressed),
static_cast<int>(PromptSuppressedReason::kRestricted));
}
TEST_F(PrivacySandboxServiceM1DelayCreation,
ActivateAllowPromptForBlocked3PCookiesWhenPrefSet) {
// Setup
base::FieldTrial* trial(
base::FieldTrialList::CreateFieldTrial("AllowPromptFor3PCStudy", "A"));
auto local_feature_list = std::make_unique<base::FeatureList>();
local_feature_list->RegisterFieldTrialOverride(
privacy_sandbox::kPrivacySandboxAllowPromptForBlocked3PCookies.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
feature_list()->InitWithFeatureList(std::move(local_feature_list));
prefs()->SetBoolean(prefs::kPrivacySandboxAllowNoticeFor3PCBlockedTrial,
true);
// Action
CreateService();
// Verification
auto* field_trial = base::FeatureList::GetFieldTrial(
privacy_sandbox::kPrivacySandboxAllowPromptForBlocked3PCookies);
ASSERT_TRUE(field_trial);
EXPECT_TRUE(base::FieldTrialList::IsTrialActive(field_trial->trial_name()));
}
TEST_F(PrivacySandboxServiceM1DelayCreation,
DoNotActivateAllowPromptForBlocked3PCookiesWhenPrefNotSet) {
// Setup
base::FieldTrial* trial(
base::FieldTrialList::CreateFieldTrial("AllowPromptFor3PCStudy", "A"));
auto local_feature_list = std::make_unique<base::FeatureList>();
local_feature_list->RegisterFieldTrialOverride(
privacy_sandbox::kPrivacySandboxAllowPromptForBlocked3PCookies.name,
base::FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
feature_list()->InitWithFeatureList(std::move(local_feature_list));
prefs()->SetBoolean(prefs::kPrivacySandboxAllowNoticeFor3PCBlockedTrial,
false);
// Action
CreateService();
// Verification
auto* field_trial = base::FeatureList::GetFieldTrial(
privacy_sandbox::kPrivacySandboxAllowPromptForBlocked3PCookies);
ASSERT_TRUE(field_trial);
EXPECT_FALSE(base::FieldTrialList::IsTrialActive(field_trial->trial_name()));
}
TEST_F(
PrivacySandboxServiceM1DelayCreation,
ThirdPartyCookieBlockedSuppressReasonClearedWhenAllowPromptFeatureEnabled) {
feature_list()->InitAndEnableFeature(
privacy_sandbox::kPrivacySandboxAllowPromptForBlocked3PCookies);
prefs()->SetInteger(
prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kThirdPartyCookiesBlocked));
CreateService();
EXPECT_EQ(prefs()->GetValue(prefs::kPrivacySandboxM1PromptSuppressed),
static_cast<int>(PromptSuppressedReason::kNone));
EXPECT_TRUE(
prefs()->GetBoolean(prefs::kPrivacySandboxAllowNoticeFor3PCBlockedTrial));
}
TEST_F(
PrivacySandboxServiceM1DelayCreation,
ThirdPartyCookieBlockedSuppressReasonClearedWhenAllowPromptFeatureDisabled) {
feature_list()->InitAndDisableFeature(
privacy_sandbox::kPrivacySandboxAllowPromptForBlocked3PCookies);
prefs()->SetInteger(
prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kThirdPartyCookiesBlocked));
CreateService();
EXPECT_EQ(
prefs()->GetValue(prefs::kPrivacySandboxM1PromptSuppressed),
static_cast<int>(PromptSuppressedReason::kThirdPartyCookiesBlocked));
EXPECT_TRUE(
prefs()->GetBoolean(prefs::kPrivacySandboxAllowNoticeFor3PCBlockedTrial));
}
class PrivacySandboxServiceM1DelayCreationRestricted
: public PrivacySandboxServiceM1DelayCreation {
public:
std::unique_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
CreateMockDelegate() override {
auto mock_delegate = std::make_unique<testing::NiceMock<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>>();
mock_delegate->SetUpIsPrivacySandboxRestrictedResponse(
/*restricted=*/true);
return mock_delegate;
}
};
TEST_F(PrivacySandboxServiceM1DelayCreationRestricted,
RestrictedDisablesAndClearsConsent) {
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxTopicsConsentGiven, true);
prefs()->SetTime(prefs::kPrivacySandboxTopicsConsentLastUpdateTime,
base::Time::Now());
prefs()->SetInteger(
prefs::kPrivacySandboxTopicsConsentLastUpdateReason,
static_cast<int>(
privacy_sandbox::TopicsConsentUpdateSource::kConfirmation));
prefs()->SetString(prefs::kPrivacySandboxTopicsConsentTextAtLastUpdate,
"foo");
CreateService();
EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled));
EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxM1FledgeEnabled));
EXPECT_FALSE(
prefs()->GetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled));
EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxTopicsConsentGiven));
EXPECT_EQ(prefs()->GetTime(prefs::kPrivacySandboxTopicsConsentLastUpdateTime),
base::Time());
EXPECT_EQ(static_cast<privacy_sandbox::TopicsConsentUpdateSource>(
prefs()->GetInteger(
prefs::kPrivacySandboxTopicsConsentLastUpdateReason)),
privacy_sandbox::TopicsConsentUpdateSource::kDefaultValue);
EXPECT_EQ(
prefs()->GetString(prefs::kPrivacySandboxTopicsConsentTextAtLastUpdate),
"");
}
TEST_F(PrivacySandboxServiceM1DelayCreationRestricted,
RestrictedEnabledDoesntClearAdMeasurementPref) {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, true);
prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, true);
CreateService();
EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled));
EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxM1FledgeEnabled));
EXPECT_TRUE(
prefs()->GetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled));
}
class PrivacySandboxServiceM1PromptTest : public PrivacySandboxServiceTest {
public:
void InitializeFeaturesBeforeStart() override {
feature_list()->InitWithFeaturesAndParameters(
{{privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName,
"true"},
{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName,
"false"}}}},
{privacy_sandbox::kPrivacySandboxAllowPromptForBlocked3PCookies});
}
};
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(PrivacySandboxServiceM1PromptTest, DeviceLocalAccountUser) {
privacy_sandbox_service()->ForceChromeBuildForTests(true);
user_manager::ScopedUserManager user_manager(
std::make_unique<user_manager::FakeUserManager>(local_state()));
// No prompt should be shown for a public session account.
ash::ScopedTestPublicSessionLoginState login_state;
// TODO(crbug.com/361794340): Ensure the promptType is correct across
// different surfaceTypes.
EXPECT_EQ(
privacy_sandbox_service()->GetRequiredPromptType(SurfaceType::kDesktop),
PromptType::kNone);
histogram_tester_.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
// A prompt should be shown for a regular user.
ash::LoginState::Get()->SetLoggedInState(
ash::LoginState::LoggedInState::LOGGED_IN_ACTIVE,
ash::LoginState::LoggedInUserType::LOGGED_IN_USER_REGULAR);
EXPECT_EQ(
privacy_sandbox_service()->GetRequiredPromptType(SurfaceType::kDesktop),
PromptType::kM1Consent);
histogram_tester_.ExpectBucketCount(
kPromptMigrationHistogram, PromptTypeCombination::kPSConsent_NSConsent,
1);
// No prompt should be shown for a web kiosk account.
chromeos::SetUpFakeChromeAppKioskSession();
EXPECT_EQ(
privacy_sandbox_service()->GetRequiredPromptType(SurfaceType::kDesktop),
PromptType::kNone);
}
#endif // BUILDFLAG(IS_CHROMEOS)
#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
TEST_F(PrivacySandboxServiceM1PromptTest, NonChromeBuildPrompt) {
base::HistogramTester histogram_tester;
// A case that will normally show a prompt will not if is a non-Chrome build.
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}},
TestInput{{kForceChromeBuild, false}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
#endif
TEST_F(PrivacySandboxServiceM1PromptTest, ThirdPartyCookiesBlockedPostTP3PC) {
// If third party cookies are blocked, set the suppressed reason as
// kThirdPartyCookiesBlocked and return kNone.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kBlockAll3pcToggleEnabledUserPrefValue, true},
{kTrackingProtection3pcdEnabledUserPrefValue, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(
PromptSuppressedReason::kThirdPartyCookiesBlocked)}});
histogram_tester_.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1PromptTest, ThirdPartyCookiesBlockedPreTP3PC) {
// If third party cookies are blocked, set the suppressed reason as
// kThirdPartyCookiesBlocked and return kNone.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kCookieControlsModeUserPrefValue,
content_settings::CookieControlsMode::kBlockThirdParty},
{kTrackingProtection3pcdEnabledUserPrefValue, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(
PromptSuppressedReason::kThirdPartyCookiesBlocked)}});
histogram_tester_.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1PromptTest, RestrictedPrompt) {
base::HistogramTester histogram_tester;
// If the Privacy Sandbox is restricted, no prompt is shown.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kIsRestrictedAccount, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kRestricted)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
// After being restricted, even if the restriction is removed, no prompt
// should be shown. No call should even need to be made to see if the
// sandbox is still restricted.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kRestricted)},
{kIsRestrictedAccount, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kRestricted)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 2);
}
class PrivacySandboxServiceM1ConsentPromptTest
: public PrivacySandboxServiceM1PromptTest {};
TEST_F(PrivacySandboxServiceM1ConsentPromptTest, SuppressedConsent) {
// A case that will normally show a consent will not if there is any
// suppression reason.
for (int suppressed_reason = static_cast<int>(PromptSuppressedReason::kNone);
suppressed_reason <= static_cast<int>(PromptSuppressedReason::kMaxValue);
++suppressed_reason) {
bool suppressed =
suppressed_reason != static_cast<int>(PromptSuppressedReason::kNone);
auto expected_prompt =
suppressed ? PromptType::kNone : PromptType::kM1Consent;
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason, suppressed_reason},
{kIsRestrictedAccount, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(expected_prompt)},
{kM1PromptSuppressedReason, suppressed_reason}});
histogram_tester_.ExpectBucketCount(
kPromptMigrationHistogram, PromptTypeCombination::kPSConsent_NSConsent,
1);
}
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest, TrialsConsentDeclined) {
// If a previous consent decision was made to decline privacy sandbox, set
// kTrialsConsentDeclined as suppressed reason and return kNone.
// Now that the trials pref is deprecated users won't be able to enter that
// state. Users who had the prompt suppressed due to declining the trials
// consent should remain in this state.
RunTestCase(
TestState{
{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kTrialsConsentDeclined)},
{kTrialsConsentDecisionMade, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{
{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kTrialsConsentDeclined)}});
histogram_tester_.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest, M1ConsentDecisionNotMade) {
// If m1 consent required, and decision has not been made, return
// kM1Consent.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1ConsentDecisionPreviouslyMade, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kM1Consent)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester_.ExpectBucketCount(
kPromptMigrationHistogram, PromptTypeCombination::kPSConsent_NSConsent,
1);
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
M1ConsentDecisionMadeAndEEANoticeNotAcknowledged) {
// If m1 consent decision has been made and the eea notice has not been
// acknowledged, return kM1NoticeEEA.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1ConsentDecisionPreviouslyMade, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kM1NoticeEEA)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester_.ExpectBucketCount(
kPromptMigrationHistogram,
PromptTypeCombination::kPSNoticeEEA_NSNoticeEEA, 1);
}
TEST_F(PrivacySandboxServiceTest,
UserMigratesToEEAAfterRowAckWithNoticeServiceEnabled) {
feature_list()->InitAndEnableFeature(
privacy_sandbox::kPrivacySandboxGetPromptFromNoticeService);
// User starts in ROW.
MoveToROW();
// A ROW notice is shown.
RunTestCase(
TestState{}, TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kM1NoticeROW)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
// User acknowledges the notice.
RunTestCase(TestState{},
TestInput{{kForceChromeBuild, true},
{kPromptAction, static_cast<int>(kNoticeAcknowledge)}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
// User moves to EEA.
MoveToEEA();
// A consent prompt should be shown.
RunTestCase(
TestState{}, TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kM1Consent)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
}
TEST_F(PrivacySandboxServiceTest,
UserMigratesToEEAAfterRowAckWithNoticeServiceDisabled) {
feature_list()->InitAndDisableFeature(
privacy_sandbox::kPrivacySandboxGetPromptFromNoticeService);
// User starts in ROW.
MoveToROW();
// A ROW notice is shown.
RunTestCase(
TestState{}, TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kM1NoticeROW)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
// User acknowledges the notice.
RunTestCase(TestState{},
TestInput{{kForceChromeBuild, true},
{kPromptAction, static_cast<int>(kNoticeAcknowledge)}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
// User moves to EEA.
MoveToEEA();
// A consent prompt should be shown, but isn't. This is a known bug in the PS
// implementation. The fix is to be deployed using the
// kPrivacySandboxGetPromptFromNoticeService above.
RunTestCase(TestState{}, TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
M1ConsentDecisionMadeAndEEANoticeAcknowledged) {
// If m1 consent decision has been made and the eea notice has been
// acknowledged, return kNone.
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1ConsentDecisionPreviouslyMade, true},
{kM1EEANoticePreviouslyAcknowledged, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester_.ExpectUniqueSample(
kPromptMigrationHistogram, PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest, ROWNoticeAckTopicsDisabled) {
// If the user saw the ROW notice, and then disable Topics from settings, and
// is now in EEA, they should not see a prompt.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1RowNoticePreviouslyAcknowledged, true},
{kM1TopicsEnabledUserPrefValue, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{
{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(
PromptSuppressedReason::
kROWFlowCompletedAndTopicsDisabledBeforeEEAMigration)}});
histogram_tester_.ExpectUniqueSample(
kPromptMigrationHistogram, PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest, PromptAction_ConsentAccepted) {
// Confirm that when the service is informed that the consent prompt was
// accepted, it correctly adjusts the Privacy Sandbox prefs.
RunTestCase(
TestState{{kActiveTopicsConsent, false},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{{kPromptAction, static_cast<int>(kConsentAccepted)}},
TestOutput{
{kM1ConsentDecisionMade, true},
{kM1TopicsEnabled, true},
{kTopicsConsentGiven, true},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kConfirmation},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsConfirmationStringIdentifiers()}});
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest, PromptAction_ConsentDeclined) {
// Confirm that when the service is informed that the consent prompt was
// declined, it correctly adjusts the Privacy Sandbox prefs.
RunTestCase(
TestState{{kActiveTopicsConsent, true},
{kAdvanceClockBy, base::Hours(1)}},
TestInput{{kPromptAction, static_cast<int>(kConsentDeclined)}},
TestOutput{
{kM1ConsentDecisionMade, true},
{kM1TopicsEnabled, false},
{kTopicsConsentGiven, false},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kConfirmation},
{kTopicsConsentLastUpdateTime, base::Time::Now() + base::Hours(1)},
{kTopicsConsentStringIdentifiers,
GetTopicsConfirmationStringIdentifiers()}});
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
PromptAction_EEANoticeAcknowledged) {
// Confirm that when the service is informed that the eea notice was
// acknowledged, it correctly adjusts the Privacy Sandbox prefs.
RunTestCase(TestState{{kM1ConsentDecisionPreviouslyMade, true},
{kM1EEANoticePreviouslyAcknowledged, false}},
TestInput{{kPromptAction, static_cast<int>(kNoticeAcknowledge)}},
TestOutput{{kM1EEANoticeAcknowledged, true},
{kM1FledgeEnabled, true},
{kM1AdMeasurementEnabled, true}});
RunTestCase(
TestState{{kM1ConsentDecisionPreviouslyMade, true},
{kM1EEANoticePreviouslyAcknowledged, false}},
TestInput{{kPromptAction, static_cast<int>(kNoticeOpenSettings)}},
TestOutput{{kM1EEANoticeAcknowledged, true},
{kM1FledgeEnabled, true},
{kM1AdMeasurementEnabled, true},
{kTopicsConsentGiven, false},
{kTopicsConsentLastUpdateReason,
privacy_sandbox::TopicsConsentUpdateSource::kDefaultValue}});
}
TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
PromptAction_EEANoticeAcknowledged_ROWNoticeAcknowledged) {
// Confirm that if the user has already acknowledged an ROW notice, that the
// EEA notice does not attempt to re-enable APIs. This is important for the
// ROW -> EEA upgrade flow, where the user may have already visited settings.
RunTestCase(TestState{{kM1ConsentDecisionPreviouslyMade, true},
{kM1EEANoticePreviouslyAcknowledged, false},
{kM1RowNoticePreviouslyAcknowledged, true}},
TestInput{{kPromptAction, static_cast<int>(kNoticeAcknowledge)}},
TestOutput{{kM1EEANoticeAcknowledged, true},
{kM1FledgeEnabled, false},
{kM1AdMeasurementEnabled, false}});
}
class PrivacySandboxServiceM1NoticePromptTest
: public PrivacySandboxServiceM1PromptTest {
public:
void InitializeFeaturesBeforeStart() override {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName,
"false"},
{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName,
"true"}});
}
};
TEST_F(PrivacySandboxServiceM1NoticePromptTest, SuppressedNotice) {
// A case that will normally show a notice will not if there is any
// suppression reason.
for (int suppressed_reason = static_cast<int>(PromptSuppressedReason::kNone);
suppressed_reason <= static_cast<int>(PromptSuppressedReason::kMaxValue);
++suppressed_reason) {
bool suppressed =
suppressed_reason != static_cast<int>(PromptSuppressedReason::kNone);
auto expected_prompt =
suppressed ? PromptType::kNone : PromptType::kM1NoticeROW;
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason, suppressed_reason}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(expected_prompt)},
{kM1PromptSuppressedReason, suppressed_reason}});
}
}
TEST_F(PrivacySandboxServiceM1NoticePromptTest, TrialsDisabledAfterNotice) {
// If a previous notice was shown and then privacy sandbox was disabled after,
// set kTrialsDisabledAfterNotice as suppressed reason and return kNone.
// Now that the trials pref is deprecated users won't be able to enter that
// state. Users who had the prompt suppressed due to declining the trials
// consent should remain in this state.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(
PromptSuppressedReason::kTrialsDisabledAfterNotice)},
{kTrialsNoticeDisplayed, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(
PromptSuppressedReason::kTrialsDisabledAfterNotice)}});
histogram_tester_.ExpectUniqueSample(
kPromptMigrationHistogram, PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1NoticeNotAcknowledged) {
base::HistogramTester histogram_tester;
// If m1 notice required, and the row notice has not been acknowledged, return
// kM1NoticeROW.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1RowNoticePreviouslyAcknowledged, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kM1NoticeROW)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(
kPromptMigrationHistogram,
PromptTypeCombination::kPSNoticeROW_NSNoticeROW, 1);
}
TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1NoticeAcknowledged) {
base::HistogramTester histogram_tester;
// If m1 notice required, and the row notice has been acknowledged, return
// kNone.
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1RowNoticePreviouslyAcknowledged, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1EEAFlowInterrupted) {
base::HistogramTester histogram_tester;
// If a user has migrated from EEA to ROW and has already completed the eea
// consent but not yet acknowledged the notice, return kM1NoticeROW.
// If the notice is served from the NoticeService, this will return
// kM1NoticeEEA as Topics doesn't need to be re acked.
PromptType expected =
base::FeatureList::IsEnabled(
privacy_sandbox::kPrivacySandboxGetPromptFromNoticeService)
? PromptType::kM1NoticeEEA
: PromptType::kM1NoticeROW;
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1ConsentDecisionPreviouslyMade, true},
{kM1EEANoticePreviouslyAcknowledged, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(expected)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
// The Histogram Mismatch here is known, and is expected. This is because
// Topics is already addressed in a previous notice, and the Notice Service
// will not include notices that would present it again.
histogram_tester.ExpectBucketCount(
kPromptMigrationHistogram,
PromptTypeCombination::kPSNoticeROW_NSNoticeEEA, 1);
}
TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1EEAFlowCompleted) {
base::HistogramTester histogram_tester;
// If a user has migrated from EEA to ROW and has already completed the eea
// flow, set kEEAFlowCompleted as suppressed reason return kNone.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1ConsentDecisionPreviouslyMade, true},
{kM1EEANoticePreviouslyAcknowledged, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{
{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(
PromptSuppressedReason::kEEAFlowCompletedBeforeRowMigration)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1NoticePromptTest,
PromptAction_RowNoticeAcknowledged) {
// Confirm that when the service is informed that the row notice was
// acknowledged, it correctly adjusts the Privacy Sandbox prefs.
RunTestCase(TestState{},
TestInput{{kPromptAction, static_cast<int>(kNoticeAcknowledge)}},
TestOutput{{kM1RowNoticeAcknowledged, true},
{kM1TopicsEnabled, true},
{kM1FledgeEnabled, true},
{kM1AdMeasurementEnabled, true},
{kTopicsConsentGiven, false}});
}
TEST_F(PrivacySandboxServiceM1NoticePromptTest, PromptAction_OpenSettings) {
// Confirm that when the service is informed that the row notice was
// acknowledged, it correctly adjusts the Privacy Sandbox prefs.
RunTestCase(TestState{},
TestInput{{kPromptAction, static_cast<int>(kNoticeOpenSettings)}},
TestOutput{{kM1RowNoticeAcknowledged, true},
{kM1TopicsEnabled, true},
{kM1FledgeEnabled, true},
{kM1AdMeasurementEnabled, true},
{kTopicsConsentGiven, false}});
}
TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxPromptPolicy) {
base::HistogramTester histogram_tester;
// Disable the prompt via policy and check the returned prompt type is kNone.
RunTestCase(TestState{{kM1PromptDisabledByPolicy,
static_cast<int>(PromptSuppressedReason::kPolicy)}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxTopicsPolicy) {
base::HistogramTester histogram_tester;
// Disable the Topics api via policy and check the returned prompt type is
// kNone and topics is not allowed.
RunTestCase(TestState{{kM1TopicsDisabledByPolicy, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kIsTopicsAllowed, false}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxFledgePolicy) {
base::HistogramTester histogram_tester;
// Disable the Fledge api via policy and check the returned prompt type is
// kNone and fledge is not allowed.
RunTestCase(TestState{{kM1FledgeDisabledByPolicy, true}},
TestInput{{kForceChromeBuild, true},
{kTopFrameOrigin,
url::Origin::Create(GURL("https://top-frame.com"))},
{kFledgeAuctionPartyOrigin,
url::Origin::Create(GURL("https://embedded.com"))}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kIsFledgeJoinAllowed, false}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxAdMeasurementPolicy) {
base::HistogramTester histogram_tester;
// Disable the ad measurement api via policy and check the returned prompt
// type is kNone and the api is not allowed.
RunTestCase(TestState{{kM1AdMesaurementDisabledByPolicy, true}},
TestInput{{kTopFrameOrigin,
url::Origin::Create(GURL("https://top-frame.com"))},
{kAdMeasurementReportingOrigin,
url::Origin::Create(GURL("https://embedded.com"))},
{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kIsAttributionReportingAllowed, false}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
// TODO(crbug.com/40262246): consider parameterizing other tests for the various
// feature flags, particularly `kPrivacySandboxSettings4RestrictedNotice`.
class PrivacySandboxServiceM1RestrictedNoticePromptTest
: public PrivacySandboxServiceM1PromptTest {
public:
std::unique_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
CreateMockDelegate() override {
auto mock_delegate = std::make_unique<testing::NiceMock<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>>();
mock_delegate->SetUpIsSubjectToM1NoticeRestrictedResponse(
/*is_subject_to_restricted_notice=*/true);
return mock_delegate;
}
void InitializeFeaturesBeforeStart() override {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName,
"false"},
{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"},
{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
}
};
TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest, RestrictedNotice) {
base::HistogramTester histogram_tester;
// Ensure that kM1NoticeRestricted is returned when configured to do so.
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kTrialsNoticeDisplayed, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType,
static_cast<int>(PromptType::kM1NoticeRestricted)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(
kPromptMigrationHistogram,
PromptTypeCombination::kPSNoticeRestricted_NSNoticeRestricted, 1);
}
TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
RestrictedNoticeAlreadyAcknowledged) {
base::HistogramTester histogram_tester;
// If the user already acknowledged the notice, don't show it, or the ROW
// notice, again.
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kTrialsNoticeDisplayed, false},
{kM1RestrictedNoticePreviouslyAcknowledged, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
ROWNoticeAlreadyAcknowledged) {
base::HistogramTester histogram_tester;
// If the user already acknowledged a different notice, don't show it again.
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kTrialsNoticeDisplayed, false},
{kM1RowNoticePreviouslyAcknowledged, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
EEANoticeAlreadyAcknowledged) {
base::HistogramTester histogram_tester;
// If the user already acknowledged a different notice, don't show the
// restricted notice again. Ensure the existing suppression reason is
// respected.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kTrialsNoticeDisplayed, false},
{kM1ConsentDecisionPreviouslyMade, true},
{kM1EEANoticePreviouslyAcknowledged, true}},
TestInput{{kForceChromeBuild, true}},
TestOutput{
{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(
PromptSuppressedReason::kEEAFlowCompletedBeforeRowMigration)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed) {
base::HistogramTester histogram_tester;
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
// Ensure prompt not suppressed.
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNone));
base::test::ScopedFeatureList feature_list_notice_required;
std::map<std::string, std::string> notice_required_feature_param = {
{std::string(
privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName),
"false"},
{std::string(privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName),
"true"}};
feature_list_notice_required.InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4, notice_required_feature_param);
// Notice flow not completed.
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
false);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticePromptWaiting),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticePromptWaiting),
/*expected_count=*/1);
// Notice flow completed.
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeFlowCompleted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeFlowCompleted),
/*expected_count=*/1);
// ROW flow completed, which implies no restricted prompt.
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
false);
prefs()->SetBoolean(prefs::kPrivacySandboxM1RowNoticeAcknowledged, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeNotShownDueToFullNoticeAcknowledged),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeNotShownDueToFullNoticeAcknowledged),
/*expected_count=*/1);
// EAA flow completed, which implies no restricted prompt.
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
false);
prefs()->SetBoolean(prefs::kPrivacySandboxM1EEANoticeAcknowledged, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeNotShownDueToFullNoticeAcknowledged),
// One when the ROW notice acknowledged pref was set, plus the latest
// call.
/*expected_count=*/2);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeNotShownDueToFullNoticeAcknowledged),
/*expected_count=*/2);
}
class PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted
: public PrivacySandboxServiceM1RestrictedNoticePromptTest {
public:
std::unique_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
CreateMockDelegate() override {
auto mock_delegate = std::make_unique<testing::NiceMock<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>>();
mock_delegate->SetUpIsSubjectToM1NoticeRestrictedResponse(
/*is_subject_to_restricted_notice=*/true);
mock_delegate->SetUpIsPrivacySandboxCurrentlyUnrestrictedResponse(
/*is_unrestricted=*/true);
return mock_delegate;
}
void InitializeFeaturesBeforeStart() override {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName,
"false"},
{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"},
{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
}
};
TEST_F(PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted,
RecordPrivacySandbox4StartupMetrics_GraduationFlow) {
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
// Ensure prompt not suppressed.
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNone));
// Restricted Notice flow NOT completed
{
base::HistogramTester histogram_tester;
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
false);
// User was reported restricted
prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kWaitingForGraduationRestrictedNoticeFlowNotCompleted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kWaitingForGraduationRestrictedNoticeFlowNotCompleted),
/*expected_count=*/1);
}
// Restricted Notice flow completed
{
base::HistogramTester histogram_tester;
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
true);
// User was reported restricted
prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kWaitingForGraduationRestrictedNoticeFlowCompleted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kWaitingForGraduationRestrictedNoticeFlowCompleted),
/*expected_count=*/1);
}
}
TEST_F(
PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted,
RecordPrivacySandbox4StartupMetrics_GraduationFlowWhenNoticeShownToGuardian) {
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
base::HistogramTester histogram_tester;
// User was reported restricted
prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
// Prompt is suppressed because direct notice was shown to guardian
prefs()->SetInteger(
prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNoticeShownToGuardian));
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kWaitingForGraduationRestrictedNoticeFlowNotCompleted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(
PrivacySandboxServiceImpl::PromptStartupState::
kWaitingForGraduationRestrictedNoticeFlowNotCompleted),
/*expected_count=*/1);
}
class PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyRestricted
: public PrivacySandboxServiceM1RestrictedNoticePromptTest {
public:
std::unique_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
CreateMockDelegate() override {
auto mock_delegate = std::make_unique<testing::NiceMock<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>>();
mock_delegate->SetUpIsSubjectToM1NoticeRestrictedResponse(
/*is_subject_to_restricted_notice=*/true);
mock_delegate->SetUpIsPrivacySandboxCurrentlyUnrestrictedResponse(
/*is_unrestricted=*/false);
return mock_delegate;
}
void InitializeFeaturesBeforeStart() override {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName,
"false"},
{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"},
{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
}
};
TEST_F(PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyRestricted,
RecordPrivacySandbox4StartupMetrics_GraduationFlow) {
const std::string privacy_sandbox_prompt_startup_histogram =
"Settings.PrivacySandbox.PromptStartupState";
const std::string privacy_sandbox_prompt_startup_histogram_profile_level =
"Settings.PrivacySandbox.Profile_1.PromptStartupState";
// Ensure prompt not suppressed.
prefs()->SetInteger(prefs::kPrivacySandboxM1PromptSuppressed,
static_cast<int>(PromptSuppressedReason::kNone));
// Restricted Notice flow completed
{
base::HistogramTester histogram_tester;
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
true);
// User was reported restricted
prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeFlowCompleted),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticeFlowCompleted),
/*expected_count=*/1);
}
// Restricted Notice flow NOT completed
{
base::HistogramTester histogram_tester;
prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
false);
// User was reported restricted
prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticePromptWaiting),
/*expected_count=*/1);
histogram_tester.ExpectBucketCount(
privacy_sandbox_prompt_startup_histogram_profile_level,
static_cast<int>(PrivacySandboxServiceImpl::PromptStartupState::
kRestrictedNoticePromptWaiting),
/*expected_count=*/1);
}
}
TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
RestrictedNoticeAcknowledged) {
base::HistogramTester histogram_tester;
// Ensure that Ad measurement pref is not re-enabled if user disabled it
// after acknowledging the restricted notice.
RunTestCase(TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kM1RestrictedNoticePreviouslyAcknowledged, true},
{kM1AdMeasurementEnabledUserPrefValue, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1AdMeasurementEnabled, false},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
class PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest
: public PrivacySandboxServiceM1PromptTest {
public:
std::unique_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
CreateMockDelegate() override {
auto mock_delegate = std::make_unique<testing::NiceMock<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>>();
mock_delegate->SetUpIsPrivacySandboxRestrictedResponse(
/*restricted=*/true);
return mock_delegate;
}
void InitializeFeaturesBeforeStart() override {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName,
"false"},
{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"},
{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
}
};
TEST_F(PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest,
NotSubjectToNoticeButIsRestricted) {
base::HistogramTester histogram_tester;
// Ensure that kNoticeShownToGuardian, with no prompt, is returned in the
// event that the user is not subject to the m1 notice restricted prompt.
// Ensure measurements API is enabled for these users.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kTrialsNoticeDisplayed, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{
{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNoticeShownToGuardian)},
{kM1AdMeasurementEnabled, true}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
TEST_F(PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest,
NotSubjectToNoticeButIsRestrictedWithAdMeasurementDisabled) {
base::HistogramTester histogram_tester;
// Ensure that Ad measurement pref is not re-enabled if user disabled it
// after the notice was suppressed due to kNoticeShownToGuardian.
RunTestCase(
TestState{
{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNoticeShownToGuardian)},
{kM1AdMeasurementEnabledUserPrefValue, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{
{kPromptType, static_cast<int>(PromptType::kNone)},
{kM1AdMeasurementEnabled, false},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNoticeShownToGuardian)}});
histogram_tester.ExpectBucketCount(kPromptMigrationHistogram,
PromptTypeCombination::kPSNone_NSNone, 1);
}
class PrivacySandboxServiceM1RestrictedNoticeEnabledNoRestrictionsTest
: public PrivacySandboxServiceM1PromptTest {
public:
std::unique_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
CreateMockDelegate() override {
auto mock_delegate = std::make_unique<testing::NiceMock<
privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>>();
mock_delegate->SetUpIsPrivacySandboxRestrictedResponse(
/*restricted=*/false);
mock_delegate->SetUpIsSubjectToM1NoticeRestrictedResponse(
/*is_subject_to_restricted_notice=*/false);
return mock_delegate;
}
void InitializeFeaturesBeforeStart() override {
feature_list()->InitAndEnableFeatureWithParameters(
privacy_sandbox::kPrivacySandboxSettings4,
{{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName,
"false"},
{privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"},
{privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName,
"true"}});
}
};
TEST_F(PrivacySandboxServiceM1RestrictedNoticeEnabledNoRestrictionsTest,
VerifyPromptType) {
base::HistogramTester histogram_tester;
// The restricted notice feature is enabled, but the account is not subject to
// the restrictions, and the privacy sandbox is not otherwise restricted. The
// ROW notice is still applicable, however.
RunTestCase(
TestState{{kM1PromptPreviouslySuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)},
{kTrialsNoticeDisplayed, false}},
TestInput{{kForceChromeBuild, true}},
TestOutput{{kPromptType, static_cast<int>(PromptType::kM1NoticeROW)},
{kM1PromptSuppressedReason,
static_cast<int>(PromptSuppressedReason::kNone)}});
histogram_tester.ExpectBucketCount(
kPromptMigrationHistogram,
PromptTypeCombination::kPSNoticeROW_NSNoticeROW, 1);
}
class PrivacySandboxNoticeFrameworkResultCallbackUnitTest
: public PrivacySandboxServiceTest,
public testing::WithParamInterface<bool> {};
TEST_P(PrivacySandboxNoticeFrameworkResultCallbackUnitTest,
UpdateTopicsApiResult_UpdatesCorrectly) {
privacy_sandbox_service()->UpdateTopicsApiResult(GetParam());
EXPECT_EQ(GetParam(),
prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled));
}
TEST_P(PrivacySandboxNoticeFrameworkResultCallbackUnitTest,
UpdateProtectedAudienceApiResult_UpdatesCorrectly) {
privacy_sandbox_service()->UpdateProtectedAudienceApiResult(GetParam());
EXPECT_EQ(GetParam(),
prefs()->GetBoolean(prefs::kPrivacySandboxM1FledgeEnabled));
}
TEST_P(PrivacySandboxNoticeFrameworkResultCallbackUnitTest,
UpdateMeasurementApiResult_UpdatesCorrectly) {
privacy_sandbox_service()->UpdateMeasurementApiResult(GetParam());
EXPECT_EQ(GetParam(),
prefs()->GetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled));
}
INSTANTIATE_TEST_SUITE_P(PrivacySandboxNoticeFrameworkResultCallbackUnitTest,
PrivacySandboxNoticeFrameworkResultCallbackUnitTest,
testing::Bool());
class PrivacySandboxNoticeFrameworkEligibilityTest
: public PrivacySandboxServiceTest {};
TEST_F(PrivacySandboxNoticeFrameworkEligibilityTest, EligibilityCallbacks) {
// TODO(crbug.com/408017260): These are currently placeholders. Update tests
// when real eligibility logic is implemented.
EXPECT_EQ(privacy_sandbox_service()->GetTopicsApiEligibility(),
EligibilityLevel::kNotEligible);
EXPECT_EQ(privacy_sandbox_service()->GetProtectedAudienceApiEligibility(),
EligibilityLevel::kNotEligible);
EXPECT_EQ(privacy_sandbox_service()->GetAdMeasurementApiEligibility(),
EligibilityLevel::kNotEligible);
}