resource_prefetch_predictor_unittest.cc revision bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3
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 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 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 181ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() { 182 profile_.reset(NULL); 183 loop_.RunUntilIdle(); 184} 185 186void 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 206void ResourcePrefetchPredictorTest::TearDown() { 207 predictor_.reset(NULL); 208 profile_->DestroyHistoryService(); 209} 210 211void 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 345TEST_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 351TEST_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 374TEST_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 431TEST_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", false); 474 predictor_->OnSubresourceLoadedFromMemory( 475 resource7.navigation_id, 476 resource7.resource_url, 477 resource7.mime_type, 478 resource7.resource_type); 479 480 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/"); 481 url_data.resources.push_back(ResourceRow(std::string(), 482 "http://google.com/style1.css", 483 ResourceType::STYLESHEET, 484 1, 485 0, 486 0, 487 1.0)); 488 url_data.resources.push_back(ResourceRow(std::string(), 489 "http://google.com/script1.js", 490 ResourceType::SCRIPT, 491 1, 492 0, 493 0, 494 2.0)); 495 url_data.resources.push_back(ResourceRow(std::string(), 496 "http://google.com/script2.js", 497 ResourceType::SCRIPT, 498 1, 499 0, 500 0, 501 3.0)); 502 url_data.resources.push_back(ResourceRow(std::string(), 503 "http://google.com/style2.css", 504 ResourceType::STYLESHEET, 505 1, 506 0, 507 0, 508 7.0)); 509 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_)); 510 511 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com"); 512 host_data.resources = url_data.resources; 513 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data)); 514 515 predictor_->OnNavigationComplete(main_frame.navigation_id); 516 profile_->BlockUntilHistoryProcessesPendingRequests(); 517} 518 519TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) { 520 // Tests that navigation is recorded correctly for URL already present in 521 // the database cache. 522 AddUrlToHistory("http://www.google.com", 4); 523 524 EXPECT_CALL(*mock_tables_.get(), 525 GetAllData(Pointee(ContainerEq(PrefetchDataMap())), 526 Pointee(ContainerEq(PrefetchDataMap())))) 527 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), 528 SetArgPointee<1>(test_host_data_))); 529 ResetPredictor(); 530 InitializePredictor(); 531 EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size())); 532 EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size())); 533 534 URLRequestSummary main_frame = 535 CreateURLRequestSummary(1, 536 1, 537 "http://www.google.com", 538 "http://www.google.com", 539 ResourceType::MAIN_FRAME, 540 std::string(), 541 false); 542 predictor_->RecordURLRequest(main_frame); 543 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 544 545 URLRequestSummary resource1 = CreateURLRequestSummary( 546 1, 1, "http://www.google.com", "http://google.com/style1.css", 547 ResourceType::STYLESHEET, "text/css", false); 548 predictor_->RecordUrlResponse(resource1); 549 URLRequestSummary resource2 = CreateURLRequestSummary( 550 1, 1, "http://www.google.com", "http://google.com/script1.js", 551 ResourceType::SCRIPT, "text/javascript", false); 552 predictor_->RecordUrlResponse(resource2); 553 URLRequestSummary resource3 = CreateURLRequestSummary( 554 1, 1, "http://www.google.com", "http://google.com/script2.js", 555 ResourceType::SCRIPT, "text/javascript", false); 556 predictor_->RecordUrlResponse(resource3); 557 URLRequestSummary resource4 = CreateURLRequestSummary( 558 1, 1, "http://www.google.com", "http://google.com/script1.js", 559 ResourceType::SCRIPT, "text/javascript", true); 560 predictor_->RecordUrlResponse(resource4); 561 URLRequestSummary resource5 = CreateURLRequestSummary( 562 1, 1, "http://www.google.com", "http://google.com/image1.png", 563 ResourceType::IMAGE, "image/png", false); 564 predictor_->RecordUrlResponse(resource5); 565 URLRequestSummary resource6 = CreateURLRequestSummary( 566 1, 1, "http://www.google.com", "http://google.com/image2.png", 567 ResourceType::IMAGE, "image/png", false); 568 predictor_->RecordUrlResponse(resource6); 569 URLRequestSummary resource7 = CreateURLRequestSummary( 570 1, 1, "http://www.google.com", "http://google.com/style2.css", 571 ResourceType::STYLESHEET, "text/css", false); 572 predictor_->OnSubresourceLoadedFromMemory( 573 resource7.navigation_id, 574 resource7.resource_url, 575 resource7.mime_type, 576 resource7.resource_type); 577 578 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/"); 579 url_data.resources.push_back(ResourceRow(std::string(), 580 "http://google.com/style1.css", 581 ResourceType::STYLESHEET, 582 4, 583 2, 584 0, 585 1.0)); 586 url_data.resources.push_back(ResourceRow(std::string(), 587 "http://google.com/script1.js", 588 ResourceType::SCRIPT, 589 1, 590 0, 591 0, 592 2.0)); 593 url_data.resources.push_back(ResourceRow(std::string(), 594 "http://google.com/script4.js", 595 ResourceType::SCRIPT, 596 11, 597 1, 598 1, 599 2.1)); 600 url_data.resources.push_back(ResourceRow(std::string(), 601 "http://google.com/script2.js", 602 ResourceType::SCRIPT, 603 1, 604 0, 605 0, 606 3.0)); 607 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_)); 608 609 EXPECT_CALL( 610 *mock_tables_.get(), 611 DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST)); 612 613 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com"); 614 host_data.resources.push_back(ResourceRow(std::string(), 615 "http://google.com/style1.css", 616 ResourceType::STYLESHEET, 617 1, 618 0, 619 0, 620 1.0)); 621 host_data.resources.push_back(ResourceRow(std::string(), 622 "http://google.com/script1.js", 623 ResourceType::SCRIPT, 624 1, 625 0, 626 0, 627 2.0)); 628 host_data.resources.push_back(ResourceRow(std::string(), 629 "http://google.com/script2.js", 630 ResourceType::SCRIPT, 631 1, 632 0, 633 0, 634 3.0)); 635 host_data.resources.push_back(ResourceRow(std::string(), 636 "http://google.com/style2.css", 637 ResourceType::STYLESHEET, 638 1, 639 0, 640 0, 641 7.0)); 642 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data)); 643 644 predictor_->OnNavigationComplete(main_frame.navigation_id); 645 profile_->BlockUntilHistoryProcessesPendingRequests(); 646} 647 648TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDBAndDBFull) { 649 // Tests that a URL is deleted before another is added if the cache is full. 650 AddUrlToHistory("http://www.nike.com/", 4); 651 652 EXPECT_CALL(*mock_tables_.get(), 653 GetAllData(Pointee(ContainerEq(PrefetchDataMap())), 654 Pointee(ContainerEq(PrefetchDataMap())))) 655 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), 656 SetArgPointee<1>(test_host_data_))); 657 ResetPredictor(); 658 InitializePredictor(); 659 EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size())); 660 EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size())); 661 662 URLRequestSummary main_frame = 663 CreateURLRequestSummary(1, 664 1, 665 "http://www.nike.com", 666 "http://www.nike.com", 667 ResourceType::MAIN_FRAME, 668 std::string(), 669 false); 670 predictor_->RecordURLRequest(main_frame); 671 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 672 673 URLRequestSummary resource1 = CreateURLRequestSummary( 674 1, 1, "http://www.nike.com", "http://nike.com/style1.css", 675 ResourceType::STYLESHEET, "text/css", false); 676 predictor_->RecordUrlResponse(resource1); 677 URLRequestSummary resource2 = CreateURLRequestSummary( 678 1, 1, "http://www.nike.com", "http://nike.com/image2.png", 679 ResourceType::IMAGE, "image/png", false); 680 predictor_->RecordUrlResponse(resource2); 681 682 EXPECT_CALL( 683 *mock_tables_.get(), 684 DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL)); 685 EXPECT_CALL( 686 *mock_tables_.get(), 687 DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST)); 688 689 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/"); 690 url_data.resources.push_back(ResourceRow(std::string(), 691 "http://nike.com/style1.css", 692 ResourceType::STYLESHEET, 693 1, 694 0, 695 0, 696 1.0)); 697 url_data.resources.push_back(ResourceRow(std::string(), 698 "http://nike.com/image2.png", 699 ResourceType::IMAGE, 700 1, 701 0, 702 0, 703 2.0)); 704 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_)); 705 706 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.nike.com"); 707 host_data.resources = url_data.resources; 708 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data)); 709 710 predictor_->OnNavigationComplete(main_frame.navigation_id); 711 profile_->BlockUntilHistoryProcessesPendingRequests(); 712} 713 714TEST_F(ResourcePrefetchPredictorTest, DeleteUrls) { 715 // Add some dummy entries to cache. 716 predictor_->url_table_cache_->insert(std::make_pair( 717 "http://www.google.com/page1.html", 718 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page1.html"))); 719 predictor_->url_table_cache_->insert(std::make_pair( 720 "http://www.google.com/page2.html", 721 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page2.html"))); 722 predictor_->url_table_cache_->insert(std::make_pair( 723 "http://www.yahoo.com/", 724 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/"))); 725 predictor_->url_table_cache_->insert(std::make_pair( 726 "http://www.apple.com/", 727 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.apple.com/"))); 728 predictor_->url_table_cache_->insert(std::make_pair( 729 "http://www.nike.com/", 730 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/"))); 731 732 predictor_->host_table_cache_->insert(std::make_pair( 733 "www.google.com", 734 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.google.com"))); 735 predictor_->host_table_cache_->insert(std::make_pair( 736 "www.yahoo.com", 737 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com"))); 738 predictor_->host_table_cache_->insert(std::make_pair( 739 "www.apple.com", 740 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com"))); 741 742 history::URLRows rows; 743 rows.push_back(history::URLRow(GURL("http://www.google.com/page2.html"))); 744 rows.push_back(history::URLRow(GURL("http://www.apple.com"))); 745 rows.push_back(history::URLRow(GURL("http://www.nike.com"))); 746 747 std::vector<std::string> urls_to_delete, hosts_to_delete; 748 urls_to_delete.push_back("http://www.google.com/page2.html"); 749 urls_to_delete.push_back("http://www.apple.com/"); 750 urls_to_delete.push_back("http://www.nike.com/"); 751 hosts_to_delete.push_back("www.google.com"); 752 hosts_to_delete.push_back("www.apple.com"); 753 754 EXPECT_CALL( 755 *mock_tables_.get(), 756 DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete))); 757 758 predictor_->DeleteUrls(rows); 759 EXPECT_EQ(2, static_cast<int>(predictor_->url_table_cache_->size())); 760 EXPECT_EQ(1, static_cast<int>(predictor_->host_table_cache_->size())); 761 762 EXPECT_CALL(*mock_tables_.get(), DeleteAllData()); 763 764 predictor_->DeleteAllUrls(); 765 EXPECT_TRUE(predictor_->url_table_cache_->empty()); 766 EXPECT_TRUE(predictor_->host_table_cache_->empty()); 767} 768 769TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) { 770 URLRequestSummary summary1 = CreateURLRequestSummary(1, 771 1, 772 "http://www.google.com", 773 "http://www.google.com", 774 ResourceType::MAIN_FRAME, 775 std::string(), 776 false); 777 URLRequestSummary summary2 = CreateURLRequestSummary(1, 778 2, 779 "http://www.google.com", 780 "http://www.google.com", 781 ResourceType::MAIN_FRAME, 782 std::string(), 783 false); 784 URLRequestSummary summary3 = CreateURLRequestSummary(2, 785 1, 786 "http://www.yahoo.com", 787 "http://www.yahoo.com", 788 ResourceType::MAIN_FRAME, 789 std::string(), 790 false); 791 792 predictor_->OnMainFrameRequest(summary1); 793 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 794 predictor_->OnMainFrameRequest(summary2); 795 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size())); 796 predictor_->OnMainFrameRequest(summary3); 797 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 798 799 // Insert anther with same navigation id. It should replace. 800 URLRequestSummary summary4 = CreateURLRequestSummary(1, 801 1, 802 "http://www.nike.com", 803 "http://www.nike.com", 804 ResourceType::MAIN_FRAME, 805 std::string(), 806 false); 807 URLRequestSummary summary5 = CreateURLRequestSummary(1, 808 2, 809 "http://www.google.com", 810 "http://www.google.com", 811 ResourceType::MAIN_FRAME, 812 std::string(), 813 false); 814 815 predictor_->OnMainFrameRequest(summary4); 816 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 817 818 // Change this creation time so that it will go away on the next insert. 819 summary5.navigation_id.creation_time = base::TimeTicks::Now() - 820 base::TimeDelta::FromDays(1); 821 predictor_->OnMainFrameRequest(summary5); 822 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 823 824 URLRequestSummary summary6 = CreateURLRequestSummary(3, 825 1, 826 "http://www.shoes.com", 827 "http://www.shoes.com", 828 ResourceType::MAIN_FRAME, 829 std::string(), 830 false); 831 predictor_->OnMainFrameRequest(summary6); 832 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size())); 833 834 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary3.navigation_id) != 835 predictor_->inflight_navigations_.end()); 836 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary4.navigation_id) != 837 predictor_->inflight_navigations_.end()); 838 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary6.navigation_id) != 839 predictor_->inflight_navigations_.end()); 840} 841 842TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) { 843 URLRequestSummary summary1 = CreateURLRequestSummary(1, 844 1, 845 "http://www.google.com", 846 "http://www.google.com", 847 ResourceType::MAIN_FRAME, 848 std::string(), 849 false); 850 URLRequestSummary summary2 = CreateURLRequestSummary(1, 851 2, 852 "http://www.google.com", 853 "http://www.google.com", 854 ResourceType::MAIN_FRAME, 855 std::string(), 856 false); 857 URLRequestSummary summary3 = CreateURLRequestSummary(2, 858 1, 859 "http://www.yahoo.com", 860 "http://www.yahoo.com", 861 ResourceType::MAIN_FRAME, 862 std::string(), 863 false); 864 865 predictor_->OnMainFrameRedirect(summary1); 866 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 867 868 predictor_->OnMainFrameRequest(summary1); 869 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 870 predictor_->OnMainFrameRequest(summary2); 871 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size())); 872 873 predictor_->OnMainFrameRedirect(summary3); 874 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size())); 875 predictor_->OnMainFrameRedirect(summary1); 876 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 877 predictor_->OnMainFrameRedirect(summary2); 878 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 879} 880 881TEST_F(ResourcePrefetchPredictorTest, OnSubresourceResponse) { 882 // If there is no inflight navigation, nothing happens. 883 URLRequestSummary resource1 = CreateURLRequestSummary( 884 1, 1, "http://www.google.com", "http://google.com/style1.css", 885 ResourceType::STYLESHEET, "text/css", false); 886 predictor_->OnSubresourceResponse(resource1); 887 EXPECT_TRUE(predictor_->inflight_navigations_.empty()); 888 889 // Add an inflight navigation. 890 URLRequestSummary main_frame1 = 891 CreateURLRequestSummary(1, 892 1, 893 "http://www.google.com", 894 "http://www.google.com", 895 ResourceType::MAIN_FRAME, 896 std::string(), 897 false); 898 predictor_->OnMainFrameRequest(main_frame1); 899 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 900 901 // Now add a few subresources. 902 URLRequestSummary resource2 = CreateURLRequestSummary( 903 1, 1, "http://www.google.com", "http://google.com/script1.js", 904 ResourceType::SCRIPT, "text/javascript", false); 905 URLRequestSummary resource3 = CreateURLRequestSummary( 906 1, 1, "http://www.google.com", "http://google.com/script2.js", 907 ResourceType::SCRIPT, "text/javascript", false); 908 predictor_->OnSubresourceResponse(resource1); 909 predictor_->OnSubresourceResponse(resource2); 910 predictor_->OnSubresourceResponse(resource3); 911 912 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size())); 913 EXPECT_EQ(3, static_cast<int>( 914 predictor_->inflight_navigations_[main_frame1.navigation_id]->size())); 915 EXPECT_TRUE(URLRequestSummaryAreEqual( 916 resource1, 917 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0))); 918 EXPECT_TRUE(URLRequestSummaryAreEqual( 919 resource2, 920 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1))); 921 EXPECT_TRUE(URLRequestSummaryAreEqual( 922 resource3, 923 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2))); 924} 925 926} // namespace predictors 927