Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_tracker_unittest.cc
blob8d35e49463dc4fa2f80f03e7ad437f947ccc4ae2
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/browser/prerender/prerender_tracker.h"
18 #include "chrome/test/base/testing_browser_process.h"
19 #include "content/public/browser/resource_controller.h"
20 #include "content/public/browser/resource_request_info.h"
21 #include "content/public/test/test_browser_thread.h"
22 #include "content/test/net/url_request_mock_http_job.h"
23 #include "ipc/ipc_message.h"
24 #include "net/base/request_priority.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;
31 namespace prerender {
33 namespace {
35 class TestPrerenderContents : public PrerenderContents {
36 public:
37 TestPrerenderContents(PrerenderManager* prerender_manager,
38 int child_id, int route_id)
39 : PrerenderContents(prerender_manager, static_cast<Profile*>(NULL),
40 GURL(), content::Referrer(), ORIGIN_NONE,
41 PrerenderManager::kNoExperiment),
42 child_id_(child_id),
43 route_id_(route_id) {
44 PrerenderResourceThrottle::OverridePrerenderContentsForTesting(this);
47 virtual ~TestPrerenderContents() {
48 if (final_status() == FINAL_STATUS_MAX)
49 SetFinalStatus(FINAL_STATUS_USED);
50 PrerenderResourceThrottle::OverridePrerenderContentsForTesting(NULL);
53 virtual bool GetChildId(int* child_id) const OVERRIDE {
54 *child_id = child_id_;
55 return true;
58 virtual bool GetRouteId(int* route_id) const OVERRIDE {
59 *route_id = route_id_;
60 return true;
63 void Start() {
64 AddObserver(prerender_manager()->prerender_tracker());
65 prerendering_has_started_ = true;
66 NotifyPrerenderStart();
69 void Cancel() {
70 Destroy(FINAL_STATUS_CANCELLED);
73 void Use() {
74 SetFinalStatus(FINAL_STATUS_USED);
75 PrepareForUse();
78 private:
79 int child_id_;
80 int route_id_;
83 class TestPrerenderManager : public PrerenderManager {
84 public:
85 explicit TestPrerenderManager(PrerenderTracker* prerender_tracker) :
86 PrerenderManager(NULL, prerender_tracker) {
87 mutable_config().rate_limit_enabled = false;
90 // We never allocate our PrerenderContents in PrerenderManager, so we don't
91 // ever want the default pending delete behaviour.
92 virtual void MoveEntryToPendingDelete(PrerenderContents* entry,
93 FinalStatus final_status) OVERRIDE {
97 class DeferredRedirectDelegate : public net::URLRequest::Delegate,
98 public content::ResourceController {
99 public:
100 DeferredRedirectDelegate()
101 : throttle_(NULL),
102 was_deferred_(false),
103 cancel_called_(false),
104 resume_called_(false) {
107 void SetThrottle(PrerenderResourceThrottle* throttle) {
108 throttle_ = throttle;
109 throttle_->set_controller_for_testing(this);
112 void Run() {
113 run_loop_.reset(new base::RunLoop());
114 run_loop_->Run();
117 bool was_deferred() const { return was_deferred_; }
118 bool cancel_called() const { return cancel_called_; }
119 bool resume_called() const { return resume_called_; }
121 // net::URLRequest::Delegate implementation:
122 virtual void OnReceivedRedirect(net::URLRequest* request,
123 const GURL& new_url,
124 bool* defer_redirect) OVERRIDE {
125 // Defer the redirect either way.
126 *defer_redirect = true;
128 // Find out what the throttle would have done.
129 throttle_->WillRedirectRequest(new_url, &was_deferred_);
130 run_loop_->Quit();
132 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE { }
133 virtual void OnReadCompleted(net::URLRequest* request,
134 int bytes_read) OVERRIDE {
137 // content::ResourceController implementation:
138 virtual void Cancel() OVERRIDE {
139 EXPECT_FALSE(cancel_called_);
140 EXPECT_FALSE(resume_called_);
142 cancel_called_ = true;
143 run_loop_->Quit();
145 virtual void CancelAndIgnore() OVERRIDE { Cancel(); }
146 virtual void CancelWithError(int error_code) OVERRIDE { Cancel(); }
147 virtual void Resume() OVERRIDE {
148 EXPECT_TRUE(was_deferred_);
149 EXPECT_FALSE(cancel_called_);
150 EXPECT_FALSE(resume_called_);
152 resume_called_ = true;
153 run_loop_->Quit();
156 private:
157 scoped_ptr<base::RunLoop> run_loop_;
158 PrerenderResourceThrottle* throttle_;
159 bool was_deferred_;
160 bool cancel_called_;
161 bool resume_called_;
163 DISALLOW_COPY_AND_ASSIGN(DeferredRedirectDelegate);
166 } // namespace
168 class PrerenderTrackerTest : public testing::Test {
169 public:
170 static const int kDefaultChildId = 0;
171 static const int kDefaultRouteId = 100;
173 PrerenderTrackerTest() :
174 ui_thread_(BrowserThread::UI, &message_loop_),
175 io_thread_(BrowserThread::IO, &message_loop_),
176 prerender_manager_(prerender_tracker()),
177 test_contents_(&prerender_manager_, kDefaultChildId, kDefaultRouteId) {
178 chrome_browser_net::SetUrlRequestMocksEnabled(true);
181 virtual ~PrerenderTrackerTest() {
182 chrome_browser_net::SetUrlRequestMocksEnabled(false);
184 // Cleanup work so the file IO tasks from URLRequestMockHTTPJob
185 // are gone.
186 content::BrowserThread::GetBlockingPool()->FlushForTesting();
187 RunEvents();
190 PrerenderTracker* prerender_tracker() {
191 return g_browser_process->prerender_tracker();
194 TestPrerenderManager* prerender_manager() {
195 return &prerender_manager_;
198 TestPrerenderContents* test_contents() {
199 return &test_contents_;
202 // Runs any tasks queued on either thread.
203 void RunEvents() {
204 message_loop_.RunUntilIdle();
207 private:
208 base::MessageLoopForIO message_loop_;
209 content::TestBrowserThread ui_thread_;
210 content::TestBrowserThread io_thread_;
212 TestPrerenderManager prerender_manager_;
213 TestPrerenderContents test_contents_;
216 TEST_F(PrerenderTrackerTest, IsPrerenderingOnIOThread) {
217 EXPECT_FALSE(prerender_tracker()->IsPrerenderingOnIOThread(
218 kDefaultChildId, kDefaultRouteId));
220 test_contents()->Start();
221 // This calls AddPrerenderOnIOThreadTask().
222 RunEvents();
223 EXPECT_TRUE(prerender_tracker()->IsPrerenderingOnIOThread(
224 kDefaultChildId, kDefaultRouteId));
226 test_contents()->Cancel();
227 // This calls RemovePrerenderOnIOThreadTask().
228 RunEvents();
229 EXPECT_FALSE(prerender_tracker()->IsPrerenderingOnIOThread(
230 kDefaultChildId, kDefaultRouteId));
233 // Checks that deferred redirects are throttled and resumed correctly.
234 TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectResume) {
235 const base::FilePath::CharType kRedirectPath[] =
236 FILE_PATH_LITERAL("prerender/image-deferred.png");
238 test_contents()->Start();
239 // This calls AddPrerenderOnIOThreadTask().
240 RunEvents();
241 EXPECT_TRUE(prerender_tracker()->IsPrerenderingOnIOThread(
242 kDefaultChildId, kDefaultRouteId));
244 // Fake a request.
245 net::TestURLRequestContext url_request_context;
246 DeferredRedirectDelegate delegate;
247 net::URLRequest request(
248 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
249 net::DEFAULT_PRIORITY,
250 &delegate,
251 &url_request_context);
252 content::ResourceRequestInfo::AllocateForTesting(
253 &request, ResourceType::IMAGE, NULL,
254 kDefaultChildId, kDefaultRouteId, MSG_ROUTING_NONE, true);
256 // Install a prerender throttle.
257 PrerenderResourceThrottle throttle(&request, prerender_tracker());
258 delegate.SetThrottle(&throttle);
260 // Start the request and wait for a redirect.
261 request.Start();
262 delegate.Run();
263 EXPECT_TRUE(delegate.was_deferred());
264 // This calls WillRedirectRequestOnUI().
265 RunEvents();
267 // Display the prerendered RenderView and wait for the throttle to
268 // notice.
269 test_contents()->Use();
270 delegate.Run();
271 EXPECT_TRUE(delegate.resume_called());
272 EXPECT_FALSE(delegate.cancel_called());
275 // Checks that deferred redirects are cancelled on prerender cancel.
276 TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectCancel) {
277 const base::FilePath::CharType kRedirectPath[] =
278 FILE_PATH_LITERAL("prerender/image-deferred.png");
280 test_contents()->Start();
281 // This calls AddPrerenderOnIOThreadTask().
282 RunEvents();
283 EXPECT_TRUE(prerender_tracker()->IsPrerenderingOnIOThread(
284 kDefaultChildId, kDefaultRouteId));
286 // Fake a request.
287 net::TestURLRequestContext url_request_context;
288 DeferredRedirectDelegate delegate;
289 net::URLRequest request(
290 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
291 net::DEFAULT_PRIORITY,
292 &delegate,
293 &url_request_context);
294 content::ResourceRequestInfo::AllocateForTesting(
295 &request, ResourceType::IMAGE, NULL,
296 kDefaultChildId, kDefaultRouteId, MSG_ROUTING_NONE, true);
298 // Install a prerender throttle.
299 PrerenderResourceThrottle throttle(&request, prerender_tracker());
300 delegate.SetThrottle(&throttle);
302 // Start the request and wait for a redirect.
303 request.Start();
304 delegate.Run();
305 EXPECT_TRUE(delegate.was_deferred());
306 // This calls WillRedirectRequestOnUI().
307 RunEvents();
309 // Display the prerendered RenderView and wait for the throttle to
310 // notice.
311 test_contents()->Cancel();
312 delegate.Run();
313 EXPECT_FALSE(delegate.resume_called());
314 EXPECT_TRUE(delegate.cancel_called());
317 // Checks that redirects in main frame loads are not deferred.
318 TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectMainFrame) {
319 const base::FilePath::CharType kRedirectPath[] =
320 FILE_PATH_LITERAL("prerender/image-deferred.png");
322 test_contents()->Start();
323 // This calls AddPrerenderOnIOThreadTask().
324 RunEvents();
325 EXPECT_TRUE(prerender_tracker()->IsPrerenderingOnIOThread(
326 kDefaultChildId, kDefaultRouteId));
328 // Fake a request.
329 net::TestURLRequestContext url_request_context;
330 DeferredRedirectDelegate delegate;
331 net::URLRequest request(
332 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
333 net::DEFAULT_PRIORITY,
334 &delegate,
335 &url_request_context);
336 content::ResourceRequestInfo::AllocateForTesting(
337 &request, ResourceType::MAIN_FRAME, NULL,
338 kDefaultChildId, kDefaultRouteId, MSG_ROUTING_NONE, true);
340 // Install a prerender throttle.
341 PrerenderResourceThrottle throttle(&request, prerender_tracker());
342 delegate.SetThrottle(&throttle);
344 // Start the request and wait for a redirect. This time, it should
345 // not be deferred.
346 request.Start();
347 delegate.Run();
348 // This calls WillRedirectRequestOnUI().
349 RunEvents();
351 // Cleanup work so the prerender is gone.
352 test_contents()->Cancel();
353 RunEvents();
356 // Checks that attempting to defer a synchronous request aborts the
357 // prerender.
358 TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectSyncXHR) {
359 const base::FilePath::CharType kRedirectPath[] =
360 FILE_PATH_LITERAL("prerender/image-deferred.png");
362 test_contents()->Start();
363 // This calls AddPrerenderOnIOThreadTask().
364 RunEvents();
365 EXPECT_TRUE(prerender_tracker()->IsPrerenderingOnIOThread(
366 kDefaultChildId, kDefaultRouteId));
368 // Fake a request.
369 net::TestURLRequestContext url_request_context;
370 DeferredRedirectDelegate delegate;
371 net::URLRequest request(
372 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
373 net::DEFAULT_PRIORITY,
374 &delegate,
375 &url_request_context);
376 content::ResourceRequestInfo::AllocateForTesting(
377 &request, ResourceType::XHR, NULL,
378 kDefaultChildId, kDefaultRouteId, MSG_ROUTING_NONE, false);
380 // Install a prerender throttle.
381 PrerenderResourceThrottle throttle(&request, prerender_tracker());
382 delegate.SetThrottle(&throttle);
384 // Start the request and wait for a redirect.
385 request.Start();
386 delegate.Run();
387 // This calls WillRedirectRequestOnUI().
388 RunEvents();
390 // We should have cancelled the prerender.
391 EXPECT_EQ(FINAL_STATUS_BAD_DEFERRED_REDIRECT,
392 test_contents()->final_status());
394 // Cleanup work so the prerender is gone.
395 test_contents()->Cancel();
396 RunEvents();
399 } // namespace prerender