Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_resource_throttle_unittest.cc
bloba66296e33ac6efb2b9b7dc715418ccf1e54b1e10
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 <set>
6 #include <utility>
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/browser/net/url_request_mock_util.h"
14 #include "chrome/browser/prerender/prerender_contents.h"
15 #include "chrome/browser/prerender/prerender_manager.h"
16 #include "chrome/browser/prerender/prerender_resource_throttle.h"
17 #include "chrome/test/base/testing_browser_process.h"
18 #include "content/public/browser/resource_controller.h"
19 #include "content/public/browser/resource_request_info.h"
20 #include "content/public/test/test_browser_thread.h"
21 #include "ipc/ipc_message.h"
22 #include "net/base/request_priority.h"
23 #include "net/test/url_request/url_request_mock_http_job.h"
24 #include "net/url_request/redirect_info.h"
25 #include "net/url_request/url_request.h"
26 #include "net/url_request/url_request_test_util.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using content::BrowserThread;
30 using content::ResourceType;
32 namespace prerender {
34 namespace {
36 class TestPrerenderContents : public PrerenderContents {
37 public:
38 TestPrerenderContents(PrerenderManager* prerender_manager,
39 int child_id, int route_id)
40 : PrerenderContents(prerender_manager, static_cast<Profile*>(NULL),
41 GURL(), content::Referrer(), ORIGIN_NONE),
42 child_id_(child_id),
43 route_id_(route_id) {
44 PrerenderResourceThrottle::OverridePrerenderContentsForTesting(this);
47 ~TestPrerenderContents() override {
48 if (final_status() == FINAL_STATUS_MAX)
49 SetFinalStatus(FINAL_STATUS_USED);
50 PrerenderResourceThrottle::OverridePrerenderContentsForTesting(NULL);
53 bool GetChildId(int* child_id) const override {
54 *child_id = child_id_;
55 return true;
58 bool GetRouteId(int* route_id) const override {
59 *route_id = route_id_;
60 return true;
63 void Start() {
64 prerendering_has_started_ = true;
65 NotifyPrerenderStart();
68 void Cancel() {
69 Destroy(FINAL_STATUS_CANCELLED);
72 void Use() {
73 PrepareForUse();
76 private:
77 int child_id_;
78 int route_id_;
81 class TestPrerenderManager : public PrerenderManager {
82 public:
83 TestPrerenderManager() : PrerenderManager(nullptr) {
84 mutable_config().rate_limit_enabled = false;
87 // We never allocate our PrerenderContents in PrerenderManager, so we don't
88 // ever want the default pending delete behaviour.
89 void MoveEntryToPendingDelete(PrerenderContents* entry,
90 FinalStatus final_status) override {}
93 class DeferredRedirectDelegate : public net::URLRequest::Delegate,
94 public content::ResourceController {
95 public:
96 DeferredRedirectDelegate()
97 : throttle_(NULL),
98 was_deferred_(false),
99 cancel_called_(false),
100 resume_called_(false) {
103 void SetThrottle(PrerenderResourceThrottle* throttle) {
104 throttle_ = throttle;
105 throttle_->set_controller_for_testing(this);
108 void Run() {
109 run_loop_.reset(new base::RunLoop());
110 run_loop_->Run();
113 bool was_deferred() const { return was_deferred_; }
114 bool cancel_called() const { return cancel_called_; }
115 bool resume_called() const { return resume_called_; }
117 // net::URLRequest::Delegate implementation:
118 void OnReceivedRedirect(net::URLRequest* request,
119 const net::RedirectInfo& redirect_info,
120 bool* defer_redirect) override {
121 // Defer the redirect either way.
122 *defer_redirect = true;
124 // Find out what the throttle would have done.
125 throttle_->WillRedirectRequest(redirect_info, &was_deferred_);
126 run_loop_->Quit();
128 void OnResponseStarted(net::URLRequest* request) override {}
129 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {}
131 // content::ResourceController implementation:
132 void Cancel() override {
133 EXPECT_FALSE(cancel_called_);
134 EXPECT_FALSE(resume_called_);
136 cancel_called_ = true;
137 run_loop_->Quit();
139 void CancelAndIgnore() override { Cancel(); }
140 void CancelWithError(int error_code) override { Cancel(); }
141 void Resume() override {
142 EXPECT_TRUE(was_deferred_);
143 EXPECT_FALSE(cancel_called_);
144 EXPECT_FALSE(resume_called_);
146 resume_called_ = true;
147 run_loop_->Quit();
150 private:
151 scoped_ptr<base::RunLoop> run_loop_;
152 PrerenderResourceThrottle* throttle_;
153 bool was_deferred_;
154 bool cancel_called_;
155 bool resume_called_;
157 DISALLOW_COPY_AND_ASSIGN(DeferredRedirectDelegate);
160 } // namespace
162 class PrerenderResourceThrottleTest : public testing::Test {
163 public:
164 static const int kDefaultChildId = 0;
165 static const int kDefaultRouteId = 100;
167 PrerenderResourceThrottleTest() :
168 ui_thread_(BrowserThread::UI, &message_loop_),
169 io_thread_(BrowserThread::IO, &message_loop_),
170 test_contents_(&prerender_manager_, kDefaultChildId, kDefaultRouteId) {
171 chrome_browser_net::SetUrlRequestMocksEnabled(true);
174 ~PrerenderResourceThrottleTest() override {
175 chrome_browser_net::SetUrlRequestMocksEnabled(false);
177 // Cleanup work so the file IO tasks from URLRequestMockHTTPJob
178 // are gone.
179 content::BrowserThread::GetBlockingPool()->FlushForTesting();
180 RunEvents();
183 TestPrerenderManager* prerender_manager() {
184 return &prerender_manager_;
187 TestPrerenderContents* test_contents() {
188 return &test_contents_;
191 // Runs any tasks queued on either thread.
192 void RunEvents() {
193 message_loop_.RunUntilIdle();
196 private:
197 base::MessageLoopForIO message_loop_;
198 content::TestBrowserThread ui_thread_;
199 content::TestBrowserThread io_thread_;
201 TestPrerenderManager prerender_manager_;
202 TestPrerenderContents test_contents_;
205 // Checks that deferred redirects are throttled and resumed correctly.
206 TEST_F(PrerenderResourceThrottleTest, RedirectResume) {
207 const base::FilePath::CharType kRedirectPath[] =
208 FILE_PATH_LITERAL("prerender/image-deferred.png");
210 test_contents()->Start();
211 RunEvents();
213 // Fake a request.
214 net::TestURLRequestContext url_request_context;
215 DeferredRedirectDelegate delegate;
216 scoped_ptr<net::URLRequest> request(url_request_context.CreateRequest(
217 net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
218 net::DEFAULT_PRIORITY,
219 &delegate));
220 content::ResourceRequestInfo::AllocateForTesting(
221 request.get(),
222 content::RESOURCE_TYPE_IMAGE,
223 NULL,
224 kDefaultChildId,
225 kDefaultRouteId,
226 MSG_ROUTING_NONE,
227 false, // is_main_frame
228 false, // parent_is_main_frame
229 true, // allow_download
230 true); // is_async
232 // Install a prerender throttle.
233 PrerenderResourceThrottle throttle(request.get());
234 delegate.SetThrottle(&throttle);
236 // Start the request and wait for a redirect.
237 request->Start();
238 delegate.Run();
239 EXPECT_TRUE(delegate.was_deferred());
240 // This calls WillRedirectRequestOnUI().
241 RunEvents();
243 // Display the prerendered RenderView and wait for the throttle to
244 // notice.
245 test_contents()->Use();
246 delegate.Run();
247 EXPECT_TRUE(delegate.resume_called());
248 EXPECT_FALSE(delegate.cancel_called());
251 // Checks that redirects in main frame loads are not deferred.
252 TEST_F(PrerenderResourceThrottleTest, RedirectMainFrame) {
253 const base::FilePath::CharType kRedirectPath[] =
254 FILE_PATH_LITERAL("prerender/image-deferred.png");
256 test_contents()->Start();
257 RunEvents();
259 // Fake a request.
260 net::TestURLRequestContext url_request_context;
261 DeferredRedirectDelegate delegate;
262 scoped_ptr<net::URLRequest> request(url_request_context.CreateRequest(
263 net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
264 net::DEFAULT_PRIORITY,
265 &delegate));
266 content::ResourceRequestInfo::AllocateForTesting(
267 request.get(),
268 content::RESOURCE_TYPE_MAIN_FRAME,
269 NULL,
270 kDefaultChildId,
271 kDefaultRouteId,
272 MSG_ROUTING_NONE,
273 true, // is_main_frame
274 false, // parent_is_main_frame
275 true, // allow_download
276 true); // is_async
278 // Install a prerender throttle.
279 PrerenderResourceThrottle throttle(request.get());
280 delegate.SetThrottle(&throttle);
282 // Start the request and wait for a redirect. This time, it should
283 // not be deferred.
284 request->Start();
285 delegate.Run();
286 // This calls WillRedirectRequestOnUI().
287 RunEvents();
289 // Cleanup work so the prerender is gone.
290 test_contents()->Cancel();
291 RunEvents();
294 // Checks that attempting to defer a synchronous request aborts the
295 // prerender.
296 TEST_F(PrerenderResourceThrottleTest, RedirectSyncXHR) {
297 const base::FilePath::CharType kRedirectPath[] =
298 FILE_PATH_LITERAL("prerender/image-deferred.png");
300 test_contents()->Start();
301 RunEvents();
303 // Fake a request.
304 net::TestURLRequestContext url_request_context;
305 DeferredRedirectDelegate delegate;
306 scoped_ptr<net::URLRequest> request(url_request_context.CreateRequest(
307 net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
308 net::DEFAULT_PRIORITY,
309 &delegate));
310 content::ResourceRequestInfo::AllocateForTesting(
311 request.get(),
312 content::RESOURCE_TYPE_XHR,
313 NULL,
314 kDefaultChildId,
315 kDefaultRouteId,
316 MSG_ROUTING_NONE,
317 false, // is_main_frame
318 false, // parent_is_main_frame
319 true, // allow_download
320 false); // is_async
322 // Install a prerender throttle.
323 PrerenderResourceThrottle throttle(request.get());
324 delegate.SetThrottle(&throttle);
326 // Start the request and wait for a redirect.
327 request->Start();
328 delegate.Run();
329 // This calls WillRedirectRequestOnUI().
330 RunEvents();
332 // We should have cancelled the prerender.
333 EXPECT_EQ(FINAL_STATUS_BAD_DEFERRED_REDIRECT,
334 test_contents()->final_status());
336 // Cleanup work so the prerender is gone.
337 test_contents()->Cancel();
338 RunEvents();
341 } // namespace prerender