resource_prefetch_predictor_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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.h" 9#include "base/run_loop.h" 10#include "base/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 23using testing::ContainerEq; 24using testing::Pointee; 25using testing::SetArgPointee; 26using testing::StrictMock; 27 28namespace predictors { 29 30typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary; 31typedef ResourcePrefetchPredictorTables::ResourceRow ResourceRow; 32typedef std::vector<ResourceRow> ResourceRows; 33typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData; 34typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap; 35 36// For printing failures nicely. 37void 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 44void 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 55class 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 74class 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 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 172ResourcePrefetchPredictorTest::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 predictor_(NULL), 178 mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()), 179 empty_url_data_(PREFETCH_KEY_TYPE_URL, std::string()), 180 empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()) {} 181 182ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() { 183 profile_.reset(NULL); 184 loop_.RunUntilIdle(); 185} 186 187void ResourcePrefetchPredictorTest::SetUp() { 188 InitializeSampleData(); 189 190 profile_->CreateHistoryService(true, false); 191 profile_->BlockUntilHistoryProcessesPendingRequests(); 192 EXPECT_TRUE(HistoryServiceFactory::GetForProfile(profile_.get(), 193 Profile::EXPLICIT_ACCESS)); 194 // Initialize the predictor with empty data. 195 ResetPredictor(); 196 EXPECT_EQ(predictor_->initialization_state_, 197 ResourcePrefetchPredictor::NOT_INITIALIZED); 198 EXPECT_CALL(*mock_tables_.get(), 199 GetAllData(Pointee(ContainerEq(PrefetchDataMap())), 200 Pointee(ContainerEq(PrefetchDataMap())))); 201 InitializePredictor(); 202 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 203 EXPECT_EQ(predictor_->initialization_state_, 204 ResourcePrefetchPredictor::INITIALIZED); 205} 206 207void ResourcePrefetchPredictorTest::TearDown() { 208 predictor_.reset(NULL); 209 profile_->DestroyHistoryService(); 210} 211 212void ResourcePrefetchPredictorTest::InitializeSampleData() { 213 { // Url data. 214 PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com/"); 215 google.last_visit = base::Time::FromInternalValue(1); 216 google.resources.push_back(ResourceRow(std::string(), 217 "http://google.com/style1.css", 218 ResourceType::STYLESHEET, 219 3, 220 2, 221 1, 222 1.0)); 223 google.resources.push_back(ResourceRow(std::string(), 224 "http://google.com/script3.js", 225 ResourceType::SCRIPT, 226 4, 227 0, 228 1, 229 2.1)); 230 google.resources.push_back(ResourceRow(std::string(), 231 "http://google.com/script4.js", 232 ResourceType::SCRIPT, 233 11, 234 0, 235 0, 236 2.1)); 237 google.resources.push_back(ResourceRow(std::string(), 238 "http://google.com/image1.png", 239 ResourceType::IMAGE, 240 6, 241 3, 242 0, 243 2.2)); 244 google.resources.push_back(ResourceRow(std::string(), 245 "http://google.com/a.font", 246 ResourceType::LAST_TYPE, 247 2, 248 0, 249 0, 250 5.1)); 251 252 PrefetchData reddit(PREFETCH_KEY_TYPE_URL, "http://www.reddit.com/"); 253 reddit.last_visit = base::Time::FromInternalValue(2); 254 reddit.resources 255 .push_back(ResourceRow(std::string(), 256 "http://reddit-resource.com/script1.js", 257 ResourceType::SCRIPT, 258 4, 259 0, 260 1, 261 1.0)); 262 reddit.resources 263 .push_back(ResourceRow(std::string(), 264 "http://reddit-resource.com/script2.js", 265 ResourceType::SCRIPT, 266 2, 267 0, 268 0, 269 2.1)); 270 271 PrefetchData yahoo(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/"); 272 yahoo.last_visit = base::Time::FromInternalValue(3); 273 yahoo.resources.push_back(ResourceRow(std::string(), 274 "http://google.com/image.png", 275 ResourceType::IMAGE, 276 20, 277 1, 278 0, 279 10.0)); 280 281 test_url_data_.clear(); 282 test_url_data_.insert(std::make_pair("http://www.google.com/", google)); 283 test_url_data_.insert(std::make_pair("http://www.reddit.com/", reddit)); 284 test_url_data_.insert(std::make_pair("http://www.yahoo.com/", yahoo)); 285 } 286 287 { // Host data. 288 PrefetchData facebook(PREFETCH_KEY_TYPE_HOST, "www.facebook.com"); 289 facebook.last_visit = base::Time::FromInternalValue(4); 290 facebook.resources 291 .push_back(ResourceRow(std::string(), 292 "http://www.facebook.com/style.css", 293 ResourceType::STYLESHEET, 294 5, 295 2, 296 1, 297 1.1)); 298 facebook.resources 299 .push_back(ResourceRow(std::string(), 300 "http://www.facebook.com/script.js", 301 ResourceType::SCRIPT, 302 4, 303 0, 304 1, 305 2.1)); 306 facebook.resources 307 .push_back(ResourceRow(std::string(), 308 "http://www.facebook.com/image.png", 309 ResourceType::IMAGE, 310 6, 311 3, 312 0, 313 2.2)); 314 facebook.resources.push_back(ResourceRow(std::string(), 315 "http://www.facebook.com/a.font", 316 ResourceType::LAST_TYPE, 317 2, 318 0, 319 0, 320 5.1)); 321 facebook.resources 322 .push_back(ResourceRow(std::string(), 323 "http://www.resources.facebook.com/script.js", 324 ResourceType::SCRIPT, 325 11, 326 0, 327 0, 328 8.5)); 329 330 PrefetchData yahoo(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com"); 331 yahoo.last_visit = base::Time::FromInternalValue(5); 332 yahoo.resources.push_back(ResourceRow(std::string(), 333 "http://google.com/image.png", 334 ResourceType::IMAGE, 335 20, 336 1, 337 0, 338 10.0)); 339 340 test_host_data_.clear(); 341 test_host_data_.insert(std::make_pair("www.facebook.com", facebook)); 342 test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo)); 343 } 344} 345 346TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeEmpty) { 347 // Tests that the predictor initializes correctly without any data. 348 EXPECT_TRUE(predictor_->url_table_cache_->empty()); 349 EXPECT_TRUE(predictor_->host_table_cache_->empty()); 350} 351 352TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeWithData) { 353 // Tests that the history and the db tables data are loaded correctly. 354 AddUrlToHistory("http://www.google.com/", 4); 355 AddUrlToHistory("http://www.yahoo.com/", 2); 356 357 EXPECT_CALL(*mock_tables_.get(), 358 GetAllData(Pointee(ContainerEq(PrefetchDataMap())), 359 Pointee(ContainerEq(PrefetchDataMap())))) 360 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), 361 SetArgPointee<1>(test_host_data_))); 362 363 ResetPredictor(); 364 InitializePredictor(); 365 366 // Test that the internal variables correctly initialized. 367 EXPECT_EQ(predictor_->initialization_state_, 368 ResourcePrefetchPredictor::INITIALIZED); 369 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 370 371 EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_); 372 EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_); 373} 374 375TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) { 376 // Single navigation but history count is low, so should not record. 377 AddUrlToHistory("http://www.google.com", 1); 378 379 URLRequestSummary main_frame = 380 CreateURLRequestSummary(1, 381 1, 382 "http://www.google.com", 383 "http://www.google.com", 384 ResourceType::MAIN_FRAME, 385 std::string(), 386 false); 387 predictor_->RecordURLRequest(main_frame); 388 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 389 390 // Now add a few subresources. 391 URLRequestSummary resource1 = CreateURLRequestSummary( 392 1, 1, "http://www.google.com", "http://google.com/style1.css", 393 ResourceType::STYLESHEET, "text/css", false); 394 predictor_->RecordUrlResponse(resource1); 395 URLRequestSummary resource2 = CreateURLRequestSummary( 396 1, 1, "http://www.google.com", "http://google.com/script1.js", 397 ResourceType::SCRIPT, "text/javascript", false); 398 predictor_->RecordUrlResponse(resource2); 399 URLRequestSummary resource3 = CreateURLRequestSummary( 400 1, 1, "http://www.google.com", "http://google.com/script2.js", 401 ResourceType::SCRIPT, "text/javascript", false); 402 predictor_->RecordUrlResponse(resource3); 403 404 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com"); 405 host_data.resources.push_back(ResourceRow(std::string(), 406 "http://google.com/style1.css", 407 ResourceType::STYLESHEET, 408 1, 409 0, 410 0, 411 1.0)); 412 host_data.resources.push_back(ResourceRow(std::string(), 413 "http://google.com/script1.js", 414 ResourceType::SCRIPT, 415 1, 416 0, 417 0, 418 2.0)); 419 host_data.resources.push_back(ResourceRow(std::string(), 420 "http://google.com/script2.js", 421 ResourceType::SCRIPT, 422 1, 423 0, 424 0, 425 3.0)); 426 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data)); 427 428 predictor_->OnNavigationComplete(main_frame.navigation_id); 429 profile_->BlockUntilHistoryProcessesPendingRequests(); 430} 431 432TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDB) { 433 // Single navigation that will be recorded. Will check for duplicate 434 // resources and also for number of resources saved. 435 AddUrlToHistory("http://www.google.com", 4); 436 437 URLRequestSummary main_frame = 438 CreateURLRequestSummary(1, 439 1, 440 "http://www.google.com", 441 "http://www.google.com", 442 ResourceType::MAIN_FRAME, 443 std::string(), 444 false); 445 predictor_->RecordURLRequest(main_frame); 446 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 447 448 URLRequestSummary resource1 = CreateURLRequestSummary( 449 1, 1, "http://www.google.com", "http://google.com/style1.css", 450 ResourceType::STYLESHEET, "text/css", false); 451 predictor_->RecordUrlResponse(resource1); 452 URLRequestSummary resource2 = CreateURLRequestSummary( 453 1, 1, "http://www.google.com", "http://google.com/script1.js", 454 ResourceType::SCRIPT, "text/javascript", false); 455 predictor_->RecordUrlResponse(resource2); 456 URLRequestSummary resource3 = CreateURLRequestSummary( 457 1, 1, "http://www.google.com", "http://google.com/script2.js", 458 ResourceType::SCRIPT, "text/javascript", false); 459 predictor_->RecordUrlResponse(resource3); 460 URLRequestSummary resource4 = CreateURLRequestSummary( 461 1, 1, "http://www.google.com", "http://google.com/script1.js", 462 ResourceType::SCRIPT, "text/javascript", true); 463 predictor_->RecordUrlResponse(resource4); 464 URLRequestSummary resource5 = CreateURLRequestSummary( 465 1, 1, "http://www.google.com", "http://google.com/image1.png", 466 ResourceType::IMAGE, "image/png", false); 467 predictor_->RecordUrlResponse(resource5); 468 URLRequestSummary resource6 = CreateURLRequestSummary( 469 1, 1, "http://www.google.com", "http://google.com/image2.png", 470 ResourceType::IMAGE, "image/png", false); 471 predictor_->RecordUrlResponse(resource6); 472 URLRequestSummary resource7 = CreateURLRequestSummary( 473 1, 1, "http://www.google.com", "http://google.com/style2.css", 474 ResourceType::STYLESHEET, "text/css", false); 475 predictor_->OnSubresourceLoadedFromMemory( 476 resource7.navigation_id, 477 resource7.resource_url, 478 resource7.mime_type, 479 resource7.resource_type); 480 481 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/"); 482 url_data.resources.push_back(ResourceRow(std::string(), 483 "http://google.com/style1.css", 484 ResourceType::STYLESHEET, 485 1, 486 0, 487 0, 488 1.0)); 489 url_data.resources.push_back(ResourceRow(std::string(), 490 "http://google.com/script1.js", 491 ResourceType::SCRIPT, 492 1, 493 0, 494 0, 495 2.0)); 496 url_data.resources.push_back(ResourceRow(std::string(), 497 "http://google.com/script2.js", 498 ResourceType::SCRIPT, 499 1, 500 0, 501 0, 502 3.0)); 503 url_data.resources.push_back(ResourceRow(std::string(), 504 "http://google.com/style2.css", 505 ResourceType::STYLESHEET, 506 1, 507 0, 508 0, 509 7.0)); 510 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_)); 511 512 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com"); 513 host_data.resources = url_data.resources; 514 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data)); 515 516 predictor_->OnNavigationComplete(main_frame.navigation_id); 517 profile_->BlockUntilHistoryProcessesPendingRequests(); 518} 519 520TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) { 521 // Tests that navigation is recorded correctly for URL already present in 522 // the database cache. 523 AddUrlToHistory("http://www.google.com", 4); 524 525 EXPECT_CALL(*mock_tables_.get(), 526 GetAllData(Pointee(ContainerEq(PrefetchDataMap())), 527 Pointee(ContainerEq(PrefetchDataMap())))) 528 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), 529 SetArgPointee<1>(test_host_data_))); 530 ResetPredictor(); 531 InitializePredictor(); 532 EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size())); 533 EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size())); 534 535 URLRequestSummary main_frame = 536 CreateURLRequestSummary(1, 537 1, 538 "http://www.google.com", 539 "http://www.google.com", 540 ResourceType::MAIN_FRAME, 541 std::string(), 542 false); 543 predictor_->RecordURLRequest(main_frame); 544 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 545 546 URLRequestSummary resource1 = CreateURLRequestSummary( 547 1, 1, "http://www.google.com", "http://google.com/style1.css", 548 ResourceType::STYLESHEET, "text/css", false); 549 predictor_->RecordUrlResponse(resource1); 550 URLRequestSummary resource2 = CreateURLRequestSummary( 551 1, 1, "http://www.google.com", "http://google.com/script1.js", 552 ResourceType::SCRIPT, "text/javascript", false); 553 predictor_->RecordUrlResponse(resource2); 554 URLRequestSummary resource3 = CreateURLRequestSummary( 555 1, 1, "http://www.google.com", "http://google.com/script2.js", 556 ResourceType::SCRIPT, "text/javascript", false); 557 predictor_->RecordUrlResponse(resource3); 558 URLRequestSummary resource4 = CreateURLRequestSummary( 559 1, 1, "http://www.google.com", "http://google.com/script1.js", 560 ResourceType::SCRIPT, "text/javascript", true); 561 predictor_->RecordUrlResponse(resource4); 562 URLRequestSummary resource5 = CreateURLRequestSummary( 563 1, 1, "http://www.google.com", "http://google.com/image1.png", 564 ResourceType::IMAGE, "image/png", false); 565 predictor_->RecordUrlResponse(resource5); 566 URLRequestSummary resource6 = CreateURLRequestSummary( 567 1, 1, "http://www.google.com", "http://google.com/image2.png", 568 ResourceType::IMAGE, "image/png", false); 569 predictor_->RecordUrlResponse(resource6); 570 URLRequestSummary resource7 = CreateURLRequestSummary( 571 1, 1, "http://www.google.com", "http://google.com/style2.css", 572 ResourceType::STYLESHEET, "text/css", false); 573 predictor_->OnSubresourceLoadedFromMemory( 574 resource7.navigation_id, 575 resource7.resource_url, 576 resource7.mime_type, 577 resource7.resource_type); 578 579 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/"); 580 url_data.resources.push_back(ResourceRow(std::string(), 581 "http://google.com/style1.css", 582 ResourceType::STYLESHEET, 583 4, 584 2, 585 0, 586 1.0)); 587 url_data.resources.push_back(ResourceRow(std::string(), 588 "http://google.com/script1.js", 589 ResourceType::SCRIPT, 590 1, 591 0, 592 0, 593 2.0)); 594 url_data.resources.push_back(ResourceRow(std::string(), 595 "http://google.com/script4.js", 596 ResourceType::SCRIPT, 597 11, 598 1, 599 1, 600 2.1)); 601 url_data.resources.push_back(ResourceRow(std::string(), 602 "http://google.com/script2.js", 603 ResourceType::SCRIPT, 604 1, 605 0, 606 0, 607 3.0)); 608 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_)); 609 610 EXPECT_CALL( 611 *mock_tables_.get(), 612 DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST)); 613 614 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com"); 615 host_data.resources.push_back(ResourceRow(std::string(), 616 "http://google.com/style1.css", 617 ResourceType::STYLESHEET, 618 1, 619 0, 620 0, 621 1.0)); 622 host_data.resources.push_back(ResourceRow(std::string(), 623 "http://google.com/script1.js", 624 ResourceType::SCRIPT, 625 1, 626 0, 627 0, 628 2.0)); 629 host_data.resources.push_back(ResourceRow(std::string(), 630 "http://google.com/script2.js", 631 ResourceType::SCRIPT, 632 1, 633 0, 634 0, 635 3.0)); 636 host_data.resources.push_back(ResourceRow(std::string(), 637 "http://google.com/style2.css", 638 ResourceType::STYLESHEET, 639 1, 640 0, 641 0, 642 7.0)); 643 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data)); 644 645 predictor_->OnNavigationComplete(main_frame.navigation_id); 646 profile_->BlockUntilHistoryProcessesPendingRequests(); 647} 648 649TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDBAndDBFull) { 650 // Tests that a URL is deleted before another is added if the cache is full. 651 AddUrlToHistory("http://www.nike.com/", 4); 652 653 EXPECT_CALL(*mock_tables_.get(), 654 GetAllData(Pointee(ContainerEq(PrefetchDataMap())), 655 Pointee(ContainerEq(PrefetchDataMap())))) 656 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), 657 SetArgPointee<1>(test_host_data_))); 658 ResetPredictor(); 659 InitializePredictor(); 660 EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size())); 661 EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size())); 662 663 URLRequestSummary main_frame = 664 CreateURLRequestSummary(1, 665 1, 666 "http://www.nike.com", 667 "http://www.nike.com", 668 ResourceType::MAIN_FRAME, 669 std::string(), 670 false); 671 predictor_->RecordURLRequest(main_frame); 672 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 673 674 URLRequestSummary resource1 = CreateURLRequestSummary( 675 1, 1, "http://www.nike.com", "http://nike.com/style1.css", 676 ResourceType::STYLESHEET, "text/css", false); 677 predictor_->RecordUrlResponse(resource1); 678 URLRequestSummary resource2 = CreateURLRequestSummary( 679 1, 1, "http://www.nike.com", "http://nike.com/image2.png", 680 ResourceType::IMAGE, "image/png", false); 681 predictor_->RecordUrlResponse(resource2); 682 683 EXPECT_CALL( 684 *mock_tables_.get(), 685 DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL)); 686 EXPECT_CALL( 687 *mock_tables_.get(), 688 DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST)); 689 690 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/"); 691 url_data.resources.push_back(ResourceRow(std::string(), 692 "http://nike.com/style1.css", 693 ResourceType::STYLESHEET, 694 1, 695 0, 696 0, 697 1.0)); 698 url_data.resources.push_back(ResourceRow(std::string(), 699 "http://nike.com/image2.png", 700 ResourceType::IMAGE, 701 1, 702 0, 703 0, 704 2.0)); 705 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_)); 706 707 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.nike.com"); 708 host_data.resources = url_data.resources; 709 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data)); 710 711 predictor_->OnNavigationComplete(main_frame.navigation_id); 712 profile_->BlockUntilHistoryProcessesPendingRequests(); 713} 714 715TEST_F(ResourcePrefetchPredictorTest, DeleteUrls) { 716 // Add some dummy entries to cache. 717 predictor_->url_table_cache_->insert(std::make_pair( 718 "http://www.google.com/page1.html", 719 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page1.html"))); 720 predictor_->url_table_cache_->insert(std::make_pair( 721 "http://www.google.com/page2.html", 722 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page2.html"))); 723 predictor_->url_table_cache_->insert(std::make_pair( 724 "http://www.yahoo.com/", 725 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/"))); 726 predictor_->url_table_cache_->insert(std::make_pair( 727 "http://www.apple.com/", 728 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.apple.com/"))); 729 predictor_->url_table_cache_->insert(std::make_pair( 730 "http://www.nike.com/", 731 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/"))); 732 733 predictor_->host_table_cache_->insert(std::make_pair( 734 "www.google.com", 735 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.google.com"))); 736 predictor_->host_table_cache_->insert(std::make_pair( 737 "www.yahoo.com", 738 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com"))); 739 predictor_->host_table_cache_->insert(std::make_pair( 740 "www.apple.com", 741 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com"))); 742 743 history::URLRows rows; 744 rows.push_back(history::URLRow(GURL("http://www.google.com/page2.html"))); 745 rows.push_back(history::URLRow(GURL("http://www.apple.com"))); 746 rows.push_back(history::URLRow(GURL("http://www.nike.com"))); 747 748 std::vector<std::string> urls_to_delete, hosts_to_delete; 749 urls_to_delete.push_back("http://www.google.com/page2.html"); 750 urls_to_delete.push_back("http://www.apple.com/"); 751 urls_to_delete.push_back("http://www.nike.com/"); 752 hosts_to_delete.push_back("www.google.com"); 753 hosts_to_delete.push_back("www.apple.com"); 754 755 EXPECT_CALL( 756 *mock_tables_.get(), 757 DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete))); 758 759 predictor_->DeleteUrls(rows); 760 EXPECT_EQ(2, static_cast<int>(predictor_->url_table_cache_->size())); 761 EXPECT_EQ(1, static_cast<int>(predictor_->host_table_cache_->size())); 762 763 EXPECT_CALL(*mock_tables_.get(), DeleteAllData()); 764 765 predictor_->DeleteAllUrls(); 766 EXPECT_TRUE(predictor_->url_table_cache_->empty()); 767 EXPECT_TRUE(predictor_->host_table_cache_->empty()); 768} 769 770TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) { 771 URLRequestSummary summary1 = CreateURLRequestSummary(1, 772 1, 773 "http://www.google.com", 774 "http://www.google.com", 775 ResourceType::MAIN_FRAME, 776 std::string(), 777 false); 778 URLRequestSummary summary2 = CreateURLRequestSummary(1, 779 2, 780 "http://www.google.com", 781 "http://www.google.com", 782 ResourceType::MAIN_FRAME, 783 std::string(), 784 false); 785 URLRequestSummary summary3 = CreateURLRequestSummary(2, 786 1, 787 "http://www.yahoo.com", 788 "http://www.yahoo.com", 789 ResourceType::MAIN_FRAME, 790 std::string(), 791 false); 792 793 predictor_->OnMainFrameRequest(summary1); 794 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 795 predictor_->OnMainFrameRequest(summary2); 796 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size())); 797 predictor_->OnMainFrameRequest(summary3); 798 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 799 800 // Insert anther with same navigation id. It should replace. 801 URLRequestSummary summary4 = CreateURLRequestSummary(1, 802 1, 803 "http://www.nike.com", 804 "http://www.nike.com", 805 ResourceType::MAIN_FRAME, 806 std::string(), 807 false); 808 URLRequestSummary summary5 = CreateURLRequestSummary(1, 809 2, 810 "http://www.google.com", 811 "http://www.google.com", 812 ResourceType::MAIN_FRAME, 813 std::string(), 814 false); 815 816 predictor_->OnMainFrameRequest(summary4); 817 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 818 819 // Change this creation time so that it will go away on the next insert. 820 summary5.navigation_id.creation_time = base::TimeTicks::Now() - 821 base::TimeDelta::FromDays(1); 822 predictor_->OnMainFrameRequest(summary5); 823 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 824 825 URLRequestSummary summary6 = CreateURLRequestSummary(3, 826 1, 827 "http://www.shoes.com", 828 "http://www.shoes.com", 829 ResourceType::MAIN_FRAME, 830 std::string(), 831 false); 832 predictor_->OnMainFrameRequest(summary6); 833 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 834 835 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary3.navigation_id) != 836 predictor_->inflight_navigations_.end()); 837 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary4.navigation_id) != 838 predictor_->inflight_navigations_.end()); 839 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary6.navigation_id) != 840 predictor_->inflight_navigations_.end()); 841} 842 843TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) { 844 URLRequestSummary summary1 = CreateURLRequestSummary(1, 845 1, 846 "http://www.google.com", 847 "http://www.google.com", 848 ResourceType::MAIN_FRAME, 849 std::string(), 850 false); 851 URLRequestSummary summary2 = CreateURLRequestSummary(1, 852 2, 853 "http://www.google.com", 854 "http://www.google.com", 855 ResourceType::MAIN_FRAME, 856 std::string(), 857 false); 858 URLRequestSummary summary3 = CreateURLRequestSummary(2, 859 1, 860 "http://www.yahoo.com", 861 "http://www.yahoo.com", 862 ResourceType::MAIN_FRAME, 863 std::string(), 864 false); 865 866 predictor_->OnMainFrameRedirect(summary1); 867 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 868 869 predictor_->OnMainFrameRequest(summary1); 870 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 871 predictor_->OnMainFrameRequest(summary2); 872 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size())); 873 874 predictor_->OnMainFrameRedirect(summary3); 875 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size())); 876 predictor_->OnMainFrameRedirect(summary1); 877 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 878 predictor_->OnMainFrameRedirect(summary2); 879 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 880} 881 882TEST_F(ResourcePrefetchPredictorTest, OnSubresourceResponse) { 883 // If there is no inflight navigation, nothing happens. 884 URLRequestSummary resource1 = CreateURLRequestSummary( 885 1, 1, "http://www.google.com", "http://google.com/style1.css", 886 ResourceType::STYLESHEET, "text/css", false); 887 predictor_->OnSubresourceResponse(resource1); 888 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 889 890 // Add an inflight navigation. 891 URLRequestSummary main_frame1 = 892 CreateURLRequestSummary(1, 893 1, 894 "http://www.google.com", 895 "http://www.google.com", 896 ResourceType::MAIN_FRAME, 897 std::string(), 898 false); 899 predictor_->OnMainFrameRequest(main_frame1); 900 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 901 902 // Now add a few subresources. 903 URLRequestSummary resource2 = CreateURLRequestSummary( 904 1, 1, "http://www.google.com", "http://google.com/script1.js", 905 ResourceType::SCRIPT, "text/javascript", false); 906 URLRequestSummary resource3 = CreateURLRequestSummary( 907 1, 1, "http://www.google.com", "http://google.com/script2.js", 908 ResourceType::SCRIPT, "text/javascript", false); 909 predictor_->OnSubresourceResponse(resource1); 910 predictor_->OnSubresourceResponse(resource2); 911 predictor_->OnSubresourceResponse(resource3); 912 913 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 914 EXPECT_EQ(3, static_cast<int>( 915 predictor_->inflight_navigations_[main_frame1.navigation_id]->size())); 916 EXPECT_TRUE(URLRequestSummaryAreEqual( 917 resource1, 918 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0))); 919 EXPECT_TRUE(URLRequestSummaryAreEqual( 920 resource2, 921 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1))); 922 EXPECT_TRUE(URLRequestSummaryAreEqual( 923 resource3, 924 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2))); 925} 926 927} // namespace predictors 928