| // 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 "base/containers/to_vector.h" |
| #include "base/feature_list.h" |
| #include "base/json/values_util.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 "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/privacy_sandbox_settings_factory.h" |
| #include "chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/test/base/scoped_testing_local_state.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.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/metrics/metrics_pref_names.h" |
| #include "components/policy/core/common/mock_policy_service.h" |
| #include "components/policy/policy_constants.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_notice_constants.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_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 "chromeos/components/kiosk/kiosk_test_utils.h" |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #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 "components/user_manager/fake_user_manager.h" |
| #include "components/user_manager/scoped_user_manager.h" |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| #include "chromeos/crosapi/mojom/crosapi.mojom.h" |
| #include "chromeos/startup/browser_init_params.h" |
| #endif |
| |
| namespace { |
| using ::browsing_topics::Topic; |
| using ::privacy_sandbox::CanonicalTopic; |
| using ::testing::ElementsAre; |
| using PromptAction = ::PrivacySandboxService::PromptAction; |
| using PromptSuppressedReason = ::PrivacySandboxService::PromptSuppressedReason; |
| using PromptType = ::PrivacySandboxService::PromptType; |
| using SurfaceType = ::PrivacySandboxService::SurfaceType; |
| |
| #if BUILDFLAG(IS_ANDROID) |
| using ActivityType = PrivacySandboxService::PrivacySandboxStorageActivityType; |
| using UserSegment = |
| PrivacySandboxService::PrivacySandboxStorageUserSegmentByRecentActivity; |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| using enum privacy_sandbox_test_util::StateKey; |
| using enum privacy_sandbox_test_util::InputKey; |
| using enum privacy_sandbox_test_util::OutputKey; |
| |
| using privacy_sandbox_test_util::InputKey; |
| using privacy_sandbox_test_util::OutputKey; |
| using privacy_sandbox_test_util::StateKey; |
| |
| 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 base::Version kFirstPartySetsVersion("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_IN_MIGRATION(); |
| } |
| 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_IN_MIGRATION(); |
| } |
| |
| private: |
| std::vector<InterestGroupDataKey> data_keys_; |
| }; |
| |
| // Remove any user preference settings for First Party Set related preferences, |
| // returning them to their default value. |
| void ClearFpsUserPrefs( |
| sync_preferences::TestingPrefServiceSyncable* pref_service) { |
| pref_service->RemoveUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled); |
| pref_service->RemoveUserPref( |
| prefs::kPrivacySandboxFirstPartySetsDataAccessAllowedInitialized); |
| } |
| |
| 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, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_DISABLED, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_1, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_2, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_EMPTY, |
| 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, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_DISABLED, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_1, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_2, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION, |
| 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, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_1, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_2, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION, |
| 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, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_1, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_2, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_EMPTY, |
| 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, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_1, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_2, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION, |
| 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, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_1, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_2, |
| IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3_CANONICAL, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_HEADING, |
| IDS_SETTINGS_TOPICS_PAGE_BLOCKED_TOPICS_DESCRIPTION_EMPTY, |
| IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL}; |
| } |
| |
| NOTREACHED_IN_MIGRATION() << "Invalid topics settings consent state"; |
| return {}; |
| } |
| |
| 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 |
| |
| class PrivacySandboxServiceTest : public testing::Test { |
| public: |
| PrivacySandboxServiceTest() |
| : browser_task_environment_( |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME), |
| scoped_attestations_( |
| privacy_sandbox::PrivacySandboxAttestations::CreateForTesting()) { |
| notice_storage_ = |
| std::make_unique<privacy_sandbox::PrivacySandboxNoticeStorage>(); |
| } |
| |
| 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(); |
| } |
| |
| virtual void InitializeFeaturesBeforeStart() {} |
| |
| 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; |
| } |
| |
| void CreateService() { |
| auto mock_delegate = CreateMockDelegate(); |
| mock_delegate_ = mock_delegate.get(); |
| |
| privacy_sandbox_settings_ = |
| std::make_unique<privacy_sandbox::PrivacySandboxSettingsImpl>( |
| std::move(mock_delegate), host_content_settings_map(), |
| cookie_settings(), tracking_protection_settings(), prefs()); |
| #if !BUILDFLAG(IS_ANDROID) |
| mock_sentiment_service_ = |
| std::make_unique<::testing::NiceMock<MockTrustSafetySentimentService>>( |
| profile()); |
| #endif |
| privacy_sandbox_service_ = std::make_unique<PrivacySandboxServiceImpl>( |
| privacy_sandbox_settings(), tracking_protection_settings(), |
| cookie_settings(), profile()->GetPrefs(), test_interest_group_manager(), |
| GetProfileType(), browsing_data_remover(), host_content_settings_map(), |
| #if !BUILDFLAG(IS_ANDROID) |
| mock_sentiment_service(), |
| #endif |
| mock_browsing_topics_service(), first_party_sets_policy_service()); |
| } |
| |
| virtual profile_metrics::BrowserProfileType GetProfileType() { |
| return profile_metrics::BrowserProfileType::kRegular; |
| } |
| |
| 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)); |
| } |
| |
| TestingProfile* profile() { return &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_; |
| } |
| content::BrowserTaskEnvironment* browser_task_environment() { |
| return &browser_task_environment_; |
| } |
| #if !BUILDFLAG(IS_ANDROID) |
| MockTrustSafetySentimentService* mock_sentiment_service() { |
| return mock_sentiment_service_.get(); |
| } |
| #endif |
| |
| protected: |
| base::HistogramTester histogram_tester; |
| std::unique_ptr<privacy_sandbox::PrivacySandboxNoticeStorage> notice_storage_; |
| |
| private: |
| content::BrowserTaskEnvironment browser_task_environment_; |
| |
| TestingProfile profile_; |
| base::test::ScopedFeatureList outer_feature_list_; |
| base::test::ScopedFeatureList inner_feature_list_; |
| TestInterestGroupManager test_interest_group_manager_; |
| browsing_topics::MockBrowsingTopicsService mock_browsing_topics_service_; |
| raw_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate, |
| DanglingUntriaged> |
| mock_delegate_; |
| |
| first_party_sets::ScopedMockFirstPartySetsHandler |
| mock_first_party_sets_handler_; |
| first_party_sets::FirstPartySetsPolicyService |
| first_party_sets_policy_service_ = |
| first_party_sets::FirstPartySetsPolicyService( |
| profile_.GetOriginalProfile()); |
| #if !BUILDFLAG(IS_ANDROID) |
| std::unique_ptr<MockTrustSafetySentimentService> mock_sentiment_service_; |
| #endif |
| std::unique_ptr<privacy_sandbox::PrivacySandboxSettings> |
| privacy_sandbox_settings_; |
| privacy_sandbox::ScopedPrivacySandboxAttestations scoped_attestations_; |
| |
| std::unique_ptr<PrivacySandboxServiceImpl> privacy_sandbox_service_; |
| }; |
| |
| 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(3u, returned_sites.size()); |
| 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(2u, returned_sites.size()); |
| EXPECT_EQ(returned_sites[0], sites[1]); |
| EXPECT_EQ(returned_sites[1], sites[2]); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, HistogramsAreEmptyOnStartup) { |
| const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); |
| for (const auto& notice_name : privacy_sandbox::kPrivacySandboxNoticeNames) { |
| EXPECT_THAT( |
| histograms, |
| testing::Not(testing::AnyOf(base::StrCat( |
| {"PrivacySandbox.Notice.NoticeStartupState.", notice_name})))); |
| } |
| } |
| |
| 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(PromptAction::kNoticeShown, |
| SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.Shown")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kNoticeOpenSettings, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.OpenedSettings")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kNoticeAcknowledge, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.Acknowledged")); |
| |
| privacy_sandbox_service()->PromptActionOccurred(PromptAction::kNoticeDismiss, |
| SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.Dismissed")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kNoticeClosedNoInteraction, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.ClosedNoInteraction")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kNoticeLearnMore, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.LearnMore")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kNoticeMoreInfoOpened, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.LearnMoreExpanded")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kNoticeMoreInfoClosed, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.LearnMoreClosed")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentMoreButtonClicked, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Consent.MoreButtonClicked")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kNoticeMoreButtonClicked, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Notice.MoreButtonClicked")); |
| |
| feature_list()->Reset(); |
| feature_list()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxSettings4, |
| {{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName, "true"}}); |
| |
| privacy_sandbox_service()->PromptActionOccurred(PromptAction::kConsentShown, |
| SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Consent.Shown")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentAccepted, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Consent.Accepted")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentDeclined, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Consent.Declined")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentMoreInfoOpened, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Consent.LearnMoreExpanded")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentMoreInfoClosed, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Consent.LearnMoreClosed")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentClosedNoDecision, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.Consent.ClosedNoInteraction")); |
| |
| feature_list()->Reset(); |
| feature_list()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxSettings4, |
| {{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName, "true"}, |
| {privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName, |
| "true"}}); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kRestrictedNoticeOpenSettings, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.RestrictedNotice.OpenedSettings")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kRestrictedNoticeAcknowledge, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.RestrictedNotice.Acknowledged")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kRestrictedNoticeShown, SurfaceType::kDesktop); |
| EXPECT_EQ(1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.RestrictedNotice.Shown")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kRestrictedNoticeClosedNoInteraction, |
| SurfaceType::kDesktop); |
| EXPECT_EQ( |
| 1, user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.RestrictedNotice.ClosedNoInteraction")); |
| |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kRestrictedNoticeMoreButtonClicked, SurfaceType::kDesktop); |
| EXPECT_EQ(1, |
| user_action_tester.GetActionCount( |
| "Settings.PrivacySandbox.RestrictedNotice.MoreButtonClicked")); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, FledgeBlockDeletesData) { |
| // Allowing FLEDGE joining should not start a removal task. |
| privacy_sandbox_service()->SetFledgeJoiningAllowed("example.com", true); |
| EXPECT_EQ(0xffffffffffffffffull, // -1, indicates no last removal task. |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| |
| // When FLEDGE joining is blocked, a removal task should be started. |
| privacy_sandbox_service()->SetFledgeJoiningAllowed("example.com", false); |
| EXPECT_EQ(content::BrowsingDataRemover::DATA_TYPE_INTEREST_GROUPS, |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| EXPECT_EQ(base::Time::Min(), |
| browsing_data_remover()->GetLastUsedBeginTimeForTesting()); |
| EXPECT_EQ(content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, |
| browsing_data_remover()->GetLastUsedOriginTypeMaskForTesting()); |
| } |
| |
| 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(kNoRemovalTask, |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| |
| // Disabling should start delete topics data. |
| EXPECT_CALL(*mock_browsing_topics_service(), ClearAllTopicsData()).Times(1); |
| prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, false); |
| EXPECT_EQ(kNoRemovalTask, |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| } |
| |
| 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(kNoRemovalTask, |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| |
| // Disabling should start a task clearing all related information. |
| prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, false); |
| EXPECT_EQ( |
| content::BrowsingDataRemover::DATA_TYPE_INTEREST_GROUPS | |
| content::BrowsingDataRemover::DATA_TYPE_SHARED_STORAGE | |
| content::BrowsingDataRemover::DATA_TYPE_INTEREST_GROUPS_INTERNAL, |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| EXPECT_EQ(base::Time::Min(), |
| browsing_data_remover()->GetLastUsedBeginTimeForTesting()); |
| EXPECT_EQ(content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, |
| browsing_data_remover()->GetLastUsedOriginTypeMaskForTesting()); |
| } |
| |
| 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(kNoRemovalTask, |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| |
| // Disabling should start a task clearing all related information. |
| prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, false); |
| EXPECT_EQ( |
| content::BrowsingDataRemover::DATA_TYPE_ATTRIBUTION_REPORTING | |
| content::BrowsingDataRemover::DATA_TYPE_AGGREGATION_SERVICE | |
| content::BrowsingDataRemover::DATA_TYPE_PRIVATE_AGGREGATION_INTERNAL, |
| browsing_data_remover()->GetLastUsedRemovalMaskForTesting()); |
| EXPECT_EQ(base::Time::Min(), |
| browsing_data_remover()->GetLastUsedBeginTimeForTesting()); |
| EXPECT_EQ(content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, |
| browsing_data_remover()->GetLastUsedOriginTypeMaskForTesting()); |
| } |
| |
| 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(2u, topics.size()); |
| EXPECT_EQ(kFirstTopic, topics[0]); |
| EXPECT_EQ(kSecondTopic, topics[1]); |
| } |
| |
| 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(2u, blocked_topics.size()); |
| EXPECT_EQ(kFirstTopic, blocked_topics[0]); |
| EXPECT_EQ(kSecondTopic, blocked_topics[1]); |
| } |
| |
| 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(22u, first_level_topics.size()); |
| EXPECT_EQ(kFirstTopic, first_level_topics[0]); |
| EXPECT_EQ(kLastTopic, first_level_topics[21]); |
| } |
| |
| 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(2u, currently_assigned_child_topics.size()); |
| EXPECT_EQ(kIndirectChildTopic, currently_assigned_child_topics[0]); |
| EXPECT_EQ(kDirectChildTopic, currently_assigned_child_topics[1]); |
| } |
| |
| 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( |
| privacy_sandbox_settings(), |
| /*tracking_protection_settings=*/nullptr, cookie_settings(), |
| profile()->GetPrefs(), test_interest_group_manager(), |
| GetProfileType(), browsing_data_remover(), |
| host_content_settings_map(), |
| #if !BUILDFLAG(IS_ANDROID) |
| mock_sentiment_service(), |
| #endif |
| mock_browsing_topics_service(), first_party_sets_policy_service()); |
| }, |
| ""); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| FirstPartySetsNotRelevantMetricAllowedCookies) { |
| 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, |
| FirstPartySetsNotRelevantMetricBlockedCookies) { |
| 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, FirstPartySetsEnabledMetric) { |
| 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, FirstPartySetsDisabledMetric) { |
| 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, SampleFpsData) { |
| feature_list()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxFirstPartySetsUI, |
| {{"use-sample-sets", "true"}}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled, |
| std::make_unique<base::Value>(true)); |
| |
| EXPECT_EQ(u"google.com", |
| privacy_sandbox_service()->GetFirstPartySetOwnerForDisplay( |
| GURL("https://mail.google.com.au"))); |
| EXPECT_EQ(u"google.com", |
| privacy_sandbox_service()->GetFirstPartySetOwnerForDisplay( |
| GURL("https://youtube.com"))); |
| EXPECT_EQ(u"münchen.de", |
| privacy_sandbox_service()->GetFirstPartySetOwnerForDisplay( |
| GURL("https://muenchen.de"))); |
| EXPECT_EQ(std::nullopt, |
| privacy_sandbox_service()->GetFirstPartySetOwnerForDisplay( |
| GURL("https://example.com"))); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| GetFirstPartySetOwner_SimulatedFpsData_DisabledWhen3pcAllowed) { |
| GURL associate1_gurl("https://associate1.test"); |
| net::SchemefulSite primary_site(GURL("https://primary.test")); |
| net::SchemefulSite associate1_site(associate1_gurl); |
| |
| // Create Global First-Party Sets with the following set: |
| // { primary: "https://primary.test", |
| // associatedSites: ["https://associate1.test"} |
| net::GlobalFirstPartySets global_sets( |
| kFirstPartySetsVersion, |
| { |
| {primary_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, |
| std::nullopt)}}, |
| {associate1_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, |
| 0)}}, |
| }, |
| {}); |
| |
| // Simulate 3PC are allowed while: |
| // - FPS pref is enabled |
| // - FPS UI Feature is enabled |
| feature_list()->InitWithFeatures( |
| {privacy_sandbox::kPrivacySandboxFirstPartySetsUI}, {}); |
| CreateService(); |
| ClearFpsUserPrefs(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 FPS is disabled. |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl), |
| std::nullopt); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| GetFirstPartySetOwner_SimulatedFpsData_DisabledWhenAllCookiesBlocked) { |
| GURL associate1_gurl("https://associate1.test"); |
| net::SchemefulSite primary_site(GURL("https://primary.test")); |
| net::SchemefulSite associate1_site(associate1_gurl); |
| |
| // Create Global First-Party Sets with the following set: |
| // { primary: "https://primary.test", |
| // associatedSites: ["https://associate1.test"} |
| net::GlobalFirstPartySets global_sets( |
| kFirstPartySetsVersion, |
| { |
| {primary_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, |
| std::nullopt)}}, |
| {associate1_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, |
| 0)}}, |
| }, |
| {}); |
| |
| // Simulate all cookies are blocked while: |
| // - FPS pref is enabled |
| // - FPS UI Feature is enabled |
| feature_list()->InitWithFeatures( |
| {privacy_sandbox::kPrivacySandboxFirstPartySetsUI}, {}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK); |
| CreateService(); |
| ClearFpsUserPrefs(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 FPS is disabled. |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl), |
| std::nullopt); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| GetFirstPartySetOwner_SimulatedFpsData_DisabledByFpsUiFeature) { |
| GURL associate1_gurl("https://associate1.test"); |
| net::SchemefulSite primary_site(GURL("https://primary.test")); |
| net::SchemefulSite associate1_site(associate1_gurl); |
| |
| // Create Global First-Party Sets with the following set: |
| // { primary: "https://primary.test", |
| // associatedSites: ["https://associate1.test"} |
| net::GlobalFirstPartySets global_sets( |
| kFirstPartySetsVersion, |
| { |
| {primary_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, |
| std::nullopt)}}, |
| {associate1_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, |
| 0)}}, |
| }, |
| {}); |
| |
| // Simulate FPS UI feature disabled while: |
| // - FPS pref is enabled |
| // - 3PC are being blocked |
| feature_list()->InitWithFeatures( |
| {}, {privacy_sandbox::kPrivacySandboxFirstPartySetsUI}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| CreateService(); |
| ClearFpsUserPrefs(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 FPS is disabled. |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl), |
| std::nullopt); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| GetFirstPartySetOwner_SimulatedFpsData_DisabledByFpsPref) { |
| GURL associate1_gurl("https://associate1.test"); |
| net::SchemefulSite primary_site(GURL("https://primary.test")); |
| net::SchemefulSite associate1_site(associate1_gurl); |
| |
| // Create Global First-Party Sets with the following set: |
| // { primary: "https://primary.test", |
| // associatedSites: ["https://associate1.test"} |
| net::GlobalFirstPartySets global_sets( |
| kFirstPartySetsVersion, |
| { |
| {primary_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, |
| std::nullopt)}}, |
| {associate1_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, |
| 0)}}, |
| }, |
| {}); |
| |
| // Simulate FPS pref disabled while: |
| // - FPS UI Feature is enabled |
| // - 3PC are being blocked |
| feature_list()->InitWithFeatures( |
| {privacy_sandbox::kPrivacySandboxFirstPartySetsUI}, {}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| CreateService(); |
| ClearFpsUserPrefs(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 FPS is disabled. |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl), |
| std::nullopt); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| SimulatedFpsData_FpsEnabled_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 that fully enables the First-Party Sets for UI; blocking 3PC, |
| // and enabling the FPS UI feature and the FPS enabled pref. |
| feature_list()->InitWithFeatures( |
| {privacy_sandbox::kPrivacySandboxFirstPartySetsUI}, {}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| CreateService(); |
| ClearFpsUserPrefs(prefs()); |
| prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled, |
| std::make_unique<base::Value>(true)); |
| |
| // Verify `GetFirstPartySetOwner` returns empty if FPS is enabled but the |
| // Global sets are not ready yet. |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl), |
| std::nullopt); |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate2_gurl), |
| std::nullopt); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| SimulatedFpsData_FpsEnabled_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 that fully enables the First-Party Sets for UI; blocking 3PC, |
| // and enabling the FPS UI feature and the FPS enabled pref. |
| feature_list()->InitWithFeatures( |
| {privacy_sandbox::kPrivacySandboxFirstPartySetsUI}, {}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| CreateService(); |
| ClearFpsUserPrefs(prefs()); |
| prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled, |
| std::make_unique<base::Value>(true)); |
| |
| // Simulate that the Global First-Party Sets 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( |
| kFirstPartySetsVersion, |
| { |
| {primary_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, |
| std::nullopt)}}, |
| {associate1_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, |
| 0)}}, |
| {associate2_site, |
| {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, |
| 1)}}, |
| }, |
| {})); |
| |
| // Simulate that associate2 is removed from the Global First-Party Sets for |
| // this profile. |
| mock_first_party_sets_handler().SetContextConfig( |
| net::FirstPartySetsContextConfig( |
| {{net::SchemefulSite(GURL("https://associate2.test")), |
| net::FirstPartySetEntryOverride()}})); |
| |
| first_party_sets_policy_service()->InitForTesting(); |
| |
| // Verify that primary owns associate1, but no longer owns associate2. |
| EXPECT_EQ( |
| privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl).value(), |
| primary_site); |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate2_gurl), |
| std::nullopt); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, FpsPrefInit) { |
| // Check that the init of the FPS pref occurs correctly. |
| ClearFpsUserPrefs(prefs()); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| |
| // Whilst the FPS UI is not available, the pref should not be init. |
| feature_list()->InitAndDisableFeature( |
| privacy_sandbox::kPrivacySandboxFirstPartySetsUI); |
| |
| CreateService(); |
| EXPECT_TRUE( |
| prefs()->GetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled)); |
| EXPECT_FALSE(prefs()->GetBoolean( |
| prefs::kPrivacySandboxFirstPartySetsDataAccessAllowedInitialized)); |
| |
| // If the UI is available, the user blocks 3PC, and the pref has not been |
| // previously init, it should be. |
| ClearFpsUserPrefs(prefs()); |
| feature_list()->Reset(); |
| feature_list()->InitAndEnableFeature( |
| privacy_sandbox::kPrivacySandboxFirstPartySetsUI); |
| |
| CreateService(); |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled)); |
| EXPECT_TRUE(prefs()->GetBoolean( |
| prefs::kPrivacySandboxFirstPartySetsDataAccessAllowedInitialized)); |
| |
| // Once the pref has been init, it should not be re-init, and updated user |
| // cookie settings should not impact it. |
| ClearFpsUserPrefs(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::kPrivacySandboxFirstPartySetsDataAccessAllowedInitialized)); |
| |
| 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::kPrivacySandboxFirstPartySetsDataAccessAllowedInitialized)); |
| |
| // Blocking all cookies should also init the FPS pref to off. |
| ClearFpsUserPrefs(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::kPrivacySandboxFirstPartySetsDataAccessAllowedInitialized)); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, UsesFpsSampleSetsWhenProvided) { |
| // Confirm that when the FPS sample sets are provided, they are used to answer |
| // First-Party Sets queries instead of the actual sets. |
| |
| // Set up state that fully enables the First-Party Sets for UI; blocking |
| // 3PC, and enabling the FPS UI feature and the FPS enabled pref. |
| // |
| // Note: this indicates that the sample sets should be used. |
| feature_list()->InitWithFeaturesAndParameters( |
| /*enabled_features=*/{{privacy_sandbox::kPrivacySandboxFirstPartySetsUI, |
| {{"use-sample-sets", "true"}}}}, |
| /*disabled_features=*/{}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| CreateService(); |
| ClearFpsUserPrefs(prefs()); |
| prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled, |
| std::make_unique<base::Value>(true)); |
| |
| // Simulate that the Global First-Party Sets 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( |
| kFirstPartySetsVersion, |
| { |
| {youtube_primary_site, |
| {net::FirstPartySetEntry(youtube_primary_site, |
| net::SiteType::kPrimary, std::nullopt)}}, |
| {youtube_site, |
| {net::FirstPartySetEntry(youtube_primary_site, |
| net::SiteType::kAssociated, 0)}}, |
| }, |
| {})); |
| |
| // Simulate that https://google.de is moved into a new First-Party Set for |
| // this profile. |
| mock_first_party_sets_handler().SetContextConfig( |
| net::FirstPartySetsContextConfig( |
| {{net::SchemefulSite(GURL("https://google.de")), |
| net::FirstPartySetEntryOverride(net::FirstPartySetEntry( |
| net::SchemefulSite(GURL("https://new-primary.test")), |
| net::SiteType::kAssociated, 0))}})); |
| |
| first_party_sets_policy_service()->InitForTesting(); |
| |
| // Expect queries to be resolved based on the FPS sample sets. |
| EXPECT_GT(privacy_sandbox_service()->GetSampleFirstPartySets().size(), 0u); |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner( |
| GURL("https://youtube.com")), |
| net::SchemefulSite(GURL("https://google.com"))); |
| EXPECT_TRUE(privacy_sandbox_service()->IsPartOfManagedFirstPartySet( |
| net::SchemefulSite(GURL("https://googlesource.com")))); |
| EXPECT_FALSE(privacy_sandbox_service()->IsPartOfManagedFirstPartySet( |
| net::SchemefulSite(GURL("https://google.de")))); |
| |
| feature_list()->Reset(); |
| feature_list()->InitWithFeatures( |
| {privacy_sandbox::kPrivacySandboxFirstPartySetsUI}, {}); |
| prefs()->SetUserPref( |
| prefs::kCookieControlsMode, |
| std::make_unique<base::Value>(static_cast<int>( |
| content_settings::CookieControlsMode::kBlockThirdParty))); |
| CreateService(); |
| ClearFpsUserPrefs(prefs()); |
| prefs()->SetUserPref(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled, |
| std::make_unique<base::Value>(true)); |
| |
| // Expect queries to be resolved based on the FPS backend. |
| EXPECT_EQ(privacy_sandbox_service()->GetSampleFirstPartySets().size(), 0u); |
| EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(youtube_gurl), |
| youtube_primary_site); |
| EXPECT_FALSE(privacy_sandbox_service()->IsPartOfManagedFirstPartySet( |
| net::SchemefulSite(GURL("https://googlesource.com")))); |
| EXPECT_TRUE(privacy_sandbox_service()->IsPartOfManagedFirstPartySet( |
| 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"; |
| |
| 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); |
| |
| 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); |
| |
| 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); |
| |
| 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); |
| |
| 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); |
| |
| 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); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| RecordPrivacySandbox4StartupMetrics_PromptSuppressed_Implicitly) { |
| base::HistogramTester histogram_tester; |
| const std::string privacy_sandbox_prompt_startup_histogram = |
| "Settings.PrivacySandbox.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); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_EEA) { |
| base::HistogramTester histogram_tester; |
| const std::string privacy_sandbox_prompt_startup_histogram = |
| "Settings.PrivacySandbox.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); |
| |
| // 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); |
| |
| // 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); |
| |
| // 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); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, |
| RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_ROW) { |
| base::HistogramTester histogram_tester; |
| const std::string privacy_sandbox_prompt_startup_histogram = |
| "Settings.PrivacySandbox.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); |
| |
| // 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); |
| } |
| |
| 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); |
| |
| prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, false); |
| privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics(); |
| histogram_tester.ExpectBucketCount("Settings.PrivacySandbox.Topics.Enabled", |
| static_cast<int>(false), |
| /*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); |
| prefs()->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, false); |
| privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics(); |
| histogram_tester.ExpectBucketCount("Settings.PrivacySandbox.Fledge.Enabled", |
| static_cast<int>(false), |
| /*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); |
| prefs()->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, false); |
| privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics(); |
| histogram_tester.ExpectBucketCount( |
| "Settings.PrivacySandbox.AdMeasurement.Enabled", |
| static_cast<int>(false), |
| /*expected_count=*/1); |
| } |
| } |
| |
| class PrivacySandboxNoticeActionToStorageTests |
| : public PrivacySandboxServiceTest, |
| public testing::WithParamInterface<NoticeTestingParameters> {}; |
| |
| using TopicsConsentTest = PrivacySandboxNoticeActionToStorageTests; |
| using NoticeAckTest = PrivacySandboxNoticeActionToStorageTests; |
| using NoticeShownTest = PrivacySandboxNoticeActionToStorageTests; |
| using NoticeSettingsTest = PrivacySandboxNoticeActionToStorageTests; |
| |
| TEST_P(TopicsConsentTest, DidConsentOptInUpdateNoticeStorage) { |
| feature_list()->Reset(); |
| feature_list()->InitWithFeaturesAndParameters( |
| /*enabled_features=*/{GetParam().feature_flag, |
| {privacy_sandbox::kPsDualWritePrefsToNoticeStorage, |
| {}}}, |
| /*disabled_features=*/{}); |
| |
| // Show then OptIn |
| privacy_sandbox_service()->PromptActionOccurred(PromptAction::kConsentShown, |
| GetParam().surface_type); |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentAccepted, GetParam().surface_type); |
| |
| // Pref |
| auto actual = |
| notice_storage_->ReadNoticeData(prefs(), GetParam().notice_name); |
| EXPECT_EQ(privacy_sandbox::NoticeActionTaken::kOptIn, |
| actual->notice_action_taken); |
| |
| // Histogram |
| CreateService(); |
| histogram_tester.ExpectBucketCount( |
| base::StrCat({"PrivacySandbox.Notice.NoticeStartupState.", |
| GetParam().notice_name}), |
| privacy_sandbox::NoticeStartupState::kFlowCompletedWithOptIn, 1); |
| } |
| |
| TEST_P(TopicsConsentTest, DidConsentOptOutUpdateNoticeStorage) { |
| feature_list()->Reset(); |
| feature_list()->InitWithFeaturesAndParameters( |
| /*enabled_features=*/{GetParam().feature_flag, |
| {privacy_sandbox::kPsDualWritePrefsToNoticeStorage, |
| {}}}, |
| /*disabled_features=*/{}); |
| |
| // Show then OptOut |
| privacy_sandbox_service()->PromptActionOccurred(PromptAction::kConsentShown, |
| GetParam().surface_type); |
| privacy_sandbox_service()->PromptActionOccurred( |
| PromptAction::kConsentDeclined, GetParam().surface_type); |
| |
| // Pref |
| auto actual = |
| notice_storage_->ReadNoticeData(prefs(), GetParam().notice_name); |
| EXPECT_EQ(privacy_sandbox::NoticeActionTaken::kOptOut, |
| actual->notice_action_taken); |
| |
| // Histogram |
| CreateService(); |
| histogram_tester.ExpectBucketCount( |
| base::StrCat({"PrivacySandbox.Notice.NoticeStartupState.", |
| GetParam().notice_name}), |
| privacy_sandbox::NoticeStartupState::kFlowCompletedWithOptOut, 1); |
| } |
| |
| TEST_P(NoticeShownTest, NoticeShownUpdateNoticeStorage) { |
| feature_list()->Reset(); |
| feature_list()->InitWithFeaturesAndParameters( |
| /*enabled_features=*/{GetParam().feature_flag, |
| {privacy_sandbox::kPsDualWritePrefsToNoticeStorage, |
| {}}}, |
| /*disabled_features=*/{}); |
| |
| privacy_sandbox_service()->PromptActionOccurred(GetParam().shown_type, |
| GetParam().surface_type); |
| |
| auto actual = |
| notice_storage_->ReadNoticeData(prefs(), GetParam().notice_name); |
| EXPECT_TRUE(actual.has_value()); |
| } |
| |
| TEST_P(NoticeAckTest, DidNoticeAckUpdateNoticeStorage) { |
| feature_list()->Reset(); |
| feature_list()->InitWithFeaturesAndParameters( |
| /*enabled_features=*/{GetParam().feature_flag, |
| {privacy_sandbox::kPsDualWritePrefsToNoticeStorage, |
| {}}}, |
| /*disabled_features=*/{}); |
| |
| // Show then ack |
| privacy_sandbox_service()->PromptActionOccurred(GetParam().shown_type, |
| GetParam().surface_type); |
| privacy_sandbox_service()->PromptActionOccurred(GetParam().prompt_action, |
| GetParam().surface_type); |
| |
| // Pref |
| auto actual = |
| notice_storage_->ReadNoticeData(prefs(), GetParam().notice_name); |
| EXPECT_EQ(privacy_sandbox::NoticeActionTaken::kAck, |
| actual->notice_action_taken); |
| |
| // Histogram |
| CreateService(); |
| histogram_tester.ExpectBucketCount( |
| base::StrCat({"PrivacySandbox.Notice.NoticeStartupState.", |
| GetParam().notice_name}), |
| privacy_sandbox::NoticeStartupState::kFlowCompleted, 1); |
| } |
| |
| TEST_P(NoticeSettingsTest, DidNoticeSettingsUpdateNoticeStorage) { |
| feature_list()->Reset(); |
| feature_list()->InitWithFeaturesAndParameters( |
| /*enabled_features=*/{GetParam().feature_flag, |
| {privacy_sandbox::kPsDualWritePrefsToNoticeStorage, |
| {}}}, |
| /*disabled_features=*/{}); |
| |
| // Show then open settings |
| privacy_sandbox_service()->PromptActionOccurred(GetParam().shown_type, |
| GetParam().surface_type); |
| privacy_sandbox_service()->PromptActionOccurred(GetParam().prompt_action, |
| GetParam().surface_type); |
| |
| // Pref |
| auto actual = |
| notice_storage_->ReadNoticeData(prefs(), GetParam().notice_name); |
| EXPECT_EQ(privacy_sandbox::NoticeActionTaken::kSettings, |
| actual->notice_action_taken); |
| |
| // Histogram |
| CreateService(); |
| histogram_tester.ExpectBucketCount( |
| base::StrCat({"PrivacySandbox.Notice.NoticeStartupState.", |
| GetParam().notice_name}), |
| privacy_sandbox::NoticeStartupState::kFlowCompleted, 1); |
| } |
| |
| 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"}}}; |
| } |
| |
| // The following tests test variations of all 4 notice storage prefs across 3 |
| // surface types. For each promptAction that can be taken on the notices, we |
| // ensure the pref service and histograms were updated correctly. |
| INSTANTIATE_TEST_SUITE_P( |
| NoticeShownTestSuite, |
| NoticeShownTest, |
| testing::ValuesIn<NoticeTestingParameters>( |
| // Topics Consent Shown |
| {{.surface_type = SurfaceType::kDesktop, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kConsentShown, |
| .notice_name = privacy_sandbox::kTopicsConsentModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kConsentShown, |
| .notice_name = privacy_sandbox::kTopicsConsentModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kConsentShown, |
| .notice_name = privacy_sandbox::kTopicsConsentModalClankCCT}, |
| // EEA regional API notice Shown |
| {.surface_type = SurfaceType::kDesktop, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .notice_name = |
| privacy_sandbox::kProtectedAudienceMeasurementNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .notice_name = privacy_sandbox:: |
| kProtectedAudienceMeasurementNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .notice_name = privacy_sandbox:: |
| kProtectedAudienceMeasurementNoticeModalClankCCT}, |
| // ROW regional API notice Shown |
| {.surface_type = SurfaceType::kDesktop, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModalClankCCT}, |
| // Restricted API notice Shown |
| {.surface_type = SurfaceType::kDesktop, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModalClankCCT}})); |
| |
| INSTANTIATE_TEST_SUITE_P( |
| TopicsConsentTestSuite, |
| TopicsConsentTest, |
| testing::ValuesIn<NoticeTestingParameters>( |
| // Actions on consent (OptIn/OptOut) |
| {{.surface_type = SurfaceType::kDesktop, |
| .feature_flag = ConsentFeature(), |
| .notice_name = privacy_sandbox::kTopicsConsentModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = ConsentFeature(), |
| .notice_name = privacy_sandbox::kTopicsConsentModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = ConsentFeature(), |
| .notice_name = privacy_sandbox::kTopicsConsentModalClankCCT}})); |
| |
| INSTANTIATE_TEST_SUITE_P( |
| NoticeTestSuite, |
| NoticeAckTest, |
| // Ack on ROW, EEA, Restricted Notices |
| testing::ValuesIn<NoticeTestingParameters>( |
| {{.surface_type = SurfaceType::kDesktop, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeAcknowledge, |
| .notice_name = |
| privacy_sandbox::kProtectedAudienceMeasurementNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeAcknowledge, |
| .notice_name = privacy_sandbox:: |
| kProtectedAudienceMeasurementNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeAcknowledge, |
| .notice_name = privacy_sandbox:: |
| kProtectedAudienceMeasurementNoticeModalClankCCT}, |
| {.surface_type = SurfaceType::kDesktop, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeAcknowledge, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeAcknowledge, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeAcknowledge, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModalClankCCT}, |
| {.surface_type = SurfaceType::kDesktop, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .prompt_action = PromptAction::kRestrictedNoticeAcknowledge, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .prompt_action = PromptAction::kRestrictedNoticeAcknowledge, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .prompt_action = PromptAction::kRestrictedNoticeAcknowledge, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModalClankCCT}})); |
| |
| INSTANTIATE_TEST_SUITE_P( |
| NoticeTestSuite, |
| NoticeSettingsTest, |
| testing::ValuesIn<NoticeTestingParameters>( |
| // Settings click on ROW, EEA, Restricted Notices |
| {{.surface_type = SurfaceType::kDesktop, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeOpenSettings, |
| .notice_name = |
| privacy_sandbox::kProtectedAudienceMeasurementNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeOpenSettings, |
| .notice_name = privacy_sandbox:: |
| kProtectedAudienceMeasurementNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = ConsentFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeOpenSettings, |
| .notice_name = privacy_sandbox:: |
| kProtectedAudienceMeasurementNoticeModalClankCCT}, |
| {.surface_type = SurfaceType::kDesktop, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeOpenSettings, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeOpenSettings, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = NoticeFeature(), |
| .shown_type = PromptAction::kNoticeShown, |
| .prompt_action = PromptAction::kNoticeOpenSettings, |
| .notice_name = privacy_sandbox::kThreeAdsAPIsNoticeModalClankCCT}, |
| {.surface_type = SurfaceType::kDesktop, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .prompt_action = PromptAction::kRestrictedNoticeOpenSettings, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModal}, |
| {.surface_type = SurfaceType::kBrApp, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .prompt_action = PromptAction::kRestrictedNoticeOpenSettings, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModalClankBrApp}, |
| {.surface_type = SurfaceType::kAGACCT, |
| .feature_flag = RestrictedNoticeFeature(), |
| .shown_type = PromptAction::kRestrictedNoticeShown, |
| .prompt_action = PromptAction::kRestrictedNoticeOpenSettings, |
| .notice_name = privacy_sandbox::kMeasurementNoticeModalClankCCT}})); |
| |
| 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>(PromptAction::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>( |
| PromptAction::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( |
| base::Time::Now(), |
| prefs()->GetTime(prefs::kPrivacySandboxTopicsConsentLastUpdateTime)); |
| EXPECT_EQ(privacy_sandbox::TopicsConsentUpdateSource::kConfirmation, |
| static_cast<privacy_sandbox::TopicsConsentUpdateSource>( |
| prefs()->GetInteger( |
| prefs::kPrivacySandboxTopicsConsentLastUpdateReason))); |
| EXPECT_EQ("foo", prefs()->GetString( |
| prefs::kPrivacySandboxTopicsConsentTextAtLastUpdate)); |
| } |
| |
| 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(static_cast<int>(PromptSuppressedReason::kNone), |
| prefs()->GetValue(prefs::kPrivacySandboxM1PromptSuppressed)); |
| } |
| |
| 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(static_cast<int>(PromptSuppressedReason::kRestricted), |
| prefs()->GetValue(prefs::kPrivacySandboxM1PromptSuppressed)); |
| } |
| |
| 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( |
| base::Time(), |
| prefs()->GetTime(prefs::kPrivacySandboxTopicsConsentLastUpdateTime)); |
| EXPECT_EQ(privacy_sandbox::TopicsConsentUpdateSource::kDefaultValue, |
| static_cast<privacy_sandbox::TopicsConsentUpdateSource>( |
| prefs()->GetInteger( |
| prefs::kPrivacySandboxTopicsConsentLastUpdateReason))); |
| 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()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxSettings4, |
| {{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName, "true"}, |
| {privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, |
| "false"}}); |
| } |
| }; |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| TEST_F(PrivacySandboxServiceM1PromptTest, DeviceLocalAccountUser) { |
| privacy_sandbox_service()->ForceChromeBuildForTests(true); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| user_manager::ScopedUserManager user_manager( |
| std::make_unique<user_manager::FakeUserManager>()); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // No prompt should be shown for a public session account. |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ash::ScopedTestPublicSessionLoginState login_state; |
| #elif BUILDFLAG(IS_CHROMEOS_LACROS) |
| crosapi::mojom::BrowserInitParamsPtr init_params = |
| crosapi::mojom::BrowserInitParams::New(); |
| init_params->session_type = crosapi::mojom::SessionType::kPublicSession; |
| chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params)); |
| #endif |
| // TODO(crbug.com/361794340): Ensure the promptType is correct across |
| // different surfaceTypes. |
| EXPECT_EQ(PromptType::kNone, privacy_sandbox_service()->GetRequiredPromptType( |
| SurfaceType::kDesktop)); |
| |
| // A prompt should be shown for a regular user. |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ash::LoginState::Get()->SetLoggedInState( |
| ash::LoginState::LoggedInState::LOGGED_IN_ACTIVE, |
| ash::LoginState::LoggedInUserType::LOGGED_IN_USER_REGULAR); |
| #elif BUILDFLAG(IS_CHROMEOS_LACROS) |
| init_params = crosapi::mojom::BrowserInitParams::New(); |
| init_params->session_type = crosapi::mojom::SessionType::kRegularSession; |
| chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params)); |
| #endif |
| EXPECT_EQ( |
| PromptType::kM1Consent, |
| privacy_sandbox_service()->GetRequiredPromptType(SurfaceType::kDesktop)); |
| |
| // No prompt should be shown for a web kiosk account. |
| chromeos::SetUpFakeKioskSession(); |
| EXPECT_EQ(PromptType::kNone, privacy_sandbox_service()->GetRequiredPromptType( |
| SurfaceType::kDesktop)); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| #if !BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| TEST_F(PrivacySandboxServiceM1PromptTest, NonChromeBuildPrompt) { |
| // 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)}}); |
| } |
| #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)}}); |
| } |
| |
| 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1PromptTest, RestrictedPrompt) { |
| // 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)}}); |
| |
| // 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)}}); |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| TEST_F(PrivacySandboxServiceM1PromptTest, PromptActionsSentimentService) { |
| // Settings both consent and notice to be true so that we can loop through all |
| // cases interacting with the sentiment service cleanly, without breaking |
| // DCHECKs. Other tests / code paths check that PromptActionOccurred is |
| // working correctly based on notice and consent, and assert that only one is |
| // enabled. |
| feature_list()->Reset(); |
| feature_list()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxSettings4, |
| {{privacy_sandbox::kPrivacySandboxSettings4ConsentRequiredName, "true"}, |
| {privacy_sandbox::kPrivacySandboxSettings4NoticeRequiredName, "true"}, |
| {privacy_sandbox::kPrivacySandboxSettings4RestrictedNoticeName, |
| "true"}}); |
| |
| std::map<PromptAction, TrustSafetySentimentService::FeatureArea> |
| expected_feature_areas; |
| expected_feature_areas = { |
| {PromptAction::kNoticeOpenSettings, |
| TrustSafetySentimentService::FeatureArea:: |
| kPrivacySandbox4NoticeSettings}, |
| {PromptAction::kNoticeAcknowledge, |
| TrustSafetySentimentService::FeatureArea::kPrivacySandbox4NoticeOk}, |
| {PromptAction::kConsentAccepted, |
| TrustSafetySentimentService::FeatureArea::kPrivacySandbox4ConsentAccept}, |
| {PromptAction::kConsentDeclined, |
| TrustSafetySentimentService::FeatureArea:: |
| kPrivacySandbox4ConsentDecline}}; |
| |
| for (int enum_value = 0; |
| enum_value <= static_cast<int>(PromptAction::kMaxValue); ++enum_value) { |
| auto prompt_action = static_cast<PromptAction>(enum_value); |
| if (expected_feature_areas.count(prompt_action)) { |
| EXPECT_CALL( |
| *mock_sentiment_service(), |
| InteractedWithPrivacySandbox4(expected_feature_areas[prompt_action])) |
| .Times(1); |
| } else { |
| EXPECT_CALL(*mock_sentiment_service(), |
| InteractedWithPrivacySandbox4(testing::_)) |
| .Times(0); |
| } |
| privacy_sandbox_service()->PromptActionOccurred(prompt_action, |
| SurfaceType::kDesktop); |
| testing::Mock::VerifyAndClearExpectations(mock_sentiment_service()); |
| } |
| } |
| #endif |
| |
| 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}}); |
| } |
| } |
| |
| 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)}}); |
| } |
| |
| 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)}}); |
| } |
| |
| 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)}}); |
| } |
| |
| 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)}}); |
| } |
| |
| 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)}}); |
| } |
| |
| 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>(PromptAction::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>(PromptAction::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>(PromptAction::kNoticeAcknowledge)}}, |
| TestOutput{{kM1EEANoticeAcknowledged, true}, |
| {kM1FledgeEnabled, true}, |
| {kM1AdMeasurementEnabled, true}}); |
| RunTestCase( |
| TestState{{kM1ConsentDecisionPreviouslyMade, true}, |
| {kM1EEANoticePreviouslyAcknowledged, false}}, |
| TestInput{ |
| {kPromptAction, static_cast<int>(PromptAction::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>(PromptAction::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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1NoticeNotAcknowledged) { |
| // 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1NoticeAcknowledged) { |
| // 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1EEAFlowInterrupted) { |
| // If a user has migrated from EEA to ROW and has already completed the eea |
| // consent but not yet acknowledged the notice, return kM1NoticeROW. |
| RunTestCase( |
| TestState{{kM1PromptPreviouslySuppressedReason, |
| static_cast<int>(PromptSuppressedReason::kNone)}, |
| {kM1ConsentDecisionPreviouslyMade, true}, |
| {kM1EEANoticePreviouslyAcknowledged, false}}, |
| TestInput{{kForceChromeBuild, true}}, |
| TestOutput{{kPromptType, static_cast<int>(PromptType::kM1NoticeROW)}, |
| {kM1PromptSuppressedReason, |
| static_cast<int>(PromptSuppressedReason::kNone)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1EEAFlowCompleted) { |
| // 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)}}); |
| } |
| |
| 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>(PromptAction::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>(PromptAction::kNoticeOpenSettings)}}, |
| TestOutput{{kM1RowNoticeAcknowledged, true}, |
| {kM1TopicsEnabled, true}, |
| {kM1FledgeEnabled, true}, |
| {kM1AdMeasurementEnabled, true}, |
| {kTopicsConsentGiven, false}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxPromptPolicy) { |
| // 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxTopicsPolicy) { |
| // 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}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxFledgePolicy) { |
| // 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}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxAdMeasurementPolicy) { |
| // 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}}); |
| } |
| |
| // 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) { |
| // 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest, |
| RestrictedNoticeAlreadyAcknowledged) { |
| // 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest, |
| ROWNoticeAlreadyAcknowledged) { |
| // 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest, |
| EEANoticeAlreadyAcknowledged) { |
| // 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)}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest, |
| RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed) { |
| base::HistogramTester histogram_tester; |
| const std::string privacy_sandbox_prompt_startup_histogram = |
| "Settings.PrivacySandbox.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); |
| |
| // 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); |
| |
| // 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); |
| |
| // 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); |
| } |
| |
| 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"; |
| |
| // 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); |
| } |
| |
| // 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); |
| } |
| } |
| |
| TEST_F( |
| PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted, |
| RecordPrivacySandbox4StartupMetrics_GraduationFlowWhenNoticeShownToGuardian) { |
| const std::string privacy_sandbox_prompt_startup_histogram = |
| "Settings.PrivacySandbox.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); |
| } |
| |
| 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"; |
| |
| // 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); |
| } |
| |
| // 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); |
| } |
| } |
| |
| TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest, |
| RestrictedNoticeAcknowledged) { |
| // 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)}}); |
| } |
| |
| 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) { |
| // 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}}); |
| } |
| |
| TEST_F(PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest, |
| NotSubjectToNoticeButIsRestrictedWithAdMeasurementDisabled) { |
| // 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)}}); |
| } |
| |
| 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) { |
| // 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)}}); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| class PrivacySandboxActivityTypeStorageTests |
| : public PrivacySandboxServiceTest { |
| public: |
| PrivacySandboxActivityTypeStorageTests() |
| : local_state_(std::make_unique<ScopedTestingLocalState>( |
| TestingBrowserProcess::GetGlobal())) {} |
| |
| void InitializeFeaturesBeforeStart() override { |
| feature_list()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxActivityTypeStorage, |
| {{"last-n-launches", "5"}, |
| {"within-x-days", "2"}, |
| {"skip-pre-first-tab", "false"}}); |
| } |
| |
| protected: |
| base::HistogramTester histogram_tester; |
| ScopedTestingLocalState* local_state() { return local_state_.get(); } |
| |
| private: |
| std::unique_ptr<ScopedTestingLocalState> local_state_; |
| }; |
| |
| TEST_F(PrivacySandboxActivityTypeStorageTests, VerifyListOverflow) { |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| EXPECT_EQ(1u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kNonAGSACustomTab); |
| EXPECT_EQ(2u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| EXPECT_EQ(3u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebApk); |
| EXPECT_EQ(4u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebapp); |
| EXPECT_EQ(5u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| // Since we are already at a size of 5, and last-n-launches is set to 5, the |
| // next call of another launch will remove the first element in the list |
| // before adding the newly created one. The size should still be 5. |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| EXPECT_EQ(5u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| } |
| |
| // This test is ensuring that the start of the list is represented as the newest |
| // records and the end is the oldest records. |
| TEST_F(PrivacySandboxActivityTypeStorageTests, VerifyListOrder) { |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| EXPECT_EQ(static_cast<int>(ActivityType::kAGSACustomTab), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[0] |
| .GetDict() |
| .Find("activity_type")); |
| |
| browser_task_environment()->FastForwardBy(base::Minutes(5)); |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kNonAGSACustomTab); |
| EXPECT_EQ(static_cast<int>(ActivityType::kNonAGSACustomTab), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[0] |
| .GetDict() |
| .Find("activity_type")); |
| |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| EXPECT_EQ(static_cast<int>(ActivityType::kTrustedWebActivity), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[0] |
| .GetDict() |
| .Find("activity_type")); |
| |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebapp); |
| EXPECT_EQ(static_cast<int>(ActivityType::kWebapp), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[0] |
| .GetDict() |
| .Find("activity_type")); |
| |
| browser_task_environment()->FastForwardBy(base::Minutes(5)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebApk); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| EXPECT_EQ(static_cast<int>(ActivityType::kAGSACustomTab), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[0] |
| .GetDict() |
| .Find("activity_type")); |
| EXPECT_EQ(static_cast<int>(ActivityType::kWebApk), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[1] |
| .GetDict() |
| .Find("activity_type")); |
| EXPECT_EQ(static_cast<int>(ActivityType::kWebapp), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[2] |
| .GetDict() |
| .Find("activity_type")); |
| EXPECT_EQ(static_cast<int>(ActivityType::kTabbed), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[3] |
| .GetDict() |
| .Find("activity_type")); |
| EXPECT_EQ(static_cast<int>(ActivityType::kTrustedWebActivity), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[4] |
| .GetDict() |
| .Find("activity_type")); |
| } |
| |
| TEST_F(PrivacySandboxActivityTypeStorageTests, VerifyListExpiration) { |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kOther); |
| EXPECT_EQ(1u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kNonAGSACustomTab); |
| EXPECT_EQ(2u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| // Even though within-x-days is set to 2 days, we still include records that |
| // are inclusive of the time boundary. When we fast forward by 2 days and add |
| // a third record, all three entries are still in the record list. |
| browser_task_environment()->FastForwardBy(base::Days(2)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kPreFirstTab); |
| EXPECT_EQ(3u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| // Now by fast forwarding by 1 more day, we have exceeded the within-x-days of |
| // 2 days, so the first two entries should be removed and the size should |
| // be 2. |
| browser_task_environment()->FastForwardBy(base::Days(1)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebApk); |
| EXPECT_EQ(2u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| } |
| |
| TEST_F(PrivacySandboxActivityTypeStorageTests, VerifyTimeBackwards) { |
| // Initializing the activity type record list with entries that have |
| // timestamps set for future dates (e.g., 5 and 7 days from now). |
| base::Value::List old_records; |
| base::Value::Dict first_record; |
| base::Value::Dict second_record; |
| |
| first_record.Set("timestamp", |
| base::TimeToValue(base::Time::Now() + base::Days(5))); |
| first_record.Set("activity_type", |
| static_cast<int>(ActivityType::kAGSACustomTab)); |
| |
| second_record.Set("timestamp", |
| base::TimeToValue(base::Time::Now() + base::Days(7))); |
| second_record.Set("activity_type", static_cast<int>(ActivityType::kTabbed)); |
| |
| old_records.Append(std::move(first_record)); |
| old_records.Append(std::move(second_record)); |
| |
| prefs()->SetList(prefs::kPrivacySandboxActivityTypeRecord2, |
| std::move(old_records)); |
| |
| EXPECT_EQ(2u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| |
| // After recording a new activity, any previous records with timestamps in the |
| // future (greater than the current timestamp) are not added to the updated |
| // list. |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| EXPECT_EQ(1u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| EXPECT_EQ(static_cast<int>(ActivityType::kTrustedWebActivity), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[0] |
| .GetDict() |
| .Find("activity_type")); |
| } |
| |
| class PrivacySandboxActivityTypeStorageMetricsTests |
| : public PrivacySandboxServiceTest { |
| public: |
| PrivacySandboxActivityTypeStorageMetricsTests() |
| : local_state_(std::make_unique<ScopedTestingLocalState>( |
| TestingBrowserProcess::GetGlobal())) {} |
| |
| void InitializeFeaturesBeforeStart() override { |
| feature_list()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxActivityTypeStorage, |
| {{"last-n-launches", "100"}, |
| {"within-x-days", "60"}, |
| {"skip-pre-first-tab", "false"}}); |
| } |
| |
| struct PercentageMetricValues { |
| int AGSACCTPercent = 0; |
| int AGSACCTBucketCount = 1; |
| int BrAppPercent = 0; |
| int BrAppBucketCount = 1; |
| int NonAGSACCTPercent = 0; |
| int NonAGSACCTBucketCount = 1; |
| int TWAPercent = 0; |
| int TWABucketCount = 1; |
| int WebappPercent = 0; |
| int WebappBucketCount = 1; |
| int WebAPKPercent = 0; |
| int WebAPKBucketCount = 1; |
| int OtherPercent = 0; |
| int OtherBucketCount = 1; |
| int PreFirstTabPercent = 0; |
| int PreFirstTabCount = 1; |
| }; |
| |
| void TestMetricValues(PercentageMetricValues values) { |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.AGSACCT2", |
| values.AGSACCTPercent, values.AGSACCTBucketCount); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.BrApp2", |
| values.BrAppPercent, values.BrAppBucketCount); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.NonAGSACCT2", |
| values.NonAGSACCTPercent, values.NonAGSACCTBucketCount); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.TWA2", values.TWAPercent, |
| values.TWABucketCount); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.WebApp2", |
| values.WebappPercent, values.WebappBucketCount); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.WebApk2", |
| values.WebAPKPercent, values.WebAPKBucketCount); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.Other2", |
| values.OtherPercent, values.OtherBucketCount); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.PreFirstTab2", |
| values.PreFirstTabPercent, values.PreFirstTabCount); |
| } |
| |
| protected: |
| base::HistogramTester histogram_tester; |
| ScopedTestingLocalState* local_state() { return local_state_.get(); } |
| |
| private: |
| std::unique_ptr<ScopedTestingLocalState> local_state_; |
| }; |
| |
| TEST_F(PrivacySandboxActivityTypeStorageMetricsTests, |
| VerifyMetricsRecordsLength) { |
| local_state()->Get()->SetInt64( |
| metrics::prefs::kMetricsReportingEnabledTimestamp, |
| (base::Time::Now() - base::Days(10)).ToTimeT()); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength", 1, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebapp); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength", 2, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebApk); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength", 3, 1); |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength", 4, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength", 5, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kOther); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength", 6, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kPreFirstTab); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength", 7, 1); |
| } |
| |
| TEST_F(PrivacySandboxActivityTypeStorageMetricsTests, |
| VerifyMetricsPercentages) { |
| local_state()->Get()->SetInt64( |
| metrics::prefs::kMetricsReportingEnabledTimestamp, |
| (base::Time::Now() - base::Days(10)).ToTimeT()); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| TestMetricValues({.AGSACCTPercent = 100}); |
| |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kNonAGSACustomTab); |
| TestMetricValues({.AGSACCTPercent = 50, |
| .BrAppBucketCount = 2, |
| .NonAGSACCTPercent = 50, |
| .TWABucketCount = 2, |
| .WebappBucketCount = 2, |
| .WebAPKBucketCount = 2, |
| .OtherBucketCount = 2, |
| .PreFirstTabCount = 2}); |
| |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| TestMetricValues({.AGSACCTPercent = 33, |
| .BrAppBucketCount = 3, |
| .NonAGSACCTPercent = 33, |
| .TWAPercent = 33, |
| .WebappBucketCount = 3, |
| .WebAPKBucketCount = 3, |
| .OtherBucketCount = 3, |
| .PreFirstTabCount = 3}); |
| |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| TestMetricValues({.AGSACCTPercent = 50, |
| .AGSACCTBucketCount = 2, |
| .BrAppBucketCount = 4, |
| .NonAGSACCTPercent = 25, |
| .TWAPercent = 25, |
| .WebappBucketCount = 4, |
| .WebAPKBucketCount = 4, |
| .OtherBucketCount = 4, |
| .PreFirstTabCount = 4}); |
| |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebApk); |
| TestMetricValues({.AGSACCTPercent = 40, |
| .BrAppBucketCount = 5, |
| .NonAGSACCTPercent = 20, |
| .TWAPercent = 20, |
| .WebappBucketCount = 5, |
| .WebAPKPercent = 20, |
| .OtherBucketCount = 5, |
| .PreFirstTabCount = 5}); |
| |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| TestMetricValues({.AGSACCTPercent = 33, |
| .AGSACCTBucketCount = 2, |
| .BrAppBucketCount = 6, |
| .NonAGSACCTPercent = 17, |
| .TWAPercent = 33, |
| .TWABucketCount = 2, |
| .WebappBucketCount = 6, |
| .WebAPKPercent = 17, |
| .OtherBucketCount = 6, |
| .PreFirstTabCount = 6}); |
| |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebapp); |
| TestMetricValues({.AGSACCTPercent = 29, |
| .BrAppBucketCount = 7, |
| .NonAGSACCTPercent = 14, |
| .TWAPercent = 29, |
| .WebappPercent = 14, |
| .WebAPKPercent = 14, |
| .OtherBucketCount = 7, |
| .PreFirstTabCount = 7}); |
| |
| browser_task_environment()->FastForwardBy(base::Days(61)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| // Since 61 days have passed, the activity log gets cleared because it is |
| // passed our within-x-days feature param. |
| TestMetricValues({.BrAppPercent = 100, |
| .NonAGSACCTBucketCount = 2, |
| .TWABucketCount = 3, |
| .WebappBucketCount = 7, |
| .WebAPKBucketCount = 5, |
| .OtherBucketCount = 8, |
| .PreFirstTabCount = 8}); |
| } |
| |
| TEST_F(PrivacySandboxActivityTypeStorageMetricsTests, |
| VerifyUserSegmentMetrics) { |
| local_state()->Get()->SetInt64( |
| metrics::prefs::kMetricsReportingEnabledTimestamp, |
| (base::Time::Now() - base::Days(10)).ToTimeT()); |
| for (int i = 0; i < 10; ++i) { |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebapp); |
| } |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", 1); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasWebapp, 1); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.20MostRecentRecordsUserSegment2", 0); |
| |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasTWA, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebapp); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasTWA, 2); |
| |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebApk); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasPWA, 1); |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kTrustedWebActivity); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasPWA, 2); |
| |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kNonAGSACustomTab); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasNonAGSACCT, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kWebApk); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasNonAGSACCT, 2); |
| |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasAGSACCT, 1); |
| privacy_sandbox_service()->RecordActivityType( |
| ActivityType::kNonAGSACustomTab); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasAGSACCT, 2); |
| |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasBrowserApp, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasBrowserApp, 2); |
| |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.20MostRecentRecordsUserSegment2", 1); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.20MostRecentRecordsUserSegment2", |
| UserSegment::kHasBrowserApp, 1); |
| |
| for (int i = 0; i < 9; ++i) { |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kAGSACustomTab); |
| } |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasBrowserApp, 10); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasAGSACCT, 3); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.20MostRecentRecordsUserSegment2", |
| UserSegment::kHasBrowserApp, 10); |
| |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasOther, 0); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.20MostRecentRecordsUserSegment2", |
| UserSegment::kHasOther, 0); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", |
| UserSegment::kHasPreFirstTab, 0); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.20MostRecentRecordsUserSegment2", |
| UserSegment::kHasPreFirstTab, 0); |
| } |
| |
| TEST_F(PrivacySandboxActivityTypeStorageMetricsTests, VerifyNoMetrics) { |
| // Set the kMetricsReportingEnabledTimestamp of UMA opt in to 10 days in the |
| // future and we should receive no metrics on any of the data in the Activity |
| // Type storage list. The list should still be populated to a size of 10 |
| // records. |
| local_state()->Get()->SetInt64( |
| metrics::prefs::kMetricsReportingEnabledTimestamp, |
| (base::Time::Now() + base::Days(10)).ToTimeT()); |
| for (int i = 0; i < 10; ++i) { |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| } |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.10MostRecentRecordsUserSegment2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.20MostRecentRecordsUserSegment2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.AGSACCT2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.BrApp2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.NonAGSACCT2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.TWA2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.WebApp2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.Other2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.PreFirstTab2", 0); |
| histogram_tester.ExpectTotalCount( |
| "PrivacySandbox.ActivityTypeStorage.RecordsLength2", 0); |
| EXPECT_EQ(10u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| } |
| |
| TEST_F(PrivacySandboxActivityTypeStorageMetricsTests, |
| VerifyDurationSinceOldestRecordMetrics) { |
| local_state()->Get()->SetInt64( |
| metrics::prefs::kMetricsReportingEnabledTimestamp, |
| (base::Time::Now() - base::Days(10)).ToTimeT()); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 0, 1); |
| browser_task_environment()->FastForwardBy(base::Days(5)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 5, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 5, 2); |
| browser_task_environment()->FastForwardBy(base::Days(10)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 15, 1); |
| browser_task_environment()->FastForwardBy(base::Days(10)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 25, 1); |
| browser_task_environment()->FastForwardBy(base::Days(10)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 35, 1); |
| browser_task_environment()->FastForwardBy(base::Days(10)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 45, 1); |
| browser_task_environment()->FastForwardBy(base::Days(10)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 55, 1); |
| browser_task_environment()->FastForwardBy(base::Days(10)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 60, 1); |
| browser_task_environment()->FastForwardBy(base::Days(10)); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.DaysSinceOldestRecord", 60, 2); |
| } |
| |
| class PrivacySandboxActivityTypeStorageMetricsTypeReceivedTests |
| : public PrivacySandboxActivityTypeStorageMetricsTests, |
| public testing::WithParamInterface<int> {}; |
| |
| TEST_P(PrivacySandboxActivityTypeStorageMetricsTypeReceivedTests, |
| VerifyTypeReceivedMetric) { |
| privacy_sandbox_service()->RecordActivityType( |
| static_cast<ActivityType>(GetParam())); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.TypeReceived", |
| static_cast<ActivityType>(GetParam()), 1); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| , |
| PrivacySandboxActivityTypeStorageMetricsTypeReceivedTests, |
| testing::Range(static_cast<int>(ActivityType::kOther), |
| static_cast<int>(ActivityType::kMaxValue) + 1)); |
| |
| class PrivacySandboxActivityTypeStorageSkipPreFirstTabTests |
| : public PrivacySandboxActivityTypeStorageTests { |
| void InitializeFeaturesBeforeStart() override { |
| feature_list()->InitAndEnableFeatureWithParameters( |
| privacy_sandbox::kPrivacySandboxActivityTypeStorage, |
| {{"last-n-launches", "100"}, |
| {"within-x-days", "60"}, |
| {"skip-pre-first-tab", "true"}}); |
| } |
| }; |
| |
| TEST_F(PrivacySandboxActivityTypeStorageSkipPreFirstTabTests, |
| RecordsOnlyTabbedActivity) { |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kTabbed); |
| EXPECT_EQ(1u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.TypeReceived", ActivityType::kTabbed, |
| 1); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.BrApp2", 100, 1); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.PreFirstTab2", 0, 1); |
| privacy_sandbox_service()->RecordActivityType(ActivityType::kPreFirstTab); |
| EXPECT_EQ(1u, |
| prefs()->GetList(prefs::kPrivacySandboxActivityTypeRecord2).size()); |
| EXPECT_EQ(static_cast<int>(ActivityType::kTabbed), |
| *prefs() |
| ->GetList(prefs::kPrivacySandboxActivityTypeRecord2)[0] |
| .GetDict() |
| .Find("activity_type")); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.TypeReceived", |
| ActivityType::kPreFirstTab, 1); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.BrApp2", 100, 1); |
| histogram_tester.ExpectBucketCount( |
| "PrivacySandbox.ActivityTypeStorage.Percentage.PreFirstTab2", 0, 1); |
| } |
| #endif // BUILDFLAG(IS_ANDROID) |