blob: 5cea5ad9db3387a24e9db3c23fee329c02f7d9f8 [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/previews/previews_lite_page_decider.h"
#include <memory>
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/simple_test_tick_clock.h"
#include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/previews/core/previews_switches.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kTestUrl[] = "http://www.test.com/";
}
class PreviewsLitePageDeciderTest : public testing::Test {
protected:
PreviewsLitePageDeciderTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
};
TEST_F(PreviewsLitePageDeciderTest, TestHostBypassBlacklist) {
const int kBlacklistDurationDays = 30;
const std::string kHost = "google.com";
const std::string kOtherHost = "chromium.org";
const base::TimeDelta kYesterday = base::TimeDelta::FromDays(-1);
const base::TimeDelta kOneDay = base::TimeDelta::FromDays(1);
std::unique_ptr<PreviewsLitePageDecider> decider =
std::make_unique<PreviewsLitePageDecider>(nullptr);
// Simple happy case.
decider->BlacklistBypassedHost(kHost, kOneDay);
EXPECT_TRUE(decider->HostBlacklistedFromBypass(kHost));
decider->ClearStateForTesting();
// Old entries are deleted.
decider->BlacklistBypassedHost(kHost, kYesterday);
EXPECT_FALSE(decider->HostBlacklistedFromBypass(kHost));
decider->ClearStateForTesting();
// Oldest entry is thrown out.
decider->BlacklistBypassedHost(kHost, kOneDay);
EXPECT_TRUE(decider->HostBlacklistedFromBypass(kHost));
for (int i = 1; i <= kBlacklistDurationDays; i++) {
decider->BlacklistBypassedHost(kHost + base::NumberToString(i),
kOneDay + base::TimeDelta::FromSeconds(i));
}
EXPECT_FALSE(decider->HostBlacklistedFromBypass(kHost));
decider->ClearStateForTesting();
// Oldest entry is not thrown out if there was a stale entry to remove.
decider->BlacklistBypassedHost(kHost, kOneDay);
EXPECT_TRUE(decider->HostBlacklistedFromBypass(kHost));
for (int i = 1; i <= kBlacklistDurationDays - 1; i++) {
decider->BlacklistBypassedHost(kHost + base::NumberToString(i),
kOneDay + base::TimeDelta::FromSeconds(i));
}
decider->BlacklistBypassedHost(kOtherHost, kYesterday);
EXPECT_TRUE(decider->HostBlacklistedFromBypass(kHost));
decider->ClearStateForTesting();
}
TEST_F(PreviewsLitePageDeciderTest, TestClearHostBypassBlacklist) {
const std::string kHost = "1.chromium.org";
std::unique_ptr<PreviewsLitePageDecider> decider =
std::make_unique<PreviewsLitePageDecider>(nullptr);
decider->BlacklistBypassedHost(kHost, base::TimeDelta::FromMinutes(1));
EXPECT_TRUE(decider->HostBlacklistedFromBypass(kHost));
decider->ClearBlacklist();
EXPECT_FALSE(decider->HostBlacklistedFromBypass(kHost));
}
TEST_F(PreviewsLitePageDeciderTest, TestServerUnavailable) {
struct TestCase {
base::TimeDelta set_available_after;
base::TimeDelta check_available_after;
bool want_is_unavailable;
};
const TestCase kTestCases[]{
{
base::TimeDelta::FromMinutes(1), base::TimeDelta::FromMinutes(2),
false,
},
{
base::TimeDelta::FromMinutes(2), base::TimeDelta::FromMinutes(1),
true,
},
};
for (const TestCase& test_case : kTestCases) {
std::unique_ptr<PreviewsLitePageDecider> decider =
std::make_unique<PreviewsLitePageDecider>(nullptr);
std::unique_ptr<base::SimpleTestTickClock> clock =
std::make_unique<base::SimpleTestTickClock>();
decider->SetClockForTesting(clock.get());
decider->SetServerUnavailableFor(test_case.set_available_after);
EXPECT_TRUE(decider->IsServerUnavailable());
clock->Advance(test_case.check_available_after);
EXPECT_EQ(decider->IsServerUnavailable(), test_case.want_is_unavailable);
}
}
TEST_F(PreviewsLitePageDeciderTest, TestSingleBypass) {
const std::string kUrl = "http://test.com";
struct TestCase {
std::string add_url;
base::TimeDelta clock_advance;
std::string check_url;
bool want_check;
};
const TestCase kTestCases[]{
{
kUrl, base::TimeDelta::FromMinutes(1), kUrl, true,
},
{
kUrl, base::TimeDelta::FromMinutes(6), kUrl, false,
},
{
"bad", base::TimeDelta::FromMinutes(1), kUrl, false,
},
{
"bad", base::TimeDelta::FromMinutes(6), kUrl, false,
},
{
kUrl, base::TimeDelta::FromMinutes(1), "bad", false,
},
{
kUrl, base::TimeDelta::FromMinutes(6), "bad", false,
},
};
for (const TestCase& test_case : kTestCases) {
std::unique_ptr<PreviewsLitePageDecider> decider =
std::make_unique<PreviewsLitePageDecider>(nullptr);
std::unique_ptr<base::SimpleTestTickClock> clock =
std::make_unique<base::SimpleTestTickClock>();
decider->SetClockForTesting(clock.get());
decider->AddSingleBypass(test_case.add_url);
clock->Advance(test_case.clock_advance);
EXPECT_EQ(decider->CheckSingleBypass(test_case.check_url),
test_case.want_check);
}
}
class PreviewsLitePageDeciderPrefTest : public ChromeRenderViewHostTestHarness {
protected:
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
drp_test_context_ =
data_reduction_proxy::DataReductionProxyTestContext::Builder()
.WithMockConfig()
.SkipSettingsInitialization()
.Build();
}
void TearDown() override {
drp_test_context_->DestroySettings();
ChromeRenderViewHostTestHarness::TearDown();
}
PreviewsLitePageDecider* GetDeciderWithDRPEnabled(bool enabled) {
drp_test_context_->SetDataReductionProxyEnabled(enabled);
decider_ = std::make_unique<PreviewsLitePageDecider>(
web_contents()->GetBrowserContext());
decider_->SetDRPSettingsForTesting(drp_test_context_->settings());
drp_test_context_->InitSettings();
return decider_.get();
}
private:
std::unique_ptr<data_reduction_proxy::DataReductionProxyTestContext>
drp_test_context_;
std::unique_ptr<PreviewsLitePageDecider> decider_;
};
TEST_F(PreviewsLitePageDeciderPrefTest, TestDRPDisabled) {
PreviewsLitePageDecider* decider = GetDeciderWithDRPEnabled(false);
EXPECT_FALSE(decider->NeedsToNotifyUser());
content::WebContentsTester::For(web_contents())
->NavigateAndCommit(GURL(kTestUrl));
// Should still be false after a navigation
EXPECT_FALSE(decider->NeedsToNotifyUser());
}
TEST_F(PreviewsLitePageDeciderPrefTest, TestDRPEnabled) {
PreviewsLitePageDecider* decider = GetDeciderWithDRPEnabled(true);
EXPECT_TRUE(decider->NeedsToNotifyUser());
content::WebContentsTester::For(web_contents())
->NavigateAndCommit(GURL(kTestUrl));
// Should still be true after a navigation
EXPECT_TRUE(decider->NeedsToNotifyUser());
}
TEST_F(PreviewsLitePageDeciderPrefTest, TestDRPEnabledCmdLineIgnored) {
PreviewsLitePageDecider* decider = GetDeciderWithDRPEnabled(true);
base::CommandLine::ForCurrentProcess()->AppendSwitch(
previews::switches::kDoNotRequireLitePageRedirectInfoBar);
EXPECT_FALSE(decider->NeedsToNotifyUser());
content::WebContentsTester::For(web_contents())
->NavigateAndCommit(GURL(kTestUrl));
// Should still be false after a navigation.
EXPECT_FALSE(decider->NeedsToNotifyUser());
}
TEST_F(PreviewsLitePageDeciderPrefTest, TestDRPEnabledThenNotify) {
PreviewsLitePageDecider* decider = GetDeciderWithDRPEnabled(true);
EXPECT_TRUE(decider->NeedsToNotifyUser());
// Simulate the callback being run.
decider->SetUserHasSeenUINotification();
content::WebContentsTester::For(web_contents())
->NavigateAndCommit(GURL(kTestUrl));
EXPECT_FALSE(decider->NeedsToNotifyUser());
}
class TestPreviewsLitePageDeciderWebContentsObserver
: public content::WebContentsObserver,
public content::WebContentsUserData<
TestPreviewsLitePageDeciderWebContentsObserver> {
public:
explicit TestPreviewsLitePageDeciderWebContentsObserver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {}
~TestPreviewsLitePageDeciderWebContentsObserver() override {}
uint64_t last_navigation_page_id() { return last_navigation_page_id_; }
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override {
auto* chrome_navigation_ui_data =
static_cast<const ChromeNavigationUIData*>(
navigation_handle->GetNavigationUIData());
last_navigation_page_id_ =
chrome_navigation_ui_data->data_reduction_proxy_page_id();
}
private:
friend class content::WebContentsUserData<
TestPreviewsLitePageDeciderWebContentsObserver>;
uint64_t last_navigation_page_id_ = 0;
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
WEB_CONTENTS_USER_DATA_KEY_IMPL(TestPreviewsLitePageDeciderWebContentsObserver)
TEST_F(PreviewsLitePageDeciderPrefTest, TestDRPPageIDIncremented) {
TestPreviewsLitePageDeciderWebContentsObserver::CreateForWebContents(
web_contents());
content::WebContentsTester::For(web_contents())
->NavigateAndCommit(GURL(kTestUrl));
uint64_t last_navigation_page_id =
TestPreviewsLitePageDeciderWebContentsObserver::FromWebContents(
web_contents())
->last_navigation_page_id();
// Tests that the page ID is set for the last navigation, and subsequent
// generates give an increment.
EXPECT_NE(static_cast<uint64_t>(0U), last_navigation_page_id);
EXPECT_EQ(
static_cast<uint64_t>(last_navigation_page_id + 1U),
PreviewsLitePageDecider::GeneratePageIdForWebContents(web_contents()));
}