chromium/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc

// 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 {
Topic;
CanonicalTopic;
ElementsAre;
PromptAction;
PromptSuppressedReason;
PromptType;
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;

InputKey;
OutputKey;
StateKey;

MultipleInputKeys;
MultipleOutputKeys;
MultipleStateKeys;
SiteDataExceptions;
TestCase;
TestInput;
TestOutput;
TestState;

const char kFirstPartySetsStateHistogram[] =;

const base::Version kFirstPartySetsVersion("1.2.3");

constexpr int kTestTaxonomyVersion =;

class TestPrivacySandboxService
    : public privacy_sandbox_test_util::PrivacySandboxServiceTestInterface {};

class TestInterestGroupManager : public content::InterestGroupManager {};

// Remove any user preference settings for First Party Set related preferences,
// returning them to their default value.
void ClearFpsUserPrefs(
    sync_preferences::TestingPrefServiceSyncable* pref_service) {}

std::vector<int> GetTopicsSettingsStringIdentifiers(bool did_consent,
                                                    bool has_current_topics,
                                                    bool has_blocked_topics) {}

std::vector<int> GetTopicsConfirmationStringIdentifiers() {}

struct NoticeTestingParameters {};
}  // namespace

class PrivacySandboxServiceTest : public testing::Test {};

TEST_F(PrivacySandboxServiceTest, GetFledgeJoiningEtldPlusOne) {}

TEST_F(PrivacySandboxServiceTest, GetFledgeJoiningEtldPlusOne_InvalidTopFrame) {}

TEST_F(PrivacySandboxServiceTest, GetFledgeBlockedEtldPlusOne) {}

TEST_F(PrivacySandboxServiceTest, HistogramsAreEmptyOnStartup) {}

TEST_F(PrivacySandboxServiceTest, PromptActionsUMAActions) {}

TEST_F(PrivacySandboxServiceTest, FledgeBlockDeletesData) {}

TEST_F(PrivacySandboxServiceTest, DisablingTopicsPrefClearsData) {}

TEST_F(PrivacySandboxServiceTest, DisablingFledgePrefClearsData) {}

TEST_F(PrivacySandboxServiceTest, DisablingAdMeasurementePrefClearsData) {}

TEST_F(PrivacySandboxServiceTest, GetTopTopics) {}

TEST_F(PrivacySandboxServiceTest, GetBlockedTopics) {}

TEST_F(PrivacySandboxServiceTest, GetFirstLevelTopics) {}

TEST_F(PrivacySandboxServiceTest, GetChildTopicsCurrentlyAssigned) {}

TEST_F(PrivacySandboxServiceTest, SetTopicAllowed) {}

TEST_F(PrivacySandboxServiceTest, TestNoFakeTopics) {}

TEST_F(PrivacySandboxServiceTest, TestNoFakeTopicsPrefOff) {}

TEST_F(PrivacySandboxServiceTest, TestFakeTopics) {}
PrivacySandboxServiceDeathTest;

TEST_F(PrivacySandboxServiceDeathTest, TPSettingsNullExpectDeath) {}

TEST_F(PrivacySandboxServiceTest,
       FirstPartySetsNotRelevantMetricAllowedCookies) {}

TEST_F(PrivacySandboxServiceTest,
       FirstPartySetsNotRelevantMetricBlockedCookies) {}

TEST_F(PrivacySandboxServiceTest, FirstPartySetsEnabledMetric) {}

TEST_F(PrivacySandboxServiceTest, FirstPartySetsDisabledMetric) {}

TEST_F(PrivacySandboxServiceTest, SampleFpsData) {}

TEST_F(PrivacySandboxServiceTest,
       GetFirstPartySetOwner_SimulatedFpsData_DisabledWhen3pcAllowed) {}

TEST_F(PrivacySandboxServiceTest,
       GetFirstPartySetOwner_SimulatedFpsData_DisabledWhenAllCookiesBlocked) {}

TEST_F(PrivacySandboxServiceTest,
       GetFirstPartySetOwner_SimulatedFpsData_DisabledByFpsUiFeature) {}

