blob: 0fcf6c388d63c6c12d3bfc4e823062b88d5e2b86 [file] [log] [blame]
// Copyright 2018 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 "chrome/browser/navigation_predictor/navigation_predictor.h"
#include <map>
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/loader/navigation_predictor.mojom.h"
#include "url/gurl.h"
namespace {
class TestNavigationPredictor : public NavigationPredictor {
public:
explicit TestNavigationPredictor(
mojo::InterfaceRequest<AnchorElementMetricsHost> request,
content::RenderFrameHost* render_frame_host)
: NavigationPredictor(render_frame_host), binding_(this) {
binding_.Bind(std::move(request));
}
~TestNavigationPredictor() override {}
base::Optional<GURL> prefetch_url() const { return prefetch_url_; }
const std::map<GURL, int>& GetAreaRankMap() const { return area_rank_map_; }
private:
double CalculateAnchorNavigationScore(
const blink::mojom::AnchorElementMetrics& metrics,
double document_engagement_score,
double target_engagement_score,
int area_rank,
int number_of_anchors) const override {
area_rank_map_.emplace(std::make_pair(metrics.target_url, area_rank));
return 100 * metrics.ratio_area;
}
// Maps from target URL to area rank of the anchor element.
mutable std::map<GURL, int> area_rank_map_;
// Used to bind Mojo interface
mojo::Binding<AnchorElementMetricsHost> binding_;
};
class NavigationPredictorTest : public ChromeRenderViewHostTestHarness {
public:
NavigationPredictorTest() = default;
~NavigationPredictorTest() override = default;
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
predictor_service_helper_ = std::make_unique<TestNavigationPredictor>(
mojo::MakeRequest(&predictor_service_), main_rfh());
}
// Helper function to generate mojom metrics.
blink::mojom::AnchorElementMetricsPtr CreateMetricsPtr(
const std::string& source_url,
const std::string& target_url,
float ratio_area) const {
auto metrics = blink::mojom::AnchorElementMetrics::New();
metrics->source_url = GURL(source_url);
metrics->target_url = GURL(target_url);
metrics->ratio_area = ratio_area;
return metrics;
}
blink::mojom::AnchorElementMetricsHost* predictor_service() const {
return predictor_service_.get();
}
TestNavigationPredictor* predictor_service_helper() const {
return predictor_service_helper_.get();
}
base::Optional<GURL> prefetch_url() const {
return predictor_service_helper_->prefetch_url();
}
private:
blink::mojom::AnchorElementMetricsHostPtr predictor_service_;
std::unique_ptr<TestNavigationPredictor> predictor_service_helper_;
};
} // namespace
// Basic test to check the ReportAnchorElementMetricsOnClick method can be
// called.
TEST_F(NavigationPredictorTest, ReportAnchorElementMetricsOnClick) {
base::HistogramTester histogram_tester;
auto metrics =
CreateMetricsPtr("https://example.com", "https://google.com", 0.1);
predictor_service()->ReportAnchorElementMetricsOnClick(std::move(metrics));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"AnchorElementMetrics.Clicked.HrefEngagementScore2", 1);
}
// Test that ReportAnchorElementMetricsOnLoad method can be called.
TEST_F(NavigationPredictorTest, ReportAnchorElementMetricsOnLoad) {
base::HistogramTester histogram_tester;
auto metrics =
CreateMetricsPtr("https://example.com", "https://google.com", 0.1);
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
metrics_vector.push_back(std::move(metrics));
predictor_service()->ReportAnchorElementMetricsOnLoad(
std::move(metrics_vector));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"AnchorElementMetrics.Visible.HighestNavigationScore", 1);
}
// Test that if source/target url is not http or https, no score will be
// calculated.
TEST_F(NavigationPredictorTest,
BadUrlReportAnchorElementMetricsOnClick_ftp_src) {
base::HistogramTester histogram_tester;
auto metrics =
CreateMetricsPtr("ftp://example.com", "https://google.com", 0.1);
predictor_service()->ReportAnchorElementMetricsOnClick(std::move(metrics));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"AnchorElementMetrics.Clicked.HrefEngagementScore2", 0);
}
// Test that if source/target url is not http or https, no navigation score will
// be calculated.
TEST_F(NavigationPredictorTest,
BadUrlReportAnchorElementMetricsOnLoad_ftp_target) {
base::HistogramTester histogram_tester;
auto metrics =
CreateMetricsPtr("https://example.com", "ftp://google.com", 0.1);
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
metrics_vector.push_back(std::move(metrics));
predictor_service()->ReportAnchorElementMetricsOnLoad(
std::move(metrics_vector));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"AnchorElementMetrics.Visible.HighestNavigationScore", 0);
}
// Test that if the target url is not https, no navigation score will
// be calculated.
TEST_F(NavigationPredictorTest,
BadUrlReportAnchorElementMetricsOnLoad_http_target) {
base::HistogramTester histogram_tester;
auto metrics =
CreateMetricsPtr("https://example.com", "http://google.com", 0.1);
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
metrics_vector.push_back(std::move(metrics));
predictor_service()->ReportAnchorElementMetricsOnLoad(
std::move(metrics_vector));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"AnchorElementMetrics.Visible.HighestNavigationScore", 0);
}
// Test that if the source url is not https, no navigation score will
// be calculated.
TEST_F(NavigationPredictorTest,
BadUrlReportAnchorElementMetricsOnLoad_http_src) {
base::HistogramTester histogram_tester;
auto metrics =
CreateMetricsPtr("http://example.com", "https://google.com", 0.1);
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
metrics_vector.push_back(std::move(metrics));
predictor_service()->ReportAnchorElementMetricsOnLoad(
std::move(metrics_vector));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"AnchorElementMetrics.Visible.HighestNavigationScore", 0);
}
// In this test, multiple anchor element metrics are sent to
// ReportAnchorElementMetricsOnLoad. Test that CalculateAnchorNavigationScore
// works, and that highest navigation score can be recorded correctly.
TEST_F(NavigationPredictorTest, MultipleAnchorElementMetricsOnLoad) {
base::HistogramTester histogram_tester;
const std::string source = "https://example.com";
const std::string href_xlarge = "https://example.com/xlarge";
const std::string href_large = "https://google.com/large";
const std::string href_medium = "https://google.com/medium";
const std::string href_small = "https://google.com/small";
const std::string href_xsmall = "https://google.com/xsmall";
const std::string http_href_xsmall = "http://google.com/xsmall";
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
metrics.push_back(CreateMetricsPtr(source, href_xsmall, 0.01));
metrics.push_back(CreateMetricsPtr(source, http_href_xsmall, 0.01));
metrics.push_back(CreateMetricsPtr(source, href_large, 0.08));
metrics.push_back(CreateMetricsPtr(source, href_xlarge, 0.1));
metrics.push_back(CreateMetricsPtr(source, href_small, 0.02));
metrics.push_back(CreateMetricsPtr(source, href_medium, 0.05));
int number_of_metrics_sent = metrics.size();
predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
base::RunLoop().RunUntilIdle();
const std::map<GURL, int>& area_rank_map =
predictor_service_helper()->GetAreaRankMap();
// Exclude the http anchor element from |number_of_metrics_sent|.
EXPECT_EQ(number_of_metrics_sent - 1, static_cast<int>(area_rank_map.size()));
EXPECT_EQ(0, area_rank_map.find(GURL(href_xlarge))->second);
EXPECT_EQ(1, area_rank_map.find(GURL(href_large))->second);
EXPECT_EQ(2, area_rank_map.find(GURL(href_medium))->second);
EXPECT_EQ(3, area_rank_map.find(GURL(href_small))->second);
EXPECT_EQ(4, area_rank_map.find(GURL(href_xsmall))->second);
EXPECT_EQ(area_rank_map.end(), area_rank_map.find(GURL(http_href_xsmall)));
// The highest score is 100 (scale factor) * 0.1 (largest area) = 10.
// After scaling the navigation score across all anchor elements, the score
// becomes 38.
histogram_tester.ExpectUniqueSample(
"AnchorElementMetrics.Visible.HighestNavigationScore", 38, 1);
histogram_tester.ExpectTotalCount("AnchorElementMetrics.Visible.RatioArea",
5);
}
TEST_F(NavigationPredictorTest, ActionTaken_NoSameHost_Prefetch) {
const std::string source = "https://example.com";
const std::string href_xlarge = "https://example2.com/xlarge";
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
metrics.push_back(CreateMetricsPtr(source, href_xlarge, 0.1));
base::HistogramTester histogram_tester;
predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectUniqueSample(
"NavigationPredictor.OnNonDSE.ActionTaken",
NavigationPredictor::Action::kNone, 1);
EXPECT_FALSE(prefetch_url().has_value());
}
TEST_F(NavigationPredictorTest, ActionTaken_SameOrigin_Prefetch) {
const std::string source = "https://example.com";
const std::string same_origin_href_small = "https://example.com/small";
const std::string diff_origin_href_xlarge = "https://example2.com/xlarge";
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
metrics.push_back(CreateMetricsPtr(source, same_origin_href_small, 0.01));
metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xlarge, 1));
base::HistogramTester histogram_tester;
predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectUniqueSample(
"NavigationPredictor.OnNonDSE.ActionTaken",
NavigationPredictor::Action::kPrefetch, 1);
EXPECT_EQ(GURL(same_origin_href_small), prefetch_url());
}
TEST_F(NavigationPredictorTest,
ActionTaken_SameOrigin_DifferentScheme_Prefetch) {
const std::string source = "https://example.com";
const std::string same_origin_href_small = "http://example.com/small";
const std::string diff_origin_href_xlarge = "https://example2.com/xlarge";
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
metrics.push_back(CreateMetricsPtr(source, same_origin_href_small, 0.01));
metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xlarge, 1));
base::HistogramTester histogram_tester;
predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectUniqueSample(
"NavigationPredictor.OnNonDSE.ActionTaken",
NavigationPredictor::Action::kNone, 1);
EXPECT_FALSE(prefetch_url().has_value());
}