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.
5 #include "base/memory/ref_counted.h"
6 #include "base/message_loop.h"
7 #include "base/memory/scoped_ptr.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/url_request.h"
13 #include "net/url_request/url_request_test_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "testing/gmock/include/gmock/gmock.h"
18 using testing::Property
;
20 namespace predictors
{
22 // Wrapper over the ResourcePrefetcher that stubs out the StartURLRequest call
23 // since we do not want to do network fetches in this unittest.
24 class TestResourcePrefetcher
: public ResourcePrefetcher
{
26 TestResourcePrefetcher(ResourcePrefetcher::Delegate
* delegate
,
27 const ResourcePrefetchPredictorConfig
& config
,
28 const NavigationID
& navigation_id
,
29 PrefetchKeyType key_type
,
30 scoped_ptr
<RequestVector
> requests
)
31 : ResourcePrefetcher(delegate
, config
, navigation_id
,
32 key_type
, requests
.Pass()) { }
34 virtual ~TestResourcePrefetcher() { }
36 MOCK_METHOD1(StartURLRequest
, void(net::URLRequest
* request
));
38 void ReadFullResponse(net::URLRequest
* request
) OVERRIDE
{
39 FinishRequest(request
, Request::PREFETCH_STATUS_FROM_CACHE
);
43 DISALLOW_COPY_AND_ASSIGN(TestResourcePrefetcher
);
47 // Delegate for ResourcePrefetcher.
48 class TestResourcePrefetcherDelegate
: public ResourcePrefetcher::Delegate
{
50 explicit TestResourcePrefetcherDelegate(MessageLoop
* loop
)
51 : request_context_getter_(new net::TestURLRequestContextGetter(
52 loop
->message_loop_proxy())) { }
53 ~TestResourcePrefetcherDelegate() { }
55 virtual net::URLRequestContext
* GetURLRequestContext() OVERRIDE
{
56 return request_context_getter_
->GetURLRequestContext();
59 MOCK_METHOD2(ResourcePrefetcherFinished
,
60 void(ResourcePrefetcher
* prefetcher
,
61 ResourcePrefetcher::RequestVector
* requests
));
64 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_getter_
;
66 DISALLOW_COPY_AND_ASSIGN(TestResourcePrefetcherDelegate
);
70 // The following unittest tests most of the ResourcePrefetcher except for:
71 // 1. Call to ReadFullResponse. There does not seem to be a good way to test the
72 // function in a unittest, and probably requires a browser_test.
73 // 2. Setting of the Prefetch status for cache vs non cache.
74 class ResourcePrefetcherTest
: public testing::Test
{
76 ResourcePrefetcherTest();
77 virtual ~ResourcePrefetcherTest();
80 typedef ResourcePrefetcher::Request Request
;
82 void AddStartUrlRequestExpectation(const std::string
& url
) {
83 EXPECT_CALL(*prefetcher_
,
84 StartURLRequest(Property(&net::URLRequest::original_url
,
88 void CheckPrefetcherState(size_t inflight
, size_t queue
, size_t host
) {
89 EXPECT_EQ(prefetcher_
->inflight_requests_
.size(), inflight
);
90 EXPECT_EQ(prefetcher_
->request_queue_
.size(), queue
);
91 EXPECT_EQ(prefetcher_
->host_inflight_counts_
.size(), host
);
94 net::URLRequest
* GetInFlightRequest(const std::string
& url_str
) {
97 for (std::list
<Request
*>::const_iterator it
=
98 prefetcher_
->request_queue_
.begin();
99 it
!= prefetcher_
->request_queue_
.end(); ++it
) {
100 EXPECT_NE((*it
)->resource_url
, url
);
102 for (std::map
<net::URLRequest
*, Request
*>::const_iterator it
=
103 prefetcher_
->inflight_requests_
.begin();
104 it
!= prefetcher_
->inflight_requests_
.end(); ++it
) {
105 if (it
->first
->original_url() == url
)
108 EXPECT_TRUE(false) << "Infligh request not found: " << url_str
;
113 void OnReceivedRedirect(const std::string
& url
) {
114 prefetcher_
->OnReceivedRedirect(
115 GetInFlightRequest(url
), GURL(std::string()), NULL
);
117 void OnAuthRequired(const std::string
& url
) {
118 prefetcher_
->OnAuthRequired(GetInFlightRequest(url
), NULL
);
120 void OnCertificateRequested(const std::string
& url
) {
121 prefetcher_
->OnCertificateRequested(GetInFlightRequest(url
), NULL
);
123 void OnSSLCertificateError(const std::string
& url
) {
124 prefetcher_
->OnSSLCertificateError(GetInFlightRequest(url
),
125 net::SSLInfo(), false);
127 void OnResponse(const std::string
& url
) {
128 prefetcher_
->OnResponseStarted(GetInFlightRequest(url
));
132 content::TestBrowserThread io_thread_
;
133 ResourcePrefetchPredictorConfig config_
;
134 TestResourcePrefetcherDelegate prefetcher_delegate_
;
135 scoped_ptr
<TestResourcePrefetcher
> prefetcher_
;
138 DISALLOW_COPY_AND_ASSIGN(ResourcePrefetcherTest
);
141 ResourcePrefetcherTest::ResourcePrefetcherTest()
142 : loop_(MessageLoop::TYPE_IO
),
143 io_thread_(content::BrowserThread::IO
, &loop_
),
144 prefetcher_delegate_(&loop_
) {
145 config_
.max_prefetches_inflight_per_navigation
= 5;
146 config_
.max_prefetches_inflight_per_host_per_navigation
= 2;
149 ResourcePrefetcherTest::~ResourcePrefetcherTest() {
152 TEST_F(ResourcePrefetcherTest
, TestPrefetcherFinishes
) {
153 scoped_ptr
<ResourcePrefetcher::RequestVector
> requests(
154 new ResourcePrefetcher::RequestVector
);
155 requests
->push_back(new ResourcePrefetcher::Request(GURL(
156 "http://www.google.com/resource1.html")));
157 requests
->push_back(new ResourcePrefetcher::Request(GURL(
158 "http://www.google.com/resource2.png")));
159 requests
->push_back(new ResourcePrefetcher::Request(GURL(
160 "http://yahoo.com/resource1.png")));
161 requests
->push_back(new ResourcePrefetcher::Request(GURL(
162 "http://yahoo.com/resource2.png")));
163 requests
->push_back(new ResourcePrefetcher::Request(GURL(
164 "http://yahoo.com/resource3.png")));
165 requests
->push_back(new ResourcePrefetcher::Request(GURL(
166 "http://m.google.com/resource1.jpg")));
167 requests
->push_back(new ResourcePrefetcher::Request(GURL(
168 "http://www.google.com/resource3.html")));
169 requests
->push_back(new ResourcePrefetcher::Request(GURL(
170 "http://m.google.com/resource2.html")));
171 requests
->push_back(new ResourcePrefetcher::Request(GURL(
172 "http://m.google.com/resource3.css")));
173 requests
->push_back(new ResourcePrefetcher::Request(GURL(
174 "http://m.google.com/resource4.png")));
175 requests
->push_back(new ResourcePrefetcher::Request(GURL(
176 "http://yahoo.com/resource4.png")));
177 requests
->push_back(new ResourcePrefetcher::Request(GURL(
178 "http://yahoo.com/resource5.png")));
180 NavigationID navigation_id
;
181 navigation_id
.render_process_id
= 1;
182 navigation_id
.render_view_id
= 2;
183 navigation_id
.main_frame_url
= GURL("http://www.google.com");
185 // Needed later for comparison.
186 ResourcePrefetcher::RequestVector
* requests_ptr
= requests
.get();
188 prefetcher_
.reset(new TestResourcePrefetcher(&prefetcher_delegate_
,
191 PREFETCH_KEY_TYPE_URL
,
194 // Starting the prefetcher maxes out the number of possible requests.
195 AddStartUrlRequestExpectation("http://www.google.com/resource1.html");
196 AddStartUrlRequestExpectation("http://www.google.com/resource2.png");
197 AddStartUrlRequestExpectation("http://yahoo.com/resource1.png");
198 AddStartUrlRequestExpectation("http://yahoo.com/resource2.png");
199 AddStartUrlRequestExpectation("http://m.google.com/resource1.jpg");
201 prefetcher_
->Start();
202 CheckPrefetcherState(5, 7, 3);
204 AddStartUrlRequestExpectation("http://m.google.com/resource2.html");
205 OnResponse("http://m.google.com/resource1.jpg");
206 CheckPrefetcherState(5, 6, 3);
208 AddStartUrlRequestExpectation("http://www.google.com/resource3.html");
209 OnSSLCertificateError("http://www.google.com/resource1.html");
210 CheckPrefetcherState(5, 5, 3);
212 AddStartUrlRequestExpectation("http://m.google.com/resource3.css");
213 OnResponse("http://m.google.com/resource2.html");
214 CheckPrefetcherState(5, 4, 3);
216 AddStartUrlRequestExpectation("http://m.google.com/resource4.png");
217 OnReceivedRedirect("http://www.google.com/resource3.html");
218 CheckPrefetcherState(5, 3, 3);
220 OnResponse("http://www.google.com/resource2.png");
221 CheckPrefetcherState(4, 3, 2);
223 AddStartUrlRequestExpectation("http://yahoo.com/resource3.png");
224 OnReceivedRedirect("http://yahoo.com/resource2.png");
225 CheckPrefetcherState(4, 2, 2);
227 AddStartUrlRequestExpectation("http://yahoo.com/resource4.png");
228 OnResponse("http://yahoo.com/resource1.png");
229 CheckPrefetcherState(4, 1, 2);
231 AddStartUrlRequestExpectation("http://yahoo.com/resource5.png");
232 OnResponse("http://yahoo.com/resource4.png");
233 CheckPrefetcherState(4, 0, 2);
235 OnResponse("http://yahoo.com/resource5.png");
236 CheckPrefetcherState(3, 0, 2);
238 OnCertificateRequested("http://m.google.com/resource4.png");
239 CheckPrefetcherState(2, 0, 2);
241 OnAuthRequired("http://m.google.com/resource3.css");
242 CheckPrefetcherState(1, 0, 1);
244 // Expect the final call.
245 EXPECT_CALL(prefetcher_delegate_
,
246 ResourcePrefetcherFinished(Eq(prefetcher_
.get()),
249 OnResponse("http://yahoo.com/resource3.png");
250 CheckPrefetcherState(0, 0, 0);
252 // Check the prefetch status.
253 EXPECT_EQ((*requests_ptr
)[0]->prefetch_status
,
254 Request::PREFETCH_STATUS_CERT_ERROR
);
255 EXPECT_EQ((*requests_ptr
)[1]->prefetch_status
,
256 Request::PREFETCH_STATUS_FROM_CACHE
);
257 EXPECT_EQ((*requests_ptr
)[2]->prefetch_status
,
258 Request::PREFETCH_STATUS_FROM_CACHE
);
259 EXPECT_EQ((*requests_ptr
)[3]->prefetch_status
,
260 Request::PREFETCH_STATUS_REDIRECTED
);
261 EXPECT_EQ((*requests_ptr
)[4]->prefetch_status
,
262 Request::PREFETCH_STATUS_FROM_CACHE
);
263 EXPECT_EQ((*requests_ptr
)[5]->prefetch_status
,
264 Request::PREFETCH_STATUS_FROM_CACHE
);
265 EXPECT_EQ((*requests_ptr
)[6]->prefetch_status
,
266 Request::PREFETCH_STATUS_REDIRECTED
);
267 EXPECT_EQ((*requests_ptr
)[7]->prefetch_status
,
268 Request::PREFETCH_STATUS_FROM_CACHE
);
269 EXPECT_EQ((*requests_ptr
)[8]->prefetch_status
,
270 Request::PREFETCH_STATUS_AUTH_REQUIRED
);
271 EXPECT_EQ((*requests_ptr
)[9]->prefetch_status
,
272 Request::PREFETCH_STATUS_CERT_REQUIRED
);
273 EXPECT_EQ((*requests_ptr
)[10]->prefetch_status
,
274 Request::PREFETCH_STATUS_FROM_CACHE
);
275 EXPECT_EQ((*requests_ptr
)[11]->prefetch_status
,
276 Request::PREFETCH_STATUS_FROM_CACHE
);
281 TEST_F(ResourcePrefetcherTest
, TestPrefetcherStopped
) {
282 scoped_ptr
<ResourcePrefetcher::RequestVector
> requests(
283 new ResourcePrefetcher::RequestVector
);
284 requests
->push_back(new ResourcePrefetcher::Request(GURL(
285 "http://www.google.com/resource1.html")));
286 requests
->push_back(new ResourcePrefetcher::Request(GURL(
287 "http://www.google.com/resource2.png")));
288 requests
->push_back(new ResourcePrefetcher::Request(GURL(
289 "http://yahoo.com/resource1.png")));
290 requests
->push_back(new ResourcePrefetcher::Request(GURL(
291 "http://yahoo.com/resource2.png")));
292 requests
->push_back(new ResourcePrefetcher::Request(GURL(
293 "http://yahoo.com/resource3.png")));
294 requests
->push_back(new ResourcePrefetcher::Request(GURL(
295 "http://m.google.com/resource1.jpg")));
297 NavigationID navigation_id
;
298 navigation_id
.render_process_id
= 1;
299 navigation_id
.render_view_id
= 2;
300 navigation_id
.main_frame_url
= GURL("http://www.google.com");
302 // Needed later for comparison.
303 ResourcePrefetcher::RequestVector
* requests_ptr
= requests
.get();
305 prefetcher_
.reset(new TestResourcePrefetcher(&prefetcher_delegate_
,
308 PREFETCH_KEY_TYPE_HOST
,
311 // Starting the prefetcher maxes out the number of possible requests.
312 AddStartUrlRequestExpectation("http://www.google.com/resource1.html");
313 AddStartUrlRequestExpectation("http://www.google.com/resource2.png");
314 AddStartUrlRequestExpectation("http://yahoo.com/resource1.png");
315 AddStartUrlRequestExpectation("http://yahoo.com/resource2.png");
316 AddStartUrlRequestExpectation("http://m.google.com/resource1.jpg");
318 prefetcher_
->Start();
319 CheckPrefetcherState(5, 1, 3);
321 OnResponse("http://www.google.com/resource1.html");
322 CheckPrefetcherState(4, 1, 3);
324 prefetcher_
->Stop(); // No more queueing.
326 OnResponse("http://www.google.com/resource2.png");
327 CheckPrefetcherState(3, 1, 2);
329 OnResponse("http://yahoo.com/resource1.png");
330 CheckPrefetcherState(2, 1, 2);
332 OnResponse("http://yahoo.com/resource2.png");
333 CheckPrefetcherState(1, 1, 1);
335 // Expect the final call.
336 EXPECT_CALL(prefetcher_delegate_
,
337 ResourcePrefetcherFinished(Eq(prefetcher_
.get()),
340 OnResponse("http://m.google.com/resource1.jpg");
341 CheckPrefetcherState(0, 1, 0);
346 } // namespace predictors