blob: 1b7e0dc1f678ab8edbb346d7346588089a2458c9 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/bind.h"
#include "chrome/browser/federated_learning/floc_eligibility_observer.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/page_load_metrics/observers/ad_metrics/floc_page_load_metrics_observer.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/federated_learning/features/features.h"
#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include "components/history/content/browser/history_context_helper.h"
#include "components/history/core/browser/history_service.h"
#include "components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
#include "components/page_load_metrics/common/page_load_metrics.mojom.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/web_contents_tester.h"
namespace federated_learning {
class FlocEligibilityUnitTest : public ChromeRenderViewHostTestHarness {
public:
FlocEligibilityUnitTest() = default;
~FlocEligibilityUnitTest() override = default;
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
TestingBrowserProcess::GetGlobal()->SetFlocSortingLshClustersService(
std::make_unique<federated_learning::FlocSortingLshClustersService>());
ASSERT_TRUE(profile()->CreateHistoryService());
InitWebContents();
tester_ =
std::make_unique<page_load_metrics::PageLoadMetricsObserverTester>(
GetWebContents(), this,
base::BindRepeating(&FlocEligibilityUnitTest::RegisterObservers,
base::Unretained(this)));
}
// Can be overridden in child class to initialize an incognito web_contents.
virtual void InitWebContents() {}
virtual content::WebContents* GetWebContents() { return web_contents(); }
history::HistoryService* history_service() {
return HistoryServiceFactory::GetForProfile(
profile(), ServiceAccessType::EXPLICIT_ACCESS);
}
bool IsUrlVisitEligibleToComputeFloc(const GURL& url) {
bool eligible = false;
history::QueryOptions options;
options.duplicate_policy = history::QueryOptions::KEEP_ALL_DUPLICATES;
base::RunLoop run_loop;
base::CancelableTaskTracker tracker;
history_service()->QueryHistory(
std::u16string(), options,
base::BindLambdaForTesting([&](history::QueryResults results) {
ASSERT_EQ(1u, results.size());
eligible = results[0].content_annotations().annotation_flags &
history::VisitContentAnnotationFlag::kFlocEligibleRelaxed;
run_loop.Quit();
}),
&tracker);
run_loop.Run();
return eligible;
}
void SimulateResourceDataUseUpdate(bool is_ad_resource) {
page_load_metrics::mojom::ResourceDataUpdatePtr resource =
page_load_metrics::mojom::ResourceDataUpdate::New();
resource->reported_as_ad_resource = is_ad_resource;
resource->received_data_length = 1;
std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources;
resources.push_back(std::move(resource));
tester_->SimulateResourceDataUseUpdate(resources,
GetWebContents()->GetMainFrame());
}
void NavigateToPage(const GURL& url,
bool publicly_routable,
bool floc_permissions_policy_enabled) {
auto simulator = content::NavigationSimulator::CreateBrowserInitiated(
url, GetWebContents());
simulator->SetTransition(ui::PageTransition::PAGE_TRANSITION_TYPED);
if (!publicly_routable) {
net::IPAddress address;
EXPECT_TRUE(address.AssignFromIPLiteral("0.0.0.0"));
simulator->SetSocketAddress(net::IPEndPoint(address, /*port=*/0));
}
if (!floc_permissions_policy_enabled) {
simulator->SetPermissionsPolicyHeader(
{{blink::mojom::PermissionsPolicyFeature::kInterestCohort,
/*values=*/{}, /*matches_all_origins=*/false,
/*matches_opaque_src=*/false}});
}
simulator->Commit();
history_service()->AddPage(
url, base::Time::Now(),
history::ContextIDForWebContents(GetWebContents()),
GetWebContents()
->GetController()
.GetLastCommittedEntry()
->GetUniqueID(),
/*referrer=*/GURL(),
/*redirects=*/{}, ui::PageTransition::PAGE_TRANSITION_TYPED,
history::VisitSource::SOURCE_BROWSED,
/*did_replace_entry=*/false,
/*floc_allowed=*/false);
}
FlocEligibilityObserver* GetFlocEligibilityObserver() {
return FlocEligibilityObserver::GetOrCreateForCurrentDocument(
GetWebContents()->GetMainFrame());
}
private:
void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) {
auto floc_plm_observer = std::make_unique<FlocPageLoadMetricsObserver>();
floc_plm_observer_ = floc_plm_observer.get();
tracker->AddObserver(std::move(floc_plm_observer));
}
FlocPageLoadMetricsObserver* floc_plm_observer_;
std::unique_ptr<page_load_metrics::PageLoadMetricsObserverTester> tester_;
};
TEST_F(FlocEligibilityUnitTest, OnInterestCohortApiUsed) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/true,
/*floc_permissions_policy_enabled=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
GetFlocEligibilityObserver()->OnInterestCohortApiUsed();
EXPECT_TRUE(IsUrlVisitEligibleToComputeFloc(url));
}
TEST_F(FlocEligibilityUnitTest, OnAdResourceObserved) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/true,
/*floc_permissions_policy_enabled=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
SimulateResourceDataUseUpdate(/*is_ad_resource=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
}
TEST_F(FlocEligibilityUnitTest, OnNonAdResourceObserved) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/true,
/*floc_permissions_policy_enabled=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
SimulateResourceDataUseUpdate(/*is_ad_resource=*/false);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
}
TEST_F(FlocEligibilityUnitTest, StopObservingPrivateIP) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/false,
/*floc_permissions_policy_enabled=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
SimulateResourceDataUseUpdate(/*is_ad_resource=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
GetFlocEligibilityObserver()->OnInterestCohortApiUsed();
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
}
TEST_F(FlocEligibilityUnitTest, StopObservingFlocPermissionsPolicyDisabled) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/true,
/*floc_permissions_policy_enabled=*/false);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
SimulateResourceDataUseUpdate(/*is_ad_resource=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
GetFlocEligibilityObserver()->OnInterestCohortApiUsed();
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
}
class FlocEligibilityUnitTestkBypassIPIsPubliclyRoutableCheck
: public FlocEligibilityUnitTest {
public:
FlocEligibilityUnitTestkBypassIPIsPubliclyRoutableCheck() {
feature_list_.InitAndEnableFeature(kFlocBypassIPIsPubliclyRoutableCheck);
}
protected:
base::test::ScopedFeatureList feature_list_;
};
TEST_F(FlocEligibilityUnitTestkBypassIPIsPubliclyRoutableCheck,
ContinueObservingPrivateIP) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/false,
/*floc_permissions_policy_enabled=*/true);
GetFlocEligibilityObserver()->OnInterestCohortApiUsed();
EXPECT_TRUE(IsUrlVisitEligibleToComputeFloc(url));
}
class FlocEligibilityUnitTestPagesWithAdResourcesDefaultIncluded
: public FlocEligibilityUnitTest {
public:
FlocEligibilityUnitTestPagesWithAdResourcesDefaultIncluded() {
feature_list_.InitAndEnableFeature(
kFlocPagesWithAdResourcesDefaultIncludedInFlocComputation);
}
protected:
base::test::ScopedFeatureList feature_list_;
};
TEST_F(FlocEligibilityUnitTestPagesWithAdResourcesDefaultIncluded,
OnAdResourceObserved) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/true,
/*floc_permissions_policy_enabled=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
SimulateResourceDataUseUpdate(/*is_ad_resource=*/true);
EXPECT_TRUE(IsUrlVisitEligibleToComputeFloc(url));
}
TEST_F(FlocEligibilityUnitTestPagesWithAdResourcesDefaultIncluded,
OnNonAdResourceObserved) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/true,
/*floc_permissions_policy_enabled=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
SimulateResourceDataUseUpdate(/*is_ad_resource=*/false);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
}
class FlocEligibilityIncognitoUnitTest : public FlocEligibilityUnitTest {
public:
FlocEligibilityIncognitoUnitTest() = default;
~FlocEligibilityIncognitoUnitTest() override = default;
void InitWebContents() override {
TestingProfile::Builder().BuildIncognito(profile());
incognito_web_contents_ = content::WebContentsTester::CreateTestWebContents(
profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true),
content::SiteInstance::Create(
profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true)));
}
content::WebContents* GetWebContents() override {
return incognito_web_contents_.get();
}
void TearDown() override {
incognito_web_contents_.reset();
FlocEligibilityUnitTest::TearDown();
}
private:
std::unique_ptr<content::WebContents> incognito_web_contents_;
};
TEST_F(FlocEligibilityIncognitoUnitTest, SkipSettingFlocAllowedInIncognito) {
GURL url("https://foo.com");
NavigateToPage(url, /*publicly_routable=*/true,
/*floc_permissions_policy_enabled=*/true);
SimulateResourceDataUseUpdate(/*is_ad_resource=*/true);
EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
}
} // namespace federated_learning