blob: 58037c90a333cc6c143745fb1a6c68caff74ba70 [file] [log] [blame]
// Copyright (c) 2012 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 <stddef.h>
#include <stdint.h>
#include <map>
#include <utility>
#include "base/command_line.h"
#include "base/format_macros.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_param_associator.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "chrome/browser/net/prediction_options.h"
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/prerender/prerender_handle.h"
#include "chrome/browser/prerender/prerender_link_manager.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/prerender/prerender_origin.h"
#include "chrome/browser/prerender/prerender_test_utils.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/prerender_types.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/test/test_browser_thread.h"
#include "net/base/network_change_notifier.h"
#include "net/http/http_cache.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
using content::BrowserThread;
using content::Referrer;
namespace prerender {
class UnitTestPrerenderManager;
namespace {
class DummyPrerenderContents : public PrerenderContents {
public:
DummyPrerenderContents(UnitTestPrerenderManager* test_prerender_manager,
const GURL& url,
Origin origin,
FinalStatus expected_final_status);
~DummyPrerenderContents() override;
void StartPrerendering(
const gfx::Rect& bounds,
content::SessionStorageNamespace* session_storage_namespace) override;
bool GetChildId(int* child_id) const override {
// Having a default child_id of -1 forces pending prerenders not to fail
// on session storage and cross domain checking.
*child_id = -1;
return true;
}
bool GetRouteId(int* route_id) const override {
*route_id = route_id_;
return true;
}
FinalStatus expected_final_status() const { return expected_final_status_; }
bool prerendering_has_been_cancelled() const {
return PrerenderContents::prerendering_has_been_cancelled();
}
private:
static int g_next_route_id_;
int route_id_;
UnitTestPrerenderManager* test_prerender_manager_;
FinalStatus expected_final_status_;
};
class TestNetworkBytesChangedObserver
: public prerender::PrerenderHandle::Observer {
public:
TestNetworkBytesChangedObserver() : network_bytes_changed_(false) {}
// prerender::PrerenderHandle::Observer
void OnPrerenderStart(PrerenderHandle* prerender_handle) override {}
void OnPrerenderStopLoading(PrerenderHandle* prerender_handle) override {}
void OnPrerenderDomContentLoaded(PrerenderHandle* prerender_handle) override {
}
void OnPrerenderStop(PrerenderHandle* prerender_handle) override {}
void OnPrerenderNetworkBytesChanged(
PrerenderHandle* prerender_handle) override {
network_bytes_changed_ = true;
}
bool network_bytes_changed() const { return network_bytes_changed_; }
private:
bool network_bytes_changed_;
DISALLOW_COPY_AND_ASSIGN(TestNetworkBytesChangedObserver);
};
int DummyPrerenderContents::g_next_route_id_ = 0;
const gfx::Size kSize(640, 480);
const uint32_t kDefaultRelTypes = PrerenderRelTypePrerender;
base::SimpleTestTickClock* OverridePrerenderManagerTimeTicks(
PrerenderManager* prerender_manager) {
auto tick_clock = base::MakeUnique<base::SimpleTestTickClock>();
base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
prerender_manager->SetTickClockForTesting(std::move(tick_clock));
return tick_clock_ptr;
}
bool OverridePrerenderManagerTime(const char* utc_time,
PrerenderManager* prerender_manager) {
auto test_clock = base::MakeUnique<base::SimpleTestClock>();
base::Time test_time;
if (!base::Time::FromUTCString(utc_time, &test_time))
return false;
test_clock->SetNow(test_time);
prerender_manager->SetClockForTesting(std::move(test_clock));
return true;
}
} // namespace
class UnitTestPrerenderManager : public PrerenderManager {
public:
using PrerenderManager::kMinTimeBetweenPrerendersMs;
using PrerenderManager::kNavigationRecordWindowMs;
explicit UnitTestPrerenderManager(Profile* profile)
: PrerenderManager(profile) {
set_rate_limit_enabled(false);
}
~UnitTestPrerenderManager() override {}
// From KeyedService, via PrererenderManager:
void Shutdown() override {
if (next_prerender_contents())
next_prerender_contents_->Destroy(FINAL_STATUS_MANAGER_SHUTDOWN);
PrerenderManager::Shutdown();
}
// From PrerenderManager:
void MoveEntryToPendingDelete(PrerenderContents* entry,
FinalStatus final_status) override {
if (entry == next_prerender_contents_.get())
return;
PrerenderManager::MoveEntryToPendingDelete(entry, final_status);
}
PrerenderContents* FindEntry(const GURL& url) {
DeleteOldEntries();
to_delete_prerenders_.clear();
PrerenderData* data = FindPrerenderData(url, nullptr);
return data ? data->contents() : nullptr;
}
std::unique_ptr<PrerenderContents> FindAndUseEntry(const GURL& url) {
PrerenderData* prerender_data = FindPrerenderData(url, nullptr);
if (!prerender_data)
return nullptr;
PrerenderDataVector::iterator to_erase =
FindIteratorForPrerenderContents(prerender_data->contents());
CHECK(to_erase != active_prerenders_.end());
std::unique_ptr<PrerenderContents> prerender_contents =
prerender_data->ReleaseContents();
active_prerenders_.erase(to_erase);
prerender_contents->PrepareForUse();
return prerender_contents;
}
DummyPrerenderContents* CreateNextPrerenderContents(
const GURL& url,
FinalStatus expected_final_status) {
return SetNextPrerenderContents(base::MakeUnique<DummyPrerenderContents>(
this, url, ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN,
expected_final_status));
}
DummyPrerenderContents* CreateNextPrerenderContents(
const GURL& url,
Origin origin,
FinalStatus expected_final_status) {
return SetNextPrerenderContents(base::MakeUnique<DummyPrerenderContents>(
this, url, origin, expected_final_status));
}
DummyPrerenderContents* CreateNextPrerenderContents(
const GURL& url,
const std::vector<GURL>& alias_urls,
FinalStatus expected_final_status) {
auto prerender_contents = base::MakeUnique<DummyPrerenderContents>(
this, url, ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN,
expected_final_status);
for (const GURL& alias : alias_urls)
EXPECT_TRUE(prerender_contents->AddAliasURL(alias));
return SetNextPrerenderContents(std::move(prerender_contents));
}
void set_rate_limit_enabled(bool enabled) {
mutable_config().rate_limit_enabled = enabled;
}
PrerenderContents* next_prerender_contents() {
return next_prerender_contents_.get();
}
PrerenderContents* GetPrerenderContentsForRoute(int child_id,
int route_id) const override {
// Overridden for the PrerenderLinkManager's pending prerender logic.
PrerenderContentsMap::const_iterator it =
prerender_contents_map_.find(std::make_pair(child_id, route_id));
return it != prerender_contents_map_.end() ? it->second : nullptr;
}
void DummyPrerenderContentsStarted(int child_id,
int route_id,
PrerenderContents* prerender_contents) {
prerender_contents_map_[std::make_pair(child_id, route_id)] =
prerender_contents;
}
void DummyPrerenderContentsDestroyed(int child_id,
int route_id) {
prerender_contents_map_.erase(std::make_pair(child_id, route_id));
}
void SetIsLowEndDevice(bool is_low_end_device) {
is_low_end_device_ = is_low_end_device;
}
private:
bool IsLowEndDevice() const override { return is_low_end_device_; }
DummyPrerenderContents* SetNextPrerenderContents(
std::unique_ptr<DummyPrerenderContents> prerender_contents) {
CHECK(!next_prerender_contents_);
DummyPrerenderContents* contents_ptr = prerender_contents.get();
next_prerender_contents_ = std::move(prerender_contents);
return contents_ptr;
}
std::unique_ptr<PrerenderContents> CreatePrerenderContents(
const GURL& url,
const Referrer& referrer,
Origin origin) override {
CHECK(next_prerender_contents_);
EXPECT_EQ(url, next_prerender_contents_->prerender_url());
EXPECT_EQ(origin, next_prerender_contents_->origin());
return std::move(next_prerender_contents_);
}
// Maintain a map from route pairs to PrerenderContents for
// GetPrerenderContentsForRoute.
using PrerenderContentsMap =
std::map<std::pair<int, int>, PrerenderContents*>;
PrerenderContentsMap prerender_contents_map_;
std::unique_ptr<PrerenderContents> next_prerender_contents_;
bool is_low_end_device_;
};
class MockNetworkChangeNotifier4G : public net::NetworkChangeNotifier {
public:
ConnectionType GetCurrentConnectionType() const override {
return NetworkChangeNotifier::CONNECTION_4G;
}
};
DummyPrerenderContents::DummyPrerenderContents(
UnitTestPrerenderManager* test_prerender_manager,
const GURL& url,
Origin origin,
FinalStatus expected_final_status)
: PrerenderContents(test_prerender_manager,
nullptr,
url,
Referrer(),
origin),
route_id_(g_next_route_id_++),
test_prerender_manager_(test_prerender_manager),
expected_final_status_(expected_final_status) {}
DummyPrerenderContents::~DummyPrerenderContents() {
EXPECT_EQ(expected_final_status_, final_status());
test_prerender_manager_->DummyPrerenderContentsDestroyed(-1, route_id_);
}
void DummyPrerenderContents::StartPrerendering(
const gfx::Rect& bounds,
content::SessionStorageNamespace* session_storage_namespace) {
load_start_time_ = test_prerender_manager_->GetCurrentTimeTicks();
prerendering_has_started_ = true;
test_prerender_manager_->DummyPrerenderContentsStarted(-1, route_id_, this);
NotifyPrerenderStart();
}
class PrerenderTest : public testing::Test {
public:
static const int kDefaultChildId = -1;
static const int kDefaultRenderViewRouteId = -1;
PrerenderTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
prerender_manager_(new UnitTestPrerenderManager(&profile_)),
prerender_link_manager_(
new PrerenderLinkManager(prerender_manager_.get())),
last_prerender_id_(0),
field_trial_list_(nullptr) {
prerender_manager()->SetIsLowEndDevice(false);
// Enable omnibox prerendering.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kPrerenderFromOmnibox,
switches::kPrerenderFromOmniboxSwitchValueEnabled);
}
~PrerenderTest() override {
prerender_link_manager_->OnChannelClosing(kDefaultChildId);
prerender_link_manager_->Shutdown();
prerender_manager_->Shutdown();
}
void TearDown() override {
base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
}
UnitTestPrerenderManager* prerender_manager() {
return prerender_manager_.get();
}
PrerenderLinkManager* prerender_link_manager() {
return prerender_link_manager_.get();
}
Profile* profile() { return &profile_; }
void SetConcurrency(size_t concurrency) {
prerender_manager()->mutable_config().max_link_concurrency_per_launcher =
concurrency;
prerender_manager()->mutable_config().max_link_concurrency =
std::max(prerender_manager()->mutable_config().max_link_concurrency,
concurrency);
}
bool IsEmptyPrerenderLinkManager() const {
return prerender_link_manager_->IsEmpty();
}
int last_prerender_id() const {
return last_prerender_id_;
}
int GetNextPrerenderID() {
return ++last_prerender_id_;
}
bool LauncherHasRunningPrerender(int child_id, int prerender_id) {
PrerenderLinkManager::LinkPrerender* prerender =
prerender_link_manager()->FindByLauncherChildIdAndPrerenderId(
child_id, prerender_id);
return prerender && prerender->handle;
}
bool LauncherHasScheduledPrerender(int child_id, int prerender_id) {
PrerenderLinkManager::LinkPrerender* prerender =
prerender_link_manager()->FindByLauncherChildIdAndPrerenderId(
child_id, prerender_id);
return prerender != nullptr;
}
// Shorthand to add a simple prerender with a reasonable source. Returns
// true iff the prerender has been added to the PrerenderManager by the
// PrerenderLinkManager and the PrerenderManager returned a handle.
bool AddSimplePrerender(const GURL& url) {
prerender_link_manager()->OnAddPrerender(
kDefaultChildId, GetNextPrerenderID(), url, kDefaultRelTypes,
content::Referrer(), kSize, kDefaultRenderViewRouteId);
return LauncherHasRunningPrerender(kDefaultChildId, last_prerender_id());
}
void DisablePrerender() {
profile_.GetPrefs()->SetInteger(
prefs::kNetworkPredictionOptions,
chrome_browser_net::NETWORK_PREDICTION_NEVER);
}
void EnablePrerender() {
profile_.GetPrefs()->SetInteger(
prefs::kNetworkPredictionOptions,
chrome_browser_net::NETWORK_PREDICTION_ALWAYS);
}
void SetUpFieldTrial(const std::map<std::string, std::string>& params,
base::test::ScopedFeatureList* scoped_feature_list) {
// Set up the prerender mode through a field trial.
std::string kTrialName = "name";
std::string kTrialGroup = "group";
base::FieldTrial* trial =
base::FieldTrialList::CreateFieldTrial(kTrialName, kTrialGroup);
ASSERT_TRUE(
base::FieldTrialParamAssociator::GetInstance()
->AssociateFieldTrialParams(kTrialName, kTrialGroup, params));
std::unique_ptr<base::FeatureList> feature_list =
base::MakeUnique<base::FeatureList>();
feature_list->RegisterFieldTrialOverride(
kNoStatePrefetchFeature.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
scoped_feature_list->InitWithFeatureList(std::move(feature_list));
ASSERT_EQ(base::FeatureList::GetFieldTrial(kNoStatePrefetchFeature), trial);
std::map<std::string, std::string> actual_params;
ASSERT_TRUE(base::GetFieldTrialParamsByFeature(kNoStatePrefetchFeature,
&actual_params));
ASSERT_EQ(params, actual_params);
}
const base::HistogramTester& histogram_tester() { return histogram_tester_; }
private:
// Needed to pass PrerenderManager's DCHECKs.
base::MessageLoop message_loop_;
content::TestBrowserThread ui_thread_;
TestingProfile profile_;
std::unique_ptr<UnitTestPrerenderManager> prerender_manager_;
std::unique_ptr<PrerenderLinkManager> prerender_link_manager_;
int last_prerender_id_;
base::HistogramTester histogram_tester_;
// An instance of base::FieldTrialList is necessary in order to initialize
// global state.
base::FieldTrialList field_trial_list_;
};
TEST_F(PrerenderTest, PrerenderRespectsDisableFlag) {
test_utils::RestorePrerenderMode restore_prerender_mode;
ASSERT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
ASSERT_EQ(PrerenderManager::PRERENDER_MODE_ENABLED,
PrerenderManager::GetMode(ORIGIN_NONE));
{
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(kNoStatePrefetchFeature);
prerender::ConfigurePrerender();
EXPECT_FALSE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_NONE));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_OMNIBOX));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_INSTANT));
}
}
TEST_F(PrerenderTest, PrerenderRespectsFieldTrialParameters) {
test_utils::RestorePrerenderMode restore_prerender_mode;
base::test::ScopedFeatureList scoped_feature_list;
SetUpFieldTrial({{kNoStatePrefetchFeatureModeParameterName,
kNoStatePrefetchFeatureModeParameterSimpleLoad}},
&scoped_feature_list);
prerender::ConfigurePrerender();
EXPECT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT,
PrerenderManager::GetMode(ORIGIN_NONE));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT,
PrerenderManager::GetMode(ORIGIN_OMNIBOX));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT,
PrerenderManager::GetMode(ORIGIN_INSTANT));
}
TEST_F(PrerenderTest, PrerenderRespectsFieldTrialParametersPrefetchInstant) {
test_utils::RestorePrerenderMode restore_prerender_mode;
base::test::ScopedFeatureList scoped_feature_list;
SetUpFieldTrial({{kNoStatePrefetchFeatureModeParameterName,
kNoStatePrefetchFeatureModeParameterSimpleLoad},
{kNoStatePrefetchFeatureInstantModeParameterName,
kNoStatePrefetchFeatureModeParameterPrefetch}},
&scoped_feature_list);
prerender::ConfigurePrerender();
EXPECT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT,
PrerenderManager::GetMode(ORIGIN_NONE));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT,
PrerenderManager::GetMode(ORIGIN_OMNIBOX));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH,
PrerenderManager::GetMode(ORIGIN_INSTANT));
}
TEST_F(PrerenderTest, PrerenderRespectsFieldTrialParametersPrefetchOmnibox) {
test_utils::RestorePrerenderMode restore_prerender_mode;
base::test::ScopedFeatureList scoped_feature_list;
SetUpFieldTrial({{kNoStatePrefetchFeatureModeParameterName,
kNoStatePrefetchFeatureModeParameterSimpleLoad},
{kNoStatePrefetchFeatureOmniboxModeParameterName,
kNoStatePrefetchFeatureModeParameterPrefetch}},
&scoped_feature_list);
prerender::ConfigurePrerender();
EXPECT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT,
PrerenderManager::GetMode(ORIGIN_NONE));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH,
PrerenderManager::GetMode(ORIGIN_OMNIBOX));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT,
PrerenderManager::GetMode(ORIGIN_INSTANT));
}
TEST_F(PrerenderTest, PrerenderRespectsFieldTrialParametersNoneButInstant) {
test_utils::RestorePrerenderMode restore_prerender_mode;
base::test::ScopedFeatureList scoped_feature_list;
SetUpFieldTrial({{kNoStatePrefetchFeatureModeParameterName,
kNoStatePrefetchFeatureModeParameterDisabled},
{kNoStatePrefetchFeatureInstantModeParameterName,
kNoStatePrefetchFeatureModeParameterPrerender},
{kNoStatePrefetchFeatureOmniboxModeParameterName,
kNoStatePrefetchFeatureModeParameterDisabled}},
&scoped_feature_list);
prerender::ConfigurePrerender();
EXPECT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_NONE));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_OMNIBOX));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_ENABLED,
PrerenderManager::GetMode(ORIGIN_INSTANT));
}
TEST_F(PrerenderTest, PrerenderRespectsFieldTrialParametersNoneAtAll) {
test_utils::RestorePrerenderMode restore_prerender_mode;
base::test::ScopedFeatureList scoped_feature_list;
SetUpFieldTrial({{kNoStatePrefetchFeatureModeParameterName,
kNoStatePrefetchFeatureModeParameterDisabled},
{kNoStatePrefetchFeatureOmniboxModeParameterName,
kNoStatePrefetchFeatureModeParameterDisabled},
{kNoStatePrefetchFeatureInstantModeParameterName,
kNoStatePrefetchFeatureModeParameterDisabled}},
&scoped_feature_list);
prerender::ConfigurePrerender();
EXPECT_FALSE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_NONE));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_OMNIBOX));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_INSTANT));
}
TEST_F(PrerenderTest, PrerenderRespectsFieldTrialParametersDefaultNone) {
test_utils::RestorePrerenderMode restore_prerender_mode;
base::test::ScopedFeatureList scoped_feature_list;
SetUpFieldTrial({{kNoStatePrefetchFeatureModeParameterName,
kNoStatePrefetchFeatureModeParameterDisabled}},
&scoped_feature_list);
prerender::ConfigurePrerender();
EXPECT_FALSE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_NONE));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_OMNIBOX));
EXPECT_EQ(PrerenderManager::PRERENDER_MODE_DISABLED,
PrerenderManager::GetMode(ORIGIN_INSTANT));
}
TEST_F(PrerenderTest, PrerenderRespectsThirdPartyCookiesPref) {
GURL url("http://www.google.com/");
test_utils::RestorePrerenderMode restore_prerender_mode;
ASSERT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
profile()->GetPrefs()->SetBoolean(prefs::kBlockThirdPartyCookies, true);
EXPECT_FALSE(AddSimplePrerender(url));
histogram_tester().ExpectUniqueSample(
"Prerender.FinalStatus", FINAL_STATUS_BLOCK_THIRD_PARTY_COOKIES, 1);
}
TEST_F(PrerenderTest, OfflinePrerenderIgnoresThirdPartyCookiesPref) {
GURL url("http://www.google.com/");
test_utils::RestorePrerenderMode restore_prerender_mode;
ASSERT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
profile()->GetPrefs()->SetBoolean(prefs::kBlockThirdPartyCookies, true);
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle(
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize));
EXPECT_TRUE(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_EQ(prerender_contents, prerender_handle->contents());
EXPECT_EQ(ORIGIN_OFFLINE, prerender_handle->contents()->origin());
}
// Checks that the prerender mode affects "normal" origins such as omnibox, but
// not offline origin.
TEST_F(PrerenderTest, PrerenderModePerOrigin) {
test_utils::RestorePrerenderMode restore_prerender_mode;
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
prerender_manager()->SetOmniboxMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
EXPECT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_FALSE(PrerenderManager::IsNoStatePrefetch(ORIGIN_OFFLINE));
EXPECT_TRUE(PrerenderManager::IsNoStatePrefetch(ORIGIN_OMNIBOX));
EXPECT_FALSE(PrerenderManager::IsNoStatePrefetch(ORIGIN_INSTANT));
EXPECT_FALSE(PrerenderManager::IsSimpleLoadExperiment(ORIGIN_OFFLINE));
EXPECT_FALSE(PrerenderManager::IsSimpleLoadExperiment(ORIGIN_OMNIBOX));
prerender_manager()->SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
EXPECT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_FALSE(PrerenderManager::IsNoStatePrefetch(ORIGIN_OFFLINE));
EXPECT_TRUE(PrerenderManager::IsNoStatePrefetch(ORIGIN_OMNIBOX));
EXPECT_FALSE(PrerenderManager::IsSimpleLoadExperiment(ORIGIN_OFFLINE));
EXPECT_FALSE(PrerenderManager::IsSimpleLoadExperiment(ORIGIN_OMNIBOX));
prerender_manager()->SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
prerender_manager()->SetInstantMode(
PrerenderManager::PRERENDER_MODE_DISABLED);
prerender_manager()->SetOmniboxMode(
PrerenderManager::PRERENDER_MODE_DISABLED);
EXPECT_FALSE(PrerenderManager::IsAnyPrerenderingPossible());
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT);
prerender_manager()->SetInstantMode(
PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT);
EXPECT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
EXPECT_FALSE(PrerenderManager::IsNoStatePrefetch(ORIGIN_OFFLINE));
EXPECT_FALSE(PrerenderManager::IsNoStatePrefetch(ORIGIN_OMNIBOX));
EXPECT_FALSE(PrerenderManager::IsSimpleLoadExperiment(ORIGIN_OFFLINE));
EXPECT_FALSE(PrerenderManager::IsSimpleLoadExperiment(ORIGIN_OMNIBOX));
EXPECT_TRUE(PrerenderManager::IsSimpleLoadExperiment(ORIGIN_INSTANT));
}
TEST_F(PrerenderTest, PrerenderRespectsPrerenderModeNoStatePrefetch) {
GURL url("http://www.google.com/");
test_utils::RestorePrerenderMode restore_prerender_mode;
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_MANAGER_SHUTDOWN);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_EQ(PREFETCH_ONLY, prerender_contents->prerender_mode());
}
TEST_F(PrerenderTest, PrerenderRespectsPrerenderModeSimpleLoad) {
GURL url("http://www.google.com/");
test_utils::RestorePrerenderMode restore_prerender_mode;
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT);
EXPECT_FALSE(AddSimplePrerender(url));
}
// Checks that a full prerender happens in offline mode, even if no-state
// prefetch is enabled.
TEST_F(PrerenderTest, OfflinePrerenderIgnoresPrerenderMode) {
GURL url("http://www.google.com/");
test_utils::RestorePrerenderMode restore_prerender_mode;
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
ASSERT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle(
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize));
EXPECT_EQ(FULL_PRERENDER, prerender_contents->prerender_mode());
}
TEST_F(PrerenderTest, PrerenderDisabledOnLowEndDevice) {
GURL url("http://www.google.com/");
ASSERT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
prerender_manager()->SetIsLowEndDevice(true);
EXPECT_FALSE(AddSimplePrerender(url));
histogram_tester().ExpectUniqueSample("Prerender.FinalStatus",
FINAL_STATUS_LOW_END_DEVICE, 1);
}
TEST_F(PrerenderTest, OfflinePrerenderPossibleOnLowEndDevice) {
GURL url("http://www.google.com/");
ASSERT_TRUE(PrerenderManager::IsAnyPrerenderingPossible());
prerender_manager()->SetIsLowEndDevice(true);
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle(
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize));
EXPECT_TRUE(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
}
TEST_F(PrerenderTest, FoundTest) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
TEST_F(PrerenderTest, UnfindableOfflinePrerenderTest) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle(
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize));
EXPECT_TRUE(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
ASSERT_FALSE(prerender_manager()->FindAndUseEntry(url));
}
// Make sure that if queue a request, and a second prerender request for the
// same URL comes in, that the second request attaches to the first prerender,
// and we don't use the second prerender contents.
TEST_F(PrerenderTest, DuplicateTest) {
SetConcurrency(2);
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_FALSE(prerender_manager()->next_prerender_contents());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
DummyPrerenderContents* prerender_contents1 =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_MANAGER_SHUTDOWN);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_EQ(prerender_contents1,
prerender_manager()->next_prerender_contents());
EXPECT_FALSE(prerender_contents1->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
// Make sure that if queue a request, and a second prerender request for the
// same URL comes in, that the second request attaches to the first prerender,
// and we don't use the second prerender contents.
// This test is the same as the "DuplicateTest" above, but for NoStatePrefetch.
TEST_F(PrerenderTest, DuplicateTest_NoStatePrefetch) {
test_utils::RestorePrerenderMode restore_prerender_mode;
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
SetConcurrency(2);
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_FALSE(prerender_manager()->next_prerender_contents());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
DummyPrerenderContents* prerender_contents1 =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_MANAGER_SHUTDOWN);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_EQ(prerender_contents1,
prerender_manager()->next_prerender_contents());
EXPECT_FALSE(prerender_contents1->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
// Ensure that we expire a prerendered page after the max. permitted time.
TEST_F(PrerenderTest, ExpireTest) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_FALSE(prerender_manager()->next_prerender_contents());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
tick_clock->Advance(prerender_manager()->config().time_to_live +
TimeDelta::FromSeconds(1));
ASSERT_FALSE(prerender_manager()->FindEntry(url));
}
// Ensure that we don't launch prerenders of bad urls (in this case, a mailto:
// url)
TEST_F(PrerenderTest, BadURLTest) {
GURL url("mailto:test@gmail.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_UNSUPPORTED_SCHEME);
EXPECT_FALSE(AddSimplePrerender(url));
EXPECT_FALSE(prerender_contents->prerendering_has_started());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_FALSE(prerender_manager()->FindEntry(url));
}
// When the user navigates away from a page, the prerenders it launched should
// have their time to expiry shortened from the default time to live.
TEST_F(PrerenderTest, LinkManagerNavigateAwayExpire) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
const TimeDelta time_to_live = TimeDelta::FromSeconds(300);
const TimeDelta abandon_time_to_live = TimeDelta::FromSeconds(20);
const TimeDelta test_advance = TimeDelta::FromSeconds(22);
ASSERT_LT(test_advance, time_to_live);
ASSERT_LT(abandon_time_to_live, test_advance);
prerender_manager()->mutable_config().time_to_live = time_to_live;
prerender_manager()->mutable_config().abandon_time_to_live =
abandon_time_to_live;
GURL url("http://example.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(url,
FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_FALSE(prerender_manager()->next_prerender_contents());
tick_clock->Advance(test_advance);
EXPECT_FALSE(prerender_manager()->FindEntry(url));
}
// But when we navigate away very close to the original expiry of a prerender,
// we shouldn't expect it to be extended.
TEST_F(PrerenderTest, LinkManagerNavigateAwayNearExpiry) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
const TimeDelta time_to_live = TimeDelta::FromSeconds(300);
const TimeDelta abandon_time_to_live = TimeDelta::FromSeconds(20);
// We will expect the prerender to still be alive after advancing the clock
// by first_advance. But, after second_advance, we expect it to have timed
// out, demonstrating that you can't extend a prerender by navigating away
// from its launcher.
const TimeDelta first_advance = TimeDelta::FromSeconds(298);
const TimeDelta second_advance = TimeDelta::FromSeconds(4);
ASSERT_LT(first_advance, time_to_live);
ASSERT_LT(time_to_live - first_advance, abandon_time_to_live);
ASSERT_LT(time_to_live, first_advance + second_advance);
prerender_manager()->mutable_config().time_to_live = time_to_live;
prerender_manager()->mutable_config().abandon_time_to_live =
abandon_time_to_live;
GURL url("http://example2.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(url,
FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
tick_clock->Advance(first_advance);
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_FALSE(prerender_manager()->next_prerender_contents());
tick_clock->Advance(second_advance);
EXPECT_FALSE(prerender_manager()->FindEntry(url));
}
// When the user navigates away from a page, and then launches a new prerender,
// the new prerender should preempt the abandoned prerender even if the
// abandoned prerender hasn't expired.
TEST_F(PrerenderTest, LinkManagerNavigateAwayLaunchAnother) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
const TimeDelta time_to_live = TimeDelta::FromSeconds(300);
const TimeDelta abandon_time_to_live = TimeDelta::FromSeconds(20);
const TimeDelta test_advance = TimeDelta::FromSeconds(5);
ASSERT_LT(test_advance, time_to_live);
ASSERT_GT(abandon_time_to_live, test_advance);
prerender_manager()->mutable_config().time_to_live = time_to_live;
prerender_manager()->mutable_config().abandon_time_to_live =
abandon_time_to_live;
GURL url("http://example.com");
prerender_manager()->CreateNextPrerenderContents(url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
last_prerender_id());
tick_clock->Advance(test_advance);
GURL second_url("http://example2.com");
DummyPrerenderContents* second_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
second_url, FINAL_STATUS_MANAGER_SHUTDOWN);
EXPECT_TRUE(AddSimplePrerender(second_url));
EXPECT_EQ(second_prerender_contents,
prerender_manager()->FindEntry(second_url));
}
// Prefetching the same URL twice during |time_to_live| results in a duplicate
// and is aborted.
TEST_F(PrerenderTest, NoStatePrefetchDuplicate) {
const GURL kUrl("http://www.google.com/");
test_utils::RestorePrerenderMode restore_prerender_mode;
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
prerender_manager()->SetOmniboxMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
// Prefetch the url once.
prerender_manager()->CreateNextPrerenderContents(kUrl, ORIGIN_OMNIBOX,
FINAL_STATUS_CANCELLED);
EXPECT_TRUE(
prerender_manager()->AddPrerenderFromOmnibox(kUrl, nullptr, gfx::Size()));
// Cancel the prerender so that it is not reused.
prerender_manager()->CancelAllPrerenders();
prerender_manager()->CreateNextPrerenderContents(
kUrl, ORIGIN_OMNIBOX, FINAL_STATUS_MANAGER_SHUTDOWN);
// Prefetching again before time_to_live aborts, because it is a duplicate.
tick_clock->Advance(base::TimeDelta::FromSeconds(1));
EXPECT_FALSE(
prerender_manager()->AddPrerenderFromOmnibox(kUrl, nullptr, gfx::Size()));
histogram_tester().ExpectBucketCount("Prerender.FinalStatus",
FINAL_STATUS_DUPLICATE, 1);
// Prefetching after time_to_live succeeds.
tick_clock->Advance(
base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins));
EXPECT_TRUE(
prerender_manager()->AddPrerenderFromOmnibox(kUrl, nullptr, gfx::Size()));
}
// Make sure that if we prerender more requests than we support, that we launch
// them in the order given up until we reach MaxConcurrency, at which point we
// queue them and launch them in the order given. As well, insure that limits
// are enforced for the system as a whole and on a per launcher basis.
TEST_F(PrerenderTest, MaxConcurrencyTest) {
struct TestConcurrency {
size_t max_link_concurrency;
size_t max_link_concurrency_per_launcher;
};
const TestConcurrency concurrencies_to_test[] = {
{prerender_manager()->config().max_link_concurrency,
prerender_manager()->config().max_link_concurrency_per_launcher},
// With the system limit higher than the per launcher limit, the per
// launcher limit should be in effect.
{2, 1},
// With the per launcher limit higher than system limit, the system limit
// should be in effect.
{2, 4},
};
GURL url_to_delay("http://www.google.com/delayme");
for (const TestConcurrency& current_test : concurrencies_to_test) {
prerender_manager()->mutable_config().max_link_concurrency =
current_test.max_link_concurrency;
prerender_manager()->mutable_config().max_link_concurrency_per_launcher =
current_test.max_link_concurrency_per_launcher;
const size_t effective_max_link_concurrency =
std::min(current_test.max_link_concurrency,
current_test.max_link_concurrency_per_launcher);
std::vector<GURL> urls;
std::vector<PrerenderContents*> prerender_contentses;
// Launch prerenders up to the maximum this launcher can support.
for (size_t j = 0; j < effective_max_link_concurrency; ++j) {
urls.push_back(
GURL(base::StringPrintf("http://google.com/use#%" PRIuS, j)));
prerender_contentses.push_back(
prerender_manager()->CreateNextPrerenderContents(urls.back(),
FINAL_STATUS_USED));
EXPECT_TRUE(AddSimplePrerender(urls.back()));
EXPECT_FALSE(prerender_manager()->next_prerender_contents());
EXPECT_TRUE(prerender_contentses.back()->prerendering_has_started());
}
if (current_test.max_link_concurrency > effective_max_link_concurrency) {
// We should be able to launch more prerenders on this system, but not for
// the default launcher.
GURL extra_url("http://google.com/extraurl");
EXPECT_FALSE(AddSimplePrerender(extra_url));
const int prerender_id = last_prerender_id();
EXPECT_TRUE(LauncherHasScheduledPrerender(kDefaultChildId,
prerender_id));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
prerender_id);
EXPECT_FALSE(LauncherHasScheduledPrerender(kDefaultChildId,
prerender_id));
}
DummyPrerenderContents* prerender_contents_to_delay =
prerender_manager()->CreateNextPrerenderContents(url_to_delay,
FINAL_STATUS_USED);
EXPECT_FALSE(AddSimplePrerender(url_to_delay));
EXPECT_FALSE(prerender_contents_to_delay->prerendering_has_started());
EXPECT_TRUE(prerender_manager()->next_prerender_contents());
EXPECT_FALSE(prerender_manager()->FindEntry(url_to_delay));
for (size_t j = 0; j < effective_max_link_concurrency; ++j) {
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(urls[j]);
EXPECT_EQ(prerender_contentses[j], entry.get());
EXPECT_TRUE(prerender_contents_to_delay->prerendering_has_started());
}
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url_to_delay);
EXPECT_EQ(prerender_contents_to_delay, entry.get());
EXPECT_FALSE(prerender_manager()->next_prerender_contents());
}
}
TEST_F(PrerenderTest, AliasURLTest) {
SetConcurrency(7);
GURL url("http://www.google.com/");
GURL alias_url1("http://www.google.com/index.html");
GURL alias_url2("http://google.com/");
GURL not_an_alias_url("http://google.com/index.html");
std::vector<GURL> alias_urls;
alias_urls.push_back(alias_url1);
alias_urls.push_back(alias_url2);
// Test that all of the aliases work, but not_an_alias_url does not.
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, alias_urls, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
ASSERT_FALSE(prerender_manager()->FindEntry(not_an_alias_url));
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(alias_url1);
ASSERT_EQ(prerender_contents, entry.get());
prerender_contents = prerender_manager()->CreateNextPrerenderContents(
url, alias_urls, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
entry = prerender_manager()->FindAndUseEntry(alias_url2);
ASSERT_EQ(prerender_contents, entry.get());
prerender_contents = prerender_manager()->CreateNextPrerenderContents(
url, alias_urls, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
entry = prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
// Test that alias URLs can not be added.
prerender_contents = prerender_manager()->CreateNextPrerenderContents(
url, alias_urls, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(AddSimplePrerender(alias_url1));
EXPECT_TRUE(AddSimplePrerender(alias_url2));
entry = prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
TEST_F(PrerenderTest, PendingPrerenderTest) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
int child_id;
int route_id;
ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
GURL pending_url("http://news.google.com/");
// Schedule a pending prerender launched from the prerender.
DummyPrerenderContents* pending_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
pending_url,
ORIGIN_GWS_PRERENDER,
FINAL_STATUS_USED);
prerender_link_manager()->OnAddPrerender(
child_id, GetNextPrerenderID(), pending_url, kDefaultRelTypes,
Referrer(url, blink::WebReferrerPolicyDefault),
kSize, route_id);
EXPECT_FALSE(LauncherHasRunningPrerender(child_id, last_prerender_id()));
EXPECT_FALSE(pending_prerender_contents->prerendering_has_started());
// Use the referring prerender.
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
// The pending prerender should start now.
EXPECT_TRUE(LauncherHasRunningPrerender(child_id, last_prerender_id()));
EXPECT_TRUE(pending_prerender_contents->prerendering_has_started());
entry = prerender_manager()->FindAndUseEntry(pending_url);
ASSERT_EQ(pending_prerender_contents, entry.get());
}
TEST_F(PrerenderTest, InvalidPendingPrerenderTest) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
int child_id;
int route_id;
ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
// This pending URL has an unsupported scheme, and won't be able
// to start.
GURL pending_url("ftp://news.google.com/");
// Schedule a pending prerender launched from the prerender.
DummyPrerenderContents* pending_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
pending_url,
ORIGIN_GWS_PRERENDER,
FINAL_STATUS_UNSUPPORTED_SCHEME);
prerender_link_manager()->OnAddPrerender(
child_id, GetNextPrerenderID(), pending_url, kDefaultRelTypes,
Referrer(url, blink::WebReferrerPolicyDefault),
kSize, route_id);
EXPECT_FALSE(LauncherHasRunningPrerender(child_id, last_prerender_id()));
EXPECT_FALSE(pending_prerender_contents->prerendering_has_started());
// Use the referring prerender.
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
// The pending prerender still doesn't start.
EXPECT_FALSE(LauncherHasRunningPrerender(child_id, last_prerender_id()));
EXPECT_FALSE(pending_prerender_contents->prerendering_has_started());
}
TEST_F(PrerenderTest, CancelPendingPrerenderTest) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
int child_id;
int route_id;
ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
GURL pending_url("http://news.google.com/");
// Schedule a pending prerender launched from the prerender.
prerender_link_manager()->OnAddPrerender(
child_id, GetNextPrerenderID(), pending_url, kDefaultRelTypes,
Referrer(url, blink::WebReferrerPolicyDefault),
kSize, route_id);
EXPECT_FALSE(LauncherHasRunningPrerender(child_id, last_prerender_id()));
// Cancel the pending prerender.
prerender_link_manager()->OnCancelPrerender(child_id, last_prerender_id());
// Use the referring prerender.
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
// The pending prerender doesn't start.
EXPECT_FALSE(LauncherHasRunningPrerender(child_id, last_prerender_id()));
}
// Tests that prerendering is cancelled when the source render view does not
// exist. On failure, the DCHECK in CreatePrerenderContents() above should be
// triggered.
TEST_F(PrerenderTest, SourceRenderViewClosed) {
GURL url("http://www.google.com/");
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_MANAGER_SHUTDOWN);
prerender_link_manager()->OnAddPrerender(
100, GetNextPrerenderID(), url, kDefaultRelTypes, Referrer(), kSize, 200);
EXPECT_FALSE(LauncherHasRunningPrerender(100, last_prerender_id()));
}
// Tests that prerendering doesn't launch rel=next prerenders without the field
// trial.
TEST_F(PrerenderTest, NoRelNextByDefault) {
GURL url("http://www.google.com/");
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_MANAGER_SHUTDOWN);
prerender_link_manager()->OnAddPrerender(
kDefaultChildId, GetNextPrerenderID(), url, PrerenderRelTypeNext,
Referrer(), kSize, kDefaultRenderViewRouteId);
EXPECT_FALSE(prerender_manager()->FindEntry(url));
}
// Tests that prerendering does launch rel=next prerenders with the field trial.
TEST_F(PrerenderTest, RelNextByFieldTrial) {
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("PrerenderRelNextTrial",
"Yes"));
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_LINK_REL_NEXT, FINAL_STATUS_USED);
prerender_link_manager()->OnAddPrerender(
kDefaultChildId, GetNextPrerenderID(), url, PrerenderRelTypeNext,
Referrer(), kSize, kDefaultRenderViewRouteId);
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
EXPECT_EQ(prerender_contents, entry.get());
}
// Tests that prerendering is cancelled when we launch a second prerender of
// the same target within a short time interval.
TEST_F(PrerenderTest, RecentlyVisited) {
GURL url("http://www.google.com/");
prerender_manager()->RecordNavigation(url);
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_RECENTLY_VISITED);
EXPECT_FALSE(AddSimplePrerender(url));
EXPECT_FALSE(prerender_contents->prerendering_has_started());
}
TEST_F(PrerenderTest, NotSoRecentlyVisited) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
GURL url("http://www.google.com/");
prerender_manager()->RecordNavigation(url);
tick_clock->Advance(TimeDelta::FromMilliseconds(
UnitTestPrerenderManager::kNavigationRecordWindowMs + 500));
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
// Tests that the offline origin is not restricted by recently visited check.
TEST_F(PrerenderTest, OfflinePrerenderStartsWhenRecentlyVisited) {
GURL url("http://www.google.com/");
prerender_manager()->RecordNavigation(url);
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle =
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize);
EXPECT_TRUE(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
}
// Tests that the prerender manager matches include the fragment.
TEST_F(PrerenderTest, FragmentMatchesTest) {
GURL fragment_url("http://www.google.com/#test");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(fragment_url,
FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(fragment_url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(fragment_url);
ASSERT_EQ(prerender_contents, entry.get());
}
// Tests that the prerender manager uses fragment references when matching
// prerender URLs in the case a different fragment is in both URLs.
TEST_F(PrerenderTest, FragmentsDifferTest) {
GURL fragment_url("http://www.google.com/#test");
GURL other_fragment_url("http://www.google.com/#other_test");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(fragment_url,
FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(fragment_url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
ASSERT_FALSE(prerender_manager()->FindEntry(other_fragment_url));
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(fragment_url);
ASSERT_EQ(prerender_contents, entry.get());
}
// Make sure that clearing works as expected.
TEST_F(PrerenderTest, ClearTest) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
FINAL_STATUS_CACHE_OR_HISTORY_CLEARED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
prerender_manager()->ClearData(PrerenderManager::CLEAR_PRERENDER_CONTENTS);
EXPECT_FALSE(prerender_manager()->FindEntry(url));
}
// Make sure canceling works as expected.
TEST_F(PrerenderTest, CancelAllTest) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
prerender_manager()->CancelAllPrerenders();
EXPECT_FALSE(prerender_manager()->FindEntry(url));
}
TEST_F(PrerenderTest, OmniboxNotAllowedWhenDisabled) {
DisablePrerender();
EXPECT_FALSE(prerender_manager()->AddPrerenderFromOmnibox(
GURL("http://www.example.com"), nullptr, gfx::Size()));
histogram_tester().ExpectUniqueSample("Prerender.FinalStatus",
FINAL_STATUS_PRERENDERING_DISABLED, 1);
}
TEST_F(PrerenderTest, LinkRelStillAllowedWhenDisabled) {
DisablePrerender();
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
TEST_F(PrerenderTest, LinkRelAllowedOnCellular) {
EnablePrerender();
GURL url("http://www.example.com");
std::unique_ptr<net::NetworkChangeNotifier> mock(
new MockNetworkChangeNotifier4G);
EXPECT_TRUE(net::NetworkChangeNotifier::IsConnectionCellular(
net::NetworkChangeNotifier::GetConnectionType()));
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
TEST_F(PrerenderTest, PrerenderNotAllowedOnCellularWithExternalOrigin) {
EnablePrerender();
std::unique_ptr<net::NetworkChangeNotifier> mock(
new MockNetworkChangeNotifier4G);
EXPECT_TRUE(net::NetworkChangeNotifier::IsConnectionCellular(
net::NetworkChangeNotifier::GetConnectionType()));
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url,
ORIGIN_EXTERNAL_REQUEST,
FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle(
prerender_manager()->AddPrerenderFromExternalRequest(
url, content::Referrer(), nullptr, gfx::Rect(kSize)));
EXPECT_FALSE(prerender_handle);
EXPECT_FALSE(prerender_contents->prerendering_has_started());
histogram_tester().ExpectUniqueSample("Prerender.FinalStatus",
FINAL_STATUS_CELLULAR_NETWORK, 1);
}
// Checks that the "PrerenderSilence" experiment does not disable offline
// prerendering.
TEST_F(PrerenderTest, PrerenderSilenceAllowsOffline) {
// Set the time to 30 seconds before the experiment expires.
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"PrerenderSilence", "ExperimentYes_expires_2016-12-20T00:01:00Z"));
ASSERT_TRUE(OverridePrerenderManagerTime("2016-12-20T00:00:30Z",
prerender_manager()));
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle =
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize);
EXPECT_TRUE(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_EQ(prerender_contents, prerender_handle->contents());
EXPECT_EQ(ORIGIN_OFFLINE, prerender_handle->contents()->origin());
}
// Checks that the "PrerenderSilence" experiment does not disable
// forced-cellular prerendering.
TEST_F(PrerenderTest, PrerenderSilenceAllowsForcedCellular) {
// Set the time to 30 seconds before the experiment expires.
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"PrerenderSilence", "ExperimentYes_expires_2016-12-20T00:01:00Z"));
ASSERT_TRUE(OverridePrerenderManagerTime("2016-12-20T00:00:30Z",
prerender_manager()));
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_EXTERNAL_REQUEST_FORCED_PRERENDER,
FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle =
prerender_manager()->AddForcedPrerenderFromExternalRequest(
url, content::Referrer(), nullptr, gfx::Rect(kSize));
EXPECT_TRUE(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_EQ(prerender_contents, prerender_handle->contents());
EXPECT_EQ(ORIGIN_EXTERNAL_REQUEST_FORCED_PRERENDER,
prerender_handle->contents()->origin());
}
// Checks that the "PrerenderSilence" experiment disables prerendering and
// re-enables it after expiration.
TEST_F(PrerenderTest, PrerenderSilenceDisallowsNonOffline) {
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"PrerenderSilence", "ExperimentYes_expires_2016-12-20T00:02:00Z"));
Origin prerender_silence_origins[] = {
ORIGIN_GWS_PRERENDER,
ORIGIN_OMNIBOX,
ORIGIN_NONE,
ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN,
ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN,
ORIGIN_EXTERNAL_REQUEST,
ORIGIN_INSTANT,
ORIGIN_LINK_REL_NEXT,
};
// Prerender before expiration of the experiment.
ASSERT_TRUE(OverridePrerenderManagerTime("2016-12-20T00:01:00Z",
prerender_manager()));
for (const Origin& origin : prerender_silence_origins) {
EXPECT_TRUE(
prerender_manager()->IsPrerenderSilenceExperimentForTesting(origin));
}
// Prerender after expiration of the experiment.
ASSERT_TRUE(OverridePrerenderManagerTime("2016-12-20T00:03:00Z",
prerender_manager()));
for (const Origin& origin : prerender_silence_origins) {
EXPECT_FALSE(
prerender_manager()->IsPrerenderSilenceExperimentForTesting(origin));
}
}
// Checks that prerendering is enabled after expiration of the
// "PrerenderSilence" experiment.
TEST_F(PrerenderTest, PrerenderSilenceAllowsAfterExpiration) {
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"PrerenderSilence", "ExperimentYes_expires_2016-12-20T00:02:00Z"));
ASSERT_TRUE(OverridePrerenderManagerTime("2016-12-20T00:01:60Z",
prerender_manager()));
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
TEST_F(PrerenderTest, PrerenderAllowedForOfflineAndForcedCellular) {
const Origin origins[] = {
ORIGIN_EXTERNAL_REQUEST_FORCED_PRERENDER, ORIGIN_OFFLINE,
};
EnablePrerender();
std::unique_ptr<net::NetworkChangeNotifier> mock(
new MockNetworkChangeNotifier4G);
EXPECT_TRUE(net::NetworkChangeNotifier::IsConnectionCellular(
net::NetworkChangeNotifier::GetConnectionType()));
GURL url("http://www.google.com/");
for (const Origin& origin : origins) {
DummyPrerenderContents* prerender_contents = nullptr;
std::unique_ptr<PrerenderHandle> prerender_handle;
if (origin == ORIGIN_OFFLINE) {
prerender_contents = prerender_manager()->CreateNextPrerenderContents(
url, origin, FINAL_STATUS_MANAGER_SHUTDOWN);
prerender_handle =
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize);
} else {
prerender_contents = prerender_manager()->CreateNextPrerenderContents(
url, origin, FINAL_STATUS_USED);
prerender_handle =
prerender_manager()->AddForcedPrerenderFromExternalRequest(
url, content::Referrer(), nullptr, gfx::Rect(kSize));
}
EXPECT_TRUE(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_EQ(prerender_contents, prerender_handle->contents());
EXPECT_EQ(origin, prerender_handle->contents()->origin());
if (origin != ORIGIN_OFFLINE) {
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
}
}
TEST_F(PrerenderTest, LinkManagerCancel) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
TEST_F(PrerenderTest, LinkManagerCancelThenAbandon) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
}
TEST_F(PrerenderTest, LinkManagerAbandon) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
}
TEST_F(PrerenderTest, LinkManagerAbandonThenCancel) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
}
TEST_F(PrerenderTest, LinkManagerCancelTwice) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
}
TEST_F(PrerenderTest, LinkManagerAddTwiceCancelTwice) {
SetConcurrency(2);
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
const int first_prerender_id = last_prerender_id();
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_TRUE(AddSimplePrerender(url));
const int second_prerender_id = last_prerender_id();
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
first_prerender_id);
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
second_prerender_id);
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
}
TEST_F(PrerenderTest, LinkManagerAddTwiceCancelTwiceThenAbandonTwice) {
SetConcurrency(2);
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
const int first_prerender_id = last_prerender_id();
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_TRUE(AddSimplePrerender(url));
const int second_prerender_id = last_prerender_id();
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
first_prerender_id);
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
second_prerender_id);
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
first_prerender_id);
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
second_prerender_id);
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
}
// TODO(gavinp): Update this test after abandon has an effect on Prerenders,
// like shortening the timeouts.
TEST_F(PrerenderTest, LinkManagerAddTwiceAbandonTwiceUseTwice) {
SetConcurrency(2);
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
const int first_prerender_id = last_prerender_id();
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
EXPECT_TRUE(AddSimplePrerender(url));
const int second_prerender_id = last_prerender_id();
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
first_prerender_id);
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
second_prerender_id);
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
// TODO(gavinp): After abandon shortens the expire time on a Prerender,
// add a series of tests testing advancing the time by either the abandon
// or normal expire, and verifying the expected behaviour with groups
// of links.
TEST_F(PrerenderTest, LinkManagerExpireThenCancel) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
tick_clock->Advance(prerender_manager()->config().time_to_live +
TimeDelta::FromSeconds(1));
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
}
TEST_F(PrerenderTest, LinkManagerExpireThenAddAgain) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* first_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(first_prerender_contents->prerendering_has_started());
EXPECT_FALSE(first_prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(first_prerender_contents,
prerender_manager()->FindEntry(url));
tick_clock->Advance(prerender_manager()->config().time_to_live +
TimeDelta::FromSeconds(1));
ASSERT_FALSE(prerender_manager()->FindEntry(url));
DummyPrerenderContents* second_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(second_prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(second_prerender_contents, entry.get());
}
TEST_F(PrerenderTest, LinkManagerCancelThenAddAgain) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* first_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_CANCELLED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(first_prerender_contents->prerendering_has_started());
EXPECT_FALSE(first_prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(first_prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_TRUE(first_prerender_contents->prerendering_has_been_cancelled());
ASSERT_FALSE(prerender_manager()->FindEntry(url));
DummyPrerenderContents* second_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(second_prerender_contents->prerendering_has_started());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(second_prerender_contents, entry.get());
}
TEST_F(PrerenderTest, LinkManagerChannelClosing) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
url, FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
prerender_link_manager()->OnChannelClosing(kDefaultChildId);
tick_clock->Advance(prerender_manager()->config().abandon_time_to_live +
TimeDelta::FromSeconds(1));
EXPECT_FALSE(prerender_manager()->FindEntry(url));
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
// Creates two prerenders, one of which should be blocked by the
// max_link_concurrency; abandons both of them and waits to make sure both
// are cleared from the PrerenderLinkManager.
TEST_F(PrerenderTest, DISABLED_LinkManagerAbandonInactivePrerender) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
SetConcurrency(1);
ASSERT_LT(prerender_manager()->config().abandon_time_to_live,
prerender_manager()->config().time_to_live);
GURL first_url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
first_url, FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(first_url));
const int first_prerender_id = last_prerender_id();
GURL second_url("http://www.neverlaunched.com");
EXPECT_FALSE(AddSimplePrerender(second_url));
const int second_prerender_id = last_prerender_id();
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(second_url));
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
first_prerender_id);
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
second_prerender_id);
tick_clock->Advance(prerender_manager()->config().abandon_time_to_live +
TimeDelta::FromSeconds(1));
EXPECT_FALSE(prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(second_url));
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
// Creates two prerenders, the second one started by the first, both of which
// should be blocked by max_concurrency; abandons both of them and waits to make
// sure both are cleared from the PrerenderLinkManager.
TEST_F(PrerenderTest, LinkManagerClearOnPendingAbandon) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
SetConcurrency(1);
ASSERT_LT(prerender_manager()->config().abandon_time_to_live,
prerender_manager()->config().time_to_live);
GURL first_url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
first_url, FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(first_url));
const int first_prerender_id = last_prerender_id();
int child_id;
int route_id;
ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
GURL pending_url("http://www.neverlaunched.com");
prerender_link_manager()->OnAddPrerender(
child_id, GetNextPrerenderID(), pending_url, kDefaultRelTypes,
content::Referrer(), kSize, route_id);
const int second_prerender_id = last_prerender_id();
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(pending_url));
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
first_prerender_id);
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
second_prerender_id);
tick_clock->Advance(prerender_manager()->config().abandon_time_to_live +
TimeDelta::FromSeconds(1));
EXPECT_FALSE(prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(pending_url));
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
// Creates two prerenders, one of which should be blocked by the
// max_link_concurrency; uses one after the max wait to launch, and
// ensures the second prerender does not start.
TEST_F(PrerenderTest, LinkManagerWaitToLaunchNotLaunched) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
SetConcurrency(1);
ASSERT_LT(prerender_manager()->config().max_wait_to_launch,
prerender_manager()->config().time_to_live);
GURL first_url("http://www.myexample.com");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
first_url, FINAL_STATUS_USED);
EXPECT_TRUE(AddSimplePrerender(first_url));
GURL second_url("http://www.neverlaunched.com");
EXPECT_FALSE(AddSimplePrerender(second_url));
EXPECT_FALSE(IsEmptyPrerenderLinkManager());
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(second_url));
tick_clock->Advance(prerender_manager()->config().max_wait_to_launch +
TimeDelta::FromSeconds(1));
EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(second_url));
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(first_url);
EXPECT_EQ(prerender_contents, entry.get());
EXPECT_FALSE(prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(second_url));
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
// Creates two prerenders, one of which should start when the first one expires.
TEST_F(PrerenderTest, LinkManagerExpireRevealingLaunch) {
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
SetConcurrency(1);
ASSERT_LT(prerender_manager()->config().max_wait_to_launch,
prerender_manager()->config().time_to_live);
GURL first_url("http://www.willexpire.com");
DummyPrerenderContents* first_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
first_url, FINAL_STATUS_TIMED_OUT);
EXPECT_TRUE(AddSimplePrerender(first_url));
EXPECT_EQ(first_prerender_contents,
prerender_manager()->FindEntry(first_url));
// Insert the second prerender so it will be still be launchable when the
// first expires.
const TimeDelta wait_to_launch_second_prerender =
prerender_manager()->config().time_to_live -
prerender_manager()->config().max_wait_to_launch +
TimeDelta::FromSeconds(2);
const TimeDelta wait_for_first_prerender_to_expire =
prerender_manager()->config().time_to_live -
wait_to_launch_second_prerender +
TimeDelta::FromSeconds(1);
ASSERT_LT(prerender_manager()->config().time_to_live,
wait_to_launch_second_prerender +
wait_for_first_prerender_to_expire);
ASSERT_GT(prerender_manager()->config().max_wait_to_launch.InSeconds(),
wait_for_first_prerender_to_expire.InSeconds());
tick_clock->Advance(wait_to_launch_second_prerender);
GURL second_url("http://www.willlaunch.com");
DummyPrerenderContents* second_prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
second_url, FINAL_STATUS_USED);
EXPECT_FALSE(AddSimplePrerender(second_url));
// The first prerender is still running, but the second has not yet launched.
EXPECT_EQ(first_prerender_contents,
prerender_manager()->FindEntry(first_url));
EXPECT_FALSE(prerender_manager()->FindEntry(second_url));
// The first prerender should have died, giving life to the second one.
tick_clock->Advance(wait_for_first_prerender_to_expire);
EXPECT_FALSE(prerender_manager()->FindEntry(first_url));
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(second_url);
EXPECT_EQ(second_prerender_contents, entry.get());
}
TEST_F(PrerenderTest, InstantSearchNotAllowedWhenDisabled) {
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"EmbeddedSearch",
"Group82 espv:8 use_cacheable_ntp:1 prefetch_results:1"));
DisablePrerender();
EXPECT_FALSE(prerender_manager()->AddPrerenderForInstant(
GURL("http://www.example.com/instant_search"), nullptr, gfx::Size()));
}
TEST_F(PrerenderTest, PrerenderContentsForInstantSearch) {
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"EmbeddedSearch",
"Group82 espv:8 use_cacheable_ntp:1 prefetch_results:1"));
GURL url("http://www.example.com/instant_search");
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(url, ORIGIN_INSTANT,
FINAL_STATUS_USED);
std::unique_ptr<PrerenderHandle> prerender_handle(
prerender_manager()->AddPrerenderForInstant(url, nullptr, kSize));
CHECK(prerender_handle);
EXPECT_TRUE(prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
EXPECT_EQ(prerender_contents, prerender_handle->contents());
EXPECT_EQ(ORIGIN_INSTANT, prerender_handle->contents()->origin());
std::unique_ptr<PrerenderContents> entry =
prerender_manager()->FindAndUseEntry(url);
ASSERT_EQ(prerender_contents, entry.get());
EXPECT_FALSE(prerender_handle->IsPrerendering());
}
TEST_F(PrerenderTest, PrerenderContentsIsValidHttpMethod) {
DummyPrerenderContents* prerender_contents =
prerender_manager()->CreateNextPrerenderContents(
GURL("my://dummy.url"), FINAL_STATUS_MANAGER_SHUTDOWN);
prerender_contents->SetPrerenderMode(FULL_PRERENDER);
EXPECT_TRUE(prerender_contents->IsValidHttpMethod("GET"));
EXPECT_TRUE(prerender_contents->IsValidHttpMethod("HEAD"));
EXPECT_TRUE(prerender_contents->IsValidHttpMethod("OPTIONS"));
EXPECT_TRUE(prerender_contents->IsValidHttpMethod("POST"));
EXPECT_TRUE(prerender_contents->IsValidHttpMethod("TRACE"));
EXPECT_FALSE(prerender_contents->IsValidHttpMethod("WHATEVER"));
prerender_contents->SetPrerenderMode(PREFETCH_ONLY);
EXPECT_TRUE(prerender_contents->IsValidHttpMethod("GET"));
EXPECT_TRUE(prerender_contents->IsValidHttpMethod("HEAD"));
EXPECT_FALSE(prerender_contents->IsValidHttpMethod("OPTIONS"));
EXPECT_FALSE(prerender_contents->IsValidHttpMethod("POST"));
EXPECT_FALSE(prerender_contents->IsValidHttpMethod("TRACE"));
EXPECT_FALSE(prerender_contents->IsValidHttpMethod("WHATEVER"));
}
TEST_F(PrerenderTest, PrerenderContentsIncrementsByteCount) {
GURL url("http://www.google.com/");
DummyPrerenderContents* prerender_contents = nullptr;
prerender_contents = prerender_manager()->CreateNextPrerenderContents(
url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
std::unique_ptr<PrerenderHandle> prerender_handle =
prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize);
TestNetworkBytesChangedObserver observer;
prerender_handle->SetObserver(&observer);
prerender_contents->AddNetworkBytes(12);
EXPECT_TRUE(observer.network_bytes_changed());
EXPECT_EQ(12, prerender_contents->network_bytes());
}
} // namespace prerender