1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 "chrome/browser/federated_learning/floc_id_provider_impl.h"
6 
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/strings/strcat.h"
9 #include "base/test/bind.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "build/build_config.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/federated_learning/floc_remote_permission_service.h"
14 #include "chrome/common/chrome_features.h"
15 #include "chrome/test/base/testing_browser_process.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "components/content_settings/core/browser/content_settings_registry.h"
18 #include "components/content_settings/core/browser/cookie_settings.h"
19 #include "components/content_settings/core/common/pref_names.h"
20 #include "components/history/core/browser/history_database_params.h"
21 #include "components/history/core/browser/history_service.h"
22 #include "components/history/core/test/test_history_database.h"
23 #include "components/sync/driver/test_sync_service.h"
24 #include "components/sync_preferences/testing_pref_service_syncable.h"
25 #include "components/sync_user_events/fake_user_event_service.h"
26 #include "content/public/test/browser_task_environment.h"
27 #include "content/public/test/test_utils.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 
30 namespace federated_learning {
31 
32 namespace {
33 
34 using ComputeFlocTrigger = FlocIdProviderImpl::ComputeFlocTrigger;
35 using ComputeFlocResult = FlocIdProviderImpl::ComputeFlocResult;
36 using ComputeFlocCompletedCallback =
37     FlocIdProviderImpl::ComputeFlocCompletedCallback;
38 using CanComputeFlocCallback = FlocIdProviderImpl::CanComputeFlocCallback;
39 
40 class MockFlocSortingLshService : public FlocSortingLshClustersService {
41  public:
42   using FlocSortingLshClustersService::FlocSortingLshClustersService;
43 
ConfigureSortingLsh(const std::unordered_map<uint64_t,base::Optional<uint64_t>> & sorting_lsh_map,base::Version version)44   void ConfigureSortingLsh(
45       const std::unordered_map<uint64_t, base::Optional<uint64_t>>&
46           sorting_lsh_map,
47       base::Version version) {
48     sorting_lsh_map_ = sorting_lsh_map;
49     version_ = version;
50   }
51 
ApplySortingLsh(uint64_t sim_hash,ApplySortingLshCallback callback)52   void ApplySortingLsh(uint64_t sim_hash,
53                        ApplySortingLshCallback callback) override {
54     if (sorting_lsh_map_.count(sim_hash)) {
55       std::move(callback).Run(sorting_lsh_map_.at(sim_hash), version_);
56       return;
57     }
58 
59     std::move(callback).Run(base::nullopt, version_);
60   }
61 
62  private:
63   std::unordered_map<uint64_t, base::Optional<uint64_t>> sorting_lsh_map_;
64   base::Version version_;
65 };
66 
67 class FakeFlocRemotePermissionService : public FlocRemotePermissionService {
68  public:
69   using FlocRemotePermissionService::FlocRemotePermissionService;
70 
QueryFlocPermission(QueryFlocPermissionCallback callback,const net::PartialNetworkTrafficAnnotationTag & partial_traffic_annotation)71   void QueryFlocPermission(QueryFlocPermissionCallback callback,
72                            const net::PartialNetworkTrafficAnnotationTag&
73                                partial_traffic_annotation) override {
74     std::move(callback).Run(swaa_nac_account_enabled_);
75   }
76 
set_swaa_nac_account_enabled(bool enabled)77   void set_swaa_nac_account_enabled(bool enabled) {
78     swaa_nac_account_enabled_ = enabled;
79   }
80 
81  private:
82   bool swaa_nac_account_enabled_ = true;
83 };
84 
85 class FakeCookieSettings : public content_settings::CookieSettings {
86  public:
87   using content_settings::CookieSettings::CookieSettings;
88 
GetCookieSettingInternal(const GURL & url,const GURL & first_party_url,bool is_third_party_request,content_settings::SettingSource * source,ContentSetting * cookie_setting) const89   void GetCookieSettingInternal(const GURL& url,
90                                 const GURL& first_party_url,
91                                 bool is_third_party_request,
92                                 content_settings::SettingSource* source,
93                                 ContentSetting* cookie_setting) const override {
94     *cookie_setting =
95         allow_cookies_internal_ ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
96   }
97 
ShouldBlockThirdPartyCookies() const98   bool ShouldBlockThirdPartyCookies() const override {
99     return should_block_third_party_cookies_;
100   }
101 
set_should_block_third_party_cookies(bool should_block_third_party_cookies)102   void set_should_block_third_party_cookies(
103       bool should_block_third_party_cookies) {
104     should_block_third_party_cookies_ = should_block_third_party_cookies;
105   }
106 
set_allow_cookies_internal(bool allow_cookies_internal)107   void set_allow_cookies_internal(bool allow_cookies_internal) {
108     allow_cookies_internal_ = allow_cookies_internal;
109   }
110 
111  private:
112   ~FakeCookieSettings() override = default;
113 
114   bool should_block_third_party_cookies_ = false;
115   bool allow_cookies_internal_ = true;
116 };
117 
118 class MockFlocIdProvider : public FlocIdProviderImpl {
119  public:
120   using FlocIdProviderImpl::FlocIdProviderImpl;
121 
OnComputeFlocCompleted(ComputeFlocTrigger trigger,ComputeFlocResult result)122   void OnComputeFlocCompleted(ComputeFlocTrigger trigger,
123                               ComputeFlocResult result) override {
124     if (should_pause_before_compute_floc_completed_) {
125       DCHECK(!paused_);
126       paused_ = true;
127       paused_trigger_ = trigger;
128       paused_result_ = result;
129       return;
130     }
131 
132     ++compute_floc_completed_count_;
133     FlocIdProviderImpl::OnComputeFlocCompleted(trigger, result);
134   }
135 
ContinueLastOnComputeFlocCompleted()136   void ContinueLastOnComputeFlocCompleted() {
137     DCHECK(paused_);
138     paused_ = false;
139     ++compute_floc_completed_count_;
140     FlocIdProviderImpl::OnComputeFlocCompleted(paused_trigger_, paused_result_);
141   }
142 
LogFlocComputedEvent(ComputeFlocTrigger trigger,const ComputeFlocResult & result)143   void LogFlocComputedEvent(ComputeFlocTrigger trigger,
144                             const ComputeFlocResult& result) override {
145     ++log_event_count_;
146     last_log_event_trigger_ = trigger;
147     last_log_event_result_ = result;
148     FlocIdProviderImpl::LogFlocComputedEvent(trigger, result);
149   }
150 
compute_floc_completed_count() const151   size_t compute_floc_completed_count() const {
152     return compute_floc_completed_count_;
153   }
154 
set_should_pause_before_compute_floc_completed(bool should_pause)155   void set_should_pause_before_compute_floc_completed(bool should_pause) {
156     should_pause_before_compute_floc_completed_ = should_pause;
157   }
158 
paused_result() const159   ComputeFlocResult paused_result() const {
160     DCHECK(paused_);
161     return paused_result_;
162   }
163 
paused_trigger() const164   ComputeFlocTrigger paused_trigger() const {
165     DCHECK(paused_);
166     return paused_trigger_;
167   }
168 
log_event_count() const169   size_t log_event_count() const { return log_event_count_; }
170 
last_log_event_trigger() const171   ComputeFlocTrigger last_log_event_trigger() const {
172     DCHECK_LT(0u, log_event_count_);
173     return last_log_event_trigger_;
174   }
175 
last_log_event_result() const176   ComputeFlocResult last_log_event_result() const {
177     DCHECK_LT(0u, log_event_count_);
178     return last_log_event_result_;
179   }
180 
181  private:
182   base::OnceCallback<void()> callback_before_compute_floc_completed_;
183 
184   // Add the support to be able to pause on the OnComputeFlocCompleted
185   // execution and let it yield to other tasks posted to the same task runner.
186   bool should_pause_before_compute_floc_completed_ = false;
187   bool paused_ = false;
188   ComputeFlocTrigger paused_trigger_;
189   ComputeFlocResult paused_result_;
190 
191   size_t compute_floc_completed_count_ = 0u;
192   size_t log_event_count_ = 0u;
193   ComputeFlocTrigger last_log_event_trigger_;
194   ComputeFlocResult last_log_event_result_;
195 };
196 
197 }  // namespace
198 
199 class FlocIdProviderUnitTest : public testing::Test {
200  public:
FlocIdProviderUnitTest()201   FlocIdProviderUnitTest()
202       : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
203 
204   ~FlocIdProviderUnitTest() override = default;
205 
SetUp()206   void SetUp() override {
207     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
208 
209     content_settings::ContentSettingsRegistry::GetInstance()->ResetForTest();
210     content_settings::CookieSettings::RegisterProfilePrefs(prefs_.registry());
211     HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
212     settings_map_ = new HostContentSettingsMap(
213         &prefs_, /*is_off_the_record=*/false, /*store_last_modified=*/false,
214         /*restore_session=*/false);
215 
216     auto sorting_lsh_service = std::make_unique<MockFlocSortingLshService>();
217     sorting_lsh_service_ = sorting_lsh_service.get();
218     TestingBrowserProcess::GetGlobal()->SetFlocSortingLshClustersService(
219         std::move(sorting_lsh_service));
220 
221     history_service_ = std::make_unique<history::HistoryService>();
222     history_service_->Init(
223         history::TestHistoryDatabaseParamsForPath(temp_dir_.GetPath()));
224 
225     test_sync_service_ = std::make_unique<syncer::TestSyncService>();
226     test_sync_service_->SetTransportState(
227         syncer::SyncService::TransportState::DISABLED);
228 
229     fake_user_event_service_ = std::make_unique<syncer::FakeUserEventService>();
230 
231     fake_floc_remote_permission_service_ =
232         std::make_unique<FakeFlocRemotePermissionService>(
233             /*url_loader_factory=*/nullptr);
234 
235     fake_cookie_settings_ = base::MakeRefCounted<FakeCookieSettings>(
236         settings_map_.get(), &prefs_, false, "chrome-extension");
237 
238     floc_id_provider_ = std::make_unique<MockFlocIdProvider>(
239         test_sync_service_.get(), fake_cookie_settings_,
240         fake_floc_remote_permission_service_.get(), history_service_.get(),
241         fake_user_event_service_.get());
242 
243     task_environment_.RunUntilIdle();
244   }
245 
TearDown()246   void TearDown() override {
247     settings_map_->ShutdownOnUIThread();
248     history_service_->RemoveObserver(floc_id_provider_.get());
249   }
250 
ApplySortingLshPostProcessing(ComputeFlocCompletedCallback callback,uint64_t sim_hash,base::Time history_begin_time,base::Time history_end_time)251   void ApplySortingLshPostProcessing(ComputeFlocCompletedCallback callback,
252                                      uint64_t sim_hash,
253                                      base::Time history_begin_time,
254                                      base::Time history_end_time) {
255     floc_id_provider_->ApplySortingLshPostProcessing(
256         std::move(callback), sim_hash, history_begin_time, history_end_time);
257   }
258 
CheckCanComputeFloc(CanComputeFlocCallback callback)259   void CheckCanComputeFloc(CanComputeFlocCallback callback) {
260     floc_id_provider_->CheckCanComputeFloc(std::move(callback));
261   }
262 
IsSwaaNacAccountEnabled(CanComputeFlocCallback callback)263   void IsSwaaNacAccountEnabled(CanComputeFlocCallback callback) {
264     floc_id_provider_->IsSwaaNacAccountEnabled(std::move(callback));
265   }
266 
OnURLsDeleted(history::HistoryService * history_service,const history::DeletionInfo & deletion_info)267   void OnURLsDeleted(history::HistoryService* history_service,
268                      const history::DeletionInfo& deletion_info) {
269     floc_id_provider_->OnURLsDeleted(history_service, deletion_info);
270   }
271 
OnGetRecentlyVisitedURLsCompleted(ComputeFlocTrigger trigger,history::QueryResults results)272   void OnGetRecentlyVisitedURLsCompleted(ComputeFlocTrigger trigger,
273                                          history::QueryResults results) {
274     auto compute_floc_completed_callback =
275         base::BindOnce(&FlocIdProviderImpl::OnComputeFlocCompleted,
276                        base::Unretained(floc_id_provider_.get()), trigger);
277 
278     floc_id_provider_->OnGetRecentlyVisitedURLsCompleted(
279         std::move(compute_floc_completed_callback), std::move(results));
280   }
281 
ExpireHistoryBeforeUninclusive(base::Time end_time)282   void ExpireHistoryBeforeUninclusive(base::Time end_time) {
283     base::CancelableTaskTracker tracker;
284     base::RunLoop run_loop;
285     history_service_->ExpireHistoryBetween(
286         /*restrict_urls=*/{}, /*begin_time=*/base::Time(), end_time,
287         /*user_initiated=*/true, run_loop.QuitClosure(), &tracker);
288     run_loop.Run();
289   }
290 
floc_id() const291   FlocId floc_id() const { return floc_id_provider_->floc_id_; }
292 
set_floc_id(const FlocId & floc_id) const293   void set_floc_id(const FlocId& floc_id) const {
294     floc_id_provider_->floc_id_ = floc_id;
295   }
296 
floc_computation_in_progress() const297   bool floc_computation_in_progress() const {
298     return floc_id_provider_->floc_computation_in_progress_;
299   }
300 
set_floc_computation_in_progress(bool floc_computation_in_progress)301   void set_floc_computation_in_progress(bool floc_computation_in_progress) {
302     floc_id_provider_->floc_computation_in_progress_ =
303         floc_computation_in_progress;
304   }
305 
first_floc_computation_triggered() const306   bool first_floc_computation_triggered() const {
307     return floc_id_provider_->first_floc_computation_triggered_;
308   }
309 
set_first_floc_computation_triggered(bool triggered)310   void set_first_floc_computation_triggered(bool triggered) {
311     floc_id_provider_->first_floc_computation_triggered_ = triggered;
312   }
313 
set_floc_id(const FlocId & floc_id)314   void set_floc_id(const FlocId& floc_id) {
315     floc_id_provider_->floc_id_ = floc_id;
316   }
317 
need_recompute()318   bool need_recompute() { return floc_id_provider_->need_recompute_; }
319 
SetRemoteSwaaNacAccountEnabled(bool enabled)320   void SetRemoteSwaaNacAccountEnabled(bool enabled) {
321     fake_floc_remote_permission_service_->set_swaa_nac_account_enabled(enabled);
322   }
323 
ForceScheduledUpdate()324   void ForceScheduledUpdate() {
325     floc_id_provider_->OnComputeFlocScheduledUpdate();
326   }
327 
328  protected:
329   base::test::ScopedFeatureList feature_list_;
330 
331   content::BrowserTaskEnvironment task_environment_;
332 
333   sync_preferences::TestingPrefServiceSyncable prefs_;
334   scoped_refptr<HostContentSettingsMap> settings_map_;
335 
336   std::unique_ptr<history::HistoryService> history_service_;
337   std::unique_ptr<syncer::TestSyncService> test_sync_service_;
338   std::unique_ptr<syncer::FakeUserEventService> fake_user_event_service_;
339   std::unique_ptr<FakeFlocRemotePermissionService>
340       fake_floc_remote_permission_service_;
341   scoped_refptr<FakeCookieSettings> fake_cookie_settings_;
342   std::unique_ptr<MockFlocIdProvider> floc_id_provider_;
343 
344   MockFlocSortingLshService* sorting_lsh_service_;
345 
346   base::ScopedTempDir temp_dir_;
347 
348   DISALLOW_COPY_AND_ASSIGN(FlocIdProviderUnitTest);
349 };
350 
TEST_F(FlocIdProviderUnitTest,QualifiedInitialHistory)351 TEST_F(FlocIdProviderUnitTest, QualifiedInitialHistory) {
352   // Add a history entry with a timestamp exactly 7 days back from now.
353   std::string domain = "foo.com";
354   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(7);
355 
356   history::HistoryAddPageArgs add_page_args;
357   add_page_args.url = GURL(base::StrCat({"https://www.", domain}));
358   add_page_args.time = kTime;
359   add_page_args.publicly_routable = true;
360   history_service_->AddPage(add_page_args);
361 
362   task_environment_.RunUntilIdle();
363 
364   // Expect that the floc computation hasn't started, as the floc_id_provider
365   // hasn't been notified about state of the sync_service.
366   EXPECT_EQ(0u, floc_id_provider_->compute_floc_completed_count());
367   EXPECT_EQ(0u, floc_id_provider_->log_event_count());
368   EXPECT_FALSE(floc_id().IsValid());
369   EXPECT_FALSE(first_floc_computation_triggered());
370 
371   // Trigger the 1st floc computation.
372   test_sync_service_->SetTransportState(
373       syncer::SyncService::TransportState::ACTIVE);
374   test_sync_service_->FireStateChanged();
375 
376   task_environment_.RunUntilIdle();
377 
378   // Expect that the 1st computation has completed.
379   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
380   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
381   EXPECT_EQ(FlocId(FlocId::SimHashHistory({domain}), kTime, kTime, 0),
382             floc_id());
383   EXPECT_TRUE(first_floc_computation_triggered());
384 
385   // Advance the clock by 1 day. Expect a computation, as there's no history in
386   // the last 7 days so the id has been reset to empty.
387   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
388 
389   EXPECT_EQ(2u, floc_id_provider_->compute_floc_completed_count());
390   EXPECT_EQ(2u, floc_id_provider_->log_event_count());
391   EXPECT_FALSE(floc_id().IsValid());
392 }
393 
TEST_F(FlocIdProviderUnitTest,UnqualifiedInitialHistory)394 TEST_F(FlocIdProviderUnitTest, UnqualifiedInitialHistory) {
395   std::string domain = "foo.com";
396 
397   // Add a history entry with a timestamp 8 days back from now.
398   history::HistoryAddPageArgs add_page_args;
399   add_page_args.url = GURL(base::StrCat({"https://www.", domain}));
400   add_page_args.time = base::Time::Now() - base::TimeDelta::FromDays(8);
401   add_page_args.publicly_routable = true;
402   history_service_->AddPage(add_page_args);
403 
404   task_environment_.RunUntilIdle();
405 
406   // Expect that the floc computation hasn't started, as the floc_id_provider
407   // hasn't been notified about state of the sync_service.
408   EXPECT_EQ(0u, floc_id_provider_->compute_floc_completed_count());
409   EXPECT_EQ(0u, floc_id_provider_->log_event_count());
410   EXPECT_FALSE(floc_id().IsValid());
411   EXPECT_FALSE(first_floc_computation_triggered());
412 
413   // Trigger the 1st floc computation.
414   test_sync_service_->SetTransportState(
415       syncer::SyncService::TransportState::ACTIVE);
416   test_sync_service_->FireStateChanged();
417 
418   task_environment_.RunUntilIdle();
419 
420   // Expect that the 1st computation has completed.
421   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
422   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
423   EXPECT_TRUE(first_floc_computation_triggered());
424 
425   // Add a history entry with a timestamp 6 days back from now.
426   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(6);
427   add_page_args.time = kTime;
428   history_service_->AddPage(add_page_args);
429 
430   // Advance the clock by 23 hours. Expect no more computation, as the id
431   // refresh interval is 24 hours.
432   task_environment_.FastForwardBy(base::TimeDelta::FromHours(23));
433 
434   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
435   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
436 
437   // Advance the clock by 1 hour. Expect one more computation, as the refresh
438   // time is reached and there's a valid history entry in the last 7 days.
439   task_environment_.FastForwardBy(base::TimeDelta::FromHours(1));
440 
441   EXPECT_EQ(2u, floc_id_provider_->compute_floc_completed_count());
442   EXPECT_EQ(2u, floc_id_provider_->log_event_count());
443 
444   EXPECT_EQ(FlocId(FlocId::SimHashHistory({domain}), kTime, kTime, 0),
445             floc_id());
446 }
447 
TEST_F(FlocIdProviderUnitTest,HistoryDeleteAndScheduledUpdate)448 TEST_F(FlocIdProviderUnitTest, HistoryDeleteAndScheduledUpdate) {
449   std::string domain1 = "foo.com";
450   std::string domain2 = "bar.com";
451 
452   // Add a history entry with a timestamp exactly 7 days back from now.
453   history::HistoryAddPageArgs add_page_args;
454   const base::Time kTime1 = base::Time::Now() - base::TimeDelta::FromDays(7);
455   add_page_args.url = GURL(base::StrCat({"https://www.", domain1}));
456   add_page_args.time = kTime1;
457   add_page_args.publicly_routable = true;
458   history_service_->AddPage(add_page_args);
459 
460   // Add a history entry with a timestamp exactly 6 days back from now.
461   add_page_args.url = GURL(base::StrCat({"https://www.", domain2}));
462   const base::Time kTime2 = base::Time::Now() - base::TimeDelta::FromDays(6);
463   add_page_args.time = kTime2;
464   history_service_->AddPage(add_page_args);
465 
466   task_environment_.RunUntilIdle();
467 
468   // Trigger the 1st floc computation.
469   test_sync_service_->SetTransportState(
470       syncer::SyncService::TransportState::ACTIVE);
471   test_sync_service_->FireStateChanged();
472 
473   task_environment_.RunUntilIdle();
474 
475   // Expect that the 1st computation has completed.
476   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
477   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
478   EXPECT_EQ(
479       FlocId(FlocId::SimHashHistory({domain1, domain2}), kTime1, kTime2, 0),
480       floc_id());
481 
482   // Advance the clock by 12 hours. Expect no more computation.
483   task_environment_.FastForwardBy(base::TimeDelta::FromHours(12));
484   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
485   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
486 
487   // Expire the oldest history entry.
488   ExpireHistoryBeforeUninclusive(kTime2);
489   task_environment_.RunUntilIdle();
490 
491   // Expect that the floc has been invalidated. Expect no more floc computation,
492   // but one more logging.
493   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
494   EXPECT_EQ(2u, floc_id_provider_->log_event_count());
495   EXPECT_FALSE(floc_id().IsValid());
496 
497   // Advance the clock by 12 hours. Expect one more computation, which implies
498   // the timer didn't get reset due to the history invalidation. Expect that
499   // the floc is derived from domain2.
500   task_environment_.FastForwardBy(base::TimeDelta::FromHours(12));
501   EXPECT_EQ(2u, floc_id_provider_->compute_floc_completed_count());
502   EXPECT_EQ(3u, floc_id_provider_->log_event_count());
503   EXPECT_EQ(FlocId(FlocId::SimHashHistory({domain2}), kTime2, kTime2, 0),
504             floc_id());
505 }
506 
TEST_F(FlocIdProviderUnitTest,ScheduledUpdateSameFloc)507 TEST_F(FlocIdProviderUnitTest, ScheduledUpdateSameFloc) {
508   std::string domain = "foo.com";
509   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(2);
510 
511   // Add a history entry with a timestamp 2 days back from now.
512   history::HistoryAddPageArgs add_page_args;
513   add_page_args.url = GURL(base::StrCat({"https://www.", domain}));
514   add_page_args.time = kTime;
515   add_page_args.publicly_routable = true;
516   history_service_->AddPage(add_page_args);
517 
518   task_environment_.RunUntilIdle();
519 
520   // Trigger the 1st floc computation.
521   test_sync_service_->SetTransportState(
522       syncer::SyncService::TransportState::ACTIVE);
523   test_sync_service_->FireStateChanged();
524 
525   task_environment_.RunUntilIdle();
526 
527   // Expect that the 1st computation has completed.
528   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
529   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
530   EXPECT_EQ(FlocId(FlocId::SimHashHistory({domain}), kTime, kTime, 0),
531             floc_id());
532 
533   // Advance the clock by 1 day. Expect one more computation, but the floc
534   // didn't change.
535   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
536 
537   EXPECT_EQ(2u, floc_id_provider_->compute_floc_completed_count());
538   EXPECT_EQ(2u, floc_id_provider_->log_event_count());
539   EXPECT_EQ(FlocId(FlocId::SimHashHistory({domain}), kTime, kTime, 0),
540             floc_id());
541 }
542 
TEST_F(FlocIdProviderUnitTest,CheckCanComputeFloc_Success)543 TEST_F(FlocIdProviderUnitTest, CheckCanComputeFloc_Success) {
544   test_sync_service_->SetTransportState(
545       syncer::SyncService::TransportState::ACTIVE);
546 
547   base::OnceCallback<void(bool)> cb = base::BindOnce(
548       [](bool can_compute_floc) { EXPECT_TRUE(can_compute_floc); });
549 
550   CheckCanComputeFloc(std::move(cb));
551   task_environment_.RunUntilIdle();
552 }
553 
TEST_F(FlocIdProviderUnitTest,CheckCanComputeFloc_Failure_SyncDisabled)554 TEST_F(FlocIdProviderUnitTest, CheckCanComputeFloc_Failure_SyncDisabled) {
555   base::OnceCallback<void(bool)> cb = base::BindOnce(
556       [](bool can_compute_floc) { EXPECT_FALSE(can_compute_floc); });
557 
558   CheckCanComputeFloc(std::move(cb));
559   task_environment_.RunUntilIdle();
560 }
561 
TEST_F(FlocIdProviderUnitTest,CheckCanComputeFloc_Failure_BlockThirdPartyCookies)562 TEST_F(FlocIdProviderUnitTest,
563        CheckCanComputeFloc_Failure_BlockThirdPartyCookies) {
564   test_sync_service_->SetTransportState(
565       syncer::SyncService::TransportState::ACTIVE);
566 
567   fake_cookie_settings_->set_should_block_third_party_cookies(true);
568 
569   base::OnceCallback<void(bool)> cb = base::BindOnce(
570       [](bool can_compute_floc) { EXPECT_FALSE(can_compute_floc); });
571 
572   CheckCanComputeFloc(std::move(cb));
573   task_environment_.RunUntilIdle();
574 }
575 
TEST_F(FlocIdProviderUnitTest,CheckCanComputeFloc_Failure_SwaaNacAccountDisabled)576 TEST_F(FlocIdProviderUnitTest,
577        CheckCanComputeFloc_Failure_SwaaNacAccountDisabled) {
578   test_sync_service_->SetTransportState(
579       syncer::SyncService::TransportState::ACTIVE);
580 
581   SetRemoteSwaaNacAccountEnabled(false);
582 
583   base::OnceCallback<void(bool)> cb = base::BindOnce(
584       [](bool can_compute_floc) { EXPECT_FALSE(can_compute_floc); });
585 
586   CheckCanComputeFloc(std::move(cb));
587   task_environment_.RunUntilIdle();
588 }
589 
TEST_F(FlocIdProviderUnitTest,EventLogging)590 TEST_F(FlocIdProviderUnitTest, EventLogging) {
591   const base::Time kTime1 = base::Time::FromTimeT(1);
592   const base::Time kTime2 = base::Time::FromTimeT(2);
593 
594   // Event logging for browser start.
595   floc_id_provider_->LogFlocComputedEvent(
596       ComputeFlocTrigger::kBrowserStart,
597       ComputeFlocResult(12345ULL, FlocId(123ULL, kTime1, kTime1, 999)));
598 
599   EXPECT_EQ(1u, fake_user_event_service_->GetRecordedUserEvents().size());
600   const sync_pb::UserEventSpecifics& specifics1 =
601       fake_user_event_service_->GetRecordedUserEvents()[0];
602   EXPECT_EQ(specifics1.event_time_usec(),
603             base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
604 
605   EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
606             specifics1.event_case());
607 
608   const sync_pb::UserEventSpecifics_FlocIdComputed& event1 =
609       specifics1.floc_id_computed_event();
610   EXPECT_EQ(sync_pb::UserEventSpecifics::FlocIdComputed::NEW,
611             event1.event_trigger());
612   EXPECT_EQ(12345ULL, event1.floc_id());
613 
614   task_environment_.FastForwardBy(base::TimeDelta::FromDays(3));
615 
616   // Event logging for scheduled update.
617   floc_id_provider_->LogFlocComputedEvent(
618       ComputeFlocTrigger::kScheduledUpdate,
619       ComputeFlocResult(999ULL, FlocId(777ULL, kTime1, kTime2, 888)));
620 
621   EXPECT_EQ(2u, fake_user_event_service_->GetRecordedUserEvents().size());
622   const sync_pb::UserEventSpecifics& specifics2 =
623       fake_user_event_service_->GetRecordedUserEvents()[1];
624   EXPECT_EQ(specifics2.event_time_usec(),
625             base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
626   EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
627             specifics2.event_case());
628 
629   const sync_pb::UserEventSpecifics_FlocIdComputed& event2 =
630       specifics2.floc_id_computed_event();
631   EXPECT_EQ(sync_pb::UserEventSpecifics::FlocIdComputed::REFRESHED,
632             event2.event_trigger());
633   EXPECT_EQ(999ULL, event2.floc_id());
634 
635   // Event logging for when sim hash is not computed.
636   floc_id_provider_->LogFlocComputedEvent(ComputeFlocTrigger::kScheduledUpdate,
637                                           ComputeFlocResult());
638 
639   EXPECT_EQ(3u, fake_user_event_service_->GetRecordedUserEvents().size());
640   const sync_pb::UserEventSpecifics& specifics3 =
641       fake_user_event_service_->GetRecordedUserEvents()[2];
642   EXPECT_EQ(specifics3.event_time_usec(),
643             base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
644   EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
645             specifics3.event_case());
646 
647   const sync_pb::UserEventSpecifics_FlocIdComputed& event3 =
648       specifics3.floc_id_computed_event();
649   EXPECT_EQ(sync_pb::UserEventSpecifics::FlocIdComputed::REFRESHED,
650             event3.event_trigger());
651   EXPECT_FALSE(event3.has_floc_id());
652 
653   // Event logging for history-delete invalidation.
654   floc_id_provider_->LogFlocComputedEvent(ComputeFlocTrigger::kHistoryDelete,
655                                           ComputeFlocResult());
656 
657   EXPECT_EQ(4u, fake_user_event_service_->GetRecordedUserEvents().size());
658   const sync_pb::UserEventSpecifics& specifics4 =
659       fake_user_event_service_->GetRecordedUserEvents()[3];
660   EXPECT_EQ(specifics4.event_time_usec(),
661             base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
662   EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
663             specifics4.event_case());
664 
665   const sync_pb::UserEventSpecifics_FlocIdComputed& event4 =
666       specifics4.floc_id_computed_event();
667   EXPECT_EQ(sync_pb::UserEventSpecifics::FlocIdComputed::HISTORY_DELETE,
668             event4.event_trigger());
669   EXPECT_FALSE(event4.has_floc_id());
670 
671   // Event logging for blocked floc.
672   floc_id_provider_->LogFlocComputedEvent(ComputeFlocTrigger::kScheduledUpdate,
673                                           ComputeFlocResult(87654, FlocId()));
674 
675   EXPECT_EQ(5u, fake_user_event_service_->GetRecordedUserEvents().size());
676   const sync_pb::UserEventSpecifics& specifics5 =
677       fake_user_event_service_->GetRecordedUserEvents()[4];
678   EXPECT_EQ(specifics5.event_time_usec(),
679             base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
680   EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
681             specifics5.event_case());
682 
683   const sync_pb::UserEventSpecifics_FlocIdComputed& event5 =
684       specifics5.floc_id_computed_event();
685   EXPECT_EQ(sync_pb::UserEventSpecifics::FlocIdComputed::REFRESHED,
686             event5.event_trigger());
687   EXPECT_EQ(87654ULL, event5.floc_id());
688 }
689 
TEST_F(FlocIdProviderUnitTest,HistoryDelete_AllHistory)690 TEST_F(FlocIdProviderUnitTest, HistoryDelete_AllHistory) {
691   const base::Time kTime1 = base::Time::FromTimeT(1);
692   const base::Time kTime2 = base::Time::FromTimeT(2);
693 
694   set_floc_id(FlocId(123, kTime1, kTime2, 0));
695   set_first_floc_computation_triggered(true);
696 
697   OnURLsDeleted(history_service_.get(), history::DeletionInfo::ForAllHistory());
698 
699   EXPECT_FALSE(floc_id().IsValid());
700 }
701 
TEST_F(FlocIdProviderUnitTest,HistoryDelete_InvalidTimeRange)702 TEST_F(FlocIdProviderUnitTest, HistoryDelete_InvalidTimeRange) {
703   const base::Time kTime1 = base::Time::FromTimeT(1);
704   const base::Time kTime2 = base::Time::FromTimeT(2);
705 
706   GURL url_a = GURL("https://a.test");
707 
708   history::URLResult url_result(url_a, kTime1);
709   url_result.set_publicly_routable(true);
710 
711   history::QueryResults query_results;
712   query_results.SetURLResults({url_result});
713 
714   const FlocId expected_floc =
715       FlocId(FlocId::SimHashHistory({"a.test"}), kTime1, kTime2, 0);
716 
717   set_floc_id(expected_floc);
718   set_first_floc_computation_triggered(true);
719 
720   OnURLsDeleted(history_service_.get(),
721                 history::DeletionInfo::ForUrls(
722                     {history::URLResult(url_a, kTime1)}, /*favicon_urls=*/{}));
723 
724   EXPECT_EQ(expected_floc, floc_id());
725 }
726 
TEST_F(FlocIdProviderUnitTest,HistoryDelete_TimeRangeNoOverlap)727 TEST_F(FlocIdProviderUnitTest, HistoryDelete_TimeRangeNoOverlap) {
728   const base::Time kTime1 = base::Time::FromTimeT(1);
729   const base::Time kTime2 = base::Time::FromTimeT(2);
730   const base::Time kTime3 = base::Time::FromTimeT(3);
731   const base::Time kTime4 = base::Time::FromTimeT(4);
732 
733   const FlocId expected_floc =
734       FlocId(FlocId::SimHashHistory({"a.test"}), kTime1, kTime2, 0);
735 
736   set_floc_id(expected_floc);
737   set_first_floc_computation_triggered(true);
738 
739   history::DeletionInfo deletion_info(
740       history::DeletionTimeRange(kTime3, kTime4),
741       /*is_from_expiration=*/false, /*deleted_rows=*/{}, /*favicon_urls=*/{},
742       /*restrict_urls=*/base::nullopt);
743   OnURLsDeleted(history_service_.get(), deletion_info);
744 
745   EXPECT_EQ(expected_floc, floc_id());
746 }
747 
TEST_F(FlocIdProviderUnitTest,HistoryDelete_TimeRangePartialOverlap)748 TEST_F(FlocIdProviderUnitTest, HistoryDelete_TimeRangePartialOverlap) {
749   const base::Time kTime1 = base::Time::FromTimeT(1);
750   const base::Time kTime2 = base::Time::FromTimeT(2);
751   const base::Time kTime3 = base::Time::FromTimeT(3);
752 
753   const FlocId expected_floc =
754       FlocId(FlocId::SimHashHistory({"a.test"}), kTime1, kTime2, 0);
755 
756   set_floc_id(expected_floc);
757   set_first_floc_computation_triggered(true);
758 
759   history::DeletionInfo deletion_info(
760       history::DeletionTimeRange(kTime2, kTime3),
761       /*is_from_expiration=*/false, /*deleted_rows=*/{}, /*favicon_urls=*/{},
762       /*restrict_urls=*/base::nullopt);
763   OnURLsDeleted(history_service_.get(), deletion_info);
764 
765   EXPECT_FALSE(floc_id().IsValid());
766 }
767 
TEST_F(FlocIdProviderUnitTest,HistoryDelete_TimeRangeFullOverlap)768 TEST_F(FlocIdProviderUnitTest, HistoryDelete_TimeRangeFullOverlap) {
769   const base::Time kTime1 = base::Time::FromTimeT(1);
770   const base::Time kTime2 = base::Time::FromTimeT(2);
771 
772   const FlocId expected_floc =
773       FlocId(FlocId::SimHashHistory({"a.test"}), kTime1, kTime2, 0);
774 
775   set_floc_id(expected_floc);
776   set_first_floc_computation_triggered(true);
777 
778   history::DeletionInfo deletion_info(
779       history::DeletionTimeRange(kTime1, kTime2),
780       /*is_from_expiration=*/false, /*deleted_rows=*/{}, /*favicon_urls=*/{},
781       /*restrict_urls=*/base::nullopt);
782   OnURLsDeleted(history_service_.get(), deletion_info);
783 
784   EXPECT_FALSE(floc_id().IsValid());
785 }
786 
TEST_F(FlocIdProviderUnitTest,HistoryEntriesWithPrivateIP)787 TEST_F(FlocIdProviderUnitTest, HistoryEntriesWithPrivateIP) {
788   history::QueryResults query_results;
789   query_results.SetURLResults(
790       {history::URLResult(GURL("https://a.test"),
791                           base::Time::Now() - base::TimeDelta::FromDays(1))});
792 
793   set_first_floc_computation_triggered(true);
794   set_floc_computation_in_progress(true);
795 
796   OnGetRecentlyVisitedURLsCompleted(ComputeFlocTrigger::kBrowserStart,
797                                     std::move(query_results));
798 
799   EXPECT_FALSE(floc_id().IsValid());
800 }
801 
TEST_F(FlocIdProviderUnitTest,MultipleHistoryEntries)802 TEST_F(FlocIdProviderUnitTest, MultipleHistoryEntries) {
803   const base::Time kTime1 = base::Time::FromTimeT(1);
804   const base::Time kTime2 = base::Time::FromTimeT(2);
805   const base::Time kTime3 = base::Time::FromTimeT(3);
806 
807   history::URLResult url_result_a(GURL("https://a.test"), kTime1);
808   url_result_a.set_publicly_routable(true);
809 
810   history::URLResult url_result_b(GURL("https://b.test"), kTime2);
811   url_result_b.set_publicly_routable(true);
812 
813   history::URLResult url_result_c(GURL("https://c.test"), kTime3);
814 
815   std::vector<history::URLResult> url_results{url_result_a, url_result_b,
816                                               url_result_c};
817 
818   history::QueryResults query_results;
819   query_results.SetURLResults(std::move(url_results));
820 
821   set_first_floc_computation_triggered(true);
822   set_floc_computation_in_progress(true);
823 
824   OnGetRecentlyVisitedURLsCompleted(ComputeFlocTrigger::kBrowserStart,
825                                     std::move(query_results));
826 
827   EXPECT_EQ(
828       FlocId(FlocId::SimHashHistory({"a.test", "b.test"}), kTime1, kTime2, 0),
829       floc_id());
830 }
831 
TEST_F(FlocIdProviderUnitTest,TurnSyncOffAndOn)832 TEST_F(FlocIdProviderUnitTest, TurnSyncOffAndOn) {
833   std::string domain = "foo.com";
834   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(1);
835 
836   history::HistoryAddPageArgs add_page_args;
837   add_page_args.url = GURL(base::StrCat({"https://www.", domain}));
838   add_page_args.time = kTime;
839   add_page_args.publicly_routable = true;
840   history_service_->AddPage(add_page_args);
841 
842   task_environment_.RunUntilIdle();
843 
844   // Trigger the 1st floc computation.
845   test_sync_service_->SetTransportState(
846       syncer::SyncService::TransportState::ACTIVE);
847   test_sync_service_->FireStateChanged();
848 
849   task_environment_.RunUntilIdle();
850 
851   // Expect that the 1st computation has completed.
852   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
853   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
854   EXPECT_EQ(FlocId(FlocId::SimHashHistory({domain}), kTime, kTime, 0),
855             floc_id());
856 
857   // Turn off sync.
858   test_sync_service_->SetTransportState(
859       syncer::SyncService::TransportState::DISABLED);
860 
861   // Advance the clock by 1 day. Expect one more computation, as the sync was
862   // turned off so the id has been reset to empty.
863   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
864 
865   EXPECT_EQ(2u, floc_id_provider_->compute_floc_completed_count());
866   EXPECT_EQ(2u, floc_id_provider_->log_event_count());
867   EXPECT_FALSE(floc_id().IsValid());
868 
869   // Turn on sync.
870   test_sync_service_->SetTransportState(
871       syncer::SyncService::TransportState::ACTIVE);
872 
873   // Advance the clock by 1 day. Expect one more floc computation.
874   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
875 
876   EXPECT_EQ(3u, floc_id_provider_->compute_floc_completed_count());
877   EXPECT_EQ(3u, floc_id_provider_->log_event_count());
878   EXPECT_EQ(FlocId(FlocId::SimHashHistory({domain}), kTime, kTime, 0),
879             floc_id());
880 }
881 
TEST_F(FlocIdProviderUnitTest,GetInterestCohortForJsApiMethod)882 TEST_F(FlocIdProviderUnitTest, GetInterestCohortForJsApiMethod) {
883   test_sync_service_->SetTransportState(
884       syncer::SyncService::TransportState::ACTIVE);
885   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(1);
886   const FlocId expected_floc = FlocId(123, kTime, kTime, 999);
887 
888   set_floc_id(expected_floc);
889 
890   EXPECT_EQ(expected_floc.ToStringForJsApi(),
891             floc_id_provider_->GetInterestCohortForJsApi(
892                 /*requesting_origin=*/{}, /*site_for_cookies=*/{}));
893 }
894 
TEST_F(FlocIdProviderUnitTest,GetInterestCohortForJsApiMethod_SyncHistoryDisabled)895 TEST_F(FlocIdProviderUnitTest,
896        GetInterestCohortForJsApiMethod_SyncHistoryDisabled) {
897   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(1);
898 
899   set_floc_id(FlocId(123, kTime, kTime, 888));
900 
901   EXPECT_EQ(std::string(),
902             floc_id_provider_->GetInterestCohortForJsApi(
903                 /*requesting_origin=*/{}, /*site_for_cookies=*/{}));
904 }
905 
TEST_F(FlocIdProviderUnitTest,GetInterestCohortForJsApiMethod_ThirdPartyCookiesDisabled)906 TEST_F(FlocIdProviderUnitTest,
907        GetInterestCohortForJsApiMethod_ThirdPartyCookiesDisabled) {
908   test_sync_service_->SetTransportState(
909       syncer::SyncService::TransportState::ACTIVE);
910   fake_cookie_settings_->set_should_block_third_party_cookies(true);
911 
912   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(1);
913 
914   set_floc_id(FlocId(123, kTime, kTime, 999));
915 
916   EXPECT_EQ(std::string(),
917             floc_id_provider_->GetInterestCohortForJsApi(
918                 /*requesting_origin=*/{}, /*site_for_cookies=*/{}));
919 }
920 
TEST_F(FlocIdProviderUnitTest,GetInterestCohortForJsApiMethod_CookiesContentSettingsDisallowed)921 TEST_F(FlocIdProviderUnitTest,
922        GetInterestCohortForJsApiMethod_CookiesContentSettingsDisallowed) {
923   test_sync_service_->SetTransportState(
924       syncer::SyncService::TransportState::ACTIVE);
925   fake_cookie_settings_->set_allow_cookies_internal(false);
926 
927   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(1);
928 
929   set_floc_id(FlocId(123, kTime, kTime, 999));
930 
931   EXPECT_EQ(std::string(),
932             floc_id_provider_->GetInterestCohortForJsApi(
933                 /*requesting_origin=*/{}, /*site_for_cookies=*/{}));
934 }
935 
TEST_F(FlocIdProviderUnitTest,GetInterestCohortForJsApiMethod_FlocUnavailable)936 TEST_F(FlocIdProviderUnitTest,
937        GetInterestCohortForJsApiMethod_FlocUnavailable) {
938   test_sync_service_->SetTransportState(
939       syncer::SyncService::TransportState::ACTIVE);
940 
941   EXPECT_EQ(std::string(),
942             floc_id_provider_->GetInterestCohortForJsApi(
943                 /*requesting_origin=*/{}, /*site_for_cookies=*/{}));
944 }
945 
TEST_F(FlocIdProviderUnitTest,HistoryDeleteDuringInProgressComputation)946 TEST_F(FlocIdProviderUnitTest, HistoryDeleteDuringInProgressComputation) {
947   base::test::ScopedFeatureList feature_list;
948   feature_list.InitWithFeatures({features::kFlocIdSortingLshBasedComputation},
949                                 {});
950 
951   std::string domain1 = "foo.com";
952   std::string domain2 = "bar.com";
953   std::string domain3 = "baz.com";
954   const base::Time kTime1 = base::Time::Now() - base::TimeDelta::FromDays(7);
955   const base::Time kTime2 = base::Time::Now() - base::TimeDelta::FromDays(6);
956   const base::Time kTime3 = base::Time::Now() - base::TimeDelta::FromDays(5);
957 
958   // Add a history entry with a timestamp exactly 7 days back from now.
959   history::HistoryAddPageArgs add_page_args;
960   add_page_args.url = GURL(base::StrCat({"https://www.", domain1}));
961   add_page_args.time = kTime1;
962   add_page_args.publicly_routable = true;
963   history_service_->AddPage(add_page_args);
964 
965   // Add a history entry with a timestamp exactly 6 days back from now.
966   add_page_args.url = GURL(base::StrCat({"https://www.", domain2}));
967   add_page_args.time = kTime2;
968   history_service_->AddPage(add_page_args);
969 
970   // Add a history entry with a timestamp exactly 5 days back from now.
971   add_page_args.url = GURL(base::StrCat({"https://www.", domain3}));
972   add_page_args.time = kTime3;
973   history_service_->AddPage(add_page_args);
974 
975   // Map SimHashHistory({domain1, domain2, domain3}) to 123.
976   // Map SimHashHistory({domain2, domain3}) to 456.
977   // Map SimHashHistory({domain3}) to 789.
978   sorting_lsh_service_->ConfigureSortingLsh(
979       {{FlocId::SimHashHistory({domain1, domain2, domain3}), 123},
980        {FlocId::SimHashHistory({domain2, domain3}), 456},
981        {FlocId::SimHashHistory({domain3}), 789}},
982       base::Version("999.0.0"));
983 
984   // Trigger the 1st floc computation.
985   test_sync_service_->SetTransportState(
986       syncer::SyncService::TransportState::ACTIVE);
987   test_sync_service_->FireStateChanged();
988   sorting_lsh_service_->OnSortingLshClustersFileReady(base::FilePath(),
989                                                       base::Version());
990 
991   task_environment_.RunUntilIdle();
992 
993   // Expect that the 1st computation has completed.
994   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
995   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
996   EXPECT_TRUE(floc_id().IsValid());
997   EXPECT_EQ(FlocId(123, kTime1, kTime3, 999), floc_id());
998 
999   // Advance the clock by 1 day. The "domain1" should expire. However, we pause
1000   // before the computation completes.
1001   floc_id_provider_->set_should_pause_before_compute_floc_completed(true);
1002   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
1003 
1004   EXPECT_TRUE(floc_computation_in_progress());
1005   EXPECT_FALSE(need_recompute());
1006   EXPECT_EQ(FlocId(123, kTime1, kTime3, 999), floc_id());
1007   EXPECT_EQ(FlocId(456, kTime2, kTime3, 999),
1008             floc_id_provider_->paused_result().floc_id);
1009   EXPECT_EQ(ComputeFlocTrigger::kScheduledUpdate,
1010             floc_id_provider_->paused_trigger());
1011 
1012   // Expire the "domain2" history entry right before the floc computation
1013   // completes. Since the computation is still considered to be in-progress, we
1014   // will recompute right after this computation completes.
1015   ExpireHistoryBeforeUninclusive(kTime3);
1016 
1017   EXPECT_TRUE(need_recompute());
1018 
1019   floc_id_provider_->set_should_pause_before_compute_floc_completed(false);
1020   floc_id_provider_->ContinueLastOnComputeFlocCompleted();
1021   task_environment_.RunUntilIdle();
1022 
1023   // Expect 2 more compute completion events and 1 more log event. This is
1024   // because we won't send log event if there's a recompute event scheduled.
1025   // The compute trigger should be the original trigger (i.e. kScheduledUpdate),
1026   // rather than kHistoryDelete.
1027   EXPECT_EQ(3u, floc_id_provider_->compute_floc_completed_count());
1028   EXPECT_EQ(2u, floc_id_provider_->log_event_count());
1029   EXPECT_EQ(ComputeFlocTrigger::kScheduledUpdate,
1030             floc_id_provider_->last_log_event_trigger());
1031   EXPECT_FALSE(need_recompute());
1032 
1033   // The final floc should be derived from "domain3".
1034   EXPECT_TRUE(floc_id().IsValid());
1035   EXPECT_EQ(FlocId(789, kTime3, kTime3, 999), floc_id());
1036 }
1037 
1038 class FlocIdProviderUnitTestSortingLshEnabled : public FlocIdProviderUnitTest {
1039  public:
FlocIdProviderUnitTestSortingLshEnabled()1040   FlocIdProviderUnitTestSortingLshEnabled() {
1041     feature_list_.InitAndEnableFeature(
1042         features::kFlocIdSortingLshBasedComputation);
1043   }
1044 };
1045 
TEST_F(FlocIdProviderUnitTestSortingLshEnabled,SyncHistoryEnabledFollowedBySortingLshLoaded)1046 TEST_F(FlocIdProviderUnitTestSortingLshEnabled,
1047        SyncHistoryEnabledFollowedBySortingLshLoaded) {
1048   // Turn on sync & sync-history. The 1st floc computation should not be
1049   // triggered as the sorting-lsh file hasn't been loaded yet.
1050   test_sync_service_->SetTransportState(
1051       syncer::SyncService::TransportState::ACTIVE);
1052   test_sync_service_->FireStateChanged();
1053 
1054   EXPECT_FALSE(first_floc_computation_triggered());
1055 
1056   // Trigger the sorting-lsh ready event. The 1st floc computation should be
1057   // triggered now as sync & sync-history are enabled the sorting-lsh is ready.
1058   sorting_lsh_service_->OnSortingLshClustersFileReady(base::FilePath(),
1059                                                       base::Version());
1060 
1061   EXPECT_TRUE(first_floc_computation_triggered());
1062 }
1063 
TEST_F(FlocIdProviderUnitTestSortingLshEnabled,SortingLshLoadedFollowedBySyncHistoryEnabled)1064 TEST_F(FlocIdProviderUnitTestSortingLshEnabled,
1065        SortingLshLoadedFollowedBySyncHistoryEnabled) {
1066   // Trigger the sorting-lsh ready event. The 1st floc computation should not be
1067   // triggered as sync & sync-history are not enabled yet.
1068   sorting_lsh_service_->OnSortingLshClustersFileReady(base::FilePath(),
1069                                                       base::Version());
1070 
1071   EXPECT_FALSE(first_floc_computation_triggered());
1072 
1073   // Turn on sync & sync-history. The 1st floc computation should be triggered
1074   // now as sync & sync-history are enabled the sorting-lsh is loaded.
1075   test_sync_service_->SetTransportState(
1076       syncer::SyncService::TransportState::ACTIVE);
1077   test_sync_service_->FireStateChanged();
1078 
1079   EXPECT_TRUE(first_floc_computation_triggered());
1080 }
1081 
TEST_F(FlocIdProviderUnitTestSortingLshEnabled,ApplyAdditionalFiltering_SortingLsh)1082 TEST_F(FlocIdProviderUnitTestSortingLshEnabled,
1083        ApplyAdditionalFiltering_SortingLsh) {
1084   const base::Time kTime1 = base::Time::FromTimeT(1);
1085   const base::Time kTime2 = base::Time::FromTimeT(2);
1086 
1087   bool callback_called = false;
1088   auto callback = base::BindLambdaForTesting([&](ComputeFlocResult result) {
1089     EXPECT_FALSE(callback_called);
1090     EXPECT_EQ(result.sim_hash, 3u);
1091     EXPECT_EQ(result.floc_id, FlocId(2, kTime1, kTime2, 99));
1092     callback_called = true;
1093   });
1094 
1095   // Map 3 to 2
1096   sorting_lsh_service_->OnSortingLshClustersFileReady(base::FilePath(),
1097                                                       base::Version());
1098   sorting_lsh_service_->ConfigureSortingLsh({{3, 2}}, base::Version("99.0"));
1099 
1100   ApplySortingLshPostProcessing(std::move(callback), /*sim_hash=*/3, kTime1,
1101                                 kTime2);
1102   task_environment_.RunUntilIdle();
1103   EXPECT_TRUE(callback_called);
1104 }
1105 
TEST_F(FlocIdProviderUnitTestSortingLshEnabled,ApplySortingLshPostProcessing_FileCorrupted)1106 TEST_F(FlocIdProviderUnitTestSortingLshEnabled,
1107        ApplySortingLshPostProcessing_FileCorrupted) {
1108   const base::Time kTime1 = base::Time::FromTimeT(1);
1109   const base::Time kTime2 = base::Time::FromTimeT(2);
1110 
1111   bool callback_called = false;
1112   auto callback = base::BindLambdaForTesting([&](ComputeFlocResult result) {
1113     EXPECT_FALSE(callback_called);
1114     EXPECT_EQ(result.sim_hash, 3u);
1115     EXPECT_EQ(result.floc_id, FlocId());
1116     callback_called = true;
1117   });
1118 
1119   sorting_lsh_service_->OnSortingLshClustersFileReady(base::FilePath(),
1120                                                       base::Version());
1121   sorting_lsh_service_->ConfigureSortingLsh({}, base::Version("3.4.5"));
1122 
1123   ApplySortingLshPostProcessing(std::move(callback), /*sim_hash=*/3, kTime1,
1124                                 kTime2);
1125   task_environment_.RunUntilIdle();
1126   EXPECT_TRUE(callback_called);
1127 }
1128 
TEST_F(FlocIdProviderUnitTestSortingLshEnabled,SortingLshPostProcessing)1129 TEST_F(FlocIdProviderUnitTestSortingLshEnabled, SortingLshPostProcessing) {
1130   std::string domain = "foo.com";
1131   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(1);
1132 
1133   history::HistoryAddPageArgs add_page_args;
1134   add_page_args.url = GURL(base::StrCat({"https://www.", domain}));
1135   add_page_args.time = kTime;
1136   add_page_args.publicly_routable = true;
1137   history_service_->AddPage(add_page_args);
1138 
1139   task_environment_.RunUntilIdle();
1140 
1141   uint64_t sim_hash = FlocId::SimHashHistory({domain});
1142 
1143   // Configure the |sorting_lsh_service_| to map |sim_hash| to 12345.
1144   sorting_lsh_service_->ConfigureSortingLsh({{sim_hash, 12345}},
1145                                             base::Version("99.0"));
1146 
1147   // Trigger the sorting-lsh ready event, and turn on sync & sync-history to
1148   // trigger the 1st floc computation.
1149   sorting_lsh_service_->OnSortingLshClustersFileReady(base::FilePath(),
1150                                                       base::Version());
1151 
1152   test_sync_service_->SetTransportState(
1153       syncer::SyncService::TransportState::ACTIVE);
1154   test_sync_service_->FireStateChanged();
1155 
1156   EXPECT_TRUE(first_floc_computation_triggered());
1157 
1158   task_environment_.RunUntilIdle();
1159 
1160   // Expect a computation. The floc should be equal to 12345.
1161   EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
1162   EXPECT_EQ(1u, floc_id_provider_->log_event_count());
1163   EXPECT_EQ(FlocId(12345, kTime, kTime, 99), floc_id());
1164 
1165   // Configure the |sorting_lsh_service_| to block |sim_hash|.
1166   sorting_lsh_service_->ConfigureSortingLsh({{sim_hash, base::nullopt}},
1167                                             base::Version("3.4.5"));
1168 
1169   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
1170 
1171   // Expect one more computation, where the result contains a valid sim_hash and
1172   // an invalid floc_id, as it was blocked. The internal floc is set to the
1173   // invalid one.
1174   EXPECT_EQ(2u, floc_id_provider_->compute_floc_completed_count());
1175   EXPECT_EQ(2u, floc_id_provider_->log_event_count());
1176   EXPECT_TRUE(floc_id_provider_->last_log_event_result().sim_hash_computed);
1177   EXPECT_EQ(floc_id_provider_->last_log_event_result().sim_hash, sim_hash);
1178   EXPECT_FALSE(floc_id_provider_->last_log_event_result().floc_id.IsValid());
1179   EXPECT_FALSE(floc_id().IsValid());
1180 
1181   // In the event when the sim_hash is valid and floc_id is invalid, we'll
1182   // still log it.
1183   EXPECT_EQ(2u, fake_user_event_service_->GetRecordedUserEvents().size());
1184   const sync_pb::UserEventSpecifics& specifics =
1185       fake_user_event_service_->GetRecordedUserEvents()[1];
1186   EXPECT_EQ(specifics.event_time_usec(),
1187             base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
1188 
1189   EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
1190             specifics.event_case());
1191 
1192   const sync_pb::UserEventSpecifics_FlocIdComputed& event =
1193       specifics.floc_id_computed_event();
1194   EXPECT_EQ(sync_pb::UserEventSpecifics::FlocIdComputed::REFRESHED,
1195             event.event_trigger());
1196   EXPECT_EQ(sim_hash, event.floc_id());
1197 
1198   // Configure the |sorting_lsh_service_| to map |sim_hash| to 6789.
1199   sorting_lsh_service_->ConfigureSortingLsh({{sim_hash, 6789}},
1200                                             base::Version("999.0"));
1201 
1202   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
1203 
1204   // Expect one more computation. The floc should be equal to 6789.
1205   EXPECT_EQ(3u, floc_id_provider_->compute_floc_completed_count());
1206   EXPECT_EQ(3u, floc_id_provider_->log_event_count());
1207   EXPECT_EQ(FlocId(6789, kTime, kTime, 999), floc_id());
1208 }
1209 
1210 }  // namespace federated_learning
1211