TEST_F(PrivacySandboxServiceTest,
       GetFirstPartySetOwner_SimulatedFpsData_DisabledByFpsPref) {}

TEST_F(PrivacySandboxServiceTest,
       SimulatedFpsData_FpsEnabled_WithoutGlobalSets) {}

TEST_F(PrivacySandboxServiceTest,
       SimulatedFpsData_FpsEnabled_WithGlobalSetsAndProfileSets) {}

TEST_F(PrivacySandboxServiceTest, FpsPrefInit) {}

TEST_F(PrivacySandboxServiceTest, UsesFpsSampleSetsWhenProvided) {}

TEST_F(PrivacySandboxServiceTest, TopicsConsentDefault) {}

TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_EnableWithBlocked) {}

TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_EnableNoBlocked) {}

TEST_F(PrivacySandboxServiceTest,
       TopicsConsentSettings_DisableCurrentAndBlocked) {}

TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_DisableBlockedOnly) {}

TEST_F(PrivacySandboxServiceTest, TopicsConsentSettings_DisableCurrentOnly) {}

TEST_F(PrivacySandboxServiceTest,
       TopicsConsentSettings_DisableNoCurrentNoBlocked) {}

TEST_F(PrivacySandboxServiceTest,
       RecordPrivacySandbox4StartupMetrics_PromptSuppressed_Explicitly) {}

TEST_F(PrivacySandboxServiceTest,
       RecordPrivacySandbox4StartupMetrics_PromptSuppressed_Implicitly) {}

TEST_F(PrivacySandboxServiceTest,
       RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_EEA) {}

TEST_F(PrivacySandboxServiceTest,
       RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_ROW) {}

TEST_F(PrivacySandboxServiceTest, RecordPrivacySandbox4StartupMetrics_APIs) {}

class PrivacySandboxNoticeActionToStorageTests
    : public PrivacySandboxServiceTest,
      public testing::WithParamInterface<NoticeTestingParameters> {};

TopicsConsentTest;
NoticeAckTest;
NoticeShownTest;
NoticeSettingsTest;

TEST_P(TopicsConsentTest, DidConsentOptInUpdateNoticeStorage) {}

TEST_P(TopicsConsentTest, DidConsentOptOutUpdateNoticeStorage) {}

TEST_P(NoticeShownTest, NoticeShownUpdateNoticeStorage) {}

TEST_P(NoticeAckTest, DidNoticeAckUpdateNoticeStorage) {}

TEST_P(NoticeSettingsTest, DidNoticeSettingsUpdateNoticeStorage) {}

base::test::FeatureRefAndParams ConsentFeature() {}

base::test::FeatureRefAndParams NoticeFeature() {}

base::test::FeatureRefAndParams RestrictedNoticeFeature() {}

// 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();

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

class PrivacySandboxServiceM1RestrictedNoticeTest
    : public PrivacySandboxServiceTest {};

TEST_F(PrivacySandboxServiceM1RestrictedNoticeTest,
       RestrictedPromptActionsUpdatePrefs) {}

class PrivacySandboxServiceM1DelayCreation : public PrivacySandboxServiceTest {};

TEST_F(PrivacySandboxServiceM1DelayCreation,
       UnrestrictedRemainsEnabledWithConsent) {}

TEST_F(PrivacySandboxServiceM1DelayCreation,
       PromptSuppressReasonClearedWhenRestrictedNoticeEnabled) {}

TEST_F(PrivacySandboxServiceM1DelayCreation,
       PromptSuppressReasonNotClearedWhenRestrictedNoticeDisabled) {}

class PrivacySandboxServiceM1DelayCreationRestricted
    : public PrivacySandboxServiceM1DelayCreation {};

TEST_F(PrivacySandboxServiceM1DelayCreationRestricted,
       RestrictedDisablesAndClearsConsent) {}

TEST_F(PrivacySandboxServiceM1DelayCreationRestricted,
       RestrictedEnabledDoesntClearAdMeasurementPref) {}

class PrivacySandboxServiceM1PromptTest : public PrivacySandboxServiceTest {};

#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) {}
#endif

TEST_F(PrivacySandboxServiceM1PromptTest, ThirdPartyCookiesBlockedPostTP3PC) {}

