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