Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / predictors / resource_prefetcher_unittest.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/memory/ref_counted.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/message_loop/message_loop.h"
8 #include "chrome/browser/predictors/resource_prefetcher.h"
9 #include "chrome/browser/predictors/resource_prefetcher_manager.h"
10 #include "chrome/test/base/testing_profile.h"
11 #include "content/public/test/test_browser_thread.h"
12 #include "net/url_request/redirect_info.h"
13 #include "net/url_request/url_request.h"
14 #include "net/url_request/url_request_test_util.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 using testing::Eq;
19 using testing::Property;
20
21 namespace predictors {
22
23 // Wrapper over the ResourcePrefetcher that stubs out the StartURLRequest call
24 // since we do not want to do network fetches in this unittest.
25 class TestResourcePrefetcher : public ResourcePrefetcher {
26  public:
27   TestResourcePrefetcher(ResourcePrefetcher::Delegate* delegate,
28                          const ResourcePrefetchPredictorConfig& config,
29                          const NavigationID& navigation_id,
30                          PrefetchKeyType key_type,
31                          scoped_ptr<RequestVector> requests)
32       : ResourcePrefetcher(delegate, config, navigation_id,
33                            key_type, requests.Pass()) { }
34
35   virtual ~TestResourcePrefetcher() { }
36
37   MOCK_METHOD1(StartURLRequest, void(net::URLRequest* request));
38
39   void ReadFullResponse(net::URLRequest* request) OVERRIDE {
40     FinishRequest(request, Request::PREFETCH_STATUS_FROM_CACHE);
41   }
42
43  private:
44   DISALLOW_COPY_AND_ASSIGN(TestResourcePrefetcher);
45 };
46
47
48 // Delegate for ResourcePrefetcher.
49 class TestResourcePrefetcherDelegate : public ResourcePrefetcher::Delegate {
50  public:
51   explicit TestResourcePrefetcherDelegate(base::MessageLoop* loop)
52       : request_context_getter_(new net::TestURLRequestContextGetter(
53           loop->message_loop_proxy())) { }
54   ~TestResourcePrefetcherDelegate() { }
55
56   virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
57     return request_context_getter_->GetURLRequestContext();
58   }
59
60   MOCK_METHOD2(ResourcePrefetcherFinished,
61                void(ResourcePrefetcher* prefetcher,
62                     ResourcePrefetcher::RequestVector* requests));
63
64  private:
65   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
66
67   DISALLOW_COPY_AND_ASSIGN(TestResourcePrefetcherDelegate);
68 };
69
70
71 // The following unittest tests most of the ResourcePrefetcher except for:
72 // 1. Call to ReadFullResponse. There does not seem to be a good way to test the
73 //    function in a unittest, and probably requires a browser_test.
74 // 2. Setting of the Prefetch status for cache vs non cache.
75 class ResourcePrefetcherTest : public testing::Test {
76  public:
77   ResourcePrefetcherTest();
78   virtual ~ResourcePrefetcherTest();
79
80  protected:
81   typedef ResourcePrefetcher::Request Request;
82
83   void AddStartUrlRequestExpectation(const std::string& url) {
84     EXPECT_CALL(*prefetcher_,
85                 StartURLRequest(Property(&net::URLRequest::original_url,
86                                          Eq(GURL(url)))));
87   }
88
89   void CheckPrefetcherState(size_t inflight, size_t queue, size_t host) {
90     EXPECT_EQ(prefetcher_->inflight_requests_.size(), inflight);
91     EXPECT_EQ(prefetcher_->request_queue_.size(), queue);
92     EXPECT_EQ(prefetcher_->host_inflight_counts_.size(), host);
93   }
94
95   net::URLRequest* GetInFlightRequest(const std::string& url_str) {
96     GURL url(url_str);
97
98     for (std::list<Request*>::const_iterator it =
99          prefetcher_->request_queue_.begin();
100          it != prefetcher_->request_queue_.end(); ++it) {
101       EXPECT_NE((*it)->resource_url, url);
102     }
103     for (std::map<net::URLRequest*, Request*>::const_iterator it =
104          prefetcher_->inflight_requests_.begin();
105          it != prefetcher_->inflight_requests_.end(); ++it) {
106       if (it->first->original_url() == url)
107         return it->first;
108     }
109     EXPECT_TRUE(false) << "Infligh request not found: " << url_str;
110     return NULL;
111   }
112
113
114   void OnReceivedRedirect(const std::string& url) {
115     prefetcher_->OnReceivedRedirect(
116         GetInFlightRequest(url), net::RedirectInfo(), NULL);
117   }
118   void OnAuthRequired(const std::string& url) {
119     prefetcher_->OnAuthRequired(GetInFlightRequest(url), NULL);
120   }
121   void OnCertificateRequested(const std::string& url) {
122     prefetcher_->OnCertificateRequested(GetInFlightRequest(url), NULL);
123   }
124   void OnSSLCertificateError(const std::string& url) {
125     prefetcher_->OnSSLCertificateError(GetInFlightRequest(url),
126                                        net::SSLInfo(), false);
127   }
128   void OnResponse(const std::string& url) {
129     prefetcher_->OnResponseStarted(GetInFlightRequest(url));
130   }
131
132   base::MessageLoop loop_;
133   content::TestBrowserThread io_thread_;
134   ResourcePrefetchPredictorConfig config_;
135   TestResourcePrefetcherDelegate prefetcher_delegate_;
136   scoped_ptr<TestResourcePrefetcher> prefetcher_;
137
138  private:
139   DISALLOW_COPY_AND_ASSIGN(ResourcePrefetcherTest);
140 };
141
142 ResourcePrefetcherTest::ResourcePrefetcherTest()
143     : loop_(base::MessageLoop::TYPE_IO),
144       io_thread_(content::BrowserThread::IO, &loop_),
145       prefetcher_delegate_(&loop_) {
146   config_.max_prefetches_inflight_per_navigation = 5;
147   config_.max_prefetches_inflight_per_host_per_navigation = 2;
148 }
149
150 ResourcePrefetcherTest::~ResourcePrefetcherTest() {
151 }
152
153 TEST_F(ResourcePrefetcherTest, TestPrefetcherFinishes) {
154   scoped_ptr<ResourcePrefetcher::RequestVector> requests(
155       new ResourcePrefetcher::RequestVector);
156   requests->push_back(new ResourcePrefetcher::Request(GURL(
157       "http://www.google.com/resource1.html")));
158   requests->push_back(new ResourcePrefetcher::Request(GURL(
159       "http://www.google.com/resource2.png")));
160   requests->push_back(new ResourcePrefetcher::Request(GURL(
161       "http://yahoo.com/resource1.png")));
162   requests->push_back(new ResourcePrefetcher::Request(GURL(
163       "http://yahoo.com/resource2.png")));
164   requests->push_back(new ResourcePrefetcher::Request(GURL(
165       "http://yahoo.com/resource3.png")));
166   requests->push_back(new ResourcePrefetcher::Request(GURL(
167       "http://m.google.com/resource1.jpg")));
168   requests->push_back(new ResourcePrefetcher::Request(GURL(
169       "http://www.google.com/resource3.html")));
170   requests->push_back(new ResourcePrefetcher::Request(GURL(
171       "http://m.google.com/resource2.html")));
172   requests->push_back(new ResourcePrefetcher::Request(GURL(
173       "http://m.google.com/resource3.css")));
174   requests->push_back(new ResourcePrefetcher::Request(GURL(
175       "http://m.google.com/resource4.png")));
176   requests->push_back(new ResourcePrefetcher::Request(GURL(
177       "http://yahoo.com/resource4.png")));
178   requests->push_back(new ResourcePrefetcher::Request(GURL(
179       "http://yahoo.com/resource5.png")));
180
181   NavigationID navigation_id;
182   navigation_id.render_process_id = 1;
183   navigation_id.render_frame_id = 2;
184   navigation_id.main_frame_url = GURL("http://www.google.com");
185
186   // Needed later for comparison.
187   ResourcePrefetcher::RequestVector* requests_ptr = requests.get();
188
189   prefetcher_.reset(new TestResourcePrefetcher(&prefetcher_delegate_,
190                                                config_,
191                                                navigation_id,
192                                                PREFETCH_KEY_TYPE_URL,
193                                                requests.Pass()));
194
195   // Starting the prefetcher maxes out the number of possible requests.
196   AddStartUrlRequestExpectation("http://www.google.com/resource1.html");
197   AddStartUrlRequestExpectation("http://www.google.com/resource2.png");
198   AddStartUrlRequestExpectation("http://yahoo.com/resource1.png");
199   AddStartUrlRequestExpectation("http://yahoo.com/resource2.png");
200   AddStartUrlRequestExpectation("http://m.google.com/resource1.jpg");
201
202   prefetcher_->Start();
203   CheckPrefetcherState(5, 7, 3);
204
205   AddStartUrlRequestExpectation("http://m.google.com/resource2.html");
206   OnResponse("http://m.google.com/resource1.jpg");
207   CheckPrefetcherState(5, 6, 3);
208
209   AddStartUrlRequestExpectation("http://www.google.com/resource3.html");
210   OnSSLCertificateError("http://www.google.com/resource1.html");
211   CheckPrefetcherState(5, 5, 3);
212
213   AddStartUrlRequestExpectation("http://m.google.com/resource3.css");
214   OnResponse("http://m.google.com/resource2.html");
215   CheckPrefetcherState(5, 4, 3);
216
217   AddStartUrlRequestExpectation("http://m.google.com/resource4.png");
218   OnReceivedRedirect("http://www.google.com/resource3.html");
219   CheckPrefetcherState(5, 3, 3);
220
221   OnResponse("http://www.google.com/resource2.png");
222   CheckPrefetcherState(4, 3, 2);
223
224   AddStartUrlRequestExpectation("http://yahoo.com/resource3.png");
225   OnReceivedRedirect("http://yahoo.com/resource2.png");
226   CheckPrefetcherState(4, 2, 2);
227
228   AddStartUrlRequestExpectation("http://yahoo.com/resource4.png");
229   OnResponse("http://yahoo.com/resource1.png");
230   CheckPrefetcherState(4, 1, 2);
231
232   AddStartUrlRequestExpectation("http://yahoo.com/resource5.png");
233   OnResponse("http://yahoo.com/resource4.png");
234   CheckPrefetcherState(4, 0, 2);
235
236   OnResponse("http://yahoo.com/resource5.png");
237   CheckPrefetcherState(3, 0, 2);
238
239   OnCertificateRequested("http://m.google.com/resource4.png");
240   CheckPrefetcherState(2, 0, 2);
241
242   OnAuthRequired("http://m.google.com/resource3.css");
243   CheckPrefetcherState(1, 0, 1);
244
245   // Expect the final call.
246   EXPECT_CALL(prefetcher_delegate_,
247               ResourcePrefetcherFinished(Eq(prefetcher_.get()),
248                                          Eq(requests_ptr)));
249
250   OnResponse("http://yahoo.com/resource3.png");
251   CheckPrefetcherState(0, 0, 0);
252
253   // Check the prefetch status.
254   EXPECT_EQ(Request::PREFETCH_STATUS_CERT_ERROR,
255             (*requests_ptr)[0]->prefetch_status);
256   EXPECT_EQ(Request::PREFETCH_STATUS_FROM_CACHE,
257             (*requests_ptr)[1]->prefetch_status);
258   EXPECT_EQ(Request::PREFETCH_STATUS_FROM_CACHE,
259             (*requests_ptr)[2]->prefetch_status);
260   EXPECT_EQ(Request::PREFETCH_STATUS_REDIRECTED,
261             (*requests_ptr)[3]->prefetch_status);
262   EXPECT_EQ(Request::PREFETCH_STATUS_FROM_CACHE,
263             (*requests_ptr)[4]->prefetch_status);
264   EXPECT_EQ(Request::PREFETCH_STATUS_FROM_CACHE,
265             (*requests_ptr)[5]->prefetch_status);
266   EXPECT_EQ(Request::PREFETCH_STATUS_REDIRECTED,
267             (*requests_ptr)[6]->prefetch_status);
268   EXPECT_EQ(Request::PREFETCH_STATUS_FROM_CACHE,
269             (*requests_ptr)[7]->prefetch_status);
270   EXPECT_EQ(Request::PREFETCH_STATUS_AUTH_REQUIRED,
271             (*requests_ptr)[8]->prefetch_status);
272   EXPECT_EQ(Request::PREFETCH_STATUS_CERT_REQUIRED,
273             (*requests_ptr)[9]->prefetch_status);
274   EXPECT_EQ(Request::PREFETCH_STATUS_FROM_CACHE,
275             (*requests_ptr)[10]->prefetch_status);
276   EXPECT_EQ(Request::PREFETCH_STATUS_FROM_CACHE,
277             (*requests_ptr)[11]->prefetch_status);
278
279   // We need to delete requests_ptr here, though it looks to be managed by the
280   // scoped_ptr requests. The scoped_ptr requests releases itself and the raw
281   // pointer requests_ptr is passed to ResourcePrefetcherFinished(). In the
282   // test, ResourcePrefetcherFinished() is a mock function and does not handle
283   // the raw pointer properly. In the real code, requests_ptr will eventually be
284   // passed to and managed by ResourcePrefetchPredictor::Result::Result.
285   delete requests_ptr;
286 }
287
288 TEST_F(ResourcePrefetcherTest, TestPrefetcherStopped) {
289   scoped_ptr<ResourcePrefetcher::RequestVector> requests(
290       new ResourcePrefetcher::RequestVector);
291   requests->push_back(new ResourcePrefetcher::Request(GURL(
292       "http://www.google.com/resource1.html")));
293   requests->push_back(new ResourcePrefetcher::Request(GURL(
294       "http://www.google.com/resource2.png")));
295   requests->push_back(new ResourcePrefetcher::Request(GURL(
296       "http://yahoo.com/resource1.png")));
297   requests->push_back(new ResourcePrefetcher::Request(GURL(
298       "http://yahoo.com/resource2.png")));
299   requests->push_back(new ResourcePrefetcher::Request(GURL(
300       "http://yahoo.com/resource3.png")));
301   requests->push_back(new ResourcePrefetcher::Request(GURL(
302       "http://m.google.com/resource1.jpg")));
303
304   NavigationID navigation_id;
305   navigation_id.render_process_id = 1;
306   navigation_id.render_frame_id = 2;
307   navigation_id.main_frame_url = GURL("http://www.google.com");
308
309   // Needed later for comparison.
310   ResourcePrefetcher::RequestVector* requests_ptr = requests.get();
311
312   prefetcher_.reset(new TestResourcePrefetcher(&prefetcher_delegate_,
313                                                config_,
314                                                navigation_id,
315                                                PREFETCH_KEY_TYPE_HOST,
316                                                requests.Pass()));
317
318   // Starting the prefetcher maxes out the number of possible requests.
319   AddStartUrlRequestExpectation("http://www.google.com/resource1.html");
320   AddStartUrlRequestExpectation("http://www.google.com/resource2.png");
321   AddStartUrlRequestExpectation("http://yahoo.com/resource1.png");
322   AddStartUrlRequestExpectation("http://yahoo.com/resource2.png");
323   AddStartUrlRequestExpectation("http://m.google.com/resource1.jpg");
324
325   prefetcher_->Start();
326   CheckPrefetcherState(5, 1, 3);
327
328   OnResponse("http://www.google.com/resource1.html");
329   CheckPrefetcherState(4, 1, 3);
330
331   prefetcher_->Stop();  // No more queueing.
332
333   OnResponse("http://www.google.com/resource2.png");
334   CheckPrefetcherState(3, 1, 2);
335
336   OnResponse("http://yahoo.com/resource1.png");
337   CheckPrefetcherState(2, 1, 2);
338
339   OnResponse("http://yahoo.com/resource2.png");
340   CheckPrefetcherState(1, 1, 1);
341
342   // Expect the final call.
343   EXPECT_CALL(prefetcher_delegate_,
344               ResourcePrefetcherFinished(Eq(prefetcher_.get()),
345                                          Eq(requests_ptr)));
346
347   OnResponse("http://m.google.com/resource1.jpg");
348   CheckPrefetcherState(0, 1, 0);
349
350   // We need to delete requests_ptr here, though it looks to be managed by the
351   // scoped_ptr requests. The scoped_ptr requests releases itself and the raw
352   // pointer requests_ptr is passed to ResourcePrefetcherFinished(). In the
353   // test, ResourcePrefetcherFinished() is a mock function and does not handle
354   // the raw pointer properly. In the real code, requests_ptr will eventually be
355   // passed to and managed by ResourcePrefetchPredictor::Result::Result.
356   delete requests_ptr;
357 }
358
359 }  // namespace predictors