- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / predictors / resource_prefetch_predictor_unittest.cc
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.
4
5 #include <iostream>
6 #include "base/memory/ref_counted.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/time/time.h"
11 #include "chrome/browser/history/history_service.h"
12 #include "chrome/browser/history/history_service_factory.h"
13 #include "chrome/browser/history/history_types.h"
14 #include "chrome/browser/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"
22
23 using testing::ContainerEq;
24 using testing::Pointee;
25 using testing::SetArgPointee;
26 using testing::StrictMock;
27
28 namespace predictors {
29
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;
35
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 << "]";
42 }
43
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) {
49     *os << "\t\t";
50     PrintTo(*it, os);
51     *os << "\n";
52   }
53 }
54
55 class MockResourcePrefetchPredictorTables
56     : public ResourcePrefetchPredictorTables {
57  public:
58   MockResourcePrefetchPredictorTables() { }
59
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());
69
70  protected:
71   ~MockResourcePrefetchPredictorTables() { }
72 };
73
74 class ResourcePrefetchPredictorTest : public testing::Test {
75  public:
76   ResourcePrefetchPredictorTest();
77   virtual ~ResourcePrefetchPredictorTest();
78   virtual void SetUp() OVERRIDE;
79   virtual void TearDown() OVERRIDE;
80
81  protected:
82   void AddUrlToHistory(const std::string& url, int visit_count) {
83     HistoryServiceFactory::GetForProfile(profile_.get(),
84                                          Profile::EXPLICIT_ACCESS)->
85         AddPageWithDetails(
86             GURL(url),
87             string16(),
88             visit_count,
89             0,
90             base::Time::Now(),
91             false,
92             history::SOURCE_BROWSED);
93     profile_->BlockUntilHistoryProcessesPendingRequests();
94   }
95
96   NavigationID CreateNavigationID(int process_id,
97                                   int render_view_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;
105   }
106
107   ResourcePrefetchPredictor::URLRequestSummary CreateURLRequestSummary(
108       int process_id,
109       int render_view_id,
110       const std::string& main_frame_url,
111       const std::string& resource_url,
112       ResourceType::Type resource_type,
113       const std::string& mime_type,
114       bool was_cached) {
115     ResourcePrefetchPredictor::URLRequestSummary summary;
116     summary.navigation_id = CreateNavigationID(process_id, render_view_id,
117                                                main_frame_url);
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;
122     return summary;
123   }
124
125   void InitializePredictor() {
126     predictor_->StartInitialization();
127     base::RunLoop loop;
128     loop.RunUntilIdle();  // Runs the DB lookup.
129     profile_->BlockUntilHistoryProcessesPendingRequests();
130   }
131
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;
139   }
140
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;
148
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_);
154   }
155
156   void InitializeSampleData();
157
158   base::MessageLoop loop_;
159   content::TestBrowserThread ui_thread_;
160   content::TestBrowserThread db_thread_;
161   scoped_ptr<TestingProfile> profile_;
162
163   scoped_ptr<ResourcePrefetchPredictor> predictor_;
164   scoped_refptr<StrictMock<MockResourcePrefetchPredictorTables> > mock_tables_;
165
166   PrefetchDataMap test_url_data_;
167   PrefetchDataMap test_host_data_;
168   PrefetchData empty_url_data_;
169   PrefetchData empty_host_data_;
170 };
171
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()) {}
180
181 ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() {
182   profile_.reset(NULL);
183   loop_.RunUntilIdle();
184 }
185
186 void ResourcePrefetchPredictorTest::SetUp() {
187   InitializeSampleData();
188
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.
194   ResetPredictor();
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);
204 }
205
206 void ResourcePrefetchPredictorTest::TearDown() {
207   predictor_.reset(NULL);
208   profile_->DestroyHistoryService();
209 }
210
211 void ResourcePrefetchPredictorTest::InitializeSampleData() {
212   {  // Url data.
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,
218                                            3,
219                                            2,
220                                            1,
221                                            1.0));
222     google.resources.push_back(ResourceRow(std::string(),
223                                            "http://google.com/script3.js",
224                                            ResourceType::SCRIPT,
225                                            4,
226                                            0,
227                                            1,
228                                            2.1));
229     google.resources.push_back(ResourceRow(std::string(),
230                                            "http://google.com/script4.js",
231                                            ResourceType::SCRIPT,
232                                            11,
233                                            0,
234                                            0,
235                                            2.1));
236     google.resources.push_back(ResourceRow(std::string(),
237                                            "http://google.com/image1.png",
238                                            ResourceType::IMAGE,
239                                            6,
240                                            3,
241                                            0,
242                                            2.2));
243     google.resources.push_back(ResourceRow(std::string(),
244                                            "http://google.com/a.font",
245                                            ResourceType::LAST_TYPE,
246                                            2,
247                                            0,
248                                            0,
249                                            5.1));
250
251     PrefetchData reddit(PREFETCH_KEY_TYPE_URL, "http://www.reddit.com/");
252     reddit.last_visit = base::Time::FromInternalValue(2);
253     reddit.resources
254         .push_back(ResourceRow(std::string(),
255                                "http://reddit-resource.com/script1.js",
256                                ResourceType::SCRIPT,
257                                4,
258                                0,
259                                1,
260                                1.0));
261     reddit.resources
262         .push_back(ResourceRow(std::string(),
263                                "http://reddit-resource.com/script2.js",
264                                ResourceType::SCRIPT,
265                                2,
266                                0,
267                                0,
268                                2.1));
269
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",
274                                           ResourceType::IMAGE,
275                                           20,
276                                           1,
277                                           0,
278                                           10.0));
279
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));
284   }
285
286   {  // Host data.
287     PrefetchData facebook(PREFETCH_KEY_TYPE_HOST, "www.facebook.com");
288     facebook.last_visit = base::Time::FromInternalValue(4);
289     facebook.resources
290         .push_back(ResourceRow(std::string(),
291                                "http://www.facebook.com/style.css",
292                                ResourceType::STYLESHEET,
293                                5,
294                                2,
295                                1,
296                                1.1));
297     facebook.resources
298         .push_back(ResourceRow(std::string(),
299                                "http://www.facebook.com/script.js",
300                                ResourceType::SCRIPT,
301                                4,
302                                0,
303                                1,
304                                2.1));
305     facebook.resources
306         .push_back(ResourceRow(std::string(),
307                                "http://www.facebook.com/image.png",
308                                ResourceType::IMAGE,
309                                6,
310                                3,
311                                0,
312                                2.2));
313     facebook.resources.push_back(ResourceRow(std::string(),
314                                              "http://www.facebook.com/a.font",
315                                              ResourceType::LAST_TYPE,
316                                              2,
317                                              0,
318                                              0,
319                                              5.1));
320     facebook.resources
321         .push_back(ResourceRow(std::string(),
322                                "http://www.resources.facebook.com/script.js",
323                                ResourceType::SCRIPT,
324                                11,
325                                0,
326                                0,
327                                8.5));
328
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",
333                                           ResourceType::IMAGE,
334                                           20,
335                                           1,
336                                           0,
337                                           10.0));
338
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));
342   }
343 }
344
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());
349 }
350
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);
355
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_)));
361
362   ResetPredictor();
363   InitializePredictor();
364
365   // Test that the internal variables correctly initialized.
366   EXPECT_EQ(predictor_->initialization_state_,
367             ResourcePrefetchPredictor::INITIALIZED);
368   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
369
370   EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_);
371   EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_);
372 }
373
374 TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) {
375   // Single navigation but history count is low, so should not record.
376   AddUrlToHistory("http://www.google.com", 1);
377
378   URLRequestSummary main_frame =
379       CreateURLRequestSummary(1,
380                               1,
381                               "http://www.google.com",
382                               "http://www.google.com",
383                               ResourceType::MAIN_FRAME,
384                               std::string(),
385                               false);
386   predictor_->RecordURLRequest(main_frame);
387   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
388
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);
402
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,
407                                             1,
408                                             0,
409                                             0,
410                                             1.0));
411   host_data.resources.push_back(ResourceRow(std::string(),
412                                             "http://google.com/script1.js",
413                                             ResourceType::SCRIPT,
414                                             1,
415                                             0,
416                                             0,
417                                             2.0));
418   host_data.resources.push_back(ResourceRow(std::string(),
419                                             "http://google.com/script2.js",
420                                             ResourceType::SCRIPT,
421                                             1,
422                                             0,
423                                             0,
424                                             3.0));
425   EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
426
427   predictor_->OnNavigationComplete(main_frame.navigation_id);
428   profile_->BlockUntilHistoryProcessesPendingRequests();
429 }
430
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);
435
436   URLRequestSummary main_frame =
437       CreateURLRequestSummary(1,
438                               1,
439                               "http://www.google.com",
440                               "http://www.google.com",
441                               ResourceType::MAIN_FRAME,
442                               std::string(),
443                               false);
444   predictor_->RecordURLRequest(main_frame);
445   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
446
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);
475
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,
480                                            1,
481                                            0,
482                                            0,
483                                            1.0));
484   url_data.resources.push_back(ResourceRow(std::string(),
485                                            "http://google.com/script1.js",
486                                            ResourceType::SCRIPT,
487                                            1,
488                                            0,
489                                            0,
490                                            2.0));
491   url_data.resources.push_back(ResourceRow(std::string(),
492                                            "http://google.com/script2.js",
493                                            ResourceType::SCRIPT,
494                                            1,
495                                            0,
496                                            0,
497                                            3.0));
498   url_data.resources.push_back(ResourceRow(std::string(),
499                                            "http://google.com/style2.css",
500                                            ResourceType::STYLESHEET,
501                                            1,
502                                            0,
503                                            0,
504                                            7.0));
505   EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
506
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));
510
511   predictor_->OnNavigationComplete(main_frame.navigation_id);
512   profile_->BlockUntilHistoryProcessesPendingRequests();
513 }
514
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);
519
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_)));
525   ResetPredictor();
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()));
529
530   URLRequestSummary main_frame =
531       CreateURLRequestSummary(1,
532                               1,
533                               "http://www.google.com",
534                               "http://www.google.com",
535                               ResourceType::MAIN_FRAME,
536                               std::string(),
537                               false);
538   predictor_->RecordURLRequest(main_frame);
539   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
540
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);
569
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,
574                                            4,
575                                            2,
576                                            0,
577                                            1.0));
578   url_data.resources.push_back(ResourceRow(std::string(),
579                                            "http://google.com/script1.js",
580                                            ResourceType::SCRIPT,
581                                            1,
582                                            0,
583                                            0,
584                                            2.0));
585   url_data.resources.push_back(ResourceRow(std::string(),
586                                            "http://google.com/script4.js",
587                                            ResourceType::SCRIPT,
588                                            11,
589                                            1,
590                                            1,
591                                            2.1));
592   url_data.resources.push_back(ResourceRow(std::string(),
593                                            "http://google.com/script2.js",
594                                            ResourceType::SCRIPT,
595                                            1,
596                                            0,
597                                            0,
598                                            3.0));
599   EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
600
601   EXPECT_CALL(
602       *mock_tables_.get(),
603       DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
604
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,
609                                             1,
610                                             0,
611                                             0,
612                                             1.0));
613   host_data.resources.push_back(ResourceRow(std::string(),
614                                             "http://google.com/script1.js",
615                                             ResourceType::SCRIPT,
616                                             1,
617                                             0,
618                                             0,
619                                             2.0));
620   host_data.resources.push_back(ResourceRow(std::string(),
621                                             "http://google.com/script2.js",
622                                             ResourceType::SCRIPT,
623                                             1,
624                                             0,
625                                             0,
626                                             3.0));
627   host_data.resources.push_back(ResourceRow(std::string(),
628                                             "http://google.com/style2.css",
629                                             ResourceType::STYLESHEET,
630                                             1,
631                                             0,
632                                             0,
633                                             7.0));
634   EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
635
636   predictor_->OnNavigationComplete(main_frame.navigation_id);
637   profile_->BlockUntilHistoryProcessesPendingRequests();
638 }
639
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);
643
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_)));
649   ResetPredictor();
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()));
653
654   URLRequestSummary main_frame =
655       CreateURLRequestSummary(1,
656                               1,
657                               "http://www.nike.com",
658                               "http://www.nike.com",
659                               ResourceType::MAIN_FRAME,
660                               std::string(),
661                               false);
662   predictor_->RecordURLRequest(main_frame);
663   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
664
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);
673
674   EXPECT_CALL(
675       *mock_tables_.get(),
676       DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL));
677   EXPECT_CALL(
678       *mock_tables_.get(),
679       DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
680
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,
685                                            1,
686                                            0,
687                                            0,
688                                            1.0));
689   url_data.resources.push_back(ResourceRow(std::string(),
690                                            "http://nike.com/image2.png",
691                                            ResourceType::IMAGE,
692                                            1,
693                                            0,
694                                            0,
695                                            2.0));
696   EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
697
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));
701
702   predictor_->OnNavigationComplete(main_frame.navigation_id);
703   profile_->BlockUntilHistoryProcessesPendingRequests();
704 }
705
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/")));
723
724   predictor_->host_table_cache_->insert(std::make_pair(
725       "www.google.com",
726       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.google.com")));
727   predictor_->host_table_cache_->insert(std::make_pair(
728       "www.yahoo.com",
729       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com")));
730   predictor_->host_table_cache_->insert(std::make_pair(
731       "www.apple.com",
732       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com")));
733
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")));
738
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");
745
746   EXPECT_CALL(
747       *mock_tables_.get(),
748       DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete)));
749
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()));
753
754   EXPECT_CALL(*mock_tables_.get(), DeleteAllData());
755
756   predictor_->DeleteAllUrls();
757   EXPECT_TRUE(predictor_->url_table_cache_->empty());
758   EXPECT_TRUE(predictor_->host_table_cache_->empty());
759 }
760
761 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) {
762   URLRequestSummary summary1 = CreateURLRequestSummary(1,
763                                                        1,
764                                                        "http://www.google.com",
765                                                        "http://www.google.com",
766                                                        ResourceType::MAIN_FRAME,
767                                                        std::string(),
768                                                        false);
769   URLRequestSummary summary2 = CreateURLRequestSummary(1,
770                                                        2,
771                                                        "http://www.google.com",
772                                                        "http://www.google.com",
773                                                        ResourceType::MAIN_FRAME,
774                                                        std::string(),
775                                                        false);
776   URLRequestSummary summary3 = CreateURLRequestSummary(2,
777                                                        1,
778                                                        "http://www.yahoo.com",
779                                                        "http://www.yahoo.com",
780                                                        ResourceType::MAIN_FRAME,
781                                                        std::string(),
782                                                        false);
783
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()));
790
791   // Insert anther with same navigation id. It should replace.
792   URLRequestSummary summary4 = CreateURLRequestSummary(1,
793                                                        1,
794                                                        "http://www.nike.com",
795                                                        "http://www.nike.com",
796                                                        ResourceType::MAIN_FRAME,
797                                                        std::string(),
798                                                        false);
799   URLRequestSummary summary5 = CreateURLRequestSummary(1,
800                                                        2,
801                                                        "http://www.google.com",
802                                                        "http://www.google.com",
803                                                        ResourceType::MAIN_FRAME,
804                                                        std::string(),
805                                                        false);
806
807   predictor_->OnMainFrameRequest(summary4);
808   EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
809
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()));
815
816   URLRequestSummary summary6 = CreateURLRequestSummary(3,
817                                                        1,
818                                                        "http://www.shoes.com",
819                                                        "http://www.shoes.com",
820                                                        ResourceType::MAIN_FRAME,
821                                                        std::string(),
822                                                        false);
823   predictor_->OnMainFrameRequest(summary6);
824   EXPECT_EQ(3, static_cast<int>(predictor_->inflight_navigations_.size()));
825
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());
832 }
833
834 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) {
835   URLRequestSummary summary1 = CreateURLRequestSummary(1,
836                                                        1,
837                                                        "http://www.google.com",
838                                                        "http://www.google.com",
839                                                        ResourceType::MAIN_FRAME,
840                                                        std::string(),
841                                                        false);
842   URLRequestSummary summary2 = CreateURLRequestSummary(1,
843                                                        2,
844                                                        "http://www.google.com",
845                                                        "http://www.google.com",
846                                                        ResourceType::MAIN_FRAME,
847                                                        std::string(),
848                                                        false);
849   URLRequestSummary summary3 = CreateURLRequestSummary(2,
850                                                        1,
851                                                        "http://www.yahoo.com",
852                                                        "http://www.yahoo.com",
853                                                        ResourceType::MAIN_FRAME,
854                                                        std::string(),
855                                                        false);
856
857   predictor_->OnMainFrameRedirect(summary1);
858   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
859
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()));
864
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());
871 }
872
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());
880
881   // Add an inflight navigation.
882   URLRequestSummary main_frame1 =
883       CreateURLRequestSummary(1,
884                               1,
885                               "http://www.google.com",
886                               "http://www.google.com",
887                               ResourceType::MAIN_FRAME,
888                               std::string(),
889                               false);
890   predictor_->OnMainFrameRequest(main_frame1);
891   EXPECT_EQ(1, static_cast<int>(predictor_->inflight_navigations_.size()));
892
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);
903
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(
908       resource1,
909       predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0)));
910   EXPECT_TRUE(URLRequestSummaryAreEqual(
911       resource2,
912       predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1)));
913   EXPECT_TRUE(URLRequestSummaryAreEqual(
914       resource3,
915       predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2)));
916 }
917
918 }  // namespace predictors