| Index: chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
|
| diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6e79971bc701bd18e1ef08a4fdf20757afad06fd
|
| --- /dev/null
|
| +++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
|
| @@ -0,0 +1,925 @@
|
| +// Copyright 2014 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 <iostream>
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/time/time.h"
|
| +#include "chrome/browser/history/history_service.h"
|
| +#include "chrome/browser/history/history_service_factory.h"
|
| +#include "chrome/browser/history/history_types.h"
|
| +#include "chrome/browser/predictors/resource_prefetch_predictor.h"
|
| +#include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
|
| +#include "chrome/test/base/testing_profile.h"
|
| +#include "content/public/test/test_browser_thread.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using testing::ContainerEq;
|
| +using testing::Pointee;
|
| +using testing::SetArgPointee;
|
| +using testing::StrictMock;
|
| +
|
| +namespace predictors {
|
| +
|
| +typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
|
| +typedef ResourcePrefetchPredictorTables::ResourceRow ResourceRow;
|
| +typedef std::vector<ResourceRow> ResourceRows;
|
| +typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData;
|
| +typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap;
|
| +
|
| +// For printing failures nicely.
|
| +void PrintTo(const ResourceRow& row, ::std::ostream* os) {
|
| + *os << "[" << row.primary_key << "," << row.resource_url
|
| + << "," << row.resource_type << "," << row.number_of_hits
|
| + << "," << row.number_of_misses << "," << row.consecutive_misses
|
| + << "," << row.average_position << "," << row.score << "]";
|
| +}
|
| +
|
| +void PrintTo(const PrefetchData& data, ::std::ostream* os) {
|
| + *os << "[" << data.key_type << "," << data.primary_key
|
| + << "," << data.last_visit.ToInternalValue() << "]\n";
|
| + for (ResourceRows::const_iterator it = data.resources.begin();
|
| + it != data.resources.end(); ++it) {
|
| + *os << "\t\t";
|
| + PrintTo(*it, os);
|
| + *os << "\n";
|
| + }
|
| +}
|
| +
|
| +class MockResourcePrefetchPredictorTables
|
| + : public ResourcePrefetchPredictorTables {
|
| + public:
|
| + MockResourcePrefetchPredictorTables() { }
|
| +
|
| + MOCK_METHOD2(GetAllData, void(PrefetchDataMap* url_data_map,
|
| + PrefetchDataMap* host_data_map));
|
| + MOCK_METHOD2(UpdateData, void(const PrefetchData& url_data,
|
| + const PrefetchData& host_data));
|
| + MOCK_METHOD2(DeleteData, void(const std::vector<std::string>& urls,
|
| + const std::vector<std::string>& hosts));
|
| + MOCK_METHOD2(DeleteSingleDataPoint, void(const std::string& key,
|
| + PrefetchKeyType key_type));
|
| + MOCK_METHOD0(DeleteAllData, void());
|
| +
|
| + protected:
|
| + ~MockResourcePrefetchPredictorTables() { }
|
| +};
|
| +
|
| +class ResourcePrefetchPredictorTest : public testing::Test {
|
| + public:
|
| + ResourcePrefetchPredictorTest();
|
| + virtual ~ResourcePrefetchPredictorTest();
|
| + virtual void SetUp() OVERRIDE;
|
| + virtual void TearDown() OVERRIDE;
|
| +
|
| + protected:
|
| + void AddUrlToHistory(const std::string& url, int visit_count) {
|
| + HistoryServiceFactory::GetForProfile(profile_.get(),
|
| + Profile::EXPLICIT_ACCESS)->
|
| + AddPageWithDetails(
|
| + GURL(url),
|
| + base::string16(),
|
| + visit_count,
|
| + 0,
|
| + base::Time::Now(),
|
| + false,
|
| + history::SOURCE_BROWSED);
|
| + profile_->BlockUntilHistoryProcessesPendingRequests();
|
| + }
|
| +
|
| + NavigationID CreateNavigationID(int process_id,
|
| + int render_frame_id,
|
| + const std::string& main_frame_url) {
|
| + NavigationID navigation_id;
|
| + navigation_id.render_process_id = process_id;
|
| + navigation_id.render_frame_id = render_frame_id;
|
| + navigation_id.main_frame_url = GURL(main_frame_url);
|
| + navigation_id.creation_time = base::TimeTicks::Now();
|
| + return navigation_id;
|
| + }
|
| +
|
| + ResourcePrefetchPredictor::URLRequestSummary CreateURLRequestSummary(
|
| + int process_id,
|
| + int render_frame_id,
|
| + const std::string& main_frame_url,
|
| + const std::string& resource_url,
|
| + content::ResourceType resource_type,
|
| + const std::string& mime_type,
|
| + bool was_cached) {
|
| + ResourcePrefetchPredictor::URLRequestSummary summary;
|
| + summary.navigation_id = CreateNavigationID(process_id, render_frame_id,
|
| + main_frame_url);
|
| + summary.resource_url = GURL(resource_url);
|
| + summary.resource_type = resource_type;
|
| + summary.mime_type = mime_type;
|
| + summary.was_cached = was_cached;
|
| + return summary;
|
| + }
|
| +
|
| + void InitializePredictor() {
|
| + predictor_->StartInitialization();
|
| + base::RunLoop loop;
|
| + loop.RunUntilIdle(); // Runs the DB lookup.
|
| + profile_->BlockUntilHistoryProcessesPendingRequests();
|
| + }
|
| +
|
| + bool URLRequestSummaryAreEqual(const URLRequestSummary& lhs,
|
| + const URLRequestSummary& rhs) {
|
| + return lhs.navigation_id == rhs.navigation_id &&
|
| + lhs.resource_url == rhs.resource_url &&
|
| + lhs.resource_type == rhs.resource_type &&
|
| + lhs.mime_type == rhs.mime_type &&
|
| + lhs.was_cached == rhs.was_cached;
|
| + }
|
| +
|
| + void ResetPredictor() {
|
| + ResourcePrefetchPredictorConfig config;
|
| + config.max_urls_to_track = 3;
|
| + config.max_hosts_to_track = 2;
|
| + config.min_url_visit_count = 2;
|
| + config.max_resources_per_entry = 4;
|
| + config.max_consecutive_misses = 2;
|
| +
|
| + // TODO(shishir): Enable the prefetching mode in the tests.
|
| + config.mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
|
| + config.mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
|
| + predictor_.reset(new ResourcePrefetchPredictor(config, profile_.get()));
|
| + predictor_->set_mock_tables(mock_tables_);
|
| + }
|
| +
|
| + void InitializeSampleData();
|
| +
|
| + base::MessageLoop loop_;
|
| + content::TestBrowserThread ui_thread_;
|
| + content::TestBrowserThread db_thread_;
|
| + scoped_ptr<TestingProfile> profile_;
|
| +
|
| + scoped_ptr<ResourcePrefetchPredictor> predictor_;
|
| + scoped_refptr<StrictMock<MockResourcePrefetchPredictorTables> > mock_tables_;
|
| +
|
| + PrefetchDataMap test_url_data_;
|
| + PrefetchDataMap test_host_data_;
|
| + PrefetchData empty_url_data_;
|
| + PrefetchData empty_host_data_;
|
| +};
|
| +
|
| +ResourcePrefetchPredictorTest::ResourcePrefetchPredictorTest()
|
| + : loop_(base::MessageLoop::TYPE_DEFAULT),
|
| + ui_thread_(content::BrowserThread::UI, &loop_),
|
| + db_thread_(content::BrowserThread::DB, &loop_),
|
| + profile_(new TestingProfile()),
|
| + mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()),
|
| + empty_url_data_(PREFETCH_KEY_TYPE_URL, std::string()),
|
| + empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()) {}
|
| +
|
| +ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() {
|
| + profile_.reset(NULL);
|
| + loop_.RunUntilIdle();
|
| +}
|
| +
|
| +void ResourcePrefetchPredictorTest::SetUp() {
|
| + InitializeSampleData();
|
| +
|
| + ASSERT_TRUE(profile_->CreateHistoryService(true, false));
|
| + profile_->BlockUntilHistoryProcessesPendingRequests();
|
| + EXPECT_TRUE(HistoryServiceFactory::GetForProfile(profile_.get(),
|
| + Profile::EXPLICIT_ACCESS));
|
| + // Initialize the predictor with empty data.
|
| + ResetPredictor();
|
| + EXPECT_EQ(predictor_->initialization_state_,
|
| + ResourcePrefetchPredictor::NOT_INITIALIZED);
|
| + EXPECT_CALL(*mock_tables_.get(),
|
| + GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
|
| + Pointee(ContainerEq(PrefetchDataMap()))));
|
| + InitializePredictor();
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.empty());
|
| + EXPECT_EQ(predictor_->initialization_state_,
|
| + ResourcePrefetchPredictor::INITIALIZED);
|
| +}
|
| +
|
| +void ResourcePrefetchPredictorTest::TearDown() {
|
| + predictor_.reset(NULL);
|
| + profile_->DestroyHistoryService();
|
| +}
|
| +
|
| +void ResourcePrefetchPredictorTest::InitializeSampleData() {
|
| + { // Url data.
|
| + PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
|
| + google.last_visit = base::Time::FromInternalValue(1);
|
| + google.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 3,
|
| + 2,
|
| + 1,
|
| + 1.0));
|
| + google.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script3.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 4,
|
| + 0,
|
| + 1,
|
| + 2.1));
|
| + google.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script4.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 11,
|
| + 0,
|
| + 0,
|
| + 2.1));
|
| + google.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/image1.png",
|
| + content::RESOURCE_TYPE_IMAGE,
|
| + 6,
|
| + 3,
|
| + 0,
|
| + 2.2));
|
| + google.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/a.font",
|
| + content::RESOURCE_TYPE_LAST_TYPE,
|
| + 2,
|
| + 0,
|
| + 0,
|
| + 5.1));
|
| +
|
| + PrefetchData reddit(PREFETCH_KEY_TYPE_URL, "http://www.reddit.com/");
|
| + reddit.last_visit = base::Time::FromInternalValue(2);
|
| + reddit.resources
|
| + .push_back(ResourceRow(std::string(),
|
| + "http://reddit-resource.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 4,
|
| + 0,
|
| + 1,
|
| + 1.0));
|
| + reddit.resources
|
| + .push_back(ResourceRow(std::string(),
|
| + "http://reddit-resource.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 2,
|
| + 0,
|
| + 0,
|
| + 2.1));
|
| +
|
| + PrefetchData yahoo(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/");
|
| + yahoo.last_visit = base::Time::FromInternalValue(3);
|
| + yahoo.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/image.png",
|
| + content::RESOURCE_TYPE_IMAGE,
|
| + 20,
|
| + 1,
|
| + 0,
|
| + 10.0));
|
| +
|
| + test_url_data_.clear();
|
| + test_url_data_.insert(std::make_pair("http://www.google.com/", google));
|
| + test_url_data_.insert(std::make_pair("http://www.reddit.com/", reddit));
|
| + test_url_data_.insert(std::make_pair("http://www.yahoo.com/", yahoo));
|
| + }
|
| +
|
| + { // Host data.
|
| + PrefetchData facebook(PREFETCH_KEY_TYPE_HOST, "www.facebook.com");
|
| + facebook.last_visit = base::Time::FromInternalValue(4);
|
| + facebook.resources
|
| + .push_back(ResourceRow(std::string(),
|
| + "http://www.facebook.com/style.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 5,
|
| + 2,
|
| + 1,
|
| + 1.1));
|
| + facebook.resources
|
| + .push_back(ResourceRow(std::string(),
|
| + "http://www.facebook.com/script.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 4,
|
| + 0,
|
| + 1,
|
| + 2.1));
|
| + facebook.resources
|
| + .push_back(ResourceRow(std::string(),
|
| + "http://www.facebook.com/image.png",
|
| + content::RESOURCE_TYPE_IMAGE,
|
| + 6,
|
| + 3,
|
| + 0,
|
| + 2.2));
|
| + facebook.resources.push_back(ResourceRow(std::string(),
|
| + "http://www.facebook.com/a.font",
|
| + content::RESOURCE_TYPE_LAST_TYPE,
|
| + 2,
|
| + 0,
|
| + 0,
|
| + 5.1));
|
| + facebook.resources
|
| + .push_back(ResourceRow(std::string(),
|
| + "http://www.resources.facebook.com/script.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 11,
|
| + 0,
|
| + 0,
|
| + 8.5));
|
| +
|
| + PrefetchData yahoo(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com");
|
| + yahoo.last_visit = base::Time::FromInternalValue(5);
|
| + yahoo.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/image.png",
|
| + content::RESOURCE_TYPE_IMAGE,
|
| + 20,
|
| + 1,
|
| + 0,
|
| + 10.0));
|
| +
|
| + test_host_data_.clear();
|
| + test_host_data_.insert(std::make_pair("www.facebook.com", facebook));
|
| + test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo));
|
| + }
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeEmpty) {
|
| + // Tests that the predictor initializes correctly without any data.
|
| + EXPECT_TRUE(predictor_->url_table_cache_->empty());
|
| + EXPECT_TRUE(predictor_->host_table_cache_->empty());
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeWithData) {
|
| + // Tests that the history and the db tables data are loaded correctly.
|
| + AddUrlToHistory("http://www.google.com/", 4);
|
| + AddUrlToHistory("http://www.yahoo.com/", 2);
|
| +
|
| + EXPECT_CALL(*mock_tables_.get(),
|
| + GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
|
| + Pointee(ContainerEq(PrefetchDataMap()))))
|
| + .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
|
| + SetArgPointee<1>(test_host_data_)));
|
| +
|
| + ResetPredictor();
|
| + InitializePredictor();
|
| +
|
| + // Test that the internal variables correctly initialized.
|
| + EXPECT_EQ(predictor_->initialization_state_,
|
| + ResourcePrefetchPredictor::INITIALIZED);
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.empty());
|
| +
|
| + EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_);
|
| + EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_);
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) {
|
| + // Single navigation but history count is low, so should not record.
|
| + AddUrlToHistory("http://www.google.com", 1);
|
| +
|
| + URLRequestSummary main_frame =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + predictor_->RecordURLRequest(main_frame);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + // Now add a few subresources.
|
| + URLRequestSummary resource1 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET, "text/css", false);
|
| + predictor_->RecordURLResponse(resource1);
|
| + URLRequestSummary resource2 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + predictor_->RecordURLResponse(resource2);
|
| + URLRequestSummary resource3 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + predictor_->RecordURLResponse(resource3);
|
| +
|
| + PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
|
| + host_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 1.0));
|
| + host_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 2.0));
|
| + host_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 3.0));
|
| + EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
|
| +
|
| + predictor_->OnNavigationComplete(main_frame.navigation_id);
|
| + profile_->BlockUntilHistoryProcessesPendingRequests();
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDB) {
|
| + // Single navigation that will be recorded. Will check for duplicate
|
| + // resources and also for number of resources saved.
|
| + AddUrlToHistory("http://www.google.com", 4);
|
| +
|
| + URLRequestSummary main_frame =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + predictor_->RecordURLRequest(main_frame);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + URLRequestSummary resource1 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET, "text/css", false);
|
| + predictor_->RecordURLResponse(resource1);
|
| + URLRequestSummary resource2 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + predictor_->RecordURLResponse(resource2);
|
| + URLRequestSummary resource3 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + predictor_->RecordURLResponse(resource3);
|
| + URLRequestSummary resource4 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", true);
|
| + predictor_->RecordURLResponse(resource4);
|
| + URLRequestSummary resource5 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/image1.png",
|
| + content::RESOURCE_TYPE_IMAGE, "image/png", false);
|
| + predictor_->RecordURLResponse(resource5);
|
| + URLRequestSummary resource6 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/image2.png",
|
| + content::RESOURCE_TYPE_IMAGE, "image/png", false);
|
| + predictor_->RecordURLResponse(resource6);
|
| + URLRequestSummary resource7 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/style2.css",
|
| + content::RESOURCE_TYPE_STYLESHEET, "text/css", true);
|
| + predictor_->RecordURLResponse(resource7);
|
| +
|
| + PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 1.0));
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 2.0));
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 3.0));
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/style2.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 7.0));
|
| + EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
|
| +
|
| + PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
|
| + host_data.resources = url_data.resources;
|
| + EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
|
| +
|
| + predictor_->OnNavigationComplete(main_frame.navigation_id);
|
| + profile_->BlockUntilHistoryProcessesPendingRequests();
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) {
|
| + // Tests that navigation is recorded correctly for URL already present in
|
| + // the database cache.
|
| + AddUrlToHistory("http://www.google.com", 4);
|
| +
|
| + EXPECT_CALL(*mock_tables_.get(),
|
| + GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
|
| + Pointee(ContainerEq(PrefetchDataMap()))))
|
| + .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
|
| + SetArgPointee<1>(test_host_data_)));
|
| + ResetPredictor();
|
| + InitializePredictor();
|
| + EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size()));
|
| + EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size()));
|
| +
|
| + URLRequestSummary main_frame =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + predictor_->RecordURLRequest(main_frame);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + URLRequestSummary resource1 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET, "text/css", false);
|
| + predictor_->RecordURLResponse(resource1);
|
| + URLRequestSummary resource2 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + predictor_->RecordURLResponse(resource2);
|
| + URLRequestSummary resource3 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + predictor_->RecordURLResponse(resource3);
|
| + URLRequestSummary resource4 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", true);
|
| + predictor_->RecordURLResponse(resource4);
|
| + URLRequestSummary resource5 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/image1.png",
|
| + content::RESOURCE_TYPE_IMAGE, "image/png", false);
|
| + predictor_->RecordURLResponse(resource5);
|
| + URLRequestSummary resource6 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/image2.png",
|
| + content::RESOURCE_TYPE_IMAGE, "image/png", false);
|
| + predictor_->RecordURLResponse(resource6);
|
| + URLRequestSummary resource7 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/style2.css",
|
| + content::RESOURCE_TYPE_STYLESHEET, "text/css", true);
|
| + predictor_->RecordURLResponse(resource7);
|
| +
|
| + PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 4,
|
| + 2,
|
| + 0,
|
| + 1.0));
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 2.0));
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script4.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 11,
|
| + 1,
|
| + 1,
|
| + 2.1));
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 3.0));
|
| + EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
|
| +
|
| + EXPECT_CALL(
|
| + *mock_tables_.get(),
|
| + DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
|
| +
|
| + PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
|
| + host_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 1.0));
|
| + host_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 2.0));
|
| + host_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 3.0));
|
| + host_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://google.com/style2.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 7.0));
|
| + EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
|
| +
|
| + predictor_->OnNavigationComplete(main_frame.navigation_id);
|
| + profile_->BlockUntilHistoryProcessesPendingRequests();
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDBAndDBFull) {
|
| + // Tests that a URL is deleted before another is added if the cache is full.
|
| + AddUrlToHistory("http://www.nike.com/", 4);
|
| +
|
| + EXPECT_CALL(*mock_tables_.get(),
|
| + GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
|
| + Pointee(ContainerEq(PrefetchDataMap()))))
|
| + .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
|
| + SetArgPointee<1>(test_host_data_)));
|
| + ResetPredictor();
|
| + InitializePredictor();
|
| + EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size()));
|
| + EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size()));
|
| +
|
| + URLRequestSummary main_frame =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.nike.com",
|
| + "http://www.nike.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + predictor_->RecordURLRequest(main_frame);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + URLRequestSummary resource1 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.nike.com", "http://nike.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET, "text/css", false);
|
| + predictor_->RecordURLResponse(resource1);
|
| + URLRequestSummary resource2 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.nike.com", "http://nike.com/image2.png",
|
| + content::RESOURCE_TYPE_IMAGE, "image/png", false);
|
| + predictor_->RecordURLResponse(resource2);
|
| +
|
| + EXPECT_CALL(
|
| + *mock_tables_.get(),
|
| + DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL));
|
| + EXPECT_CALL(
|
| + *mock_tables_.get(),
|
| + DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
|
| +
|
| + PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/");
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://nike.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 1.0));
|
| + url_data.resources.push_back(ResourceRow(std::string(),
|
| + "http://nike.com/image2.png",
|
| + content::RESOURCE_TYPE_IMAGE,
|
| + 1,
|
| + 0,
|
| + 0,
|
| + 2.0));
|
| + EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
|
| +
|
| + PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.nike.com");
|
| + host_data.resources = url_data.resources;
|
| + EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
|
| +
|
| + predictor_->OnNavigationComplete(main_frame.navigation_id);
|
| + profile_->BlockUntilHistoryProcessesPendingRequests();
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, DeleteUrls) {
|
| + // Add some dummy entries to cache.
|
| + predictor_->url_table_cache_->insert(std::make_pair(
|
| + "http://www.google.com/page1.html",
|
| + PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page1.html")));
|
| + predictor_->url_table_cache_->insert(std::make_pair(
|
| + "http://www.google.com/page2.html",
|
| + PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page2.html")));
|
| + predictor_->url_table_cache_->insert(std::make_pair(
|
| + "http://www.yahoo.com/",
|
| + PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/")));
|
| + predictor_->url_table_cache_->insert(std::make_pair(
|
| + "http://www.apple.com/",
|
| + PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.apple.com/")));
|
| + predictor_->url_table_cache_->insert(std::make_pair(
|
| + "http://www.nike.com/",
|
| + PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/")));
|
| +
|
| + predictor_->host_table_cache_->insert(std::make_pair(
|
| + "www.google.com",
|
| + PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.google.com")));
|
| + predictor_->host_table_cache_->insert(std::make_pair(
|
| + "www.yahoo.com",
|
| + PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com")));
|
| + predictor_->host_table_cache_->insert(std::make_pair(
|
| + "www.apple.com",
|
| + PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com")));
|
| +
|
| + history::URLRows rows;
|
| + rows.push_back(history::URLRow(GURL("http://www.google.com/page2.html")));
|
| + rows.push_back(history::URLRow(GURL("http://www.apple.com")));
|
| + rows.push_back(history::URLRow(GURL("http://www.nike.com")));
|
| +
|
| + std::vector<std::string> urls_to_delete, hosts_to_delete;
|
| + urls_to_delete.push_back("http://www.google.com/page2.html");
|
| + urls_to_delete.push_back("http://www.apple.com/");
|
| + urls_to_delete.push_back("http://www.nike.com/");
|
| + hosts_to_delete.push_back("www.google.com");
|
| + hosts_to_delete.push_back("www.apple.com");
|
| +
|
| + EXPECT_CALL(
|
| + *mock_tables_.get(),
|
| + DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete)));
|
| +
|
| + predictor_->DeleteUrls(rows);
|
| + EXPECT_EQ(2, static_cast<int>(predictor_->url_table_cache_->size()));
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->host_table_cache_->size()));
|
| +
|
| + EXPECT_CALL(*mock_tables_.get(), DeleteAllData());
|
| +
|
| + predictor_->DeleteAllUrls();
|
| + EXPECT_TRUE(predictor_->url_table_cache_->empty());
|
| + EXPECT_TRUE(predictor_->host_table_cache_->empty());
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) {
|
| + URLRequestSummary summary1 =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + URLRequestSummary summary2 =
|
| + CreateURLRequestSummary(1,
|
| + 2,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + URLRequestSummary summary3 =
|
| + CreateURLRequestSummary(2,
|
| + 1,
|
| + "http://www.yahoo.com",
|
| + "http://www.yahoo.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| +
|
| + predictor_->OnMainFrameRequest(summary1);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| + predictor_->OnMainFrameRequest(summary2);
|
| + EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| + predictor_->OnMainFrameRequest(summary3);
|
| + EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + // Insert anther with same navigation id. It should replace.
|
| + URLRequestSummary summary4 =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.nike.com",
|
| + "http://www.nike.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + URLRequestSummary summary5 =
|
| + CreateURLRequestSummary(1,
|
| + 2,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| +
|
| + predictor_->OnMainFrameRequest(summary4);
|
| + EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + // Change this creation time so that it will go away on the next insert.
|
| + summary5.navigation_id.creation_time = base::TimeTicks::Now() -
|
| + base::TimeDelta::FromDays(1);
|
| + predictor_->OnMainFrameRequest(summary5);
|
| + EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + URLRequestSummary summary6 =
|
| + CreateURLRequestSummary(3,
|
| + 1,
|
| + "http://www.shoes.com",
|
| + "http://www.shoes.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + predictor_->OnMainFrameRequest(summary6);
|
| + EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.find(summary3.navigation_id) !=
|
| + predictor_->inflight_navigations_.end());
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.find(summary4.navigation_id) !=
|
| + predictor_->inflight_navigations_.end());
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.find(summary6.navigation_id) !=
|
| + predictor_->inflight_navigations_.end());
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) {
|
| + URLRequestSummary summary1 =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + URLRequestSummary summary2 =
|
| + CreateURLRequestSummary(1,
|
| + 2,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + URLRequestSummary summary3 =
|
| + CreateURLRequestSummary(2,
|
| + 1,
|
| + "http://www.yahoo.com",
|
| + "http://www.yahoo.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| +
|
| + predictor_->OnMainFrameRedirect(summary1);
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.empty());
|
| +
|
| + predictor_->OnMainFrameRequest(summary1);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| + predictor_->OnMainFrameRequest(summary2);
|
| + EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + predictor_->OnMainFrameRedirect(summary3);
|
| + EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| + predictor_->OnMainFrameRedirect(summary1);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| + predictor_->OnMainFrameRedirect(summary2);
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.empty());
|
| +}
|
| +
|
| +TEST_F(ResourcePrefetchPredictorTest, OnSubresourceResponse) {
|
| + // If there is no inflight navigation, nothing happens.
|
| + URLRequestSummary resource1 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/style1.css",
|
| + content::RESOURCE_TYPE_STYLESHEET, "text/css", false);
|
| + predictor_->OnSubresourceResponse(resource1);
|
| + EXPECT_TRUE(predictor_->inflight_navigations_.empty());
|
| +
|
| + // Add an inflight navigation.
|
| + URLRequestSummary main_frame1 =
|
| + CreateURLRequestSummary(1,
|
| + 1,
|
| + "http://www.google.com",
|
| + "http://www.google.com",
|
| + content::RESOURCE_TYPE_MAIN_FRAME,
|
| + std::string(),
|
| + false);
|
| + predictor_->OnMainFrameRequest(main_frame1);
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| +
|
| + // Now add a few subresources.
|
| + URLRequestSummary resource2 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script1.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + URLRequestSummary resource3 = CreateURLRequestSummary(
|
| + 1, 1, "http://www.google.com", "http://google.com/script2.js",
|
| + content::RESOURCE_TYPE_SCRIPT, "text/javascript", false);
|
| + predictor_->OnSubresourceResponse(resource1);
|
| + predictor_->OnSubresourceResponse(resource2);
|
| + predictor_->OnSubresourceResponse(resource3);
|
| +
|
| + EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
|
| + EXPECT_EQ(3, static_cast<int>(
|
| + predictor_->inflight_navigations_[main_frame1.navigation_id]->size()));
|
| + EXPECT_TRUE(URLRequestSummaryAreEqual(
|
| + resource1,
|
| + predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0)));
|
| + EXPECT_TRUE(URLRequestSummaryAreEqual(
|
| + resource2,
|
| + predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1)));
|
| + EXPECT_TRUE(URLRequestSummaryAreEqual(
|
| + resource3,
|
| + predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2)));
|
| +}
|
| +
|
| +} // namespace predictors
|
|
|