Home | History | Annotate | Download | only in predictors
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <iostream>
      6 #include "base/memory/ref_counted.h"
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/run_loop.h"
     10 #include "base/time/time.h"
     11 #include "chrome/browser/history/history_service.h"
     12 #include "chrome/browser/history/history_service_factory.h"
     13 #include "chrome/browser/history/history_types.h"
     14 #include "chrome/browser/history/in_memory_database.h"
     15 #include "chrome/browser/history/url_database.h"
     16 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
     17 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
     18 #include "chrome/test/base/testing_profile.h"
     19 #include "content/public/test/test_browser_thread.h"
     20 #include "testing/gmock/include/gmock/gmock.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 using testing::ContainerEq;
     24 using testing::Pointee;
     25 using testing::SetArgPointee;
     26 using testing::StrictMock;
     27 
     28 namespace predictors {
     29 
     30 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
     31 typedef ResourcePrefetchPredictorTables::ResourceRow ResourceRow;
     32 typedef std::vector<ResourceRow> ResourceRows;
     33 typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData;
     34 typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap;
     35 
     36 // For printing failures nicely.
     37 void PrintTo(const ResourceRow& row, ::std::ostream* os) {
     38   *os << "[" << row.primary_key << "," << row.resource_url
     39       << "," << row.resource_type << "," << row.number_of_hits
     40       << "," << row.number_of_misses << "," << row.consecutive_misses
     41       << "," << row.average_position << "," << row.score << "]";
     42 }
     43 
     44 void PrintTo(const PrefetchData& data, ::std::ostream* os) {
     45   *os << "[" << data.key_type << "," << data.primary_key
     46       << "," << data.last_visit.ToInternalValue() << "]\n";
     47   for (ResourceRows::const_iterator it = data.resources.begin();
     48        it != data.resources.end(); ++it) {
     49     *os << "\t\t";
     50     PrintTo(*it, os);
     51     *os << "\n";
     52   }
     53 }
     54 
     55 class MockResourcePrefetchPredictorTables
     56     : public ResourcePrefetchPredictorTables {
     57  public:
     58   MockResourcePrefetchPredictorTables() { }
     59 
     60   MOCK_METHOD2(GetAllData, void(PrefetchDataMap* url_data_map,
     61                                 PrefetchDataMap* host_data_map));
     62   MOCK_METHOD2(UpdateData, void(const PrefetchData& url_data,
     63                                 const PrefetchData& host_data));
     64   MOCK_METHOD2(DeleteData, void(const std::vector<std::string>& urls,
     65                                 const std::vector<std::string>& hosts));
     66   MOCK_METHOD2(DeleteSingleDataPoint, void(const std::string& key,
     67                                            PrefetchKeyType key_type));
     68   MOCK_METHOD0(DeleteAllData, void());
     69 
     70  protected:
     71   ~MockResourcePrefetchPredictorTables() { }
     72 };
     73 
     74 class ResourcePrefetchPredictorTest : public testing::Test {
     75  public:
     76   ResourcePrefetchPredictorTest();
     77   virtual ~ResourcePrefetchPredictorTest();
     78   virtual void SetUp() OVERRIDE;
     79   virtual void TearDown() OVERRIDE;
     80 
     81  protected:
     82   void AddUrlToHistory(const std::string& url, int visit_count) {
     83     HistoryServiceFactory::GetForProfile(profile_.get(),
     84                                          Profile::EXPLICIT_ACCESS)->
     85         AddPageWithDetails(
     86             GURL(url),
     87             base::string16(),
     88             visit_count,
     89             0,
     90             base::Time::Now(),
     91             false,
     92             history::SOURCE_BROWSED);
     93     profile_->BlockUntilHistoryProcessesPendingRequests();
     94   }
     95 
     96   NavigationID CreateNavigationID(int process_id,
     97                                   int render_view_id,
     98                                   const std::string& main_frame_url) {
     99     NavigationID navigation_id;
    100     navigation_id.render_process_id = process_id;
    101     navigation_id.render_view_id = render_view_id;
    102     navigation_id.main_frame_url = GURL(main_frame_url);
    103     navigation_id.creation_time = base::TimeTicks::Now();
    104     return navigation_id;
    105   }
    106 
    107   ResourcePrefetchPredictor::URLRequestSummary CreateURLRequestSummary(
    108       int process_id,
    109       int render_view_id,
    110       const std::string& main_frame_url,
    111       const std::string& resource_url,
    112       ResourceType::Type resource_type,
    113       const std::string& mime_type,
    114       bool was_cached) {
    115     ResourcePrefetchPredictor::URLRequestSummary summary;
    116     summary.navigation_id = CreateNavigationID(process_id, render_view_id,
    117                                                main_frame_url);
    118     summary.resource_url = GURL(resource_url);
    119     summary.resource_type = resource_type;
    120     summary.mime_type = mime_type;
    121     summary.was_cached = was_cached;
    122     return summary;
    123   }
    124 
    125   void InitializePredictor() {
    126     predictor_->StartInitialization();
    127     base::RunLoop loop;
    128     loop.RunUntilIdle();  // Runs the DB lookup.
    129     profile_->BlockUntilHistoryProcessesPendingRequests();
    130   }
    131 
    132   bool URLRequestSummaryAreEqual(const URLRequestSummary& lhs,
    133                                  const URLRequestSummary& rhs) {
    134     return lhs.navigation_id == rhs.navigation_id &&
    135         lhs.resource_url == rhs.resource_url &&
    136         lhs.resource_type == rhs.resource_type &&
    137         lhs.mime_type == rhs.mime_type &&
    138         lhs.was_cached == rhs.was_cached;
    139   }
    140 
    141   void ResetPredictor() {
    142     ResourcePrefetchPredictorConfig config;
    143     config.max_urls_to_track = 3;
    144     config.max_hosts_to_track = 2;
    145     config.min_url_visit_count = 2;
    146     config.max_resources_per_entry = 4;
    147     config.max_consecutive_misses = 2;
    148 
    149     // TODO(shishir): Enable the prefetching mode in the tests.
    150     config.mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
    151     config.mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
    152     predictor_.reset(new ResourcePrefetchPredictor(config, profile_.get()));
    153     predictor_->set_mock_tables(mock_tables_);
    154   }
    155 
    156   void InitializeSampleData();
    157 
    158   base::MessageLoop loop_;
    159   content::TestBrowserThread ui_thread_;
    160   content::TestBrowserThread db_thread_;
    161   scoped_ptr<TestingProfile> profile_;
    162 
    163   scoped_ptr<ResourcePrefetchPredictor> predictor_;
    164   scoped_refptr<StrictMock<MockResourcePrefetchPredictorTables> > mock_tables_;
    165 
    166   PrefetchDataMap test_url_data_;
    167   PrefetchDataMap test_host_data_;
    168   PrefetchData empty_url_data_;
    169   PrefetchData empty_host_data_;
    170 };
    171 
    172 ResourcePrefetchPredictorTest::ResourcePrefetchPredictorTest()
    173     : loop_(base::MessageLoop::TYPE_DEFAULT),
    174       ui_thread_(content::BrowserThread::UI, &loop_),
    175       db_thread_(content::BrowserThread::DB, &loop_),
    176       profile_(new TestingProfile()),
    177       mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()),
    178       empty_url_data_(PREFETCH_KEY_TYPE_URL, std::string()),
    179       empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()) {}
    180 
    181 ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() {
    182   profile_.reset(NULL);
    183   loop_.RunUntilIdle();
    184 }
    185 
    186 void ResourcePrefetchPredictorTest::SetUp() {
    187   InitializeSampleData();
    188 
    189   ASSERT_TRUE(profile_->CreateHistoryService(true, false));
    190   profile_->BlockUntilHistoryProcessesPendingRequests();
    191   EXPECT_TRUE(HistoryServiceFactory::GetForProfile(profile_.get(),
    192                                                    Profile::EXPLICIT_ACCESS));
    193   // Initialize the predictor with empty data.
    194   ResetPredictor();
    195   EXPECT_EQ(predictor_->initialization_state_,
    196             ResourcePrefetchPredictor::NOT_INITIALIZED);
    197   EXPECT_CALL(*mock_tables_.get(),
    198               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
    199                          Pointee(ContainerEq(PrefetchDataMap()))));
    200   InitializePredictor();
    201   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
    202   EXPECT_EQ(predictor_->initialization_state_,
    203             ResourcePrefetchPredictor::INITIALIZED);
    204 }
    205 
    206 void ResourcePrefetchPredictorTest::TearDown() {
    207   predictor_.reset(NULL);
    208   profile_->DestroyHistoryService();
    209 }
    210 
    211 void ResourcePrefetchPredictorTest::InitializeSampleData() {
    212   {  // Url data.
    213     PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
    214     google.last_visit = base::Time::FromInternalValue(1);
    215     google.resources.push_back(ResourceRow(std::string(),
    216                                            "http://google.com/style1.css",
    217                                            ResourceType::STYLESHEET,
    218                                            3,
    219                                            2,
    220                                            1,
    221                                            1.0));
    222     google.resources.push_back(ResourceRow(std::string(),
    223                                            "http://google.com/script3.js",
    224                                            ResourceType::SCRIPT,
    225                                            4,
    226                                            0,
    227                                            1,
    228                                            2.1));
    229     google.resources.push_back(ResourceRow(std::string(),
    230                                            "http://google.com/script4.js",
    231                                            ResourceType::SCRIPT,
    232                                            11,
    233                                            0,
    234                                            0,
    235                                            2.1));
    236     google.resources.push_back(ResourceRow(std::string(),
    237                                            "http://google.com/image1.png",
    238                                            ResourceType::IMAGE,
    239                                            6,
    240                                            3,
    241                                            0,
    242                                            2.2));
    243     google.resources.push_back(ResourceRow(std::string(),
    244                                            "http://google.com/a.font",
    245                                            ResourceType::LAST_TYPE,
    246                                            2,
    247                                            0,
    248                                            0,
    249                                            5.1));
    250 
    251     PrefetchData reddit(PREFETCH_KEY_TYPE_URL, "http://www.reddit.com/");
    252     reddit.last_visit = base::Time::FromInternalValue(2);
    253     reddit.resources
    254         .push_back(ResourceRow(std::string(),
    255                                "http://reddit-resource.com/script1.js",
    256                                ResourceType::SCRIPT,
    257                                4,
    258                                0,
    259                                1,
    260                                1.0));
    261     reddit.resources
    262         .push_back(ResourceRow(std::string(),
    263                                "http://reddit-resource.com/script2.js",
    264                                ResourceType::SCRIPT,
    265                                2,
    266                                0,
    267                                0,
    268                                2.1));
    269 
    270     PrefetchData yahoo(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/");
    271     yahoo.last_visit = base::Time::FromInternalValue(3);
    272     yahoo.resources.push_back(ResourceRow(std::string(),
    273                                           "http://google.com/image.png",
    274                                           ResourceType::IMAGE,
    275                                           20,
    276                                           1,
    277                                           0,
    278                                           10.0));
    279 
    280     test_url_data_.clear();
    281     test_url_data_.insert(std::make_pair("http://www.google.com/", google));
    282     test_url_data_.insert(std::make_pair("http://www.reddit.com/", reddit));
    283     test_url_data_.insert(std::make_pair("http://www.yahoo.com/", yahoo));
    284   }
    285 
    286   {  // Host data.
    287     PrefetchData facebook(PREFETCH_KEY_TYPE_HOST, "www.facebook.com");
    288     facebook.last_visit = base::Time::FromInternalValue(4);
    289     facebook.resources
    290         .push_back(ResourceRow(std::string(),
    291                                "http://www.facebook.com/style.css",
    292                                ResourceType::STYLESHEET,
    293                                5,
    294                                2,
    295                                1,
    296                                1.1));
    297     facebook.resources
    298         .push_back(ResourceRow(std::string(),
    299                                "http://www.facebook.com/script.js",
    300                                ResourceType::SCRIPT,
    301                                4,
    302                                0,
    303                                1,
    304                                2.1));
    305     facebook.resources
    306         .push_back(ResourceRow(std::string(),
    307                                "http://www.facebook.com/image.png",
    308                                ResourceType::IMAGE,
    309                                6,
    310                                3,
    311                                0,
    312                                2.2));
    313     facebook.resources.push_back(ResourceRow(std::string(),
    314                                              "http://www.facebook.com/a.font",
    315                                              ResourceType::LAST_TYPE,
    316                                              2,
    317                                              0,
    318                                              0,
    319                                              5.1));
    320     facebook.resources
    321         .push_back(ResourceRow(std::string(),
    322                                "http://www.resources.facebook.com/script.js",
    323                                ResourceType::SCRIPT,
    324                                11,
    325                                0,
    326                                0,
    327                                8.5));
    328 
    329     PrefetchData yahoo(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com");
    330     yahoo.last_visit = base::Time::FromInternalValue(5);
    331     yahoo.resources.push_back(ResourceRow(std::string(),
    332                                           "http://google.com/image.png",
    333                                           ResourceType::IMAGE,
    334                                           20,
    335                                           1,
    336                                           0,
    337                                           10.0));
    338 
    339     test_host_data_.clear();
    340     test_host_data_.insert(std::make_pair("www.facebook.com", facebook));
    341     test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo));
    342   }
    343 }
    344 
    345 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeEmpty) {
    346   // Tests that the predictor initializes correctly without any data.
    347   EXPECT_TRUE(predictor_->url_table_cache_->empty());
    348   EXPECT_TRUE(predictor_->host_table_cache_->empty());
    349 }
    350 
    351 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeWithData) {
    352   // Tests that the history and the db tables data are loaded correctly.
    353   AddUrlToHistory("http://www.google.com/", 4);
    354   AddUrlToHistory("http://www.yahoo.com/", 2);
    355 
    356   EXPECT_CALL(*mock_tables_.get(),
    357               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
    358                          Pointee(ContainerEq(PrefetchDataMap()))))
    359       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
    360                       SetArgPointee<1>(test_host_data_)));
    361 
    362   ResetPredictor();
    363   InitializePredictor();
    364 
    365   // Test that the internal variables correctly initialized.
    366   EXPECT_EQ(predictor_->initialization_state_,
    367             ResourcePrefetchPredictor::INITIALIZED);
    368   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
    369 
    370   EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_);
    371   EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_);
    372 }
    373 
    374 TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) {
    375   // Single navigation but history count is low, so should not record.
    376   AddUrlToHistory("http://www.google.com", 1);
    377 
    378   URLRequestSummary main_frame =
    379       CreateURLRequestSummary(1,
    380                               1,
    381                               "http://www.google.com",
    382                               "http://www.google.com",
    383                               ResourceType::MAIN_FRAME,
    384                               std::string(),
    385                               false);
    386   predictor_->RecordURLRequest(main_frame);
    387   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    388 
    389   // Now add a few subresources.
    390   URLRequestSummary resource1 = CreateURLRequestSummary(
    391       1, 1, "http://www.google.com",  "http://google.com/style1.css",
    392       ResourceType::STYLESHEET, "text/css", false);
    393   predictor_->RecordURLResponse(resource1);
    394   URLRequestSummary resource2 = CreateURLRequestSummary(
    395       1, 1, "http://www.google.com",  "http://google.com/script1.js",
    396       ResourceType::SCRIPT, "text/javascript", false);
    397   predictor_->RecordURLResponse(resource2);
    398   URLRequestSummary resource3 = CreateURLRequestSummary(
    399       1, 1, "http://www.google.com",  "http://google.com/script2.js",
    400       ResourceType::SCRIPT, "text/javascript", false);
    401   predictor_->RecordURLResponse(resource3);
    402 
    403   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
    404   host_data.resources.push_back(ResourceRow(std::string(),
    405                                             "http://google.com/style1.css",
    406                                             ResourceType::STYLESHEET,
    407                                             1,
    408                                             0,
    409                                             0,
    410                                             1.0));
    411   host_data.resources.push_back(ResourceRow(std::string(),
    412                                             "http://google.com/script1.js",
    413                                             ResourceType::SCRIPT,
    414                                             1,
    415                                             0,
    416                                             0,
    417                                             2.0));
    418   host_data.resources.push_back(ResourceRow(std::string(),
    419                                             "http://google.com/script2.js",
    420                                             ResourceType::SCRIPT,
    421                                             1,
    422                                             0,
    423                                             0,
    424                                             3.0));
    425   EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
    426 
    427   predictor_->OnNavigationComplete(main_frame.navigation_id);
    428   profile_->BlockUntilHistoryProcessesPendingRequests();
    429 }
    430 
    431 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDB) {
    432   // Single navigation that will be recorded. Will check for duplicate
    433   // resources and also for number of resources saved.
    434   AddUrlToHistory("http://www.google.com", 4);
    435 
    436   URLRequestSummary main_frame =
    437       CreateURLRequestSummary(1,
    438                               1,
    439                               "http://www.google.com",
    440                               "http://www.google.com",
    441                               ResourceType::MAIN_FRAME,
    442                               std::string(),
    443                               false);
    444   predictor_->RecordURLRequest(main_frame);
    445   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    446 
    447   URLRequestSummary resource1 = CreateURLRequestSummary(
    448       1, 1, "http://www.google.com",  "http://google.com/style1.css",
    449       ResourceType::STYLESHEET, "text/css", false);
    450   predictor_->RecordURLResponse(resource1);
    451   URLRequestSummary resource2 = CreateURLRequestSummary(
    452       1, 1, "http://www.google.com",  "http://google.com/script1.js",
    453       ResourceType::SCRIPT, "text/javascript", false);
    454   predictor_->RecordURLResponse(resource2);
    455   URLRequestSummary resource3 = CreateURLRequestSummary(
    456       1, 1, "http://www.google.com",  "http://google.com/script2.js",
    457       ResourceType::SCRIPT, "text/javascript", false);
    458   predictor_->RecordURLResponse(resource3);
    459   URLRequestSummary resource4 = CreateURLRequestSummary(
    460       1, 1, "http://www.google.com",  "http://google.com/script1.js",
    461       ResourceType::SCRIPT, "text/javascript", true);
    462   predictor_->RecordURLResponse(resource4);
    463   URLRequestSummary resource5 = CreateURLRequestSummary(
    464       1, 1, "http://www.google.com",  "http://google.com/image1.png",
    465       ResourceType::IMAGE, "image/png", false);
    466   predictor_->RecordURLResponse(resource5);
    467   URLRequestSummary resource6 = CreateURLRequestSummary(
    468       1, 1, "http://www.google.com",  "http://google.com/image2.png",
    469       ResourceType::IMAGE, "image/png", false);
    470   predictor_->RecordURLResponse(resource6);
    471   URLRequestSummary resource7 = CreateURLRequestSummary(
    472       1, 1, "http://www.google.com",  "http://google.com/style2.css",
    473       ResourceType::STYLESHEET, "text/css", true);
    474   predictor_->RecordURLResponse(resource7);
    475 
    476   PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
    477   url_data.resources.push_back(ResourceRow(std::string(),
    478                                            "http://google.com/style1.css",
    479                                            ResourceType::STYLESHEET,
    480                                            1,
    481                                            0,
    482                                            0,
    483                                            1.0));
    484   url_data.resources.push_back(ResourceRow(std::string(),
    485                                            "http://google.com/script1.js",
    486                                            ResourceType::SCRIPT,
    487                                            1,
    488                                            0,
    489                                            0,
    490                                            2.0));
    491   url_data.resources.push_back(ResourceRow(std::string(),
    492                                            "http://google.com/script2.js",
    493                                            ResourceType::SCRIPT,
    494                                            1,
    495                                            0,
    496                                            0,
    497                                            3.0));
    498   url_data.resources.push_back(ResourceRow(std::string(),
    499                                            "http://google.com/style2.css",
    500                                            ResourceType::STYLESHEET,
    501                                            1,
    502                                            0,
    503                                            0,
    504                                            7.0));
    505   EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
    506 
    507   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
    508   host_data.resources = url_data.resources;
    509   EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
    510 
    511   predictor_->OnNavigationComplete(main_frame.navigation_id);
    512   profile_->BlockUntilHistoryProcessesPendingRequests();
    513 }
    514 
    515 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) {
    516   // Tests that navigation is recorded correctly for URL already present in
    517   // the database cache.
    518   AddUrlToHistory("http://www.google.com", 4);
    519 
    520   EXPECT_CALL(*mock_tables_.get(),
    521               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
    522                          Pointee(ContainerEq(PrefetchDataMap()))))
    523       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
    524                       SetArgPointee<1>(test_host_data_)));
    525   ResetPredictor();
    526   InitializePredictor();
    527   EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size()));
    528   EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size()));
    529 
    530   URLRequestSummary main_frame =
    531       CreateURLRequestSummary(1,
    532                               1,
    533                               "http://www.google.com",
    534                               "http://www.google.com",
    535                               ResourceType::MAIN_FRAME,
    536                               std::string(),
    537                               false);
    538   predictor_->RecordURLRequest(main_frame);
    539   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    540 
    541   URLRequestSummary resource1 = CreateURLRequestSummary(
    542       1, 1, "http://www.google.com",  "http://google.com/style1.css",
    543       ResourceType::STYLESHEET, "text/css", false);
    544   predictor_->RecordURLResponse(resource1);
    545   URLRequestSummary resource2 = CreateURLRequestSummary(
    546       1, 1, "http://www.google.com",  "http://google.com/script1.js",
    547       ResourceType::SCRIPT, "text/javascript", false);
    548   predictor_->RecordURLResponse(resource2);
    549   URLRequestSummary resource3 = CreateURLRequestSummary(
    550       1, 1, "http://www.google.com",  "http://google.com/script2.js",
    551       ResourceType::SCRIPT, "text/javascript", false);
    552   predictor_->RecordURLResponse(resource3);
    553   URLRequestSummary resource4 = CreateURLRequestSummary(
    554       1, 1, "http://www.google.com",  "http://google.com/script1.js",
    555       ResourceType::SCRIPT, "text/javascript", true);
    556   predictor_->RecordURLResponse(resource4);
    557   URLRequestSummary resource5 = CreateURLRequestSummary(
    558       1, 1, "http://www.google.com",  "http://google.com/image1.png",
    559       ResourceType::IMAGE, "image/png", false);
    560   predictor_->RecordURLResponse(resource5);
    561   URLRequestSummary resource6 = CreateURLRequestSummary(
    562       1, 1, "http://www.google.com",  "http://google.com/image2.png",
    563       ResourceType::IMAGE, "image/png", false);
    564   predictor_->RecordURLResponse(resource6);
    565   URLRequestSummary resource7 = CreateURLRequestSummary(
    566       1, 1, "http://www.google.com",  "http://google.com/style2.css",
    567       ResourceType::STYLESHEET, "text/css", true);
    568   predictor_->RecordURLResponse(resource7);
    569 
    570   PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
    571   url_data.resources.push_back(ResourceRow(std::string(),
    572                                            "http://google.com/style1.css",
    573                                            ResourceType::STYLESHEET,
    574                                            4,
    575                                            2,
    576                                            0,
    577                                            1.0));
    578   url_data.resources.push_back(ResourceRow(std::string(),
    579                                            "http://google.com/script1.js",
    580                                            ResourceType::SCRIPT,
    581                                            1,
    582                                            0,
    583                                            0,
    584                                            2.0));
    585   url_data.resources.push_back(ResourceRow(std::string(),
    586                                            "http://google.com/script4.js",
    587                                            ResourceType::SCRIPT,
    588                                            11,
    589                                            1,
    590                                            1,
    591                                            2.1));
    592   url_data.resources.push_back(ResourceRow(std::string(),
    593                                            "http://google.com/script2.js",
    594                                            ResourceType::SCRIPT,
    595                                            1,
    596                                            0,
    597                                            0,
    598                                            3.0));
    599   EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
    600 
    601   EXPECT_CALL(
    602       *mock_tables_.get(),
    603       DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
    604 
    605   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
    606   host_data.resources.push_back(ResourceRow(std::string(),
    607                                             "http://google.com/style1.css",
    608                                             ResourceType::STYLESHEET,
    609                                             1,
    610                                             0,
    611                                             0,
    612                                             1.0));
    613   host_data.resources.push_back(ResourceRow(std::string(),
    614                                             "http://google.com/script1.js",
    615                                             ResourceType::SCRIPT,
    616                                             1,
    617                                             0,
    618                                             0,
    619                                             2.0));
    620   host_data.resources.push_back(ResourceRow(std::string(),
    621                                             "http://google.com/script2.js",
    622                                             ResourceType::SCRIPT,
    623                                             1,
    624                                             0,
    625                                             0,
    626                                             3.0));
    627   host_data.resources.push_back(ResourceRow(std::string(),
    628                                             "http://google.com/style2.css",
    629                                             ResourceType::STYLESHEET,
    630                                             1,
    631                                             0,
    632                                             0,
    633                                             7.0));
    634   EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
    635 
    636   predictor_->OnNavigationComplete(main_frame.navigation_id);
    637   profile_->BlockUntilHistoryProcessesPendingRequests();
    638 }
    639 
    640 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDBAndDBFull) {
    641   // Tests that a URL is deleted before another is added if the cache is full.
    642   AddUrlToHistory("http://www.nike.com/", 4);
    643 
    644   EXPECT_CALL(*mock_tables_.get(),
    645               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
    646                          Pointee(ContainerEq(PrefetchDataMap()))))
    647       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
    648                       SetArgPointee<1>(test_host_data_)));
    649   ResetPredictor();
    650   InitializePredictor();
    651   EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size()));
    652   EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size()));
    653 
    654   URLRequestSummary main_frame =
    655       CreateURLRequestSummary(1,
    656                               1,
    657                               "http://www.nike.com",
    658                               "http://www.nike.com",
    659                               ResourceType::MAIN_FRAME,
    660                               std::string(),
    661                               false);
    662   predictor_->RecordURLRequest(main_frame);
    663   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    664 
    665   URLRequestSummary resource1 = CreateURLRequestSummary(
    666       1, 1, "http://www.nike.com",  "http://nike.com/style1.css",
    667       ResourceType::STYLESHEET, "text/css", false);
    668   predictor_->RecordURLResponse(resource1);
    669   URLRequestSummary resource2 = CreateURLRequestSummary(
    670       1, 1, "http://www.nike.com",  "http://nike.com/image2.png",
    671       ResourceType::IMAGE, "image/png", false);
    672   predictor_->RecordURLResponse(resource2);
    673 
    674   EXPECT_CALL(
    675       *mock_tables_.get(),
    676       DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL));
    677   EXPECT_CALL(
    678       *mock_tables_.get(),
    679       DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
    680 
    681   PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/");
    682   url_data.resources.push_back(ResourceRow(std::string(),
    683                                            "http://nike.com/style1.css",
    684                                            ResourceType::STYLESHEET,
    685                                            1,
    686                                            0,
    687                                            0,
    688                                            1.0));
    689   url_data.resources.push_back(ResourceRow(std::string(),
    690                                            "http://nike.com/image2.png",
    691                                            ResourceType::IMAGE,
    692                                            1,
    693                                            0,
    694                                            0,
    695                                            2.0));
    696   EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
    697 
    698   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.nike.com");
    699   host_data.resources = url_data.resources;
    700   EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
    701 
    702   predictor_->OnNavigationComplete(main_frame.navigation_id);
    703   profile_->BlockUntilHistoryProcessesPendingRequests();
    704 }
    705 
    706 TEST_F(ResourcePrefetchPredictorTest, DeleteUrls) {
    707   // Add some dummy entries to cache.
    708   predictor_->url_table_cache_->insert(std::make_pair(
    709       "http://www.google.com/page1.html",
    710       PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page1.html")));
    711   predictor_->url_table_cache_->insert(std::make_pair(
    712       "http://www.google.com/page2.html",
    713       PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page2.html")));
    714   predictor_->url_table_cache_->insert(std::make_pair(
    715       "http://www.yahoo.com/",
    716       PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/")));
    717   predictor_->url_table_cache_->insert(std::make_pair(
    718       "http://www.apple.com/",
    719       PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.apple.com/")));
    720   predictor_->url_table_cache_->insert(std::make_pair(
    721       "http://www.nike.com/",
    722       PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/")));
    723 
    724   predictor_->host_table_cache_->insert(std::make_pair(
    725       "www.google.com",
    726       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.google.com")));
    727   predictor_->host_table_cache_->insert(std::make_pair(
    728       "www.yahoo.com",
    729       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com")));
    730   predictor_->host_table_cache_->insert(std::make_pair(
    731       "www.apple.com",
    732       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com")));
    733 
    734   history::URLRows rows;
    735   rows.push_back(history::URLRow(GURL("http://www.google.com/page2.html")));
    736   rows.push_back(history::URLRow(GURL("http://www.apple.com")));
    737   rows.push_back(history::URLRow(GURL("http://www.nike.com")));
    738 
    739   std::vector<std::string> urls_to_delete, hosts_to_delete;
    740   urls_to_delete.push_back("http://www.google.com/page2.html");
    741   urls_to_delete.push_back("http://www.apple.com/");
    742   urls_to_delete.push_back("http://www.nike.com/");
    743   hosts_to_delete.push_back("www.google.com");
    744   hosts_to_delete.push_back("www.apple.com");
    745 
    746   EXPECT_CALL(
    747       *mock_tables_.get(),
    748       DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete)));
    749 
    750   predictor_->DeleteUrls(rows);
    751   EXPECT_EQ(2, static_cast<int>(predictor_->url_table_cache_->size()));
    752   EXPECT_EQ(1, static_cast<int>(predictor_->host_table_cache_->size()));
    753 
    754   EXPECT_CALL(*mock_tables_.get(), DeleteAllData());
    755 
    756   predictor_->DeleteAllUrls();
    757   EXPECT_TRUE(predictor_->url_table_cache_->empty());
    758   EXPECT_TRUE(predictor_->host_table_cache_->empty());
    759 }
    760 
    761 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) {
    762   URLRequestSummary summary1 = CreateURLRequestSummary(1,
    763                                                        1,
    764                                                        "http://www.google.com",
    765                                                        "http://www.google.com",
    766                                                        ResourceType::MAIN_FRAME,
    767                                                        std::string(),
    768                                                        false);
    769   URLRequestSummary summary2 = CreateURLRequestSummary(1,
    770                                                        2,
    771                                                        "http://www.google.com",
    772                                                        "http://www.google.com",
    773                                                        ResourceType::MAIN_FRAME,
    774                                                        std::string(),
    775                                                        false);
    776   URLRequestSummary summary3 = CreateURLRequestSummary(2,
    777                                                        1,
    778                                                        "http://www.yahoo.com",
    779                                                        "http://www.yahoo.com",
    780                                                        ResourceType::MAIN_FRAME,
    781                                                        std::string(),
    782                                                        false);
    783 
    784   predictor_->OnMainFrameRequest(summary1);
    785   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    786   predictor_->OnMainFrameRequest(summary2);
    787   EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
    788   predictor_->OnMainFrameRequest(summary3);
    789   EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
    790 
    791   // Insert anther with same navigation id. It should replace.
    792   URLRequestSummary summary4 = CreateURLRequestSummary(1,
    793                                                        1,
    794                                                        "http://www.nike.com",
    795                                                        "http://www.nike.com",
    796                                                        ResourceType::MAIN_FRAME,
    797                                                        std::string(),
    798                                                        false);
    799   URLRequestSummary summary5 = CreateURLRequestSummary(1,
    800                                                        2,
    801                                                        "http://www.google.com",
    802                                                        "http://www.google.com",
    803                                                        ResourceType::MAIN_FRAME,
    804                                                        std::string(),
    805                                                        false);
    806 
    807   predictor_->OnMainFrameRequest(summary4);
    808   EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
    809 
    810   // Change this creation time so that it will go away on the next insert.
    811   summary5.navigation_id.creation_time = base::TimeTicks::Now() -
    812       base::TimeDelta::FromDays(1);
    813   predictor_->OnMainFrameRequest(summary5);
    814   EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
    815 
    816   URLRequestSummary summary6 = CreateURLRequestSummary(3,
    817                                                        1,
    818                                                        "http://www.shoes.com",
    819                                                        "http://www.shoes.com",
    820                                                        ResourceType::MAIN_FRAME,
    821                                                        std::string(),
    822                                                        false);
    823   predictor_->OnMainFrameRequest(summary6);
    824   EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
    825 
    826   EXPECT_TRUE(predictor_->inflight_navigations_.find(summary3.navigation_id) !=
    827               predictor_->inflight_navigations_.end());
    828   EXPECT_TRUE(predictor_->inflight_navigations_.find(summary4.navigation_id) !=
    829               predictor_->inflight_navigations_.end());
    830   EXPECT_TRUE(predictor_->inflight_navigations_.find(summary6.navigation_id) !=
    831               predictor_->inflight_navigations_.end());
    832 }
    833 
    834 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) {
    835   URLRequestSummary summary1 = CreateURLRequestSummary(1,
    836                                                        1,
    837                                                        "http://www.google.com",
    838                                                        "http://www.google.com",
    839                                                        ResourceType::MAIN_FRAME,
    840                                                        std::string(),
    841                                                        false);
    842   URLRequestSummary summary2 = CreateURLRequestSummary(1,
    843                                                        2,
    844                                                        "http://www.google.com",
    845                                                        "http://www.google.com",
    846                                                        ResourceType::MAIN_FRAME,
    847                                                        std::string(),
    848                                                        false);
    849   URLRequestSummary summary3 = CreateURLRequestSummary(2,
    850                                                        1,
    851                                                        "http://www.yahoo.com",
    852                                                        "http://www.yahoo.com",
    853                                                        ResourceType::MAIN_FRAME,
    854                                                        std::string(),
    855                                                        false);
    856 
    857   predictor_->OnMainFrameRedirect(summary1);
    858   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
    859 
    860   predictor_->OnMainFrameRequest(summary1);
    861   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    862   predictor_->OnMainFrameRequest(summary2);
    863   EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
    864 
    865   predictor_->OnMainFrameRedirect(summary3);
    866   EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
    867   predictor_->OnMainFrameRedirect(summary1);
    868   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    869   predictor_->OnMainFrameRedirect(summary2);
    870   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
    871 }
    872 
    873 TEST_F(ResourcePrefetchPredictorTest, OnSubresourceResponse) {
    874   // If there is no inflight navigation, nothing happens.
    875   URLRequestSummary resource1 = CreateURLRequestSummary(
    876       1, 1, "http://www.google.com",  "http://google.com/style1.css",
    877       ResourceType::STYLESHEET, "text/css", false);
    878   predictor_->OnSubresourceResponse(resource1);
    879   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
    880 
    881   // Add an inflight navigation.
    882   URLRequestSummary main_frame1 =
    883       CreateURLRequestSummary(1,
    884                               1,
    885                               "http://www.google.com",
    886                               "http://www.google.com",
    887                               ResourceType::MAIN_FRAME,
    888                               std::string(),
    889                               false);
    890   predictor_->OnMainFrameRequest(main_frame1);
    891   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    892 
    893   // Now add a few subresources.
    894   URLRequestSummary resource2 = CreateURLRequestSummary(
    895       1, 1, "http://www.google.com",  "http://google.com/script1.js",
    896       ResourceType::SCRIPT, "text/javascript", false);
    897   URLRequestSummary resource3 = CreateURLRequestSummary(
    898       1, 1, "http://www.google.com",  "http://google.com/script2.js",
    899       ResourceType::SCRIPT, "text/javascript", false);
    900   predictor_->OnSubresourceResponse(resource1);
    901   predictor_->OnSubresourceResponse(resource2);
    902   predictor_->OnSubresourceResponse(resource3);
    903 
    904   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
    905   EXPECT_EQ(3, static_cast<int>(
    906       predictor_->inflight_navigations_[main_frame1.navigation_id]->size()));
    907   EXPECT_TRUE(URLRequestSummaryAreEqual(
    908       resource1,
    909       predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0)));
    910   EXPECT_TRUE(URLRequestSummaryAreEqual(
    911       resource2,
    912       predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1)));
    913   EXPECT_TRUE(URLRequestSummaryAreEqual(
    914       resource3,
    915       predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2)));
    916 }
    917 
    918 }  // namespace predictors
    919