TEST_F(PrivacySandboxServiceM1PromptTest, ThirdPartyCookiesBlockedPreTP3PC) {}

TEST_F(PrivacySandboxServiceM1PromptTest, RestrictedPrompt) {}

#if !BUILDFLAG(IS_ANDROID)
TEST_F(PrivacySandboxServiceM1PromptTest, PromptActionsSentimentService) {}
#endif

class PrivacySandboxServiceM1ConsentPromptTest
    : public PrivacySandboxServiceM1PromptTest {};

TEST_F(PrivacySandboxServiceM1ConsentPromptTest, SuppressedConsent) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest, TrialsConsentDeclined) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest, M1ConsentDecisionNotMade) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
       M1ConsentDecisionMadeAndEEANoticeNotAcknowledged) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
       M1ConsentDecisionMadeAndEEANoticeAcknowledged) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest, ROWNoticeAckTopicsDisabled) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest, PromptAction_ConsentAccepted) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest, PromptAction_ConsentDeclined) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
       PromptAction_EEANoticeAcknowledged) {}

TEST_F(PrivacySandboxServiceM1ConsentPromptTest,
       PromptAction_EEANoticeAcknowledged_ROWNoticeAcknowledged) {}

class PrivacySandboxServiceM1NoticePromptTest
    : public PrivacySandboxServiceM1PromptTest {};

TEST_F(PrivacySandboxServiceM1NoticePromptTest, SuppressedNotice) {}

TEST_F(PrivacySandboxServiceM1NoticePromptTest, TrialsDisabledAfterNotice) {}

TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1NoticeNotAcknowledged) {}

TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1NoticeAcknowledged) {}

TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1EEAFlowInterrupted) {}

TEST_F(PrivacySandboxServiceM1NoticePromptTest, M1EEAFlowCompleted) {}

TEST_F(PrivacySandboxServiceM1NoticePromptTest,
       PromptAction_RowNoticeAcknowledged) {}

TEST_F(PrivacySandboxServiceM1NoticePromptTest, PromptAction_OpenSettings) {}

TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxPromptPolicy) {}

TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxTopicsPolicy) {}

TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxFledgePolicy) {}

TEST_F(PrivacySandboxServiceTest, DisablePrivacySandboxAdMeasurementPolicy) {}

// TODO(crbug.com/40262246): consider parameterizing other tests for the various
// feature flags, particularly `kPrivacySandboxSettings4RestrictedNotice`.
class PrivacySandboxServiceM1RestrictedNoticePromptTest
    : public PrivacySandboxServiceM1PromptTest {};

TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest, RestrictedNotice) {}

TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
       RestrictedNoticeAlreadyAcknowledged) {}

TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
       ROWNoticeAlreadyAcknowledged) {}

TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
       EEANoticeAlreadyAcknowledged) {}

TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
       RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed) {}

class PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted
    : public PrivacySandboxServiceM1RestrictedNoticePromptTest {};

TEST_F(PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted,
       RecordPrivacySandbox4StartupMetrics_GraduationFlow) {}

TEST_F(
    PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted,
    RecordPrivacySandbox4StartupMetrics_GraduationFlowWhenNoticeShownToGuardian) {}

class PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyRestricted
    : public PrivacySandboxServiceM1RestrictedNoticePromptTest {};

TEST_F(PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyRestricted,
       RecordPrivacySandbox4StartupMetrics_GraduationFlow) {}

TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
       RestrictedNoticeAcknowledged) {}

class PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest
    : public PrivacySandboxServiceM1PromptTest {};

TEST_F(PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest,
       NotSubjectToNoticeButIsRestricted) {}

TEST_F(PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest,
       NotSubjectToNoticeButIsRestrictedWithAdMeasurementDisabled) {}

class PrivacySandboxServiceM1RestrictedNoticeEnabledNoRestrictionsTest
    : public PrivacySandboxServiceM1PromptTest {};

TEST_F(PrivacySandboxServiceM1RestrictedNoticeEnabledNoRestrictionsTest,
       VerifyPromptType) {}

#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)