Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / prerender / prerender_tracker_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 <set>
6 #include <utility>
7
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"
28
29 using content::BrowserThread;
30
31 namespace prerender {
32
33 namespace {
34
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);
45   }
46
47   virtual ~TestPrerenderContents() {
48     if (final_status() == FINAL_STATUS_MAX)
49       SetFinalStatus(FINAL_STATUS_USED);
50     PrerenderResourceThrottle::OverridePrerenderContentsForTesting(NULL);
51   }
52
53   virtual bool GetChildId(int* child_id) const OVERRIDE {
54     *child_id = child_id_;
55     return true;
56   }
57
58   virtual bool GetRouteId(int* route_id) const OVERRIDE {
59     *route_id = route_id_;
60     return true;
61   }
62
63   void Start() {
64     prerendering_has_started_ = true;
65     NotifyPrerenderStart();
66   }
67
68   void Cancel() {
69     Destroy(FINAL_STATUS_CANCELLED);
70   }
71
72   void Use() {
73     PrepareForUse();
74   }
75
76  private:
77   int child_id_;
78   int route_id_;
79 };
80
81 class TestPrerenderManager : public PrerenderManager {
82  public:
83   explicit TestPrerenderManager(PrerenderTracker* prerender_tracker) :
84       PrerenderManager(NULL, prerender_tracker) {
85     mutable_config().rate_limit_enabled = false;
86   }
87
88   // We never allocate our PrerenderContents in PrerenderManager, so we don't
89   // ever want the default pending delete behaviour.
90   virtual void MoveEntryToPendingDelete(PrerenderContents* entry,
91                                         FinalStatus final_status) OVERRIDE {
92   }
93 };
94
95 class DeferredRedirectDelegate : public net::URLRequest::Delegate,
96                                  public content::ResourceController {
97  public:
98   DeferredRedirectDelegate()
99       : throttle_(NULL),
100         was_deferred_(false),
101         cancel_called_(false),
102         resume_called_(false) {
103   }
104
105   void SetThrottle(PrerenderResourceThrottle* throttle) {
106     throttle_ = throttle;
107     throttle_->set_controller_for_testing(this);
108   }
109
110   void Run() {
111     run_loop_.reset(new base::RunLoop());
112     run_loop_->Run();
113   }
114
115   bool was_deferred() const { return was_deferred_; }
116   bool cancel_called() const { return cancel_called_; }
117   bool resume_called() const { return resume_called_; }
118
119   // net::URLRequest::Delegate implementation:
120   virtual void OnReceivedRedirect(net::URLRequest* request,
121                                   const GURL& new_url,
122                                   bool* defer_redirect) OVERRIDE {
123     // Defer the redirect either way.
124     *defer_redirect = true;
125
126     // Find out what the throttle would have done.
127     throttle_->WillRedirectRequest(new_url, &was_deferred_);
128     run_loop_->Quit();
129   }
130   virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE { }
131   virtual void OnReadCompleted(net::URLRequest* request,
132                                int bytes_read) OVERRIDE {
133   }
134
135   // content::ResourceController implementation:
136   virtual void Cancel() OVERRIDE {
137     EXPECT_FALSE(cancel_called_);
138     EXPECT_FALSE(resume_called_);
139
140     cancel_called_ = true;
141     run_loop_->Quit();
142   }
143   virtual void CancelAndIgnore() OVERRIDE { Cancel(); }
144   virtual void CancelWithError(int error_code) OVERRIDE { Cancel(); }
145   virtual void Resume() OVERRIDE {
146     EXPECT_TRUE(was_deferred_);
147     EXPECT_FALSE(cancel_called_);
148     EXPECT_FALSE(resume_called_);
149
150     resume_called_ = true;
151     run_loop_->Quit();
152   }
153
154  private:
155   scoped_ptr<base::RunLoop> run_loop_;
156   PrerenderResourceThrottle* throttle_;
157   bool was_deferred_;
158   bool cancel_called_;
159   bool resume_called_;
160
161   DISALLOW_COPY_AND_ASSIGN(DeferredRedirectDelegate);
162 };
163
164 }  // namespace
165
166 class PrerenderTrackerTest : public testing::Test {
167  public:
168   static const int kDefaultChildId = 0;
169   static const int kDefaultRouteId = 100;
170
171   PrerenderTrackerTest() :
172       ui_thread_(BrowserThread::UI, &message_loop_),
173       io_thread_(BrowserThread::IO, &message_loop_),
174       prerender_manager_(prerender_tracker()),
175       test_contents_(&prerender_manager_, kDefaultChildId, kDefaultRouteId) {
176     chrome_browser_net::SetUrlRequestMocksEnabled(true);
177   }
178
179   virtual ~PrerenderTrackerTest() {
180     chrome_browser_net::SetUrlRequestMocksEnabled(false);
181
182     // Cleanup work so the file IO tasks from URLRequestMockHTTPJob
183     // are gone.
184     content::BrowserThread::GetBlockingPool()->FlushForTesting();
185     RunEvents();
186   }
187
188   PrerenderTracker* prerender_tracker() {
189     return g_browser_process->prerender_tracker();
190   }
191
192   TestPrerenderManager* prerender_manager() {
193     return &prerender_manager_;
194   }
195
196   TestPrerenderContents* test_contents() {
197     return &test_contents_;
198   }
199
200   // Runs any tasks queued on either thread.
201   void RunEvents() {
202     message_loop_.RunUntilIdle();
203   }
204
205  private:
206   base::MessageLoopForIO message_loop_;
207   content::TestBrowserThread ui_thread_;
208   content::TestBrowserThread io_thread_;
209
210   TestPrerenderManager prerender_manager_;
211   TestPrerenderContents test_contents_;
212 };
213
214 // Checks that deferred redirects are throttled and resumed correctly.
215 TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectResume) {
216   const base::FilePath::CharType kRedirectPath[] =
217       FILE_PATH_LITERAL("prerender/image-deferred.png");
218
219   test_contents()->Start();
220   RunEvents();
221
222   // Fake a request.
223   net::TestURLRequestContext url_request_context;
224   DeferredRedirectDelegate delegate;
225   net::URLRequest request(
226       content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
227       net::DEFAULT_PRIORITY,
228       &delegate,
229       &url_request_context);
230   content::ResourceRequestInfo::AllocateForTesting(
231       &request, ResourceType::IMAGE, NULL,
232       kDefaultChildId, kDefaultRouteId, MSG_ROUTING_NONE, true);
233
234   // Install a prerender throttle.
235   PrerenderResourceThrottle throttle(&request);
236   delegate.SetThrottle(&throttle);
237
238   // Start the request and wait for a redirect.
239   request.Start();
240   delegate.Run();
241   EXPECT_TRUE(delegate.was_deferred());
242   // This calls WillRedirectRequestOnUI().
243   RunEvents();
244
245   // Display the prerendered RenderView and wait for the throttle to
246   // notice.
247   test_contents()->Use();
248   delegate.Run();
249   EXPECT_TRUE(delegate.resume_called());
250   EXPECT_FALSE(delegate.cancel_called());
251 }
252
253 // Checks that redirects in main frame loads are not deferred.
254 TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectMainFrame) {
255   const base::FilePath::CharType kRedirectPath[] =
256       FILE_PATH_LITERAL("prerender/image-deferred.png");
257
258   test_contents()->Start();
259   RunEvents();
260
261   // Fake a request.
262   net::TestURLRequestContext url_request_context;
263   DeferredRedirectDelegate delegate;
264   net::URLRequest request(
265       content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
266       net::DEFAULT_PRIORITY,
267       &delegate,
268       &url_request_context);
269   content::ResourceRequestInfo::AllocateForTesting(
270       &request, ResourceType::MAIN_FRAME, NULL,
271       kDefaultChildId, kDefaultRouteId, MSG_ROUTING_NONE, true);
272
273   // Install a prerender throttle.
274   PrerenderResourceThrottle throttle(&request);
275   delegate.SetThrottle(&throttle);
276
277   // Start the request and wait for a redirect. This time, it should
278   // not be deferred.
279   request.Start();
280   delegate.Run();
281   // This calls WillRedirectRequestOnUI().
282   RunEvents();
283
284   // Cleanup work so the prerender is gone.
285   test_contents()->Cancel();
286   RunEvents();
287 }
288
289 // Checks that attempting to defer a synchronous request aborts the
290 // prerender.
291 TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectSyncXHR) {
292   const base::FilePath::CharType kRedirectPath[] =
293       FILE_PATH_LITERAL("prerender/image-deferred.png");
294
295   test_contents()->Start();
296   RunEvents();
297
298   // Fake a request.
299   net::TestURLRequestContext url_request_context;
300   DeferredRedirectDelegate delegate;
301   net::URLRequest request(
302       content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kRedirectPath)),
303       net::DEFAULT_PRIORITY,
304       &delegate,
305       &url_request_context);
306   content::ResourceRequestInfo::AllocateForTesting(
307       &request, ResourceType::XHR, NULL,
308       kDefaultChildId, kDefaultRouteId, MSG_ROUTING_NONE, false);
309
310   // Install a prerender throttle.
311   PrerenderResourceThrottle throttle(&request);
312   delegate.SetThrottle(&throttle);
313
314   // Start the request and wait for a redirect.
315   request.Start();
316   delegate.Run();
317   // This calls WillRedirectRequestOnUI().
318   RunEvents();
319
320   // We should have cancelled the prerender.
321   EXPECT_EQ(FINAL_STATUS_BAD_DEFERRED_REDIRECT,
322             test_contents()->final_status());
323
324   // Cleanup work so the prerender is gone.
325   test_contents()->Cancel();
326   RunEvents();
327 }
328
329 }  // namespace prerender