OLD | NEW |
(Empty) | |
| 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/history/history_types.h" |
| 14 #include "chrome/browser/predictors/resource_prefetch_predictor.h" |
| 15 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h" |
| 16 #include "chrome/test/base/testing_profile.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 |
| 21 using testing::ContainerEq; |
| 22 using testing::Pointee; |
| 23 using testing::SetArgPointee; |
| 24 using testing::StrictMock; |
| 25 |
| 26 namespace predictors { |
| 27 |
| 28 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary; |
| 29 typedef ResourcePrefetchPredictorTables::ResourceRow ResourceRow; |
| 30 typedef std::vector<ResourceRow> ResourceRows; |
| 31 typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData; |
| 32 typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap; |
| 33 |
| 34 // For printing failures nicely. |
| 35 void 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 |
| 42 void 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 |
| 53 class 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 |
| 72 class 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 |
| 170 ResourcePrefetchPredictorTest::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 |
| 179 ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() { |
| 180 profile_.reset(NULL); |
| 181 loop_.RunUntilIdle(); |
| 182 } |
| 183 |
| 184 void 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 |
| 204 void ResourcePrefetchPredictorTest::TearDown() { |
| 205 predictor_.reset(NULL); |
| 206 profile_->DestroyHistoryService(); |
| 207 } |
| 208 |
| 209 void 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 |
| 343 TEST_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 |
| 349 TEST_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 |
| 372 TEST_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 |
| 429 TEST_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 |
| 513 TEST_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 |
| 638 TEST_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 |
| 704 TEST_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 |
| 759 TEST_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 |
| 838 TEST_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 |
| 880 TEST_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 |
OLD | NEW |