MD Downloads: UI review feedback
[chromium-blink-merge.git] / chrome / browser / predictors / resource_prefetch_predictor_unittest.cc
blobae8f29ebf1c0cf31bab622b412ec6c91f1238d69
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.
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_factory.h"
12 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
13 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "components/history/core/browser/history_service.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"
21 using testing::ContainerEq;
22 using testing::Pointee;
23 using testing::SetArgPointee;
24 using testing::StrictMock;
26 namespace predictors {
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;
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 << "]";
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";
53 class MockResourcePrefetchPredictorTables
54 : public ResourcePrefetchPredictorTables {
55 public:
56 MockResourcePrefetchPredictorTables() { }
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());
68 protected:
69 ~MockResourcePrefetchPredictorTables() { }
72 class ResourcePrefetchPredictorTest : public testing::Test {
73 public:
74 ResourcePrefetchPredictorTest();
75 ~ResourcePrefetchPredictorTest() override;
76 void SetUp() override;
77 void TearDown() override;
79 protected:
80 void AddUrlToHistory(const std::string& url, int visit_count) {
81 HistoryServiceFactory::GetForProfile(profile_.get(),
82 ServiceAccessType::EXPLICIT_ACCESS)->
83 AddPageWithDetails(
84 GURL(url),
85 base::string16(),
86 visit_count,
88 base::Time::Now(),
89 false,
90 history::SOURCE_BROWSED);
91 profile_->BlockUntilHistoryProcessesPendingRequests();
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;
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;
123 void InitializePredictor() {
124 predictor_->StartInitialization();
125 base::RunLoop loop;
126 loop.RunUntilIdle(); // Runs the DB lookup.
127 profile_->BlockUntilHistoryProcessesPendingRequests();
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;
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;
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_);
154 void InitializeSampleData();
156 base::MessageLoop loop_;
157 content::TestBrowserThread ui_thread_;
158 content::TestBrowserThread db_thread_;
159 scoped_ptr<TestingProfile> profile_;
161 scoped_ptr<ResourcePrefetchPredictor> predictor_;
162 scoped_refptr<StrictMock<MockResourcePrefetchPredictorTables> > mock_tables_;
164 PrefetchDataMap test_url_data_;
165 PrefetchDataMap test_host_data_;
166 PrefetchData empty_url_data_;
167 PrefetchData empty_host_data_;
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()) {}
179 ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() {
180 profile_.reset(NULL);
181 loop_.RunUntilIdle();
184 void ResourcePrefetchPredictorTest::SetUp() {
185 InitializeSampleData();
187 ASSERT_TRUE(profile_->CreateHistoryService(true, false));
188 profile_->BlockUntilHistoryProcessesPendingRequests();
189 EXPECT_TRUE(HistoryServiceFactory::GetForProfile(
190 profile_.get(), ServiceAccessType::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);
204 void ResourcePrefetchPredictorTest::TearDown() {
205 predictor_.reset(NULL);
206 profile_->DestroyHistoryService();
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,
219 1.0));
220 google.resources.push_back(ResourceRow(std::string(),
221 "http://google.com/script3.js",
222 content::RESOURCE_TYPE_SCRIPT,
226 2.1));
227 google.resources.push_back(ResourceRow(std::string(),
228 "http://google.com/script4.js",
229 content::RESOURCE_TYPE_SCRIPT,
233 2.1));
234 google.resources.push_back(ResourceRow(std::string(),
235 "http://google.com/image1.png",
236 content::RESOURCE_TYPE_IMAGE,
240 2.2));
241 google.resources.push_back(ResourceRow(std::string(),
242 "http://google.com/a.font",
243 content::RESOURCE_TYPE_LAST_TYPE,
247 5.1));
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,
258 1.0));
259 reddit.resources
260 .push_back(ResourceRow(std::string(),
261 "http://reddit-resource.com/script2.js",
262 content::RESOURCE_TYPE_SCRIPT,
266 2.1));
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,
276 10.0));
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));
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,
294 1.1));
295 facebook.resources
296 .push_back(ResourceRow(std::string(),
297 "http://www.facebook.com/script.js",
298 content::RESOURCE_TYPE_SCRIPT,
302 2.1));
303 facebook.resources
304 .push_back(ResourceRow(std::string(),
305 "http://www.facebook.com/image.png",
306 content::RESOURCE_TYPE_IMAGE,
310 2.2));
311 facebook.resources.push_back(ResourceRow(std::string(),
312 "http://www.facebook.com/a.font",
313 content::RESOURCE_TYPE_LAST_TYPE,
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,
325 8.5));
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,
335 10.0));
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));
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());
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);
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_)));
360 ResetPredictor();
361 InitializePredictor();
363 // Test that the internal variables correctly initialized.
364 EXPECT_EQ(predictor_->initialization_state_,
365 ResourcePrefetchPredictor::INITIALIZED);
366 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
368 EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_);
369 EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_);
372 TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) {
373 // Single navigation but history count is low, so should not record.
374 AddUrlToHistory("http://www.google.com", 1);
376 URLRequestSummary main_frame =
377 CreateURLRequestSummary(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(1U, predictor_->inflight_navigations_.size());
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);
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,
408 1.0));
409 host_data.resources.push_back(ResourceRow(std::string(),
410 "http://google.com/script1.js",
411 content::RESOURCE_TYPE_SCRIPT,
415 2.0));
416 host_data.resources.push_back(ResourceRow(std::string(),
417 "http://google.com/script2.js",
418 content::RESOURCE_TYPE_SCRIPT,
422 3.0));
423 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
425 predictor_->OnNavigationComplete(main_frame.navigation_id);
426 profile_->BlockUntilHistoryProcessesPendingRequests();
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);
434 URLRequestSummary main_frame =
435 CreateURLRequestSummary(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(1U, predictor_->inflight_navigations_.size());
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);
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,
481 1.0));
482 url_data.resources.push_back(ResourceRow(std::string(),
483 "http://google.com/script1.js",
484 content::RESOURCE_TYPE_SCRIPT,
488 2.0));
489 url_data.resources.push_back(ResourceRow(std::string(),
490 "http://google.com/script2.js",
491 content::RESOURCE_TYPE_SCRIPT,
495 3.0));
496 url_data.resources.push_back(ResourceRow(std::string(),
497 "http://google.com/style2.css",
498 content::RESOURCE_TYPE_STYLESHEET,
502 7.0));
503 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
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));
509 predictor_->OnNavigationComplete(main_frame.navigation_id);
510 profile_->BlockUntilHistoryProcessesPendingRequests();
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);
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(3U, predictor_->url_table_cache_->size());
526 EXPECT_EQ(2U, predictor_->host_table_cache_->size());
528 URLRequestSummary main_frame =
529 CreateURLRequestSummary(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(1U, predictor_->inflight_navigations_.size());
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);
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,
575 1.0));
576 url_data.resources.push_back(ResourceRow(std::string(),
577 "http://google.com/script1.js",
578 content::RESOURCE_TYPE_SCRIPT,
582 2.0));
583 url_data.resources.push_back(ResourceRow(std::string(),
584 "http://google.com/script4.js",
585 content::RESOURCE_TYPE_SCRIPT,
589 2.1));
590 url_data.resources.push_back(ResourceRow(std::string(),
591 "http://google.com/script2.js",
592 content::RESOURCE_TYPE_SCRIPT,
596 3.0));
597 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
599 EXPECT_CALL(
600 *mock_tables_.get(),
601 DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
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,
610 1.0));
611 host_data.resources.push_back(ResourceRow(std::string(),
612 "http://google.com/script1.js",
613 content::RESOURCE_TYPE_SCRIPT,
617 2.0));
618 host_data.resources.push_back(ResourceRow(std::string(),
619 "http://google.com/script2.js",
620 content::RESOURCE_TYPE_SCRIPT,
624 3.0));
625 host_data.resources.push_back(ResourceRow(std::string(),
626 "http://google.com/style2.css",
627 content::RESOURCE_TYPE_STYLESHEET,
631 7.0));
632 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
634 predictor_->OnNavigationComplete(main_frame.navigation_id);
635 profile_->BlockUntilHistoryProcessesPendingRequests();
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);
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(3U, predictor_->url_table_cache_->size());
650 EXPECT_EQ(2U, predictor_->host_table_cache_->size());
652 URLRequestSummary main_frame =
653 CreateURLRequestSummary(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(1U, predictor_->inflight_navigations_.size());
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);
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));
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,
686 1.0));
687 url_data.resources.push_back(ResourceRow(std::string(),
688 "http://nike.com/image2.png",
689 content::RESOURCE_TYPE_IMAGE,
693 2.0));
694 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
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));
700 predictor_->OnNavigationComplete(main_frame.navigation_id);
701 profile_->BlockUntilHistoryProcessesPendingRequests();
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/")));
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")));
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")));
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");
744 EXPECT_CALL(
745 *mock_tables_.get(),
746 DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete)));
748 predictor_->DeleteUrls(rows);
749 EXPECT_EQ(2U, predictor_->url_table_cache_->size());
750 EXPECT_EQ(1U, predictor_->host_table_cache_->size());
752 EXPECT_CALL(*mock_tables_.get(), DeleteAllData());
754 predictor_->DeleteAllUrls();
755 EXPECT_TRUE(predictor_->url_table_cache_->empty());
756 EXPECT_TRUE(predictor_->host_table_cache_->empty());
759 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) {
760 URLRequestSummary summary1 =
761 CreateURLRequestSummary(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,
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,
779 "http://www.yahoo.com",
780 "http://www.yahoo.com",
781 content::RESOURCE_TYPE_MAIN_FRAME,
782 std::string(),
783 false);
785 predictor_->OnMainFrameRequest(summary1);
786 EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
787 predictor_->OnMainFrameRequest(summary2);
788 EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
789 predictor_->OnMainFrameRequest(summary3);
790 EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
792 // Insert anther with same navigation id. It should replace.
793 URLRequestSummary summary4 =
794 CreateURLRequestSummary(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,
804 "http://www.google.com",
805 "http://www.google.com",
806 content::RESOURCE_TYPE_MAIN_FRAME,
807 std::string(),
808 false);
810 predictor_->OnMainFrameRequest(summary4);
811 EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
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(3U, predictor_->inflight_navigations_.size());
819 URLRequestSummary summary6 =
820 CreateURLRequestSummary(3,
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(3U, predictor_->inflight_navigations_.size());
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());
838 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) {
839 URLRequestSummary summary1 =
840 CreateURLRequestSummary(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,
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,
858 "http://www.yahoo.com",
859 "http://www.yahoo.com",
860 content::RESOURCE_TYPE_MAIN_FRAME,
861 std::string(),
862 false);
864 predictor_->OnMainFrameRedirect(summary1);
865 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
867 predictor_->OnMainFrameRequest(summary1);
868 EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
869 predictor_->OnMainFrameRequest(summary2);
870 EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
872 predictor_->OnMainFrameRedirect(summary3);
873 EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
874 predictor_->OnMainFrameRedirect(summary1);
875 EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
876 predictor_->OnMainFrameRedirect(summary2);
877 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
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());
888 // Add an inflight navigation.
889 URLRequestSummary main_frame1 =
890 CreateURLRequestSummary(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(1U, predictor_->inflight_navigations_.size());
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);
911 EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
912 EXPECT_EQ(3U,
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)));
925 TEST_F(ResourcePrefetchPredictorTest, GetCorrectPLT) {
926 // Single navigation but history count is low, so should not record.
927 AddUrlToHistory("http://www.google.com", 1);
929 URLRequestSummary main_frame =
930 CreateURLRequestSummary(1,
932 "http://www.google.com",
933 "http://www.google.com",
934 content::RESOURCE_TYPE_MAIN_FRAME,
935 std::string(),
936 false);
937 predictor_->RecordURLRequest(main_frame);
938 EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
940 // Reset the creation time in |main_frame.navigation_id|. The correct creation
941 // time is stored in |inflight_navigations_| and should be used later.
942 main_frame.navigation_id.creation_time = base::TimeTicks();
943 EXPECT_TRUE(main_frame.navigation_id.creation_time.is_null());
945 // Now add a subresource.
946 URLRequestSummary resource1 = CreateURLRequestSummary(
947 1, 1, "http://www.google.com", "http://google.com/style1.css",
948 content::RESOURCE_TYPE_STYLESHEET, "text/css", false);
949 predictor_->RecordURLResponse(resource1);
951 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
952 host_data.resources.push_back(ResourceRow(std::string(),
953 "http://google.com/style1.css",
954 content::RESOURCE_TYPE_STYLESHEET,
958 1.0));
959 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
961 // The page load time will be collected by RPP_HISTOGRAM_MEDIUM_TIMES, which
962 // has a upper bound of 3 minutes.
963 base::TimeDelta plt =
964 predictor_->OnNavigationComplete(main_frame.navigation_id);
965 EXPECT_LT(plt, base::TimeDelta::FromSeconds(180));
967 profile_->BlockUntilHistoryProcessesPendingRequests();
970 } // namespace predictors