| // Copyright 2022 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/browsing_topics/browsing_topics_calculator.h" |
| |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/logging.h" |
| #include "base/test/bind.h" |
| #include "base/test/gtest_util.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "components/browsing_topics/test_util.h" |
| #include "components/browsing_topics/util.h" |
| #include "components/content_settings/core/browser/cookie_settings.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "components/history/core/browser/history_database_params.h" |
| #include "components/history/core/browser/history_service.h" |
| #include "components/history/core/test/test_history_database.h" |
| #include "components/optimization_guide/content/browser/page_content_annotations_service.h" |
| #include "components/optimization_guide/content/browser/test_page_content_annotator.h" |
| #include "components/optimization_guide/core/test_model_info_builder.h" |
| #include "components/optimization_guide/core/test_optimization_guide_model_provider.h" |
| #include "components/privacy_sandbox/privacy_sandbox_prefs.h" |
| #include "components/privacy_sandbox/privacy_sandbox_settings.h" |
| #include "components/privacy_sandbox/privacy_sandbox_test_util.h" |
| #include "components/sync_preferences/testing_pref_service_syncable.h" |
| #include "components/ukm/test_ukm_recorder.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/browsing_topics_test_util.h" |
| #include "services/metrics/public/cpp/ukm_builders.h" |
| #include "third_party/blink/public/common/features.h" |
| |
| namespace browsing_topics { |
| |
| namespace { |
| |
| constexpr size_t kTaxonomySize = 349; |
| constexpr int kTaxonomyVersion = 1; |
| |
| constexpr char kHost1[] = "www.foo1.com"; |
| constexpr char kHost2[] = "www.foo2.com"; |
| constexpr char kHost3[] = "www.foo3.com"; |
| constexpr char kHost4[] = "www.foo4.com"; |
| constexpr char kHost5[] = "www.foo5.com"; |
| constexpr char kHost6[] = "www.foo6.com"; |
| |
| constexpr char kTokenizedHost1[] = "foo1 com"; |
| constexpr char kTokenizedHost2[] = "foo2 com"; |
| constexpr char kTokenizedHost3[] = "foo3 com"; |
| constexpr char kTokenizedHost4[] = "foo4 com"; |
| constexpr char kTokenizedHost5[] = "foo5 com"; |
| constexpr char kTokenizedHost6[] = "foo6 com"; |
| |
| } // namespace |
| |
| class BrowsingTopicsCalculatorTest : public testing::Test { |
| public: |
| BrowsingTopicsCalculatorTest() |
| : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { |
| EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| |
| content_settings::CookieSettings::RegisterProfilePrefs(prefs_.registry()); |
| HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry()); |
| privacy_sandbox::RegisterProfilePrefs(prefs_.registry()); |
| |
| host_content_settings_map_ = base::MakeRefCounted<HostContentSettingsMap>( |
| &prefs_, /*is_off_the_record=*/false, /*store_last_modified=*/false, |
| /*restore_session=*/false); |
| cookie_settings_ = base::MakeRefCounted<content_settings::CookieSettings>( |
| host_content_settings_map_.get(), &prefs_, false, "chrome-extension"); |
| auto privacy_sandbox_delegate = std::make_unique< |
| privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>(); |
| privacy_sandbox_delegate->SetupDefaultResponse(/*restricted=*/false, |
| /*confirmed=*/true); |
| privacy_sandbox_settings_ = |
| std::make_unique<privacy_sandbox::PrivacySandboxSettings>( |
| std::move(privacy_sandbox_delegate), |
| host_content_settings_map_.get(), cookie_settings_, &prefs_, |
| /*incognito_profile=*/false); |
| |
| topics_site_data_manager_ = |
| std::make_unique<content::TesterBrowsingTopicsSiteDataManager>( |
| temp_dir_.GetPath()); |
| |
| history_service_ = std::make_unique<history::HistoryService>(); |
| history_service_->Init( |
| history::TestHistoryDatabaseParamsForPath(temp_dir_.GetPath())); |
| |
| optimization_guide_model_provider_ = std::make_unique< |
| optimization_guide::TestOptimizationGuideModelProvider>(); |
| page_content_annotations_service_ = |
| std::make_unique<optimization_guide::PageContentAnnotationsService>( |
| "en-US", optimization_guide_model_provider_.get(), |
| history_service_.get(), nullptr, base::FilePath(), nullptr); |
| |
| page_content_annotations_service_->OverridePageContentAnnotatorForTesting( |
| &test_page_content_annotator_); |
| |
| task_environment_.RunUntilIdle(); |
| } |
| |
| ~BrowsingTopicsCalculatorTest() override { |
| host_content_settings_map_->ShutdownOnUIThread(); |
| } |
| |
| EpochTopics CalculateTopics() { |
| EpochTopics result; |
| |
| base::RunLoop run_loop; |
| |
| TesterBrowsingTopicsCalculator topics_calculator = |
| TesterBrowsingTopicsCalculator( |
| privacy_sandbox_settings_.get(), history_service_.get(), |
| topics_site_data_manager_.get(), |
| page_content_annotations_service_.get(), |
| base::BindLambdaForTesting([&](EpochTopics epoch_topics) { |
| result = std::move(epoch_topics); |
| run_loop.Quit(); |
| }), |
| /*rand_uint64_queue=*/ |
| base::queue<uint64_t>{{100, 101, 102, 103, 104}}); |
| |
| run_loop.Run(); |
| |
| return result; |
| } |
| |
| void AddHistoryEntries(const std::vector<std::string>& hosts, |
| base::Time time) { |
| history::HistoryAddPageArgs add_page_args; |
| add_page_args.time = time; |
| add_page_args.context_id = reinterpret_cast<history::ContextID>(1); |
| |
| for (const std::string& host : hosts) { |
| static int nav_entry_id = 0; |
| ++nav_entry_id; |
| |
| add_page_args.url = GURL(base::StrCat({"https://", host})); |
| add_page_args.nav_entry_id = nav_entry_id; |
| |
| history_service_->AddPage(add_page_args); |
| history_service_->SetBrowsingTopicsAllowed( |
| add_page_args.context_id, nav_entry_id, add_page_args.url); |
| } |
| |
| task_environment_.RunUntilIdle(); |
| } |
| |
| void AddApiUsageContextEntries( |
| const std::vector<std::pair<std::string, std::set<HashedDomain>>>& |
| main_frame_hosts_with_context_domains) { |
| for (auto& [main_frame_host, context_domains] : |
| main_frame_hosts_with_context_domains) { |
| topics_site_data_manager_->OnBrowsingTopicsApiUsed( |
| HashMainFrameHostForStorage(main_frame_host), |
| base::flat_set<HashedDomain>(context_domains.begin(), |
| context_domains.end()), |
| base::Time::Now()); |
| } |
| |
| task_environment_.RunUntilIdle(); |
| } |
| |
| std::vector<optimization_guide::WeightedIdentifier> TopicsAndWeight( |
| const std::vector<int32_t>& topics, |
| double weight) { |
| std::vector<optimization_guide::WeightedIdentifier> result; |
| for (int32_t topic : topics) { |
| result.emplace_back( |
| optimization_guide::WeightedIdentifier(topic, weight)); |
| } |
| |
| return result; |
| } |
| |
| void ExpectResultTopicsEqual( |
| const std::vector<TopicAndDomains>& result, |
| std::vector<std::pair<Topic, std::set<HashedDomain>>> expected) { |
| DCHECK_EQ(expected.size(), 5u); |
| EXPECT_EQ(result.size(), 5u); |
| |
| for (int i = 0; i < 5; ++i) { |
| EXPECT_EQ(result[i].topic(), expected[i].first); |
| EXPECT_EQ(result[i].hashed_domains(), expected[i].second); |
| } |
| } |
| |
| protected: |
| content::BrowserTaskEnvironment task_environment_; |
| |
| sync_preferences::TestingPrefServiceSyncable prefs_; |
| scoped_refptr<HostContentSettingsMap> host_content_settings_map_; |
| scoped_refptr<content_settings::CookieSettings> cookie_settings_; |
| std::unique_ptr<privacy_sandbox::PrivacySandboxSettings> |
| privacy_sandbox_settings_; |
| |
| std::unique_ptr<content::TesterBrowsingTopicsSiteDataManager> |
| topics_site_data_manager_; |
| |
| std::unique_ptr<history::HistoryService> history_service_; |
| |
| std::unique_ptr<optimization_guide::TestOptimizationGuideModelProvider> |
| optimization_guide_model_provider_; |
| std::unique_ptr<optimization_guide::PageContentAnnotationsService> |
| page_content_annotations_service_; |
| |
| optimization_guide::TestPageContentAnnotator test_page_content_annotator_; |
| |
| base::ScopedTempDir temp_dir_; |
| }; |
| |
| TEST_F(BrowsingTopicsCalculatorTest, PermissionDenied) { |
| base::HistogramTester histograms; |
| |
| privacy_sandbox_settings_->SetPrivacySandboxEnabled(false); |
| |
| EpochTopics result = CalculateTopics(); |
| EXPECT_TRUE(result.empty()); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus", |
| /*kFailurePermissionDenied*/ 1, |
| /*expected_bucket_count=*/1); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, ApiUsageContextQueryError) { |
| base::HistogramTester histograms; |
| |
| topics_site_data_manager_->SetQueryFailureOverride(); |
| |
| EpochTopics result = CalculateTopics(); |
| EXPECT_TRUE(result.empty()); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus", |
| /*kFailureApiUsageContextQueryError*/ 2, |
| /*expected_bucket_count=*/1); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, AnnotationExecutionError) { |
| base::HistogramTester histograms; |
| |
| EpochTopics result = CalculateTopics(); |
| EXPECT_TRUE(result.empty()); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus", |
| /*kFailureAnnotationExecutionError*/ 3, |
| /*expected_bucket_count=*/1); |
| } |
| |
| class BrowsingTopicsCalculatorUnsupporedTaxonomyVersionTest |
| : public BrowsingTopicsCalculatorTest { |
| public: |
| BrowsingTopicsCalculatorUnsupporedTaxonomyVersionTest() { |
| feature_list_.InitAndEnableFeatureWithParameters( |
| blink::features::kBrowsingTopics, {{"taxonomy_version", "999"}}); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(BrowsingTopicsCalculatorUnsupporedTaxonomyVersionTest, |
| TaxonomyVersionNotSupportedInBinary) { |
| base::HistogramTester histograms; |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), {}); |
| |
| EpochTopics result = CalculateTopics(); |
| EXPECT_TRUE(result.empty()); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus", |
| /*kFailureTaxonomyVersionNotSupportedInBinary*/ 4, |
| /*expected_bucket_count=*/1); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, TopicsMetadata) { |
| base::HistogramTester histograms; |
| base::Time begin_time = base::Time::Now(); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), {}); |
| |
| EpochTopics result1 = CalculateTopics(); |
| EXPECT_FALSE(result1.empty()); |
| EXPECT_EQ(result1.taxonomy_size(), kTaxonomySize); |
| EXPECT_EQ(result1.taxonomy_version(), kTaxonomyVersion); |
| EXPECT_EQ(result1.model_version(), 1); |
| EXPECT_EQ(result1.calculation_time(), begin_time); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus", |
| /*kSuccess*/ 0, |
| /*expected_bucket_count=*/1); |
| |
| task_environment_.AdvanceClock(base::Seconds(2)); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(50).Build(), {}); |
| |
| EpochTopics result2 = CalculateTopics(); |
| EXPECT_FALSE(result2.empty()); |
| EXPECT_EQ(result2.taxonomy_size(), kTaxonomySize); |
| EXPECT_EQ(result2.taxonomy_version(), kTaxonomyVersion); |
| EXPECT_EQ(result2.model_version(), 50); |
| EXPECT_EQ(result2.calculation_time(), begin_time + base::Seconds(2)); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus", |
| /*kSuccess*/ 0, |
| /*expected_bucket_count=*/2); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, TopTopicsRankedByFrequency) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(6), {}}, |
| {Topic(5), {}}, |
| {Topic(4), {}}, |
| {Topic(3), {}}, |
| {Topic(2), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 5u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, ModelHasNoTopicsForHost) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, {}}, |
| {kTokenizedHost2, {}}, |
| {kTokenizedHost3, {}}, |
| {kTokenizedHost4, {}}, |
| {kTokenizedHost5, {}}, |
| {kTokenizedHost6, {}}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(101), {}}, |
| {Topic(102), {}}, |
| {Topic(103), {}}, |
| {Topic(104), {}}, |
| {Topic(105), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 0u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, |
| TopTopicsRankedByFrequency_AlsoAffectedByHostsCount) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost1, kHost1, kHost1, kHost1, kHost1, kHost2, |
| kHost3, kHost4, kHost5, kHost6}, |
| begin_time); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(2), {}}, |
| {Topic(1), {}}, |
| {Topic(6), {}}, |
| {Topic(5), {}}, |
| {Topic(4), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 5u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, |
| TopTopicsRankingNotAffectedByAnnotationWeight) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time); |
| |
| // Setting the weight for Topic(1) and Topic(2) to 0.9. This weight shouldn't |
| // affect the top topics ordering. |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2}, 0.9)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(6), {}}, |
| {Topic(5), {}}, |
| {Topic(4), {}}, |
| {Topic(3), {}}, |
| {Topic(2), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 5u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, AllTopTopicsRandomlyPadded) { |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(101), {}}, |
| {Topic(102), {}}, |
| {Topic(103), {}}, |
| {Topic(104), {}}, |
| {Topic(105), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 0u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, TopTopicsPartiallyPadded) { |
| base::HistogramTester histograms; |
| |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(6), {}}, |
| {Topic(5), {}}, |
| {Topic(4), {}}, |
| {Topic(101), {}}, |
| {Topic(102), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 3u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, CalculationResultUkm_FailedCalculation) { |
| ukm::TestAutoSetUkmRecorder ukm_recorder; |
| privacy_sandbox_settings_->SetPrivacySandboxEnabled(false); |
| |
| CalculateTopics(); |
| |
| auto entries = ukm_recorder.GetEntriesByName( |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::kEntryName); |
| EXPECT_EQ(1u, entries.size()); |
| |
| EXPECT_FALSE(ukm_recorder.GetEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kTopTopic0Name)); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, CalculationResultUkm) { |
| ukm::TestAutoSetUkmRecorder ukm_recorder; |
| base::HistogramTester histograms; |
| |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| CalculateTopics(); |
| |
| auto entries = ukm_recorder.GetEntriesByName( |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::kEntryName); |
| EXPECT_EQ(1u, entries.size()); |
| |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kTopTopic0Name, |
| 6); |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kTopTopic1Name, |
| 5); |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kTopTopic2Name, |
| 4); |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kTopTopic3Name, |
| 101); |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kTopTopic4Name, |
| 102); |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kTaxonomyVersionName, |
| 1); |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kModelVersionName, |
| 1); |
| ukm_recorder.ExpectEntryMetric( |
| entries.back(), |
| ukm::builders::BrowsingTopics_EpochTopicsCalculationResult:: |
| kPaddedTopicsStartIndexName, |
| 3); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, TopTopicsAndObservingDomains) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time); |
| |
| AddApiUsageContextEntries( |
| {{kHost1, {}}, |
| {kHost2, {}}, |
| {kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual( |
| result.top_topics_and_observing_domains(), |
| {{Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(4), {HashedDomain(2), HashedDomain(3)}}, |
| {Topic(3), {HashedDomain(2)}}, |
| {Topic(2), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 5u); |
| } |
| |
| TEST_F( |
| BrowsingTopicsCalculatorTest, |
| HistoryHostsBefore21DaysAgo_IgnoredForTopTopicsDecision_IgnoredForObservingDomainsDecision) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time - base::Days(21)); |
| |
| AddApiUsageContextEntries( |
| {{kHost1, {}}, |
| {kHost2, {}}, |
| {kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 103, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 103, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({103, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(101), {}}, |
| {Topic(102), {}}, |
| {Topic(103), {}}, |
| {Topic(104), {}}, |
| {Topic(105), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 0u); |
| } |
| |
| TEST_F( |
| BrowsingTopicsCalculatorTest, |
| HistoryHostsBetween7And21Days_IgnoredForTopTopicsDecision_ConsideredForObservingDomainsDecision) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time - base::Days(20)); |
| |
| AddApiUsageContextEntries( |
| {{kHost1, {}}, |
| {kHost2, {}}, |
| {kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 103, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 103, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({103, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(101), {}}, |
| {Topic(102), {}}, |
| {Topic(103), {HashedDomain(2)}}, |
| {Topic(104), {}}, |
| {Topic(105), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 0u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, |
| DataQueryBoundedByTopicsDataAccessibleSince) { |
| base::Time begin_time = base::Time::Now(); |
| |
| prefs_.SetTime(prefs::kPrivacySandboxTopicsDataAccessibleSince, |
| begin_time + base::Days(6)); |
| |
| AddHistoryEntries({kHost1, kHost2}, begin_time); |
| AddApiUsageContextEntries({{kHost1, {}}, {kHost2, {}}}); |
| |
| task_environment_.AdvanceClock(base::Days(6)); |
| |
| AddHistoryEntries({kHost3, kHost4, kHost5, kHost6}, |
| begin_time + base::Days(6)); |
| AddApiUsageContextEntries( |
| {{kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual( |
| result.top_topics_and_observing_domains(), |
| {{Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(4), {HashedDomain(2), HashedDomain(3)}}, |
| {Topic(3), {HashedDomain(2)}}, |
| {Topic(101), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 4u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, |
| TopTopicsAndObservingDomains_DomainsSizeExceedsLimit) { |
| base::Time begin_time = base::Time::Now(); |
| |
| std::set<HashedDomain> large_size_domains; |
| for (int i = 1; i <= 1001; ++i) { |
| large_size_domains.insert(HashedDomain(i)); |
| } |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time); |
| |
| AddApiUsageContextEntries({{kHost1, {}}, |
| {kHost2, {}}, |
| {kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, large_size_domains}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| std::set<HashedDomain> expected_domains_after_capping = large_size_domains; |
| expected_domains_after_capping.erase(HashedDomain(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual(result.top_topics_and_observing_domains(), |
| {{Topic(6), expected_domains_after_capping}, |
| {Topic(5), expected_domains_after_capping}, |
| {Topic(4), {HashedDomain(2), HashedDomain(3)}}, |
| {Topic(3), {HashedDomain(2)}}, |
| {Topic(2), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 5u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, TopicBlocked) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6}, |
| begin_time); |
| |
| AddApiUsageContextEntries( |
| {{kHost1, {}}, |
| {kHost2, {}}, |
| {kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| privacy_sandbox_settings_->SetTopicAllowed( |
| privacy_sandbox::CanonicalTopic(Topic(6), kTaxonomyVersion), |
| /*allowed=*/false); |
| privacy_sandbox_settings_->SetTopicAllowed( |
| privacy_sandbox::CanonicalTopic(Topic(4), kTaxonomyVersion), |
| /*allowed=*/false); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual( |
| result.top_topics_and_observing_domains(), |
| {{Topic(0), {}}, |
| {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(0), {}}, |
| {Topic(3), {HashedDomain(2)}}, |
| {Topic(2), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 5u); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, PaddedTopicsDoNotDuplicate) { |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time); |
| |
| AddApiUsageContextEntries( |
| {{kHost1, {}}, |
| {kHost2, {}}, |
| {kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 102}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 102}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 102}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 102}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 102}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({102}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual( |
| result.top_topics_and_observing_domains(), |
| {{Topic(102), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(4), {HashedDomain(3)}}, |
| {Topic(101), {}}, |
| {Topic(103), {}}}); |
| } |
| |
| TEST_F(BrowsingTopicsCalculatorTest, Metrics) { |
| base::HistogramTester histograms; |
| |
| base::Time begin_time = base::Time::Now(); |
| |
| AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time); |
| |
| AddApiUsageContextEntries( |
| {{kHost1, {}}, |
| {kHost2, {}}, |
| {kHost3, {HashedDomain(2)}}, |
| {kHost4, {HashedDomain(3)}}, |
| {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}}); |
| |
| test_page_content_annotator_.UsePageTopics( |
| *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build(), |
| {{kTokenizedHost1, TopicsAndWeight({1, 2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost2, TopicsAndWeight({2, 3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost3, TopicsAndWeight({3, 4, 5, 6}, 0.1)}, |
| {kTokenizedHost4, TopicsAndWeight({4, 5, 6}, 0.1)}, |
| {kTokenizedHost5, TopicsAndWeight({5, 6}, 0.1)}, |
| {kTokenizedHost6, TopicsAndWeight({6}, 0.1)}}); |
| |
| task_environment_.AdvanceClock(base::Seconds(1)); |
| |
| EpochTopics result = CalculateTopics(); |
| ExpectResultTopicsEqual( |
| result.top_topics_and_observing_domains(), |
| {{Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}, |
| {Topic(4), {HashedDomain(3)}}, |
| {Topic(101), {}}, |
| {Topic(102), {}}}); |
| |
| EXPECT_EQ(result.padded_top_topics_start_index(), 3u); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.EligibleDistinctHistoryHostsCount", |
| /*sample=*/3, |
| /*expected_bucket_count=*/1); |
| |
| histograms.ExpectUniqueSample( |
| "BrowsingTopics.EpochTopicsCalculation.TopTopicsCountBeforePadding", |
| /*sample=*/3, |
| /*expected_bucket_count=*/1); |
| |
| histograms.ExpectTotalCount( |
| "BrowsingTopics.EpochTopicsCalculation." |
| "ObservationContextDomainsCountPerTopTopic", |
| /*count=*/5); |
| histograms.ExpectBucketCount( |
| "BrowsingTopics.EpochTopicsCalculation." |
| "ObservationContextDomainsCountPerTopTopic", |
| /*sample=*/0, |
| /*expected_count=*/2); |
| histograms.ExpectBucketCount( |
| "BrowsingTopics.EpochTopicsCalculation." |
| "ObservationContextDomainsCountPerTopTopic", |
| /*sample=*/1, |
| /*expected_count=*/1); |
| histograms.ExpectBucketCount( |
| "BrowsingTopics.EpochTopicsCalculation." |
| "ObservationContextDomainsCountPerTopTopic", |
| /*sample=*/3, |
| /*expected_count=*/2); |
| } |
| |
| } // namespace browsing_topics |