GN + Android: extract android_standalone_library rule.
[chromium-blink-merge.git] / components / navigation_interception / intercept_navigation_resource_throttle_unittest.cc
blobbb1e26aefe0ab0d36d7bee52b614d20f0449f6a5
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/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "components/navigation_interception/intercept_navigation_resource_throttle.h"
11 #include "components/navigation_interception/navigation_params.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/render_frame_host.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/resource_context.h"
16 #include "content/public/browser/resource_controller.h"
17 #include "content/public/browser/resource_dispatcher_host.h"
18 #include "content/public/browser/resource_dispatcher_host_delegate.h"
19 #include "content/public/browser/resource_request_info.h"
20 #include "content/public/browser/resource_throttle.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/test/mock_resource_context.h"
24 #include "content/public/test/test_renderer_host.h"
25 #include "net/base/request_priority.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/http/http_response_info.h"
28 #include "net/url_request/url_request.h"
29 #include "net/url_request/url_request_test_util.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 using content::ResourceType;
34 using testing::_;
35 using testing::Eq;
36 using testing::Ne;
37 using testing::Property;
38 using testing::Return;
40 namespace navigation_interception {
42 namespace {
44 const char kTestUrl[] = "http://www.test.com/";
45 const char kUnsafeTestUrl[] = "about:crash";
47 // The MS C++ compiler complains about not being able to resolve which url()
48 // method (const or non-const) to use if we use the Property matcher to check
49 // the return value of the NavigationParams::url() method.
50 // It is possible to suppress the error by specifying the types directly but
51 // that results in very ugly syntax, which is why these custom matchers are
52 // used instead.
53 MATCHER(NavigationParamsUrlIsTest, "") {
54 return arg.url() == GURL(kTestUrl);
57 MATCHER(NavigationParamsUrlIsSafe, "") {
58 return arg.url() != GURL(kUnsafeTestUrl);
61 } // namespace
64 // MockInterceptCallbackReceiver ----------------------------------------------
66 class MockInterceptCallbackReceiver {
67 public:
68 MOCK_METHOD2(ShouldIgnoreNavigation,
69 bool(content::WebContents* source,
70 const NavigationParams& navigation_params));
73 // MockResourceController -----------------------------------------------------
74 class MockResourceController : public content::ResourceController {
75 public:
76 enum Status {
77 UNKNOWN,
78 RESUMED,
79 CANCELLED
82 MockResourceController()
83 : status_(UNKNOWN) {
86 Status status() const { return status_; }
88 // ResourceController:
89 void Cancel() override { NOTREACHED(); }
90 void CancelAndIgnore() override { status_ = CANCELLED; }
91 void CancelWithError(int error_code) override { NOTREACHED(); }
92 void Resume() override {
93 DCHECK(status_ == UNKNOWN);
94 status_ = RESUMED;
97 private:
98 Status status_;
101 // TestIOThreadState ----------------------------------------------------------
103 enum RedirectMode {
104 REDIRECT_MODE_NO_REDIRECT,
105 REDIRECT_MODE_302,
108 class TestIOThreadState {
109 public:
110 TestIOThreadState(const GURL& url,
111 int render_process_id,
112 int render_frame_id,
113 const std::string& request_method,
114 RedirectMode redirect_mode,
115 MockInterceptCallbackReceiver* callback_receiver)
116 : resource_context_(&test_url_request_context_),
117 request_(resource_context_.GetRequestContext()->CreateRequest(
118 url,
119 net::DEFAULT_PRIORITY,
120 NULL /* delegate */,
121 NULL /* cookie_store */)) {
122 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
123 if (render_process_id != MSG_ROUTING_NONE &&
124 render_frame_id != MSG_ROUTING_NONE) {
125 content::ResourceRequestInfo::AllocateForTesting(
126 request_.get(),
127 content::RESOURCE_TYPE_MAIN_FRAME,
128 &resource_context_,
129 render_process_id,
130 MSG_ROUTING_NONE,
131 render_frame_id,
132 true, // is_main_frame
133 false, // parent_is_main_frame
134 true, // allow_download
135 false); // is_async
137 throttle_.reset(new InterceptNavigationResourceThrottle(
138 request_.get(),
139 base::Bind(&MockInterceptCallbackReceiver::ShouldIgnoreNavigation,
140 base::Unretained(callback_receiver))));
141 throttle_->set_controller_for_testing(&throttle_controller_);
142 request_->set_method(request_method);
144 if (redirect_mode == REDIRECT_MODE_302) {
145 net::HttpResponseInfo& response_info =
146 const_cast<net::HttpResponseInfo&>(request_->response_info());
147 response_info.headers = new net::HttpResponseHeaders(
148 "Status: 302 Found\0\0");
152 void ThrottleWillStartRequest(bool* defer) {
153 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
154 throttle_->WillStartRequest(defer);
157 void ThrottleWillRedirectRequest(const GURL& new_url, bool* defer) {
158 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
159 throttle_->WillRedirectRequest(new_url, defer);
162 bool request_resumed() const {
163 return throttle_controller_.status() ==
164 MockResourceController::RESUMED;
167 bool request_cancelled() const {
168 return throttle_controller_.status() ==
169 MockResourceController::CANCELLED;
172 private:
173 net::TestURLRequestContext test_url_request_context_;
174 content::MockResourceContext resource_context_;
175 scoped_ptr<net::URLRequest> request_;
176 scoped_ptr<InterceptNavigationResourceThrottle> throttle_;
177 MockResourceController throttle_controller_;
180 // InterceptNavigationResourceThrottleTest ------------------------------------
182 class InterceptNavigationResourceThrottleTest
183 : public content::RenderViewHostTestHarness {
184 public:
185 InterceptNavigationResourceThrottleTest()
186 : mock_callback_receiver_(new MockInterceptCallbackReceiver()),
187 io_thread_state_(NULL) {
190 void SetUp() override { RenderViewHostTestHarness::SetUp(); }
192 void TearDown() override {
193 if (web_contents())
194 web_contents()->SetDelegate(NULL);
196 content::BrowserThread::DeleteSoon(
197 content::BrowserThread::IO, FROM_HERE, io_thread_state_);
199 RenderViewHostTestHarness::TearDown();
202 void SetIOThreadState(TestIOThreadState* io_thread_state) {
203 io_thread_state_ = io_thread_state;
206 void RunThrottleWillStartRequestOnIOThread(
207 const GURL& url,
208 const std::string& request_method,
209 RedirectMode redirect_mode,
210 int render_process_id,
211 int render_frame_id,
212 bool* defer) {
213 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
214 TestIOThreadState* io_thread_state =
215 new TestIOThreadState(url, render_process_id, render_frame_id,
216 request_method, redirect_mode,
217 mock_callback_receiver_.get());
219 SetIOThreadState(io_thread_state);
221 if (redirect_mode == REDIRECT_MODE_NO_REDIRECT)
222 io_thread_state->ThrottleWillStartRequest(defer);
223 else
224 io_thread_state->ThrottleWillRedirectRequest(url, defer);
227 protected:
228 enum ShouldIgnoreNavigationCallbackAction {
229 IgnoreNavigation,
230 DontIgnoreNavigation
233 void SetUpWebContentsDelegateAndDrainRunLoop(
234 ShouldIgnoreNavigationCallbackAction callback_action,
235 bool* defer) {
236 ON_CALL(*mock_callback_receiver_, ShouldIgnoreNavigation(_, _))
237 .WillByDefault(Return(callback_action == IgnoreNavigation));
238 EXPECT_CALL(*mock_callback_receiver_,
239 ShouldIgnoreNavigation(web_contents(),
240 NavigationParamsUrlIsTest()))
241 .Times(1);
243 content::BrowserThread::PostTask(
244 content::BrowserThread::IO,
245 FROM_HERE,
246 base::Bind(
247 &InterceptNavigationResourceThrottleTest::
248 RunThrottleWillStartRequestOnIOThread,
249 base::Unretained(this),
250 GURL(kTestUrl),
251 "GET",
252 REDIRECT_MODE_NO_REDIRECT,
253 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
254 web_contents()->GetMainFrame()->GetRoutingID(),
255 base::Unretained(defer)));
257 // Wait for the request to finish processing.
258 base::RunLoop().RunUntilIdle();
261 void WaitForPreviouslyScheduledIoThreadWork() {
262 base::WaitableEvent io_thread_work_done(true, false);
263 content::BrowserThread::PostTask(
264 content::BrowserThread::IO,
265 FROM_HERE,
266 base::Bind(
267 &base::WaitableEvent::Signal,
268 base::Unretained(&io_thread_work_done)));
269 io_thread_work_done.Wait();
272 scoped_ptr<MockInterceptCallbackReceiver> mock_callback_receiver_;
273 TestIOThreadState* io_thread_state_;
276 TEST_F(InterceptNavigationResourceThrottleTest,
277 RequestDeferredAndResumedIfNavigationNotIgnored) {
278 bool defer = false;
279 SetUpWebContentsDelegateAndDrainRunLoop(DontIgnoreNavigation, &defer);
281 EXPECT_TRUE(defer);
282 ASSERT_TRUE(io_thread_state_);
283 EXPECT_TRUE(io_thread_state_->request_resumed());
286 TEST_F(InterceptNavigationResourceThrottleTest,
287 RequestDeferredAndCancelledIfNavigationIgnored) {
288 bool defer = false;
289 SetUpWebContentsDelegateAndDrainRunLoop(IgnoreNavigation, &defer);
291 EXPECT_TRUE(defer);
292 ASSERT_TRUE(io_thread_state_);
293 EXPECT_TRUE(io_thread_state_->request_cancelled());
296 TEST_F(InterceptNavigationResourceThrottleTest,
297 NoCallbackMadeIfContentsDeletedWhileThrottleRunning) {
298 bool defer = false;
300 // The tested scenario is when the WebContents is deleted after the
301 // ResourceThrottle has finished processing on the IO thread but before the
302 // UI thread callback has been processed. Since both threads in this test
303 // are serviced by one message loop, the post order is the execution order.
304 EXPECT_CALL(*mock_callback_receiver_,
305 ShouldIgnoreNavigation(_, _))
306 .Times(0);
308 content::BrowserThread::PostTask(
309 content::BrowserThread::IO,
310 FROM_HERE,
311 base::Bind(
312 &InterceptNavigationResourceThrottleTest::
313 RunThrottleWillStartRequestOnIOThread,
314 base::Unretained(this),
315 GURL(kTestUrl),
316 "GET",
317 REDIRECT_MODE_NO_REDIRECT,
318 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
319 web_contents()->GetMainFrame()->GetRoutingID(),
320 base::Unretained(&defer)));
322 content::BrowserThread::PostTask(
323 content::BrowserThread::UI,
324 FROM_HERE,
325 base::Bind(
326 &RenderViewHostTestHarness::DeleteContents,
327 base::Unretained(this)));
329 // The WebContents will now be deleted and only after that will the UI-thread
330 // callback posted by the ResourceThrottle be executed.
331 base::RunLoop().RunUntilIdle();
333 EXPECT_TRUE(defer);
334 ASSERT_TRUE(io_thread_state_);
335 EXPECT_TRUE(io_thread_state_->request_resumed());
338 TEST_F(InterceptNavigationResourceThrottleTest,
339 RequestNotDeferredForRequestNotAssociatedWithARenderView) {
340 bool defer = false;
342 content::BrowserThread::PostTask(
343 content::BrowserThread::IO,
344 FROM_HERE,
345 base::Bind(
346 &InterceptNavigationResourceThrottleTest::
347 RunThrottleWillStartRequestOnIOThread,
348 base::Unretained(this),
349 GURL(kTestUrl),
350 "GET",
351 REDIRECT_MODE_NO_REDIRECT,
352 MSG_ROUTING_NONE,
353 MSG_ROUTING_NONE,
354 base::Unretained(&defer)));
356 // Wait for the request to finish processing.
357 base::RunLoop().RunUntilIdle();
359 EXPECT_FALSE(defer);
362 TEST_F(InterceptNavigationResourceThrottleTest,
363 CallbackCalledWithFilteredUrl) {
364 bool defer = false;
366 ON_CALL(*mock_callback_receiver_,
367 ShouldIgnoreNavigation(_, NavigationParamsUrlIsSafe()))
368 .WillByDefault(Return(false));
369 EXPECT_CALL(*mock_callback_receiver_,
370 ShouldIgnoreNavigation(_, NavigationParamsUrlIsSafe()))
371 .Times(1);
373 content::BrowserThread::PostTask(
374 content::BrowserThread::IO,
375 FROM_HERE,
376 base::Bind(
377 &InterceptNavigationResourceThrottleTest::
378 RunThrottleWillStartRequestOnIOThread,
379 base::Unretained(this),
380 GURL(kUnsafeTestUrl),
381 "GET",
382 REDIRECT_MODE_NO_REDIRECT,
383 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
384 web_contents()->GetMainFrame()->GetRoutingID(),
385 base::Unretained(&defer)));
387 // Wait for the request to finish processing.
388 base::RunLoop().RunUntilIdle();
391 TEST_F(InterceptNavigationResourceThrottleTest,
392 CallbackIsPostFalseForGet) {
393 bool defer = false;
395 EXPECT_CALL(*mock_callback_receiver_,
396 ShouldIgnoreNavigation(_, AllOf(
397 NavigationParamsUrlIsSafe(),
398 Property(&NavigationParams::is_post, Eq(false)))))
399 .WillOnce(Return(false));
401 content::BrowserThread::PostTask(
402 content::BrowserThread::IO,
403 FROM_HERE,
404 base::Bind(
405 &InterceptNavigationResourceThrottleTest::
406 RunThrottleWillStartRequestOnIOThread,
407 base::Unretained(this),
408 GURL(kTestUrl),
409 "GET",
410 REDIRECT_MODE_NO_REDIRECT,
411 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
412 web_contents()->GetMainFrame()->GetRoutingID(),
413 base::Unretained(&defer)));
415 // Wait for the request to finish processing.
416 base::RunLoop().RunUntilIdle();
419 TEST_F(InterceptNavigationResourceThrottleTest,
420 CallbackIsPostTrueForPost) {
421 bool defer = false;
423 EXPECT_CALL(*mock_callback_receiver_,
424 ShouldIgnoreNavigation(_, AllOf(
425 NavigationParamsUrlIsSafe(),
426 Property(&NavigationParams::is_post, Eq(true)))))
427 .WillOnce(Return(false));
429 content::BrowserThread::PostTask(
430 content::BrowserThread::IO,
431 FROM_HERE,
432 base::Bind(
433 &InterceptNavigationResourceThrottleTest::
434 RunThrottleWillStartRequestOnIOThread,
435 base::Unretained(this),
436 GURL(kTestUrl),
437 "POST",
438 REDIRECT_MODE_NO_REDIRECT,
439 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
440 web_contents()->GetMainFrame()->GetRoutingID(),
441 base::Unretained(&defer)));
443 // Wait for the request to finish processing.
444 base::RunLoop().RunUntilIdle();
447 TEST_F(InterceptNavigationResourceThrottleTest,
448 CallbackIsPostFalseForPostConvertedToGetBy302) {
449 bool defer = false;
451 EXPECT_CALL(*mock_callback_receiver_,
452 ShouldIgnoreNavigation(_, AllOf(
453 NavigationParamsUrlIsSafe(),
454 Property(&NavigationParams::is_post, Eq(false)))))
455 .WillOnce(Return(false));
457 content::BrowserThread::PostTask(
458 content::BrowserThread::IO,
459 FROM_HERE,
460 base::Bind(
461 &InterceptNavigationResourceThrottleTest::
462 RunThrottleWillStartRequestOnIOThread,
463 base::Unretained(this),
464 GURL(kTestUrl),
465 "POST",
466 REDIRECT_MODE_302,
467 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
468 web_contents()->GetMainFrame()->GetRoutingID(),
469 base::Unretained(&defer)));
471 // Wait for the request to finish processing.
472 base::RunLoop().RunUntilIdle();
475 } // namespace navigation_interception