blob: f41510793f9ecb9b005c6a03dfcb915a0b09982d [file]
// Copyright 2020 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/lite_video/lite_video_decider.h"
#include <map>
#include <utility>
#include "base/bind.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/time/clock.h"
#include "chrome/browser/lite_video/lite_video_features.h"
#include "chrome/browser/lite_video/lite_video_hint.h"
#include "chrome/browser/lite_video/lite_video_switches.h"
#include "chrome/browser/lite_video/lite_video_user_blocklist.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/blocklist/opt_out_blocklist/opt_out_blocklist.h"
#include "components/blocklist/opt_out_blocklist/opt_out_blocklist_delegate.h"
#include "components/blocklist/opt_out_blocklist/opt_out_store.h"
#include "components/optimization_guide/content/optimization_guide_decider.h"
#include "components/optimization_guide/content/test_optimization_guide_decider.h"
#include "components/optimization_guide/proto/lite_video_metadata.pb.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
class TestLiteVideoUserBlocklist : public lite_video::LiteVideoUserBlocklist {
public:
TestLiteVideoUserBlocklist(
std::unique_ptr<blocklist::OptOutStore> opt_out_store,
base::Clock* clock,
blocklist::OptOutBlocklistDelegate* blocklist_delegate)
: lite_video::LiteVideoUserBlocklist(std::move(opt_out_store),
clock,
blocklist_delegate) {}
~TestLiteVideoUserBlocklist() override = default;
lite_video::LiteVideoBlocklistReason IsLiteVideoAllowedOnNavigation(
content::NavigationHandle* navigation_handle) const override {
return blocklist_reason_;
}
void set_blocklist_reason(
lite_video::LiteVideoBlocklistReason blocklist_reason) {
blocklist_reason_ = blocklist_reason;
}
private:
lite_video::LiteVideoBlocklistReason blocklist_reason_ =
lite_video::LiteVideoBlocklistReason::kAllowed;
};
class TestLiteVideoHintCache : public lite_video::LiteVideoHintCache {
public:
TestLiteVideoHintCache() = default;
~TestLiteVideoHintCache() override = default;
base::Optional<lite_video::LiteVideoHint> GetHintForNavigationURL(
const GURL& url) const override {
auto it = hint_cache_.find(url);
if (it != hint_cache_.end())
return it->second;
return base::nullopt;
}
void AddHintForTesting(const GURL& url,
const lite_video::LiteVideoHint& hint) {
hint_cache_.insert(std::make_pair(url, hint));
}
private:
std::map<GURL, lite_video::LiteVideoHint> hint_cache_;
};
class TestOptimizationGuideDecider
: public optimization_guide::TestOptimizationGuideDecider {
public:
TestOptimizationGuideDecider() = default;
~TestOptimizationGuideDecider() override = default;
void RegisterOptimizationTypes(
const std::vector<optimization_guide::proto::OptimizationType>&
optimization_types) override {
registered_optimization_types_ =
base::flat_set<optimization_guide::proto::OptimizationType>(
optimization_types.begin(), optimization_types.end());
}
// Returns the optimization types registered with the Optimization Guide
// Decider.
base::flat_set<optimization_guide::proto::OptimizationType>
registered_optimization_types() {
return registered_optimization_types_;
}
void CanApplyOptimizationAsync(
content::NavigationHandle* navigation_handle,
optimization_guide::proto::OptimizationType optimization_type,
optimization_guide::OptimizationGuideDecisionCallback callback) override {
GURL url = navigation_handle->GetURL();
auto response_iter =
responses_.find(std::make_tuple(url, optimization_type));
if (response_iter == responses_.end()) {
std::move(callback).Run(
optimization_guide::OptimizationGuideDecision::kFalse,
optimization_guide::OptimizationMetadata());
return;
}
auto response = response_iter->second;
std::move(callback).Run(std::get<0>(response), std::get<1>(response));
}
void SetResponses(
std::map<std::tuple<GURL, optimization_guide::proto::OptimizationType>,
std::tuple<optimization_guide::OptimizationGuideDecision,
optimization_guide::OptimizationMetadata>>
responses) {
responses_ = responses;
}
private:
// The optimization types that were registered with the Optimization Guide
// Decider.
base::flat_set<optimization_guide::proto::OptimizationType>
registered_optimization_types_;
std::map<std::tuple<GURL, optimization_guide::proto::OptimizationType>,
std::tuple<optimization_guide::OptimizationGuideDecision,
optimization_guide::OptimizationMetadata>>
responses_;
DISALLOW_COPY_AND_ASSIGN(TestOptimizationGuideDecider);
};
class LiteVideoDeciderTest : public ChromeRenderViewHostTestHarness {
public:
explicit LiteVideoDeciderTest(bool allow_on_forward_back = false)
: allow_on_forward_back_(allow_on_forward_back) {}
void SetUp() override {
content::RenderViewHostTestHarness::SetUp();
scoped_feature_list_.InitAndEnableFeatureWithParameters(
::features::kLiteVideo,
{{"allow_on_forward_back", allow_on_forward_back_ ? "true" : "false"}});
optimization_guide_decider_ =
std::make_unique<TestOptimizationGuideDecider>();
lite_video_decider_ = std::make_unique<lite_video::LiteVideoDecider>(
nullptr, &test_clock_, nullptr);
lite_video_decider_->OnEffectiveConnectionTypeChanged(
net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_4G);
lite_video_decider_->OnConnectionChanged(
network::mojom::ConnectionType::CONNECTION_4G);
base::CommandLine::ForCurrentProcess()->AppendSwitch(
"enable-spdy-proxy-auth");
}
void UseOptimizationGuideDecider() {
optimization_guide_decider_->RegisterOptimizationTypes(
{optimization_guide::proto::LITE_VIDEO});
lite_video_decider_->SetOptimizationGuideDeciderForTesting(
optimization_guide_decider_.get());
}
void DisableLiteVideo() {
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndDisableFeature({::features::kLiteVideo});
}
void CanApplyOnSubframeNavigation(const GURL& mainframe_url,
const GURL& subframe_url) {
// Needed so that a mainframe navigation exists.
NavigateAndCommit(mainframe_url);
content::RenderFrameHostTester* rfh_tester =
content::RenderFrameHostTester::For(main_rfh());
content::RenderFrameHost* subframe = rfh_tester->AppendChild("subframe");
content::MockNavigationHandle navigation_handle(subframe_url, subframe);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle,
base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
}
void SetDurationFromTimeDelta(optimization_guide::proto::Duration* duration,
const base::TimeDelta& delta) {
if (!duration)
return;
duration->set_seconds(delta.InSeconds());
duration->set_nanos(delta.InNanoseconds() %
base::TimeDelta::FromSeconds(1).InNanoseconds());
}
void SeedLiteVideoHintCache(const GURL& gurl,
base::Optional<lite_video::LiteVideoHint> hint,
bool use_opt_guide) {
if (use_opt_guide) {
optimization_guide::OptimizationMetadata default_metadata;
optimization_guide::proto::LiteVideoMetadata lite_video_metadata;
if (hint) {
optimization_guide::proto::LiteVideoHint* hint_proto =
lite_video_metadata.mutable_lite_video_hint();
hint_proto->set_target_downlink_bandwidth_kbps(
hint->target_downlink_bandwidth_kbps());
hint_proto->set_kilobytes_to_buffer_before_throttle(
hint->kilobytes_to_buffer_before_throttle());
SetDurationFromTimeDelta(
hint_proto->mutable_target_downlink_rtt_latency(),
hint->target_downlink_rtt_latency());
SetDurationFromTimeDelta(hint_proto->mutable_max_throttling_delay(),
hint->max_throttling_delay());
default_metadata.SetAnyMetadataForTesting(lite_video_metadata);
}
std::map<std::tuple<GURL, optimization_guide::proto::OptimizationType>,
std::tuple<optimization_guide::OptimizationGuideDecision,
optimization_guide::OptimizationMetadata>>
responses = {
{std::make_tuple(gurl, optimization_guide::proto::LITE_VIDEO),
std::make_tuple(
optimization_guide::OptimizationGuideDecision::kTrue,
default_metadata)},
};
optimization_guide_decider_->SetResponses(responses);
return;
}
std::unique_ptr<TestLiteVideoHintCache> hint_cache =
std::make_unique<TestLiteVideoHintCache>();
hint_cache->AddHintForTesting(gurl, *hint);
lite_video_decider_->SetHintCacheForTesting(std::move(hint_cache));
}
void SetBlocklistReason(lite_video::LiteVideoBlocklistReason reason) {
std::unique_ptr<TestLiteVideoUserBlocklist> user_blocklist_ =
std::make_unique<TestLiteVideoUserBlocklist>(nullptr, &test_clock_,
lite_video_decider_.get());
user_blocklist_->set_blocklist_reason(reason);
lite_video_decider_->SetUserBlocklistForTesting(std::move(user_blocklist_));
}
void SeedPermanentHostBlocklist(
const base::flat_set<std::string>& permanent_host_blocklist) {
lite_video_decider_->SetPermanentHostBlocklistForTesting(
permanent_host_blocklist);
}
lite_video::LiteVideoDecider* lite_video_decider() {
return lite_video_decider_.get();
}
void OnHintAvailable(
base::Optional<lite_video::LiteVideoHint> hint,
lite_video::LiteVideoBlocklistReason blocklist_reason,
optimization_guide::OptimizationGuideDecision opt_guide_decision) {
opt_guide_decision_ = opt_guide_decision;
hint_ = hint;
blocklist_reason_ = blocklist_reason;
}
base::Optional<lite_video::LiteVideoHint> hint() { return hint_; }
optimization_guide::OptimizationGuideDecision opt_guide_decision() {
return opt_guide_decision_;
}
lite_video::LiteVideoBlocklistReason blocklist_reason() {
return blocklist_reason_;
}
void TearDown() override { content::RenderViewHostTestHarness::TearDown(); }
void RunUntilIdle() {
task_environment()->RunUntilIdle();
base::RunLoop().RunUntilIdle();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
base::SimpleTestClock test_clock_;
std::unique_ptr<lite_video::LiteVideoDecider> lite_video_decider_;
lite_video::LiteVideoBlocklistReason blocklist_reason_;
base::Optional<lite_video::LiteVideoHint> hint_;
std::unique_ptr<TestOptimizationGuideDecider> optimization_guide_decider_;
optimization_guide::OptimizationGuideDecision opt_guide_decision_;
bool allow_on_forward_back_;
};
TEST_F(LiteVideoDeciderTest, CanApplyOnNonHTTPOrHTTPSURL) {
base::HistogramTester histogram_tester;
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(GURL("chrome:://about"));
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
EXPECT_FALSE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kUnknown);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame", 0);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", 0);
}
TEST_F(LiteVideoDeciderTest, CanApplyNoHintAndHostBlocklisted) {
base::HistogramTester histogram_tester;
SetBlocklistReason(
lite_video::LiteVideoBlocklistReason::kNavigationBlocklisted);
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(GURL("https://NoVideo.com"));
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
EXPECT_FALSE(hint());
EXPECT_EQ(blocklist_reason(),
lite_video::LiteVideoBlocklistReason::kNavigationBlocklisted);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kNavigationBlocklisted, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
}
TEST_F(LiteVideoDeciderTest, CanApplyAllowedButNoHint) {
base::HistogramTester histogram_tester;
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(GURL("https://NoVideo.com"));
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
EXPECT_FALSE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
}
TEST_F(LiteVideoDeciderTest, CanApplyLiteVideo) {
base::HistogramTester histogram_tester;
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
ASSERT_TRUE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(seeded_hint.target_downlink_bandwidth_kbps(),
hint()->target_downlink_bandwidth_kbps());
EXPECT_EQ(seeded_hint.target_downlink_rtt_latency(),
hint()->target_downlink_rtt_latency());
EXPECT_EQ(seeded_hint.kilobytes_to_buffer_before_throttle(),
hint()->kilobytes_to_buffer_before_throttle());
EXPECT_EQ(seeded_hint.max_throttling_delay(), hint()->max_throttling_delay());
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
}
TEST_F(LiteVideoDeciderTest, LiteVideoDisabled) {
DisableLiteVideo();
base::HistogramTester histogram_tester;
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
EXPECT_FALSE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kUnknown);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame", 0);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", 0);
}
TEST_F(LiteVideoDeciderTest, LiteVideoCanApplyOnSubframeNavigation) {
base::HistogramTester histogram_tester;
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
CanApplyOnSubframeNavigation(GURL("https://mainframe.com"), url);
ASSERT_TRUE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(seeded_hint.target_downlink_bandwidth_kbps(),
hint()->target_downlink_bandwidth_kbps());
EXPECT_EQ(seeded_hint.target_downlink_rtt_latency(),
hint()->target_downlink_rtt_latency());
EXPECT_EQ(seeded_hint.kilobytes_to_buffer_before_throttle(),
hint()->kilobytes_to_buffer_before_throttle());
EXPECT_EQ(seeded_hint.max_throttling_delay(), hint()->max_throttling_delay());
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
}
TEST_F(LiteVideoDeciderTest, CanApplyOnReload) {
base::HistogramTester histogram_tester;
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_RELOAD);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
EXPECT_FALSE(hint());
EXPECT_EQ(blocklist_reason(),
lite_video::LiteVideoBlocklistReason::kNavigationReload);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kNavigationReload, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
}
TEST_F(LiteVideoDeciderTest, CanApplyOnForwardBackNavigation) {
base::HistogramTester histogram_tester;
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_FORWARD_BACK);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
EXPECT_FALSE(hint());
EXPECT_EQ(blocklist_reason(),
lite_video::LiteVideoBlocklistReason::kNavigationForwardBack);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kNavigationForwardBack, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
}
TEST_F(LiteVideoDeciderTest, SetDefaultDownlinkBandwidthOverride) {
base::HistogramTester histogram_tester;
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
lite_video::switches::kLiteVideoDefaultDownlinkBandwidthKbps, "200");
base::CommandLine::ForCurrentProcess()->AppendSwitch(
lite_video::switches::kLiteVideoForceOverrideDecision);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
ASSERT_TRUE(hint());
EXPECT_EQ(200, hint()->target_downlink_bandwidth_kbps());
}
TEST_F(LiteVideoDeciderTest, OptimizationGuide_CanApplyLiteVideo) {
base::HistogramTester histogram_tester;
UseOptimizationGuideDecider();
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/true);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
ASSERT_TRUE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(seeded_hint.target_downlink_bandwidth_kbps(),
hint()->target_downlink_bandwidth_kbps());
EXPECT_EQ(seeded_hint.target_downlink_rtt_latency(),
hint()->target_downlink_rtt_latency());
EXPECT_EQ(seeded_hint.kilobytes_to_buffer_before_throttle(),
hint()->kilobytes_to_buffer_before_throttle());
EXPECT_EQ(seeded_hint.max_throttling_delay(), hint()->max_throttling_delay());
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
}
TEST_F(LiteVideoDeciderTest, OptimizationGuide_NoMetadata_CanApplyLiteVideo) {
base::HistogramTester histogram_tester;
UseOptimizationGuideDecider();
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
SeedLiteVideoHintCache(url, /*hint=*/base::nullopt, /*use_opt_guide=*/true);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
ASSERT_TRUE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(lite_video::switches::GetDefaultDownlinkBandwidthKbps(),
hint()->target_downlink_bandwidth_kbps());
EXPECT_EQ(lite_video::features::LiteVideoTargetDownlinkRTTLatency(),
hint()->target_downlink_rtt_latency());
EXPECT_EQ(lite_video::features::LiteVideoKilobytesToBufferBeforeThrottle(),
hint()->kilobytes_to_buffer_before_throttle());
EXPECT_EQ(lite_video::features::LiteVideoMaxThrottlingDelay(),
hint()->max_throttling_delay());
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
}
TEST_F(LiteVideoDeciderTest, OptimizationGuide_CanApplyOnSubframeNavigation) {
base::HistogramTester histogram_tester;
UseOptimizationGuideDecider();
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
GURL mainframe_url("https://mainframe.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(mainframe_url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(mainframe_url, seeded_hint, /*use_opt_guide=*/true);
// Force a check on the mainframe, otherwise no hint will be set for the
// subframe.
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
CanApplyOnSubframeNavigation(mainframe_url, url);
RunUntilIdle();
ASSERT_TRUE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(opt_guide_decision(),
optimization_guide::OptimizationGuideDecision::kTrue);
EXPECT_EQ(seeded_hint.target_downlink_bandwidth_kbps(),
hint()->target_downlink_bandwidth_kbps());
EXPECT_EQ(seeded_hint.target_downlink_rtt_latency(),
hint()->target_downlink_rtt_latency());
EXPECT_EQ(seeded_hint.kilobytes_to_buffer_before_throttle(),
hint()->kilobytes_to_buffer_before_throttle());
EXPECT_EQ(seeded_hint.max_throttling_delay(), hint()->max_throttling_delay());
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame", 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 2);
histogram_tester.ExpectUniqueSample(
"LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
}
TEST_F(LiteVideoDeciderTest,
OptimizationGuide_CanApplyOnSubframeNavigation_Unknown) {
base::HistogramTester histogram_tester;
UseOptimizationGuideDecider();
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
GURL mainframe_url("https://mainframe.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(mainframe_url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
SeedLiteVideoHintCache(mainframe_url, base::nullopt, /*use_opt_guide=*/true);
CanApplyOnSubframeNavigation(mainframe_url, url);
RunUntilIdle();
EXPECT_FALSE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(opt_guide_decision(),
optimization_guide::OptimizationGuideDecision::kUnknown);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 0);
}
TEST_F(LiteVideoDeciderTest,
OptimizationGuide_CanApplyOnSubframeNavigation_MainframeFalse) {
base::HistogramTester histogram_tester;
UseOptimizationGuideDecider();
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL subframe_url("https://LiteVideo.com");
GURL mainframe_url("https://mainframe.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(mainframe_url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
SeedLiteVideoHintCache(subframe_url, base::nullopt, /*use_opt_guide=*/true);
// Force a check on the mainframe, otherwise no hint will be set for the
// subframe.
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
ASSERT_FALSE(hint());
EXPECT_EQ(opt_guide_decision(),
optimization_guide::OptimizationGuideDecision::kFalse);
CanApplyOnSubframeNavigation(mainframe_url, subframe_url);
RunUntilIdle();
ASSERT_FALSE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(opt_guide_decision(),
optimization_guide::OptimizationGuideDecision::kFalse);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 2);
histogram_tester.ExpectUniqueSample(
"LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
}
TEST_F(LiteVideoDeciderTest, OptimizationGuide_HostOnPermanentBlocklist) {
base::HistogramTester histogram_tester;
UseOptimizationGuideDecider();
SeedPermanentHostBlocklist({"mainframe.com"});
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL mainframe_url("https://mainframe.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(mainframe_url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
SeedLiteVideoHintCache(mainframe_url, base::nullopt, /*use_opt_guide=*/true);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
ASSERT_FALSE(hint());
EXPECT_EQ(blocklist_reason(),
lite_video::LiteVideoBlocklistReason::kHostPermanentlyBlocklisted);
EXPECT_EQ(opt_guide_decision(),
optimization_guide::OptimizationGuideDecision::kFalse);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kHostPermanentlyBlocklisted, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
}
TEST_F(LiteVideoDeciderTest, OptimizationGuide_PermanentBlocklist_HostAllowed) {
base::HistogramTester histogram_tester;
UseOptimizationGuideDecider();
SeedPermanentHostBlocklist({"otherhost.com"});
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL mainframe_url("https://mainframe.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(mainframe_url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
SeedLiteVideoHintCache(mainframe_url, base::nullopt, /*use_opt_guide=*/true);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
ASSERT_TRUE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
EXPECT_EQ(opt_guide_decision(),
optimization_guide::OptimizationGuideDecision::kTrue);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
}
TEST_F(LiteVideoDeciderTest, HostOnPermanentBlocklist) {
base::HistogramTester histogram_tester;
SeedPermanentHostBlocklist({"mainframe.com"});
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL mainframe_url("https://mainframe.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(mainframe_url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
SeedLiteVideoHintCache(mainframe_url, base::nullopt, /*use_opt_guide=*/true);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
RunUntilIdle();
ASSERT_FALSE(hint());
EXPECT_EQ(blocklist_reason(),
lite_video::LiteVideoBlocklistReason::kHostPermanentlyBlocklisted);
EXPECT_EQ(opt_guide_decision(),
optimization_guide::OptimizationGuideDecision::kFalse);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kHostPermanentlyBlocklisted, 1);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
}
class LiteVideoDeciderAllowOnForwardBackTest : public LiteVideoDeciderTest {
public:
LiteVideoDeciderAllowOnForwardBackTest()
: LiteVideoDeciderTest(/*allow_on_forward_back=*/true) {}
};
TEST_F(LiteVideoDeciderAllowOnForwardBackTest,
CanApplyOnForwardBackNavigation) {
base::HistogramTester histogram_tester;
SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
GURL url("https://LiteVideo.com");
content::MockNavigationHandle navigation_handle(web_contents());
navigation_handle.set_url(url);
navigation_handle.set_page_transition(ui::PAGE_TRANSITION_FORWARD_BACK);
lite_video::LiteVideoHint seeded_hint(
/*target_downlink_bandwidth_kbps=*/123,
/*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
/*kilobytes_to_buffer_before_throttle=*/500,
/*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
lite_video_decider()->CanApplyLiteVideo(
&navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
base::Unretained(this)));
EXPECT_TRUE(hint());
EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
lite_video::LiteVideoBlocklistReason::kAllowed, 1);
histogram_tester.ExpectTotalCount(
"LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
histogram_tester.ExpectUniqueSample(
"LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
}