1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/memory/ref_counted.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/time/time.h"
11 #include "chrome/browser/history/history_service.h"
12 #include "chrome/browser/history/history_service_factory.h"
13 #include "chrome/browser/history/history_types.h"
14 #include "chrome/browser/history/in_memory_database.h"
15 #include "chrome/browser/history/url_database.h"
16 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
17 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using testing::ContainerEq;
24 using testing::Pointee;
25 using testing::SetArgPointee;
26 using testing::StrictMock;
28 namespace predictors {
30 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
31 typedef ResourcePrefetchPredictorTables::ResourceRow ResourceRow;
32 typedef std::vector<ResourceRow> ResourceRows;
33 typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData;
34 typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap;
36 // For printing failures nicely.
37 void PrintTo(const ResourceRow& row, ::std::ostream* os) {
38 *os << "[" << row.primary_key << "," << row.resource_url
39 << "," << row.resource_type << "," << row.number_of_hits
40 << "," << row.number_of_misses << "," << row.consecutive_misses
41 << "," << row.average_position << "," << row.score << "]";
44 void PrintTo(const PrefetchData& data, ::std::ostream* os) {
45 *os << "[" << data.key_type << "," << data.primary_key
46 << "," << data.last_visit.ToInternalValue() << "]\n";
47 for (ResourceRows::const_iterator it = data.resources.begin();
48 it != data.resources.end(); ++it) {
55 class MockResourcePrefetchPredictorTables
56 : public ResourcePrefetchPredictorTables {
58 MockResourcePrefetchPredictorTables() { }
60 MOCK_METHOD2(GetAllData, void(PrefetchDataMap* url_data_map,
61 PrefetchDataMap* host_data_map));
62 MOCK_METHOD2(UpdateData, void(const PrefetchData& url_data,
63 const PrefetchData& host_data));
64 MOCK_METHOD2(DeleteData, void(const std::vector<std::string>& urls,
65 const std::vector<std::string>& hosts));
66 MOCK_METHOD2(DeleteSingleDataPoint, void(const std::string& key,
67 PrefetchKeyType key_type));
68 MOCK_METHOD0(DeleteAllData, void());
71 ~MockResourcePrefetchPredictorTables() { }
74 class ResourcePrefetchPredictorTest : public testing::Test {
76 ResourcePrefetchPredictorTest();
77 virtual ~ResourcePrefetchPredictorTest();
78 virtual void SetUp() OVERRIDE;
79 virtual void TearDown() OVERRIDE;
82 void AddUrlToHistory(const std::string& url, int visit_count) {
83 HistoryServiceFactory::GetForProfile(profile_.get(),
84 Profile::EXPLICIT_ACCESS)->
92 history::SOURCE_BROWSED);
93 profile_->BlockUntilHistoryProcessesPendingRequests();
96 NavigationID CreateNavigationID(int process_id,
98 const std::string& main_frame_url) {
99 NavigationID navigation_id;
100 navigation_id.render_process_id = process_id;
101 navigation_id.render_view_id = render_view_id;
102 navigation_id.main_frame_url = GURL(main_frame_url);
103 navigation_id.creation_time = base::TimeTicks::Now();
104 return navigation_id;
107 ResourcePrefetchPredictor::URLRequestSummary CreateURLRequestSummary(
110 const std::string& main_frame_url,
111 const std::string& resource_url,
112 ResourceType::Type resource_type,
113 const std::string& mime_type,
115 ResourcePrefetchPredictor::URLRequestSummary summary;
116 summary.navigation_id = CreateNavigationID(process_id, render_view_id,
118 summary.resource_url = GURL(resource_url);
119 summary.resource_type = resource_type;
120 summary.mime_type = mime_type;
121 summary.was_cached = was_cached;
125 void InitializePredictor() {
126 predictor_->StartInitialization();
128 loop.RunUntilIdle(); // Runs the DB lookup.
129 profile_->BlockUntilHistoryProcessesPendingRequests();
132 bool URLRequestSummaryAreEqual(const URLRequestSummary& lhs,
133 const URLRequestSummary& rhs) {
134 return lhs.navigation_id == rhs.navigation_id &&
135 lhs.resource_url == rhs.resource_url &&
136 lhs.resource_type == rhs.resource_type &&
137 lhs.mime_type == rhs.mime_type &&
138 lhs.was_cached == rhs.was_cached;
141 void ResetPredictor() {
142 ResourcePrefetchPredictorConfig config;
143 config.max_urls_to_track = 3;
144 config.max_hosts_to_track = 2;
145 config.min_url_visit_count = 2;
146 config.max_resources_per_entry = 4;
147 config.max_consecutive_misses = 2;
149 // TODO(shishir): Enable the prefetching mode in the tests.
150 config.mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
151 config.mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
152 predictor_.reset(new ResourcePrefetchPredictor(config, profile_.get()));
153 predictor_->set_mock_tables(mock_tables_);
156 void InitializeSampleData();
158 base::MessageLoop loop_;
159 content::TestBrowserThread ui_thread_;
160 content::TestBrowserThread db_thread_;
161 scoped_ptr<TestingProfile> profile_;
163 scoped_ptr<ResourcePrefetchPredictor> predictor_;
164 scoped_refptr<StrictMock<MockResourcePrefetchPredictorTables> > mock_tables_;
166 PrefetchDataMap test_url_data_;
167 PrefetchDataMap test_host_data_;
168 PrefetchData empty_url_data_;
169 PrefetchData empty_host_data_;
172 ResourcePrefetchPredictorTest::ResourcePrefetchPredictorTest()
173 : loop_(base::MessageLoop::TYPE_DEFAULT),
174 ui_thread_(content::BrowserThread::UI, &loop_),
175 db_thread_(content::BrowserThread::DB, &loop_),
176 profile_(new TestingProfile()),
177 mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()),
178 empty_url_data_(PREFETCH_KEY_TYPE_URL, std::string()),
179 empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()) {}
181 ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() {
182 profile_.reset(NULL);
183 loop_.RunUntilIdle();
186 void ResourcePrefetchPredictorTest::SetUp() {
187 InitializeSampleData();
189 ASSERT_TRUE(profile_->CreateHistoryService(true, false));
190 profile_->BlockUntilHistoryProcessesPendingRequests();
191 EXPECT_TRUE(HistoryServiceFactory::GetForProfile(profile_.get(),
192 Profile::EXPLICIT_ACCESS));
193 // Initialize the predictor with empty data.
195 EXPECT_EQ(predictor_->initialization_state_,
196 ResourcePrefetchPredictor::NOT_INITIALIZED);
197 EXPECT_CALL(*mock_tables_.get(),
198 GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
199 Pointee(ContainerEq(PrefetchDataMap()))));
200 InitializePredictor();
201 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
202 EXPECT_EQ(predictor_->initialization_state_,
203 ResourcePrefetchPredictor::INITIALIZED);
206 void ResourcePrefetchPredictorTest::TearDown() {
207 predictor_.reset(NULL);
208 profile_->DestroyHistoryService();
211 void ResourcePrefetchPredictorTest::InitializeSampleData() {
213 PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
214 google.last_visit = base::Time::FromInternalValue(1);
215 google.resources.push_back(ResourceRow(std::string(),
216 "http://google.com/style1.css",
217 ResourceType::STYLESHEET,
222 google.resources.push_back(ResourceRow(std::string(),
223 "http://google.com/script3.js",
224 ResourceType::SCRIPT,
229 google.resources.push_back(ResourceRow(std::string(),
230 "http://google.com/script4.js",
231 ResourceType::SCRIPT,
236 google.resources.push_back(ResourceRow(std::string(),
237 "http://google.com/image1.png",
243 google.resources.push_back(ResourceRow(std::string(),
244 "http://google.com/a.font",
245 ResourceType::LAST_TYPE,
251 PrefetchData reddit(PREFETCH_KEY_TYPE_URL, "http://www.reddit.com/");
252 reddit.last_visit = base::Time::FromInternalValue(2);
254 .push_back(ResourceRow(std::string(),
255 "http://reddit-resource.com/script1.js",
256 ResourceType::SCRIPT,
262 .push_back(ResourceRow(std::string(),
263 "http://reddit-resource.com/script2.js",
264 ResourceType::SCRIPT,
270 PrefetchData yahoo(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/");
271 yahoo.last_visit = base::Time::FromInternalValue(3);
272 yahoo.resources.push_back(ResourceRow(std::string(),
273 "http://google.com/image.png",
280 test_url_data_.clear();
281 test_url_data_.insert(std::make_pair("http://www.google.com/", google));
282 test_url_data_.insert(std::make_pair("http://www.reddit.com/", reddit));
283 test_url_data_.insert(std::make_pair("http://www.yahoo.com/", yahoo));
287 PrefetchData facebook(PREFETCH_KEY_TYPE_HOST, "www.facebook.com");
288 facebook.last_visit = base::Time::FromInternalValue(4);
290 .push_back(ResourceRow(std::string(),
291 "http://www.facebook.com/style.css",
292 ResourceType::STYLESHEET,
298 .push_back(ResourceRow(std::string(),
299 "http://www.facebook.com/script.js",
300 ResourceType::SCRIPT,
306 .push_back(ResourceRow(std::string(),
307 "http://www.facebook.com/image.png",
313 facebook.resources.push_back(ResourceRow(std::string(),
314 "http://www.facebook.com/a.font",
315 ResourceType::LAST_TYPE,
321 .push_back(ResourceRow(std::string(),
322 "http://www.resources.facebook.com/script.js",
323 ResourceType::SCRIPT,
329 PrefetchData yahoo(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com");
330 yahoo.last_visit = base::Time::FromInternalValue(5);
331 yahoo.resources.push_back(ResourceRow(std::string(),
332 "http://google.com/image.png",
339 test_host_data_.clear();
340 test_host_data_.insert(std::make_pair("www.facebook.com", facebook));
341 test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo));
345 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeEmpty) {
346 // Tests that the predictor initializes correctly without any data.
347 EXPECT_TRUE(predictor_->url_table_cache_->empty());
348 EXPECT_TRUE(predictor_->host_table_cache_->empty());
351 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeWithData) {
352 // Tests that the history and the db tables data are loaded correctly.
353 AddUrlToHistory("http://www.google.com/", 4);
354 AddUrlToHistory("http://www.yahoo.com/", 2);
356 EXPECT_CALL(*mock_tables_.get(),
357 GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
358 Pointee(ContainerEq(PrefetchDataMap()))))
359 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
360 SetArgPointee<1>(test_host_data_)));
363 InitializePredictor();
365 // Test that the internal variables correctly initialized.
366 EXPECT_EQ(predictor_->initialization_state_,
367 ResourcePrefetchPredictor::INITIALIZED);
368 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
370 EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_);
371 EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_);
374 TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) {
375 // Single navigation but history count is low, so should not record.
376 AddUrlToHistory("http://www.google.com", 1);
378 URLRequestSummary main_frame =
379 CreateURLRequestSummary(1,
381 "http://www.google.com",
382 "http://www.google.com",
383 ResourceType::MAIN_FRAME,
386 predictor_->RecordURLRequest(main_frame);
387 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
389 // Now add a few subresources.
390 URLRequestSummary resource1 = CreateURLRequestSummary(
391 1, 1, "http://www.google.com", "http://google.com/style1.css",
392 ResourceType::STYLESHEET, "text/css", false);
393 predictor_->RecordURLResponse(resource1);
394 URLRequestSummary resource2 = CreateURLRequestSummary(
395 1, 1, "http://www.google.com", "http://google.com/script1.js",
396 ResourceType::SCRIPT, "text/javascript", false);
397 predictor_->RecordURLResponse(resource2);
398 URLRequestSummary resource3 = CreateURLRequestSummary(
399 1, 1, "http://www.google.com", "http://google.com/script2.js",
400 ResourceType::SCRIPT, "text/javascript", false);
401 predictor_->RecordURLResponse(resource3);
403 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
404 host_data.resources.push_back(ResourceRow(std::string(),
405 "http://google.com/style1.css",
406 ResourceType::STYLESHEET,
411 host_data.resources.push_back(ResourceRow(std::string(),
412 "http://google.com/script1.js",
413 ResourceType::SCRIPT,
418 host_data.resources.push_back(ResourceRow(std::string(),
419 "http://google.com/script2.js",
420 ResourceType::SCRIPT,
425 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
427 predictor_->OnNavigationComplete(main_frame.navigation_id);
428 profile_->BlockUntilHistoryProcessesPendingRequests();
431 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDB) {
432 // Single navigation that will be recorded. Will check for duplicate
433 // resources and also for number of resources saved.
434 AddUrlToHistory("http://www.google.com", 4);
436 URLRequestSummary main_frame =
437 CreateURLRequestSummary(1,
439 "http://www.google.com",
440 "http://www.google.com",
441 ResourceType::MAIN_FRAME,
444 predictor_->RecordURLRequest(main_frame);
445 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
447 URLRequestSummary resource1 = CreateURLRequestSummary(
448 1, 1, "http://www.google.com", "http://google.com/style1.css",
449 ResourceType::STYLESHEET, "text/css", false);
450 predictor_->RecordURLResponse(resource1);
451 URLRequestSummary resource2 = CreateURLRequestSummary(
452 1, 1, "http://www.google.com", "http://google.com/script1.js",
453 ResourceType::SCRIPT, "text/javascript", false);
454 predictor_->RecordURLResponse(resource2);
455 URLRequestSummary resource3 = CreateURLRequestSummary(
456 1, 1, "http://www.google.com", "http://google.com/script2.js",
457 ResourceType::SCRIPT, "text/javascript", false);
458 predictor_->RecordURLResponse(resource3);
459 URLRequestSummary resource4 = CreateURLRequestSummary(
460 1, 1, "http://www.google.com", "http://google.com/script1.js",
461 ResourceType::SCRIPT, "text/javascript", true);
462 predictor_->RecordURLResponse(resource4);
463 URLRequestSummary resource5 = CreateURLRequestSummary(
464 1, 1, "http://www.google.com", "http://google.com/image1.png",
465 ResourceType::IMAGE, "image/png", false);
466 predictor_->RecordURLResponse(resource5);
467 URLRequestSummary resource6 = CreateURLRequestSummary(
468 1, 1, "http://www.google.com", "http://google.com/image2.png",
469 ResourceType::IMAGE, "image/png", false);
470 predictor_->RecordURLResponse(resource6);
471 URLRequestSummary resource7 = CreateURLRequestSummary(
472 1, 1, "http://www.google.com", "http://google.com/style2.css",
473 ResourceType::STYLESHEET, "text/css", true);
474 predictor_->RecordURLResponse(resource7);
476 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
477 url_data.resources.push_back(ResourceRow(std::string(),
478 "http://google.com/style1.css",
479 ResourceType::STYLESHEET,
484 url_data.resources.push_back(ResourceRow(std::string(),
485 "http://google.com/script1.js",
486 ResourceType::SCRIPT,
491 url_data.resources.push_back(ResourceRow(std::string(),
492 "http://google.com/script2.js",
493 ResourceType::SCRIPT,
498 url_data.resources.push_back(ResourceRow(std::string(),
499 "http://google.com/style2.css",
500 ResourceType::STYLESHEET,
505 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
507 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
508 host_data.resources = url_data.resources;
509 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
511 predictor_->OnNavigationComplete(main_frame.navigation_id);
512 profile_->BlockUntilHistoryProcessesPendingRequests();
515 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) {
516 // Tests that navigation is recorded correctly for URL already present in
517 // the database cache.
518 AddUrlToHistory("http://www.google.com", 4);
520 EXPECT_CALL(*mock_tables_.get(),
521 GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
522 Pointee(ContainerEq(PrefetchDataMap()))))
523 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
524 SetArgPointee<1>(test_host_data_)));
526 InitializePredictor();
527 EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size()));
528 EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size()));
530 URLRequestSummary main_frame =
531 CreateURLRequestSummary(1,
533 "http://www.google.com",
534 "http://www.google.com",
535 ResourceType::MAIN_FRAME,
538 predictor_->RecordURLRequest(main_frame);
539 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
541 URLRequestSummary resource1 = CreateURLRequestSummary(
542 1, 1, "http://www.google.com", "http://google.com/style1.css",
543 ResourceType::STYLESHEET, "text/css", false);
544 predictor_->RecordURLResponse(resource1);
545 URLRequestSummary resource2 = CreateURLRequestSummary(
546 1, 1, "http://www.google.com", "http://google.com/script1.js",
547 ResourceType::SCRIPT, "text/javascript", false);
548 predictor_->RecordURLResponse(resource2);
549 URLRequestSummary resource3 = CreateURLRequestSummary(
550 1, 1, "http://www.google.com", "http://google.com/script2.js",
551 ResourceType::SCRIPT, "text/javascript", false);
552 predictor_->RecordURLResponse(resource3);
553 URLRequestSummary resource4 = CreateURLRequestSummary(
554 1, 1, "http://www.google.com", "http://google.com/script1.js",
555 ResourceType::SCRIPT, "text/javascript", true);
556 predictor_->RecordURLResponse(resource4);
557 URLRequestSummary resource5 = CreateURLRequestSummary(
558 1, 1, "http://www.google.com", "http://google.com/image1.png",
559 ResourceType::IMAGE, "image/png", false);
560 predictor_->RecordURLResponse(resource5);
561 URLRequestSummary resource6 = CreateURLRequestSummary(
562 1, 1, "http://www.google.com", "http://google.com/image2.png",
563 ResourceType::IMAGE, "image/png", false);
564 predictor_->RecordURLResponse(resource6);
565 URLRequestSummary resource7 = CreateURLRequestSummary(
566 1, 1, "http://www.google.com", "http://google.com/style2.css",
567 ResourceType::STYLESHEET, "text/css", true);
568 predictor_->RecordURLResponse(resource7);
570 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.google.com/");
571 url_data.resources.push_back(ResourceRow(std::string(),
572 "http://google.com/style1.css",
573 ResourceType::STYLESHEET,
578 url_data.resources.push_back(ResourceRow(std::string(),
579 "http://google.com/script1.js",
580 ResourceType::SCRIPT,
585 url_data.resources.push_back(ResourceRow(std::string(),
586 "http://google.com/script4.js",
587 ResourceType::SCRIPT,
592 url_data.resources.push_back(ResourceRow(std::string(),
593 "http://google.com/script2.js",
594 ResourceType::SCRIPT,
599 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
603 DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
605 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
606 host_data.resources.push_back(ResourceRow(std::string(),
607 "http://google.com/style1.css",
608 ResourceType::STYLESHEET,
613 host_data.resources.push_back(ResourceRow(std::string(),
614 "http://google.com/script1.js",
615 ResourceType::SCRIPT,
620 host_data.resources.push_back(ResourceRow(std::string(),
621 "http://google.com/script2.js",
622 ResourceType::SCRIPT,
627 host_data.resources.push_back(ResourceRow(std::string(),
628 "http://google.com/style2.css",
629 ResourceType::STYLESHEET,
634 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
636 predictor_->OnNavigationComplete(main_frame.navigation_id);
637 profile_->BlockUntilHistoryProcessesPendingRequests();
640 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDBAndDBFull) {
641 // Tests that a URL is deleted before another is added if the cache is full.
642 AddUrlToHistory("http://www.nike.com/", 4);
644 EXPECT_CALL(*mock_tables_.get(),
645 GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
646 Pointee(ContainerEq(PrefetchDataMap()))))
647 .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
648 SetArgPointee<1>(test_host_data_)));
650 InitializePredictor();
651 EXPECT_EQ(3, static_cast<int>(predictor_->url_table_cache_->size()));
652 EXPECT_EQ(2, static_cast<int>(predictor_->host_table_cache_->size()));
654 URLRequestSummary main_frame =
655 CreateURLRequestSummary(1,
657 "http://www.nike.com",
658 "http://www.nike.com",
659 ResourceType::MAIN_FRAME,
662 predictor_->RecordURLRequest(main_frame);
663 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
665 URLRequestSummary resource1 = CreateURLRequestSummary(
666 1, 1, "http://www.nike.com", "http://nike.com/style1.css",
667 ResourceType::STYLESHEET, "text/css", false);
668 predictor_->RecordURLResponse(resource1);
669 URLRequestSummary resource2 = CreateURLRequestSummary(
670 1, 1, "http://www.nike.com", "http://nike.com/image2.png",
671 ResourceType::IMAGE, "image/png", false);
672 predictor_->RecordURLResponse(resource2);
676 DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL));
679 DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
681 PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/");
682 url_data.resources.push_back(ResourceRow(std::string(),
683 "http://nike.com/style1.css",
684 ResourceType::STYLESHEET,
689 url_data.resources.push_back(ResourceRow(std::string(),
690 "http://nike.com/image2.png",
696 EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
698 PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.nike.com");
699 host_data.resources = url_data.resources;
700 EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
702 predictor_->OnNavigationComplete(main_frame.navigation_id);
703 profile_->BlockUntilHistoryProcessesPendingRequests();
706 TEST_F(ResourcePrefetchPredictorTest, DeleteUrls) {
707 // Add some dummy entries to cache.
708 predictor_->url_table_cache_->insert(std::make_pair(
709 "http://www.google.com/page1.html",
710 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page1.html")));
711 predictor_->url_table_cache_->insert(std::make_pair(
712 "http://www.google.com/page2.html",
713 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.google.com/page2.html")));
714 predictor_->url_table_cache_->insert(std::make_pair(
715 "http://www.yahoo.com/",
716 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com/")));
717 predictor_->url_table_cache_->insert(std::make_pair(
718 "http://www.apple.com/",
719 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.apple.com/")));
720 predictor_->url_table_cache_->insert(std::make_pair(
721 "http://www.nike.com/",
722 PrefetchData(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/")));
724 predictor_->host_table_cache_->insert(std::make_pair(
726 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.google.com")));
727 predictor_->host_table_cache_->insert(std::make_pair(
729 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com")));
730 predictor_->host_table_cache_->insert(std::make_pair(
732 PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com")));
734 history::URLRows rows;
735 rows.push_back(history::URLRow(GURL("http://www.google.com/page2.html")));
736 rows.push_back(history::URLRow(GURL("http://www.apple.com")));
737 rows.push_back(history::URLRow(GURL("http://www.nike.com")));
739 std::vector<std::string> urls_to_delete, hosts_to_delete;
740 urls_to_delete.push_back("http://www.google.com/page2.html");
741 urls_to_delete.push_back("http://www.apple.com/");
742 urls_to_delete.push_back("http://www.nike.com/");
743 hosts_to_delete.push_back("www.google.com");
744 hosts_to_delete.push_back("www.apple.com");
748 DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete)));
750 predictor_->DeleteUrls(rows);
751 EXPECT_EQ(2, static_cast<int>(predictor_->url_table_cache_->size()));
752 EXPECT_EQ(1, static_cast<int>(predictor_->host_table_cache_->size()));
754 EXPECT_CALL(*mock_tables_.get(), DeleteAllData());
756 predictor_->DeleteAllUrls();
757 EXPECT_TRUE(predictor_->url_table_cache_->empty());
758 EXPECT_TRUE(predictor_->host_table_cache_->empty());
761 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) {
762 URLRequestSummary summary1 = CreateURLRequestSummary(1,
764 "http://www.google.com",
765 "http://www.google.com",
766 ResourceType::MAIN_FRAME,
769 URLRequestSummary summary2 = CreateURLRequestSummary(1,
771 "http://www.google.com",
772 "http://www.google.com",
773 ResourceType::MAIN_FRAME,
776 URLRequestSummary summary3 = CreateURLRequestSummary(2,
778 "http://www.yahoo.com",
779 "http://www.yahoo.com",
780 ResourceType::MAIN_FRAME,
784 predictor_->OnMainFrameRequest(summary1);
785 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
786 predictor_->OnMainFrameRequest(summary2);
787 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
788 predictor_->OnMainFrameRequest(summary3);
789 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
791 // Insert anther with same navigation id. It should replace.
792 URLRequestSummary summary4 = CreateURLRequestSummary(1,
794 "http://www.nike.com",
795 "http://www.nike.com",
796 ResourceType::MAIN_FRAME,
799 URLRequestSummary summary5 = CreateURLRequestSummary(1,
801 "http://www.google.com",
802 "http://www.google.com",
803 ResourceType::MAIN_FRAME,
807 predictor_->OnMainFrameRequest(summary4);
808 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
810 // Change this creation time so that it will go away on the next insert.
811 summary5.navigation_id.creation_time = base::TimeTicks::Now() -
812 base::TimeDelta::FromDays(1);
813 predictor_->OnMainFrameRequest(summary5);
814 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
816 URLRequestSummary summary6 = CreateURLRequestSummary(3,
818 "http://www.shoes.com",
819 "http://www.shoes.com",
820 ResourceType::MAIN_FRAME,
823 predictor_->OnMainFrameRequest(summary6);
824 EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
826 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary3.navigation_id) !=
827 predictor_->inflight_navigations_.end());
828 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary4.navigation_id) !=
829 predictor_->inflight_navigations_.end());
830 EXPECT_TRUE(predictor_->inflight_navigations_.find(summary6.navigation_id) !=
831 predictor_->inflight_navigations_.end());
834 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) {
835 URLRequestSummary summary1 = CreateURLRequestSummary(1,
837 "http://www.google.com",
838 "http://www.google.com",
839 ResourceType::MAIN_FRAME,
842 URLRequestSummary summary2 = CreateURLRequestSummary(1,
844 "http://www.google.com",
845 "http://www.google.com",
846 ResourceType::MAIN_FRAME,
849 URLRequestSummary summary3 = CreateURLRequestSummary(2,
851 "http://www.yahoo.com",
852 "http://www.yahoo.com",
853 ResourceType::MAIN_FRAME,
857 predictor_->OnMainFrameRedirect(summary1);
858 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
860 predictor_->OnMainFrameRequest(summary1);
861 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
862 predictor_->OnMainFrameRequest(summary2);
863 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
865 predictor_->OnMainFrameRedirect(summary3);
866 EXPECT_EQ(2, static_cast<int>(predictor_->inflight_navigations_.size()));
867 predictor_->OnMainFrameRedirect(summary1);
868 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
869 predictor_->OnMainFrameRedirect(summary2);
870 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
873 TEST_F(ResourcePrefetchPredictorTest, OnSubresourceResponse) {
874 // If there is no inflight navigation, nothing happens.
875 URLRequestSummary resource1 = CreateURLRequestSummary(
876 1, 1, "http://www.google.com", "http://google.com/style1.css",
877 ResourceType::STYLESHEET, "text/css", false);
878 predictor_->OnSubresourceResponse(resource1);
879 EXPECT_TRUE(predictor_->inflight_navigations_.empty());
881 // Add an inflight navigation.
882 URLRequestSummary main_frame1 =
883 CreateURLRequestSummary(1,
885 "http://www.google.com",
886 "http://www.google.com",
887 ResourceType::MAIN_FRAME,
890 predictor_->OnMainFrameRequest(main_frame1);
891 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
893 // Now add a few subresources.
894 URLRequestSummary resource2 = CreateURLRequestSummary(
895 1, 1, "http://www.google.com", "http://google.com/script1.js",
896 ResourceType::SCRIPT, "text/javascript", false);
897 URLRequestSummary resource3 = CreateURLRequestSummary(
898 1, 1, "http://www.google.com", "http://google.com/script2.js",
899 ResourceType::SCRIPT, "text/javascript", false);
900 predictor_->OnSubresourceResponse(resource1);
901 predictor_->OnSubresourceResponse(resource2);
902 predictor_->OnSubresourceResponse(resource3);
904 EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
905 EXPECT_EQ(3, static_cast<int>(
906 predictor_->inflight_navigations_[main_frame1.navigation_id]->size()));
907 EXPECT_TRUE(URLRequestSummaryAreEqual(
909 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0)));
910 EXPECT_TRUE(URLRequestSummaryAreEqual(
912 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1)));
913 EXPECT_TRUE(URLRequestSummaryAreEqual(
915 predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2)));
918 } // namespace predictors