Fix emulator build error
[platform/framework/web/chromium-efl.git] / components / browsing_topics / browsing_topics_calculator_unittest.cc
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/browsing_topics/browsing_topics_calculator.h"
6 #include <memory>
7
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/logging.h"
10 #include "base/strings/strcat.h"
11 #include "base/test/bind.h"
12 #include "base/test/gtest_util.h"
13 #include "base/test/metrics/histogram_tester.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "components/browsing_topics/test_util.h"
16 #include "components/browsing_topics/util.h"
17 #include "components/content_settings/core/browser/cookie_settings.h"
18 #include "components/content_settings/core/browser/host_content_settings_map.h"
19 #include "components/history/core/browser/history_database_params.h"
20 #include "components/history/core/browser/history_service.h"
21 #include "components/history/core/test/test_history_database.h"
22 #include "components/optimization_guide/core/test_model_info_builder.h"
23 #include "components/privacy_sandbox/privacy_sandbox_prefs.h"
24 #include "components/privacy_sandbox/privacy_sandbox_settings_impl.h"
25 #include "components/privacy_sandbox/privacy_sandbox_test_util.h"
26 #include "components/privacy_sandbox/tracking_protection_settings.h"
27 #include "components/sync_preferences/testing_pref_service_syncable.h"
28 #include "components/ukm/test_ukm_recorder.h"
29 #include "content/public/test/browser_task_environment.h"
30 #include "content/public/test/browsing_topics_test_util.h"
31 #include "services/metrics/public/cpp/ukm_builders.h"
32 #include "third_party/blink/public/common/features.h"
33
34 namespace browsing_topics {
35
36 namespace {
37
38 constexpr int kTaxonomyVersion = 1;
39
40 constexpr char kHost1[] = "www.foo1.com";
41 constexpr char kHost2[] = "www.foo2.com";
42 constexpr char kHost3[] = "www.foo3.com";
43 constexpr char kHost4[] = "www.foo4.com";
44 constexpr char kHost5[] = "www.foo5.com";
45 constexpr char kHost6[] = "www.foo6.com";
46
47 }  // namespace
48
49 class BrowsingTopicsCalculatorTest : public testing::Test {
50  public:
51   BrowsingTopicsCalculatorTest()
52       : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
53     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
54
55     content_settings::CookieSettings::RegisterProfilePrefs(prefs_.registry());
56     HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
57     privacy_sandbox::RegisterProfilePrefs(prefs_.registry());
58
59     host_content_settings_map_ = base::MakeRefCounted<HostContentSettingsMap>(
60         &prefs_, /*is_off_the_record=*/false, /*store_last_modified=*/false,
61         /*restore_session=*/false, /*should_record_metrics=*/false);
62     tracking_protection_settings_ =
63         std::make_unique<privacy_sandbox::TrackingProtectionSettings>(
64             &prefs_,
65             /*onboarding_service=*/nullptr, /*is_incognito=*/false);
66     cookie_settings_ = base::MakeRefCounted<content_settings::CookieSettings>(
67         host_content_settings_map_.get(), &prefs_,
68         tracking_protection_settings_.get(), false, "chrome-extension");
69     auto privacy_sandbox_delegate = std::make_unique<
70         privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>();
71     privacy_sandbox_delegate->SetUpIsPrivacySandboxRestrictedResponse(
72         /*restricted=*/false);
73     privacy_sandbox_delegate->SetUpIsIncognitoProfileResponse(
74         /*incognito=*/false);
75     privacy_sandbox_settings_ =
76         std::make_unique<privacy_sandbox::PrivacySandboxSettingsImpl>(
77             std::move(privacy_sandbox_delegate),
78             host_content_settings_map_.get(), cookie_settings_,
79             tracking_protection_settings_.get(), &prefs_);
80     privacy_sandbox_settings_->SetAllPrivacySandboxAllowedForTesting();
81
82     topics_site_data_manager_ =
83         std::make_unique<content::TesterBrowsingTopicsSiteDataManager>(
84             temp_dir_.GetPath());
85
86     history_service_ = std::make_unique<history::HistoryService>();
87     history_service_->Init(
88         history::TestHistoryDatabaseParamsForPath(temp_dir_.GetPath()));
89
90     task_environment_.RunUntilIdle();
91   }
92
93   ~BrowsingTopicsCalculatorTest() override {
94     cookie_settings_->ShutdownOnUIThread();
95     host_content_settings_map_->ShutdownOnUIThread();
96     tracking_protection_settings_->Shutdown();
97   }
98
99   EpochTopics CalculateTopics(base::circular_deque<EpochTopics> epochs = {}) {
100     EpochTopics result = EpochTopics(base::Time());
101
102     base::RunLoop run_loop;
103
104     TesterBrowsingTopicsCalculator topics_calculator =
105         TesterBrowsingTopicsCalculator(
106             privacy_sandbox_settings_.get(), history_service_.get(),
107             topics_site_data_manager_.get(), &test_annotator_, epochs,
108             base::BindLambdaForTesting([&](EpochTopics epoch_topics) {
109               result = std::move(epoch_topics);
110               run_loop.Quit();
111             }),
112             /*rand_uint64_queue=*/
113             base::queue<uint64_t>{{100, 101, 102, 103, 104}});
114
115     run_loop.Run();
116
117     return result;
118   }
119
120   void AddHistoryEntries(const std::vector<std::string>& hosts,
121                          base::Time time) {
122     history::HistoryAddPageArgs add_page_args;
123     add_page_args.time = time;
124     add_page_args.context_id = 1;
125
126     for (const std::string& host : hosts) {
127       static int nav_entry_id = 0;
128       ++nav_entry_id;
129
130       add_page_args.url = GURL(base::StrCat({"https://", host}));
131       add_page_args.nav_entry_id = nav_entry_id;
132
133       history_service_->AddPage(add_page_args);
134       history_service_->SetBrowsingTopicsAllowed(
135           add_page_args.context_id, nav_entry_id, add_page_args.url);
136     }
137
138     task_environment_.RunUntilIdle();
139   }
140
141   void AddApiUsageContextEntries(
142       const std::vector<std::pair<std::string, std::set<HashedDomain>>>&
143           main_frame_hosts_with_context_domains) {
144     for (auto& [main_frame_host, context_domains] :
145          main_frame_hosts_with_context_domains) {
146       for (const HashedDomain& context_domain : context_domains) {
147         topics_site_data_manager_->OnBrowsingTopicsApiUsed(
148             HashMainFrameHostForStorage(main_frame_host), context_domain,
149             base::NumberToString(context_domain.value()), base::Time::Now());
150       }
151     }
152
153     task_environment_.RunUntilIdle();
154   }
155
156   void ExpectResultTopicsEqual(
157       const std::vector<TopicAndDomains>& result,
158       std::vector<std::pair<Topic, std::set<HashedDomain>>> expected) {
159     DCHECK_EQ(expected.size(), 5u);
160     EXPECT_EQ(result.size(), 5u);
161
162     for (int i = 0; i < 5; ++i) {
163       EXPECT_EQ(result[i].topic(), expected[i].first);
164       EXPECT_EQ(result[i].hashed_domains(), expected[i].second);
165     }
166   }
167
168  protected:
169   content::BrowserTaskEnvironment task_environment_;
170
171   sync_preferences::TestingPrefServiceSyncable prefs_;
172   scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
173   scoped_refptr<content_settings::CookieSettings> cookie_settings_;
174   std::unique_ptr<privacy_sandbox::TrackingProtectionSettings>
175       tracking_protection_settings_;
176   std::unique_ptr<privacy_sandbox::PrivacySandboxSettings>
177       privacy_sandbox_settings_;
178   TestAnnotator test_annotator_;
179
180   std::unique_ptr<content::TesterBrowsingTopicsSiteDataManager>
181       topics_site_data_manager_;
182
183   std::unique_ptr<history::HistoryService> history_service_;
184
185   base::ScopedTempDir temp_dir_;
186 };
187
188 TEST_F(BrowsingTopicsCalculatorTest, PermissionDenied) {
189   base::HistogramTester histograms;
190
191   privacy_sandbox_settings_->SetTopicsBlockedForTesting();
192
193   EpochTopics result = CalculateTopics();
194   EXPECT_TRUE(result.empty());
195
196   histograms.ExpectUniqueSample(
197       "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus",
198       /*kFailurePermissionDenied*/ 1,
199       /*expected_bucket_count=*/1);
200 }
201
202 TEST_F(BrowsingTopicsCalculatorTest, ApiUsageContextQueryError) {
203   base::HistogramTester histograms;
204
205   topics_site_data_manager_->SetQueryFailureOverride();
206
207   EpochTopics result = CalculateTopics();
208   EXPECT_TRUE(result.empty());
209
210   histograms.ExpectUniqueSample(
211       "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus",
212       /*kFailureApiUsageContextQueryError*/ 2,
213       /*expected_bucket_count=*/1);
214 }
215
216 TEST_F(BrowsingTopicsCalculatorTest, AnnotationExecutionError) {
217   base::HistogramTester histograms;
218
219   EpochTopics result = CalculateTopics();
220   EXPECT_TRUE(result.empty());
221
222   histograms.ExpectUniqueSample(
223       "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus",
224       /*kFailureAnnotationExecutionError*/ 3,
225       /*expected_bucket_count=*/1);
226 }
227
228 class BrowsingTopicsCalculatorUnsupporedTaxonomyVersionTest
229     : public BrowsingTopicsCalculatorTest {
230  public:
231   BrowsingTopicsCalculatorUnsupporedTaxonomyVersionTest() {
232     feature_list_.InitAndEnableFeatureWithParameters(
233         blink::features::kBrowsingTopicsParameters,
234         {{"taxonomy_version", "999"}});
235   }
236
237  private:
238   base::test::ScopedFeatureList feature_list_;
239 };
240
241 TEST_F(BrowsingTopicsCalculatorUnsupporedTaxonomyVersionTest,
242        TaxonomyVersionNotSupportedInBinary) {
243   base::HistogramTester histograms;
244
245   test_annotator_.UseModelInfo(
246       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
247
248   EpochTopics result = CalculateTopics();
249   EXPECT_TRUE(result.empty());
250
251   histograms.ExpectUniqueSample(
252       "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus",
253       /*kFailureTaxonomyVersionNotSupportedInBinary*/ 4,
254       /*expected_bucket_count=*/1);
255 }
256
257 TEST_F(BrowsingTopicsCalculatorTest, TopicsMetadata) {
258   base::HistogramTester histograms;
259   base::Time begin_time = base::Time::Now();
260
261   test_annotator_.UseModelInfo(
262       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
263
264   EpochTopics result1 = CalculateTopics();
265   EXPECT_FALSE(result1.empty());
266   EXPECT_EQ(result1.taxonomy_version(), kTaxonomyVersion);
267   EXPECT_EQ(result1.model_version(), 1);
268   EXPECT_EQ(result1.calculation_time(), begin_time);
269
270   histograms.ExpectUniqueSample(
271       "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus",
272       /*kSuccess*/ 0,
273       /*expected_bucket_count=*/1);
274
275   task_environment_.AdvanceClock(base::Seconds(2));
276
277   test_annotator_.UseModelInfo(
278       *optimization_guide::TestModelInfoBuilder().SetVersion(50).Build());
279
280   EpochTopics result2 = CalculateTopics();
281   EXPECT_FALSE(result2.empty());
282
283   EXPECT_EQ(result2.taxonomy_version(), kTaxonomyVersion);
284   EXPECT_EQ(result2.model_version(), 50);
285   EXPECT_EQ(result2.calculation_time(), begin_time + base::Seconds(2));
286
287   histograms.ExpectUniqueSample(
288       "BrowsingTopics.EpochTopicsCalculation.CalculatorResultStatus",
289       /*kSuccess*/ 0,
290       /*expected_bucket_count=*/2);
291 }
292
293 // Regression test for crbug/1495959.
294 TEST_F(BrowsingTopicsCalculatorTest, ModelAvailableAfterDelay) {
295   test_annotator_.SetModelAvailable(false);
296
297   base::Time begin_time = base::Time::Now();
298
299   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
300                     begin_time);
301
302   task_environment_.AdvanceClock(base::Seconds(1));
303
304   // This PostTask will run when the |CalculateTopics| run loop starts and will
305   // signal to the calculator that the model is ready, triggering it to start.
306   task_environment_.GetMainThreadTaskRunner()->PostTask(
307       FROM_HERE,
308       base::BindOnce(
309           [](TestAnnotator* annotator) {
310             annotator->UseModelInfo(*optimization_guide::TestModelInfoBuilder()
311                                          .SetVersion(1)
312                                          .Build());
313             annotator->UseAnnotations({
314                 {kHost1, {1, 2, 3, 4, 5, 6}},
315                 {kHost2, {2, 3, 4, 5, 6}},
316                 {kHost3, {3, 4, 5, 6}},
317                 {kHost4, {4, 5, 6}},
318                 {kHost5, {5, 6}},
319                 {kHost6, {6}},
320             });
321             annotator->SetModelAvailable(true);
322           },
323           &test_annotator_));
324
325   EpochTopics result = CalculateTopics();
326   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
327                           {{Topic(6), {}},
328                            {Topic(5), {}},
329                            {Topic(4), {}},
330                            {Topic(3), {}},
331                            {Topic(2), {}}});
332
333   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
334 }
335
336 TEST_F(BrowsingTopicsCalculatorTest, TopTopicsRankedByFrequency) {
337   base::Time begin_time = base::Time::Now();
338
339   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
340                     begin_time);
341
342   test_annotator_.UseModelInfo(
343       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
344   test_annotator_.UseAnnotations({
345       {kHost1, {1, 2, 3, 4, 5, 6}},
346       {kHost2, {2, 3, 4, 5, 6}},
347       {kHost3, {3, 4, 5, 6}},
348       {kHost4, {4, 5, 6}},
349       {kHost5, {5, 6}},
350       {kHost6, {6}},
351   });
352
353   task_environment_.AdvanceClock(base::Seconds(1));
354
355   EpochTopics result = CalculateTopics();
356   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
357                           {{Topic(6), {}},
358                            {Topic(5), {}},
359                            {Topic(4), {}},
360                            {Topic(3), {}},
361                            {Topic(2), {}}});
362
363   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
364 }
365
366 TEST_F(BrowsingTopicsCalculatorTest, ModelHasNoTopicsForHost) {
367   base::Time begin_time = base::Time::Now();
368
369   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
370                     begin_time);
371
372   test_annotator_.UseModelInfo(
373       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
374
375   task_environment_.AdvanceClock(base::Seconds(1));
376
377   EpochTopics result = CalculateTopics();
378   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
379                           {{Topic(101), {}},
380                            {Topic(102), {}},
381                            {Topic(103), {}},
382                            {Topic(104), {}},
383                            {Topic(105), {}}});
384
385   EXPECT_EQ(result.padded_top_topics_start_index(), 0u);
386 }
387
388 TEST_F(BrowsingTopicsCalculatorTest,
389        TopTopicsRankedByFrequency_AlsoAffectedByHostsCount) {
390   base::Time begin_time = base::Time::Now();
391
392   AddHistoryEntries({kHost1, kHost1, kHost1, kHost1, kHost1, kHost1, kHost2,
393                      kHost3, kHost4, kHost5, kHost6},
394                     begin_time);
395
396   test_annotator_.UseModelInfo(
397       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
398   test_annotator_.UseAnnotations({
399       {kHost1, {1, 2}},
400       {kHost2, {2, 3, 4, 5, 6}},
401       {kHost3, {3, 4, 5, 6}},
402       {kHost4, {4, 5, 6}},
403       {kHost5, {5, 6}},
404       {kHost6, {6}},
405   });
406
407   task_environment_.AdvanceClock(base::Seconds(1));
408
409   EpochTopics result = CalculateTopics();
410   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
411                           {{Topic(2), {}},
412                            {Topic(1), {}},
413                            {Topic(6), {}},
414                            {Topic(5), {}},
415                            {Topic(4), {}}});
416
417   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
418 }
419
420 TEST_F(BrowsingTopicsCalculatorTest, AllTopTopicsRandomlyPadded) {
421   test_annotator_.UseModelInfo(
422       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
423   test_annotator_.UseAnnotations({
424       {kHost1, {1, 2, 3, 4, 5, 6}},
425       {kHost2, {2, 3, 4, 5, 6}},
426       {kHost3, {3, 4, 5, 6}},
427       {kHost4, {4, 5, 6}},
428       {kHost5, {5, 6}},
429       {kHost6, {6}},
430   });
431
432   EpochTopics result = CalculateTopics();
433   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
434                           {{Topic(101), {}},
435                            {Topic(102), {}},
436                            {Topic(103), {}},
437                            {Topic(104), {}},
438                            {Topic(105), {}}});
439
440   EXPECT_EQ(result.padded_top_topics_start_index(), 0u);
441 }
442
443 TEST_F(BrowsingTopicsCalculatorTest, TopTopicsPartiallyPadded) {
444   base::HistogramTester histograms;
445
446   base::Time begin_time = base::Time::Now();
447
448   AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time);
449
450   test_annotator_.UseModelInfo(
451       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
452   test_annotator_.UseAnnotations({
453       {kHost1, {1, 2, 3, 4, 5, 6}},
454       {kHost2, {2, 3, 4, 5, 6}},
455       {kHost3, {3, 4, 5, 6}},
456       {kHost4, {4, 5, 6}},
457       {kHost5, {5, 6}},
458       {kHost6, {6}},
459   });
460
461   task_environment_.AdvanceClock(base::Seconds(1));
462
463   EpochTopics result = CalculateTopics();
464   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
465                           {{Topic(6), {}},
466                            {Topic(5), {}},
467                            {Topic(4), {}},
468                            {Topic(101), {}},
469                            {Topic(102), {}}});
470
471   EXPECT_EQ(result.padded_top_topics_start_index(), 3u);
472 }
473
474 TEST_F(BrowsingTopicsCalculatorTest, CalculationResultUkm_FailedCalculation) {
475   ukm::TestAutoSetUkmRecorder ukm_recorder;
476   privacy_sandbox_settings_->SetTopicsBlockedForTesting();
477
478   CalculateTopics();
479
480   auto entries = ukm_recorder.GetEntriesByName(
481       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::kEntryName);
482   EXPECT_EQ(1u, entries.size());
483
484   EXPECT_FALSE(ukm_recorder.GetEntryMetric(
485       entries.back(),
486       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
487           kTopTopic0Name));
488 }
489
490 TEST_F(BrowsingTopicsCalculatorTest, CalculationResultUkm) {
491   ukm::TestAutoSetUkmRecorder ukm_recorder;
492   base::HistogramTester histograms;
493
494   base::Time begin_time = base::Time::Now();
495
496   AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time);
497
498   test_annotator_.UseModelInfo(
499       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
500   test_annotator_.UseAnnotations({
501       {kHost1, {1, 2, 3, 4, 5, 6}},
502       {kHost2, {2, 3, 4, 5, 6}},
503       {kHost3, {3, 4, 5, 6}},
504       {kHost4, {4, 5, 6}},
505       {kHost5, {5, 6}},
506       {kHost6, {6}},
507   });
508
509   task_environment_.AdvanceClock(base::Seconds(1));
510
511   CalculateTopics();
512
513   auto entries = ukm_recorder.GetEntriesByName(
514       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::kEntryName);
515   EXPECT_EQ(1u, entries.size());
516
517   ukm_recorder.ExpectEntryMetric(
518       entries.back(),
519       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
520           kTopTopic0Name,
521       6);
522   ukm_recorder.ExpectEntryMetric(
523       entries.back(),
524       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
525           kTopTopic1Name,
526       5);
527   ukm_recorder.ExpectEntryMetric(
528       entries.back(),
529       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
530           kTopTopic2Name,
531       4);
532   ukm_recorder.ExpectEntryMetric(
533       entries.back(),
534       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
535           kTopTopic3Name,
536       101);
537   ukm_recorder.ExpectEntryMetric(
538       entries.back(),
539       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
540           kTopTopic4Name,
541       102);
542   ukm_recorder.ExpectEntryMetric(
543       entries.back(),
544       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
545           kTaxonomyVersionName,
546       1);
547   ukm_recorder.ExpectEntryMetric(
548       entries.back(),
549       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
550           kModelVersionName,
551       1);
552   ukm_recorder.ExpectEntryMetric(
553       entries.back(),
554       ukm::builders::BrowsingTopics_EpochTopicsCalculationResult::
555           kPaddedTopicsStartIndexName,
556       3);
557 }
558
559 TEST_F(BrowsingTopicsCalculatorTest, TopTopicsAndObservingDomains) {
560   base::Time begin_time = base::Time::Now();
561
562   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
563                     begin_time);
564
565   AddApiUsageContextEntries(
566       {{kHost1, {}},
567        {kHost2, {}},
568        {kHost3, {HashedDomain(2)}},
569        {kHost4, {HashedDomain(3)}},
570        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
571
572   test_annotator_.UseModelInfo(
573       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
574   test_annotator_.UseAnnotations({
575       {kHost1, {1, 2, 3, 4, 5, 6}},
576       {kHost2, {2, 3, 4, 5, 6}},
577       {kHost3, {3, 4, 5, 6}},
578       {kHost4, {4, 5, 6}},
579       {kHost5, {5, 6}},
580       {kHost6, {6}},
581   });
582
583   task_environment_.AdvanceClock(base::Seconds(1));
584
585   EpochTopics result = CalculateTopics();
586   ExpectResultTopicsEqual(
587       result.top_topics_and_observing_domains(),
588       {{Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
589        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
590        {Topic(4), {HashedDomain(2), HashedDomain(3)}},
591        {Topic(3), {HashedDomain(2)}},
592        {Topic(2), {}}});
593
594   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
595 }
596
597 TEST_F(
598     BrowsingTopicsCalculatorTest,
599     HistoryHostsBefore21DaysAgo_IgnoredForTopTopicsDecision_IgnoredForObservingDomainsDecision) {
600   base::Time begin_time = base::Time::Now();
601
602   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
603                     begin_time - base::Days(21));
604
605   AddApiUsageContextEntries(
606       {{kHost1, {}},
607        {kHost2, {}},
608        {kHost3, {HashedDomain(2)}},
609        {kHost4, {HashedDomain(3)}},
610        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
611
612   test_annotator_.UseModelInfo(
613       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
614   test_annotator_.UseAnnotations({
615       {kHost1, {1, 2, 103, 4, 5, 6}},
616       {kHost2, {2, 103, 4, 5, 6}},
617       {kHost3, {103, 4, 5, 6}},
618       {kHost4, {4, 5, 6}},
619       {kHost5, {5, 6}},
620       {kHost6, {6}},
621   });
622
623   task_environment_.AdvanceClock(base::Seconds(1));
624
625   EpochTopics result = CalculateTopics();
626   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
627                           {{Topic(101), {}},
628                            {Topic(102), {}},
629                            {Topic(103), {}},
630                            {Topic(104), {}},
631                            {Topic(105), {}}});
632
633   EXPECT_EQ(result.padded_top_topics_start_index(), 0u);
634 }
635
636 TEST_F(
637     BrowsingTopicsCalculatorTest,
638     HistoryHostsBetween7And21Days_IgnoredForTopTopicsDecision_ConsideredForObservingDomainsDecision) {
639   base::Time begin_time = base::Time::Now();
640
641   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
642                     begin_time - base::Days(20));
643
644   AddApiUsageContextEntries(
645       {{kHost1, {}},
646        {kHost2, {}},
647        {kHost3, {HashedDomain(2)}},
648        {kHost4, {HashedDomain(3)}},
649        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
650
651   test_annotator_.UseModelInfo(
652       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
653   test_annotator_.UseAnnotations({
654       {kHost1, {1, 2, 103, 4, 5, 6}},
655       {kHost2, {2, 103, 4, 5, 6}},
656       {kHost3, {103, 4, 5, 6}},
657       {kHost4, {4, 5, 6}},
658       {kHost5, {5, 6}},
659       {kHost6, {6}},
660   });
661
662   task_environment_.AdvanceClock(base::Seconds(1));
663
664   EpochTopics result = CalculateTopics();
665   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
666                           {{Topic(101), {}},
667                            {Topic(102), {}},
668                            {Topic(103), {HashedDomain(2)}},
669                            {Topic(104), {}},
670                            {Topic(105), {}}});
671
672   EXPECT_EQ(result.padded_top_topics_start_index(), 0u);
673 }
674
675 TEST_F(BrowsingTopicsCalculatorTest,
676        DataQueryBoundedByTopicsDataAccessibleSince) {
677   base::Time begin_time = base::Time::Now();
678
679   prefs_.SetTime(prefs::kPrivacySandboxTopicsDataAccessibleSince,
680                  begin_time + base::Days(6));
681
682   AddHistoryEntries({kHost1, kHost2}, begin_time);
683   AddApiUsageContextEntries({{kHost1, {}}, {kHost2, {}}});
684
685   task_environment_.AdvanceClock(base::Days(6));
686
687   AddHistoryEntries({kHost3, kHost4, kHost5, kHost6},
688                     begin_time + base::Days(6));
689   AddApiUsageContextEntries(
690       {{kHost3, {HashedDomain(2)}},
691        {kHost4, {HashedDomain(3)}},
692        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
693
694   test_annotator_.UseModelInfo(
695       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
696   test_annotator_.UseAnnotations({
697       {kHost1, {1, 2, 3, 4, 5, 6}},
698       {kHost2, {2, 3, 4, 5, 6}},
699       {kHost3, {3, 4, 5, 6}},
700       {kHost4, {4, 5, 6}},
701       {kHost5, {5, 6}},
702       {kHost6, {6}},
703   });
704
705   task_environment_.AdvanceClock(base::Seconds(1));
706
707   EpochTopics result = CalculateTopics();
708   ExpectResultTopicsEqual(
709       result.top_topics_and_observing_domains(),
710       {{Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
711        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
712        {Topic(4), {HashedDomain(2), HashedDomain(3)}},
713        {Topic(3), {HashedDomain(2)}},
714        {Topic(101), {}}});
715
716   EXPECT_EQ(result.padded_top_topics_start_index(), 4u);
717 }
718
719 TEST_F(BrowsingTopicsCalculatorTest,
720        HistoryDataBoundedByLastEpochCalculationTime) {
721   base::Time begin_time = base::Time::Now();
722   AddHistoryEntries({kHost1, kHost2, kHost3}, begin_time);
723   AddApiUsageContextEntries({{kHost3, {HashedDomain(5)}}});
724
725   task_environment_.AdvanceClock(base::Days(4));
726   AddHistoryEntries({kHost2, kHost3}, begin_time + base::Days(4));
727   AddApiUsageContextEntries({{kHost3, {HashedDomain(2)}}});
728
729   task_environment_.AdvanceClock(base::Days(2));
730   AddHistoryEntries({kHost3, kHost4, kHost5, kHost6},
731                     begin_time + base::Days(6));
732   AddApiUsageContextEntries(
733       {{kHost4, {HashedDomain(3)}},
734        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
735
736   test_annotator_.UseModelInfo(
737       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
738   test_annotator_.UseAnnotations({
739       {kHost1, {1, 2, 3, 4, 5, 6}},
740       {kHost2, {2, 3, 4, 5, 6}},
741       {kHost3, {3, 4, 5, 6}},
742       {kHost4, {4, 5, 6}},
743       {kHost5, {5, 6}},
744       {kHost6, {6}},
745   });
746
747   task_environment_.AdvanceClock(base::Seconds(1));
748
749   base::circular_deque<EpochTopics> epochs;
750   epochs.push_back(EpochTopics(begin_time + base::Days(6)));
751
752   EpochTopics result = CalculateTopics(std::move(epochs));
753
754   // The topics are only from hosts since `begin_time + base::Days(6)`. The
755   // observing domains are from data since `begin_time`.
756   ExpectResultTopicsEqual(
757       result.top_topics_and_observing_domains(),
758       {{Topic(6),
759         {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(5)}},
760        {Topic(5),
761         {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(5)}},
762        {Topic(4), {HashedDomain(2), HashedDomain(3), HashedDomain(5)}},
763        {Topic(3), {HashedDomain(2), HashedDomain(5)}},
764        {Topic(101), {}}});
765
766   EXPECT_EQ(result.padded_top_topics_start_index(), 4u);
767 }
768
769 TEST_F(BrowsingTopicsCalculatorTest,
770        HistoryDataAndApiUsageContextDataBoundedByPriorEpochsCalculationTime) {
771   base::Time begin_time = base::Time::Now();
772   AddHistoryEntries({kHost1, kHost2, kHost3}, begin_time);
773   AddApiUsageContextEntries({{kHost3, {HashedDomain(5)}}});
774
775   task_environment_.AdvanceClock(base::Days(4));
776   AddHistoryEntries({kHost2, kHost3}, begin_time + base::Days(4));
777   AddApiUsageContextEntries({{kHost3, {HashedDomain(2)}}});
778
779   task_environment_.AdvanceClock(base::Days(2));
780   AddHistoryEntries({kHost3, kHost4, kHost5, kHost6},
781                     begin_time + base::Days(6));
782   AddApiUsageContextEntries(
783       {{kHost4, {HashedDomain(3)}},
784        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
785
786   test_annotator_.UseModelInfo(
787       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
788   test_annotator_.UseAnnotations({
789       {kHost1, {1, 2, 3, 4, 5, 6}},
790       {kHost2, {2, 3, 4, 5, 6}},
791       {kHost3, {3, 4, 5, 6}},
792       {kHost4, {4, 5, 6}},
793       {kHost5, {5, 6}},
794       {kHost6, {6}},
795   });
796
797   task_environment_.AdvanceClock(base::Seconds(1));
798
799   base::circular_deque<EpochTopics> epochs;
800   epochs.push_back(EpochTopics(begin_time + base::Days(4)));
801   epochs.push_back(EpochTopics(begin_time + base::Days(5)));
802   epochs.push_back(EpochTopics(begin_time + base::Days(6)));
803
804   EpochTopics result = CalculateTopics(std::move(epochs));
805
806   // The topics are only from hosts since `begin_time + base::Days(6)`. The
807   // observing domains are from data since `begin_time + base::Days(4)`.
808   ExpectResultTopicsEqual(
809       result.top_topics_and_observing_domains(),
810       {{Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
811        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
812        {Topic(4), {HashedDomain(2), HashedDomain(3)}},
813        {Topic(3), {HashedDomain(2)}},
814        {Topic(101), {}}});
815
816   EXPECT_EQ(result.padded_top_topics_start_index(), 4u);
817 }
818
819 TEST_F(BrowsingTopicsCalculatorTest,
820        TopTopicsAndObservingDomains_DomainsSizeExceedsLimit) {
821   base::Time begin_time = base::Time::Now();
822
823   std::set<HashedDomain> large_size_domains;
824   for (int i = 1; i <= 1001; ++i) {
825     large_size_domains.insert(HashedDomain(i));
826   }
827
828   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
829                     begin_time);
830
831   AddApiUsageContextEntries({{kHost1, {}},
832                              {kHost2, {}},
833                              {kHost3, {HashedDomain(2)}},
834                              {kHost4, {HashedDomain(3)}},
835                              {kHost5, large_size_domains}});
836
837   test_annotator_.UseModelInfo(
838       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
839   test_annotator_.UseAnnotations({
840       {kHost1, {1, 2, 3, 4, 5, 6}},
841       {kHost2, {2, 3, 4, 5, 6}},
842       {kHost3, {3, 4, 5, 6}},
843       {kHost4, {4, 5, 6}},
844       {kHost5, {5, 6}},
845       {kHost6, {6}},
846   });
847
848   task_environment_.AdvanceClock(base::Seconds(1));
849
850   std::set<HashedDomain> expected_domains_after_capping = large_size_domains;
851   expected_domains_after_capping.erase(HashedDomain(1));
852
853   EpochTopics result = CalculateTopics();
854   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
855                           {{Topic(6), expected_domains_after_capping},
856                            {Topic(5), expected_domains_after_capping},
857                            {Topic(4), {HashedDomain(2), HashedDomain(3)}},
858                            {Topic(3), {HashedDomain(2)}},
859                            {Topic(2), {}}});
860
861   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
862 }
863
864 TEST_F(BrowsingTopicsCalculatorTest, TopicBlocked) {
865   base::Time begin_time = base::Time::Now();
866
867   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
868                     begin_time);
869
870   AddApiUsageContextEntries(
871       {{kHost1, {}},
872        {kHost2, {}},
873        {kHost3, {HashedDomain(2)}},
874        {kHost4, {HashedDomain(3)}},
875        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
876
877   test_annotator_.UseModelInfo(
878       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
879   test_annotator_.UseAnnotations({
880       {kHost1, {1, 2, 3, 4, 5, 6}},
881       {kHost2, {2, 3, 4, 5, 6}},
882       {kHost3, {3, 4, 5, 6}},
883       {kHost4, {4, 5, 6}},
884       {kHost5, {5, 6}},
885       {kHost6, {6}},
886   });
887
888   task_environment_.AdvanceClock(base::Seconds(1));
889
890   privacy_sandbox_settings_->SetTopicAllowed(
891       privacy_sandbox::CanonicalTopic(Topic(6), kTaxonomyVersion),
892       /*allowed=*/false);
893   privacy_sandbox_settings_->SetTopicAllowed(
894       privacy_sandbox::CanonicalTopic(Topic(4), kTaxonomyVersion),
895       /*allowed=*/false);
896
897   EpochTopics result = CalculateTopics();
898   ExpectResultTopicsEqual(
899       result.top_topics_and_observing_domains(),
900       {{Topic(0), {}},
901        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
902        {Topic(0), {}},
903        {Topic(3), {HashedDomain(2)}},
904        {Topic(2), {}}});
905
906   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
907 }
908
909 TEST_F(BrowsingTopicsCalculatorTest, TopicBlockedByFinch) {
910   base::Time begin_time = base::Time::Now();
911
912   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
913                     begin_time);
914
915   AddApiUsageContextEntries(
916       {{kHost1, {}},
917        {kHost2, {}},
918        {kHost3, {HashedDomain(2)}},
919        {kHost4, {HashedDomain(3)}},
920        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
921
922   test_annotator_.UseModelInfo(
923       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
924   test_annotator_.UseAnnotations({
925       {kHost1, {1, 2, 3, 4, 5, 6}},
926       {kHost2, {2, 3, 4, 5, 6}},
927       {kHost3, {3, 4, 5, 6}},
928       {kHost4, {4, 5, 6}},
929       {kHost5, {5, 6}},
930       {kHost6, {6}},
931   });
932
933   task_environment_.AdvanceClock(base::Seconds(1));
934
935   base::test::ScopedFeatureList feature_list;
936   feature_list.InitAndEnableFeatureWithParameters(
937       blink::features::kBrowsingTopicsParameters,
938       {{"disabled_topics_list", "6,4"}});
939
940   EpochTopics result = CalculateTopics();
941   ExpectResultTopicsEqual(
942       result.top_topics_and_observing_domains(),
943       {{Topic(0), {}},
944        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
945        {Topic(0), {}},
946        {Topic(3), {HashedDomain(2)}},
947        {Topic(2), {}}});
948
949   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
950 }
951
952 TEST_F(BrowsingTopicsCalculatorTest, TopicsPrioritizedByFinch) {
953   base::Time begin_time = base::Time::Now();
954
955   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
956                     begin_time);
957
958   AddApiUsageContextEntries(
959       {{kHost1, {}},
960        {kHost2, {}},
961        {kHost3, {HashedDomain(2)}},
962        {kHost4, {HashedDomain(3)}},
963        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
964
965   test_annotator_.UseModelInfo(
966       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
967   test_annotator_.UseAnnotations({
968       {kHost1, {74, 2, 3, 4, 5, 6}},
969       {kHost2, {2, 3, 4, 5, 6}},
970       {kHost3, {3, 4, 5, 6}},
971       {kHost4, {4, 5, 6}},
972       {kHost5, {5, 6}},
973       {kHost6, {6}},
974   });
975
976   task_environment_.AdvanceClock(base::Seconds(1));
977
978   base::test::ScopedFeatureList feature_list;
979   feature_list.InitAndEnableFeatureWithParameters(
980       blink::features::kBrowsingTopicsParameters,
981       {{"prioritized_topics_list", "4,57"}});  // 74 is descended from 57.
982
983   EpochTopics result = CalculateTopics();
984   ExpectResultTopicsEqual(
985       result.top_topics_and_observing_domains(),
986       {{Topic(4), {HashedDomain(2), HashedDomain(3)}},
987        {Topic(74), {}},
988        {Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
989        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
990        {Topic(3), {HashedDomain(2)}}});
991
992   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
993   EXPECT_EQ(result.config_version(), 2);
994 }
995
996 TEST_F(BrowsingTopicsCalculatorTest, PaddedTopicsDoNotDuplicate) {
997   base::Time begin_time = base::Time::Now();
998
999   AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time);
1000
1001   AddApiUsageContextEntries(
1002       {{kHost1, {}},
1003        {kHost2, {}},
1004        {kHost3, {HashedDomain(2)}},
1005        {kHost4, {HashedDomain(3)}},
1006        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
1007
1008   test_annotator_.UseModelInfo(
1009       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
1010   test_annotator_.UseAnnotations({
1011       {kHost1, {1, 2, 3, 4, 5, 102}},
1012       {kHost2, {2, 3, 4, 5, 102}},
1013       {kHost3, {3, 4, 5, 102}},
1014       {kHost4, {4, 5, 102}},
1015       {kHost5, {5, 102}},
1016       {kHost6, {102}},
1017   });
1018
1019   task_environment_.AdvanceClock(base::Seconds(1));
1020
1021   EpochTopics result = CalculateTopics();
1022   ExpectResultTopicsEqual(
1023       result.top_topics_and_observing_domains(),
1024       {{Topic(102), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1025        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1026        {Topic(4), {HashedDomain(3)}},
1027        {Topic(101), {}},
1028        {Topic(103), {}}});
1029 }
1030
1031 TEST_F(BrowsingTopicsCalculatorTest, Metrics_LessThan5HistoryTopics) {
1032   base::HistogramTester histograms;
1033
1034   base::Time begin_time = base::Time::Now();
1035
1036   AddHistoryEntries({kHost4, kHost5, kHost6}, begin_time);
1037
1038   AddApiUsageContextEntries(
1039       {{kHost1, {}},
1040        {kHost2, {}},
1041        {kHost3, {HashedDomain(2)}},
1042        {kHost4, {HashedDomain(3)}},
1043        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
1044
1045   test_annotator_.UseModelInfo(
1046       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
1047   test_annotator_.UseAnnotations({
1048       {kHost1, {1, 2, 3, 4, 5, 6}},
1049       {kHost2, {2, 3, 4, 5, 6}},
1050       {kHost3, {3, 4, 5, 6}},
1051       {kHost4, {4, 5, 6}},
1052       {kHost5, {5, 6}},
1053       {kHost6, {6}},
1054   });
1055
1056   task_environment_.AdvanceClock(base::Seconds(1));
1057
1058   EpochTopics result = CalculateTopics();
1059   ExpectResultTopicsEqual(
1060       result.top_topics_and_observing_domains(),
1061       {{Topic(6), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1062        {Topic(5), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1063        {Topic(4), {HashedDomain(3)}},
1064        {Topic(101), {}},
1065        {Topic(102), {}}});
1066
1067   EXPECT_EQ(result.padded_top_topics_start_index(), 3u);
1068
1069   histograms.ExpectUniqueSample(
1070       "BrowsingTopics.EpochTopicsCalculation.EligibleDistinctHistoryHostsCount",
1071       /*sample=*/3,
1072       /*expected_bucket_count=*/1);
1073
1074   histograms.ExpectUniqueSample(
1075       "BrowsingTopics.EpochTopicsCalculation.HistoryTopicsCount",
1076       /*sample=*/3,
1077       /*expected_bucket_count=*/1);
1078
1079   histograms.ExpectUniqueSample(
1080       "BrowsingTopics.EpochTopicsCalculation.TopTopicsCountBeforePadding",
1081       /*sample=*/3,
1082       /*expected_bucket_count=*/1);
1083
1084   histograms.ExpectTotalCount(
1085       "BrowsingTopics.EpochTopicsCalculation."
1086       "ObservationContextDomainsCountPerTopTopic",
1087       /*count=*/5);
1088   histograms.ExpectBucketCount(
1089       "BrowsingTopics.EpochTopicsCalculation."
1090       "ObservationContextDomainsCountPerTopTopic",
1091       /*sample=*/0,
1092       /*expected_count=*/2);
1093   histograms.ExpectBucketCount(
1094       "BrowsingTopics.EpochTopicsCalculation."
1095       "ObservationContextDomainsCountPerTopTopic",
1096       /*sample=*/1,
1097       /*expected_count=*/1);
1098   histograms.ExpectBucketCount(
1099       "BrowsingTopics.EpochTopicsCalculation."
1100       "ObservationContextDomainsCountPerTopTopic",
1101       /*sample=*/3,
1102       /*expected_count=*/2);
1103 }
1104
1105 TEST_F(BrowsingTopicsCalculatorTest, Metrics_MoreThan5HistoryTopics) {
1106   base::HistogramTester histograms;
1107
1108   base::Time begin_time = base::Time::Now();
1109
1110   AddHistoryEntries({kHost1, kHost2, kHost3, kHost4, kHost5, kHost6},
1111                     begin_time);
1112
1113   AddApiUsageContextEntries(
1114       {{kHost1, {}},
1115        {kHost2, {}},
1116        {kHost3, {HashedDomain(2)}},
1117        {kHost4, {HashedDomain(3)}},
1118        {kHost5, {HashedDomain(1), HashedDomain(2), HashedDomain(3)}}});
1119
1120   test_annotator_.UseModelInfo(
1121       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
1122   test_annotator_.UseAnnotations({
1123       {kHost1, {1, 2, 3, 4, 5, 6}},
1124       {kHost2, {2, 3, 4, 5, 6}},
1125       {kHost3, {3, 4, 5, 6}},
1126       {kHost4, {4, 5, 6}},
1127       {kHost5, {5, 6}},
1128       {kHost6, {6}},
1129   });
1130
1131   task_environment_.AdvanceClock(base::Seconds(1));
1132
1133   EpochTopics result = CalculateTopics();
1134
1135   EXPECT_EQ(result.padded_top_topics_start_index(), 5u);
1136
1137   histograms.ExpectUniqueSample(
1138       "BrowsingTopics.EpochTopicsCalculation.HistoryTopicsCount",
1139       /*sample=*/6,
1140       /*expected_bucket_count=*/1);
1141
1142   histograms.ExpectUniqueSample(
1143       "BrowsingTopics.EpochTopicsCalculation.TopTopicsCountBeforePadding",
1144       /*sample=*/5,
1145       /*expected_bucket_count=*/1);
1146 }
1147
1148 TEST_F(BrowsingTopicsCalculatorTest, NoDescendantTopics) {
1149   base::Time begin_time = base::Time::Now();
1150
1151   AddHistoryEntries(
1152       {
1153           kHost1,
1154           kHost2,
1155           kHost3,
1156           kHost4,
1157           kHost5,
1158       },
1159       begin_time);
1160   AddApiUsageContextEntries({{kHost1, {HashedDomain(1)}},
1161                              {kHost2, {HashedDomain(2)}},
1162                              {kHost3, {HashedDomain(3)}},
1163                              {kHost4, {HashedDomain(4)}},
1164                              {kHost5, {HashedDomain(5)}}});
1165
1166   test_annotator_.UseModelInfo(
1167       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
1168   test_annotator_.UseAnnotations({
1169       {kHost1, {2, 3, 4, 5, 6}},
1170       {kHost2, {3, 4, 5, 6}},
1171       {kHost3, {4, 5, 6}},
1172       {kHost4, {5, 6}},
1173       {kHost5, {6}},
1174   });
1175
1176   task_environment_.AdvanceClock(base::Seconds(1));
1177
1178   EpochTopics result = CalculateTopics();
1179   std::vector<std::pair<Topic, std::set<HashedDomain>>>
1180       expected_top_topics_and_observing_domains = {
1181           {Topic(6),
1182            {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(4),
1183             HashedDomain(5)}},
1184           {Topic(5),
1185            {HashedDomain(1), HashedDomain(2), HashedDomain(3),
1186             HashedDomain(4)}},
1187           {Topic(4), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1188           {Topic(3), {HashedDomain(1), HashedDomain(2)}},
1189           {Topic(2), {HashedDomain(1)}}};
1190   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
1191                           expected_top_topics_and_observing_domains);
1192 }
1193
1194 TEST_F(BrowsingTopicsCalculatorTest, DescendantTopicIsBlocked) {
1195   base::Time begin_time = base::Time::Now();
1196
1197   AddHistoryEntries(
1198       {
1199           kHost1,
1200           kHost2,
1201           kHost3,
1202           kHost4,
1203           kHost5,
1204       },
1205       begin_time);
1206   AddApiUsageContextEntries({{kHost1, {HashedDomain(1)}},
1207                              {kHost2, {HashedDomain(2)}},
1208                              {kHost3, {HashedDomain(3)}},
1209                              {kHost4, {HashedDomain(4)}},
1210                              {kHost5, {HashedDomain(5)}}});
1211
1212   test_annotator_.UseModelInfo(
1213       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
1214   // 1 is the parent topic of 2-5.
1215   test_annotator_.UseAnnotations({
1216       {kHost1, {1, 2, 3, 4, 5}},
1217       {kHost2, {2, 3, 4, 5}},
1218       {kHost3, {3, 4, 5}},
1219       {kHost4, {4, 5}},
1220       {kHost5, {5}},
1221   });
1222
1223   privacy_sandbox_settings_->SetTopicAllowed(
1224       privacy_sandbox::CanonicalTopic(Topic(5), kTaxonomyVersion),
1225       /*allowed=*/false);
1226
1227   task_environment_.AdvanceClock(base::Seconds(1));
1228
1229   EpochTopics result = CalculateTopics();
1230   // topic 5 is cleared but topic 1 can still see its observing domains
1231   std::vector<std::pair<Topic, std::set<HashedDomain>>>
1232       expected_top_topics_and_observing_domains = {
1233           {Topic(), {}},
1234           {Topic(4),
1235            {HashedDomain(1), HashedDomain(2), HashedDomain(3),
1236             HashedDomain(4)}},
1237           {Topic(3), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1238           {Topic(2), {HashedDomain(1), HashedDomain(2)}},
1239           {Topic(1),
1240            {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(4),
1241             HashedDomain(5)}}};
1242
1243   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
1244                           expected_top_topics_and_observing_domains);
1245 }
1246
1247 TEST_F(BrowsingTopicsCalculatorTest, TopicHasDistantDescendant) {
1248   base::Time begin_time = base::Time::Now();
1249
1250   AddHistoryEntries(
1251       {
1252           kHost1,
1253           kHost2,
1254           kHost3,
1255           kHost4,
1256           kHost5,
1257       },
1258       begin_time);
1259   AddApiUsageContextEntries({{kHost1, {HashedDomain(1)}},
1260                              {kHost2, {HashedDomain(2)}},
1261                              {kHost3, {HashedDomain(3)}},
1262                              {kHost4, {HashedDomain(4)}},
1263                              {kHost5, {HashedDomain(5)}}});
1264
1265   test_annotator_.UseModelInfo(
1266       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
1267   // 1 is the parent topic of 2-4, and grandparent of 21.
1268   test_annotator_.UseAnnotations({
1269       {kHost1, {1, 2, 3, 4, 21}},
1270       {kHost2, {2, 3, 4, 21}},
1271       {kHost3, {3, 4, 21}},
1272       {kHost4, {4, 21}},
1273       {kHost5, {21}},
1274   });
1275
1276   task_environment_.AdvanceClock(base::Seconds(1));
1277   EpochTopics result = CalculateTopics();
1278
1279   std::vector<std::pair<Topic, std::set<HashedDomain>>>
1280       expected_top_topics_and_observing_domains = {
1281           {Topic(21),
1282            {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(4),
1283             HashedDomain(5)}},
1284           {Topic(4),
1285            {HashedDomain(1), HashedDomain(2), HashedDomain(3),
1286             HashedDomain(4)}},
1287           {Topic(3), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1288           {Topic(2), {HashedDomain(1), HashedDomain(2)}},
1289           {Topic(1),
1290            {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(4),
1291             HashedDomain(5)}}};
1292
1293   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
1294                           expected_top_topics_and_observing_domains);
1295 }
1296
1297 TEST_F(BrowsingTopicsCalculatorTest, MultipleTopTopicsHaveDescendants) {
1298   base::Time begin_time = base::Time::Now();
1299
1300   AddHistoryEntries(
1301       {
1302           kHost1,
1303           kHost2,
1304           kHost3,
1305           kHost4,
1306           kHost5,
1307       },
1308       begin_time);
1309   AddApiUsageContextEntries({{kHost1, {HashedDomain(1)}},
1310                              {kHost2, {HashedDomain(2)}},
1311                              {kHost3, {HashedDomain(3)}},
1312                              {kHost4, {HashedDomain(4)}},
1313                              {kHost5, {HashedDomain(5)}}});
1314
1315   test_annotator_.UseModelInfo(
1316       *optimization_guide::TestModelInfoBuilder().SetVersion(1).Build());
1317   // 1 is the ancestor of 21, 57 is the ancestor of 63 and 64.
1318   test_annotator_.UseAnnotations({
1319       {kHost1, {1, 57, 63, 64, 21}},
1320       {kHost2, {57, 63, 64, 21}},
1321       {kHost3, {63, 64, 21}},
1322       {kHost4, {64, 21}},
1323       {kHost5, {21}},
1324   });
1325
1326   task_environment_.AdvanceClock(base::Seconds(1));
1327   EpochTopics result = CalculateTopics();
1328
1329   std::vector<std::pair<Topic, std::set<HashedDomain>>>
1330       expected_top_topics_and_observing_domains = {
1331           {Topic(21),
1332            {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(4),
1333             HashedDomain(5)}},
1334           {Topic(64),
1335            {HashedDomain(1), HashedDomain(2), HashedDomain(3),
1336             HashedDomain(4)}},
1337           {Topic(63), {HashedDomain(1), HashedDomain(2), HashedDomain(3)}},
1338           {Topic(57),
1339            {HashedDomain(1), HashedDomain(2), HashedDomain(3),
1340             HashedDomain(4)}},
1341           {Topic(1),
1342            {HashedDomain(1), HashedDomain(2), HashedDomain(3), HashedDomain(4),
1343             HashedDomain(5)}}};
1344
1345   ExpectResultTopicsEqual(result.top_topics_and_observing_domains(),
1346                           expected_top_topics_and_observing_domains);
1347 }
1348
1349 }  // namespace browsing_topics