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.
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
) {
53 class MockResourcePrefetchPredictorTables
54 : public ResourcePrefetchPredictorTables
{
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());
69 ~MockResourcePrefetchPredictorTables() { }
72 class ResourcePrefetchPredictorTest
: public testing::Test
{
74 ResourcePrefetchPredictorTest();
75 ~ResourcePrefetchPredictorTest() override
;
76 void SetUp() override
;
77 void TearDown() override
;
80 void AddUrlToHistory(const std::string
& url
, int visit_count
) {
81 HistoryServiceFactory::GetForProfile(profile_
.get(),
82 ServiceAccessType::EXPLICIT_ACCESS
)->
90 history::SOURCE_BROWSED
);
91 profile_
->BlockUntilHistoryProcessesPendingRequests();
94 NavigationID
CreateNavigationID(int process_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(
108 const std::string
& main_frame_url
,
109 const std::string
& resource_url
,
110 content::ResourceType resource_type
,
111 const std::string
& mime_type
,
113 ResourcePrefetchPredictor::URLRequestSummary summary
;
114 summary
.navigation_id
= CreateNavigationID(process_id
, render_frame_id
,
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
;
123 void InitializePredictor() {
124 predictor_
->StartInitialization();
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.
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() {
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
,
220 google
.resources
.push_back(ResourceRow(std::string(),
221 "http://google.com/script3.js",
222 content::RESOURCE_TYPE_SCRIPT
,
227 google
.resources
.push_back(ResourceRow(std::string(),
228 "http://google.com/script4.js",
229 content::RESOURCE_TYPE_SCRIPT
,
234 google
.resources
.push_back(ResourceRow(std::string(),
235 "http://google.com/image1.png",
236 content::RESOURCE_TYPE_IMAGE
,
241 google
.resources
.push_back(ResourceRow(std::string(),
242 "http://google.com/a.font",
243 content::RESOURCE_TYPE_LAST_TYPE
,
249 PrefetchData
reddit(PREFETCH_KEY_TYPE_URL
, "http://www.reddit.com/");
250 reddit
.last_visit
= base::Time::FromInternalValue(2);
252 .push_back(ResourceRow(std::string(),
253 "http://reddit-resource.com/script1.js",
254 content::RESOURCE_TYPE_SCRIPT
,
260 .push_back(ResourceRow(std::string(),
261 "http://reddit-resource.com/script2.js",
262 content::RESOURCE_TYPE_SCRIPT
,
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
,
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
));
285 PrefetchData
facebook(PREFETCH_KEY_TYPE_HOST
, "www.facebook.com");
286 facebook
.last_visit
= base::Time::FromInternalValue(4);
288 .push_back(ResourceRow(std::string(),
289 "http://www.facebook.com/style.css",
290 content::RESOURCE_TYPE_STYLESHEET
,
296 .push_back(ResourceRow(std::string(),
297 "http://www.facebook.com/script.js",
298 content::RESOURCE_TYPE_SCRIPT
,
304 .push_back(ResourceRow(std::string(),
305 "http://www.facebook.com/image.png",
306 content::RESOURCE_TYPE_IMAGE
,
311 facebook
.resources
.push_back(ResourceRow(std::string(),
312 "http://www.facebook.com/a.font",
313 content::RESOURCE_TYPE_LAST_TYPE
,
319 .push_back(ResourceRow(std::string(),
320 "http://www.resources.facebook.com/script.js",
321 content::RESOURCE_TYPE_SCRIPT
,
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
,
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_
)));
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
,
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
,
409 host_data
.resources
.push_back(ResourceRow(std::string(),
410 "http://google.com/script1.js",
411 content::RESOURCE_TYPE_SCRIPT
,
416 host_data
.resources
.push_back(ResourceRow(std::string(),
417 "http://google.com/script2.js",
418 content::RESOURCE_TYPE_SCRIPT
,
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
,
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
,
482 url_data
.resources
.push_back(ResourceRow(std::string(),
483 "http://google.com/script1.js",
484 content::RESOURCE_TYPE_SCRIPT
,
489 url_data
.resources
.push_back(ResourceRow(std::string(),
490 "http://google.com/script2.js",
491 content::RESOURCE_TYPE_SCRIPT
,
496 url_data
.resources
.push_back(ResourceRow(std::string(),
497 "http://google.com/style2.css",
498 content::RESOURCE_TYPE_STYLESHEET
,
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_
)));
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
,
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
,
576 url_data
.resources
.push_back(ResourceRow(std::string(),
577 "http://google.com/script1.js",
578 content::RESOURCE_TYPE_SCRIPT
,
583 url_data
.resources
.push_back(ResourceRow(std::string(),
584 "http://google.com/script4.js",
585 content::RESOURCE_TYPE_SCRIPT
,
590 url_data
.resources
.push_back(ResourceRow(std::string(),
591 "http://google.com/script2.js",
592 content::RESOURCE_TYPE_SCRIPT
,
597 EXPECT_CALL(*mock_tables_
.get(), UpdateData(url_data
, empty_host_data_
));
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
,
611 host_data
.resources
.push_back(ResourceRow(std::string(),
612 "http://google.com/script1.js",
613 content::RESOURCE_TYPE_SCRIPT
,
618 host_data
.resources
.push_back(ResourceRow(std::string(),
619 "http://google.com/script2.js",
620 content::RESOURCE_TYPE_SCRIPT
,
625 host_data
.resources
.push_back(ResourceRow(std::string(),
626 "http://google.com/style2.css",
627 content::RESOURCE_TYPE_STYLESHEET
,
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_
)));
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
,
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
);
674 DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL
));
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
,
687 url_data
.resources
.push_back(ResourceRow(std::string(),
688 "http://nike.com/image2.png",
689 content::RESOURCE_TYPE_IMAGE
,
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(
724 PrefetchData(PREFETCH_KEY_TYPE_HOST
, "www.google.com")));
725 predictor_
->host_table_cache_
->insert(std::make_pair(
727 PrefetchData(PREFETCH_KEY_TYPE_HOST
, "www.yahoo.com")));
728 predictor_
->host_table_cache_
->insert(std::make_pair(
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");
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
,
768 URLRequestSummary summary2
=
769 CreateURLRequestSummary(1,
771 "http://www.google.com",
772 "http://www.google.com",
773 content::RESOURCE_TYPE_MAIN_FRAME
,
776 URLRequestSummary summary3
=
777 CreateURLRequestSummary(2,
779 "http://www.yahoo.com",
780 "http://www.yahoo.com",
781 content::RESOURCE_TYPE_MAIN_FRAME
,
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
,
801 URLRequestSummary summary5
=
802 CreateURLRequestSummary(1,
804 "http://www.google.com",
805 "http://www.google.com",
806 content::RESOURCE_TYPE_MAIN_FRAME
,
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
,
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
,
847 URLRequestSummary summary2
=
848 CreateURLRequestSummary(1,
850 "http://www.google.com",
851 "http://www.google.com",
852 content::RESOURCE_TYPE_MAIN_FRAME
,
855 URLRequestSummary summary3
=
856 CreateURLRequestSummary(2,
858 "http://www.yahoo.com",
859 "http://www.yahoo.com",
860 content::RESOURCE_TYPE_MAIN_FRAME
,
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
,
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());
913 predictor_
->inflight_navigations_
[main_frame1
.navigation_id
]->size());
914 EXPECT_TRUE(URLRequestSummaryAreEqual(
916 predictor_
->inflight_navigations_
[main_frame1
.navigation_id
]->at(0)));
917 EXPECT_TRUE(URLRequestSummaryAreEqual(
919 predictor_
->inflight_navigations_
[main_frame1
.navigation_id
]->at(1)));
920 EXPECT_TRUE(URLRequestSummaryAreEqual(
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
,
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
,
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