Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: content/public/test/navigation_simulator.cc

Issue 2682313002: Introduce NavigationSimulator to use in unit tests (Closed)
Patch Set: Addressed comments Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/public/test/navigation_simulator.h ('k') | content/public/test/test_renderer_host.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 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 "content/public/test/navigation_simulator.h"
6
7 #include "content/browser/frame_host/navigation_handle_impl.h"
8 #include "content/browser/frame_host/navigation_request.h"
9 #include "content/common/frame_messages.h"
10 #include "content/public/browser/navigation_throttle.h"
11 #include "content/public/browser/web_contents.h"
12 #include "content/public/common/browser_side_navigation_policy.h"
13 #include "content/test/test_navigation_url_loader.h"
14 #include "content/test/test_render_frame_host.h"
15 #include "net/base/load_flags.h"
16 #include "net/url_request/redirect_info.h"
17
18 namespace content {
19
20 namespace {
21
22 class NavigationThrottleCallbackRunner : public NavigationThrottle {
23 public:
24 NavigationThrottleCallbackRunner(
25 NavigationHandle* handle,
26 const base::Closure& on_will_start_request,
27 const base::Closure& on_will_redirect_request,
28 const base::Closure& on_will_process_response)
29 : NavigationThrottle(handle),
30 on_will_start_request_(on_will_start_request),
31 on_will_redirect_request_(on_will_redirect_request),
32 on_will_process_response_(on_will_process_response) {}
33
34 NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
35 on_will_start_request_.Run();
36 return NavigationThrottle::PROCEED;
37 }
38
39 NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override {
40 on_will_redirect_request_.Run();
41 return NavigationThrottle::PROCEED;
42 }
43
44 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
45 on_will_process_response_.Run();
46 return NavigationThrottle::PROCEED;
47 }
48
49 private:
50 base::Closure on_will_start_request_;
51 base::Closure on_will_redirect_request_;
52 base::Closure on_will_process_response_;
53 };
54
55 } // namespace
56
57 // static
58 void NavigationSimulator::NavigateAndCommitFromDocument(
59 const GURL& original_url,
60 RenderFrameHost* render_frame_host) {
61 NavigationSimulator simulator(
62 original_url, static_cast<TestRenderFrameHost*>(render_frame_host));
63 simulator.Commit();
64 }
65
66 // static
67 void NavigationSimulator::NavigateAndFailFromDocument(
68 const GURL& original_url,
69 int net_error_code,
70 RenderFrameHost* render_frame_host) {
71 NavigationSimulator simulator(
72 original_url, static_cast<TestRenderFrameHost*>(render_frame_host));
73 simulator.Fail(net_error_code);
74 if (net_error_code != net::ERR_ABORTED)
75 simulator.CommitErrorPage();
76 }
77
78 // static
79 std::unique_ptr<NavigationSimulator>
80 NavigationSimulator::CreateRendererInitiated(
81 const GURL& original_url,
82 RenderFrameHost* render_frame_host) {
83 return base::MakeUnique<NavigationSimulator>(
84 original_url, static_cast<TestRenderFrameHost*>(render_frame_host));
85 }
86
87 NavigationSimulator::NavigationSimulator(const GURL& original_url,
88 TestRenderFrameHost* render_frame_host)
89 : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
90 render_frame_host_(render_frame_host),
91 handle_(nullptr),
92 navigation_url_(original_url),
93 weak_factory_(this) {
94 if (render_frame_host->GetParent()) {
95 if (!render_frame_host->frame_tree_node()->has_committed_real_load())
96 transition_ = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
97 else
98 transition_ = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
99 }
100 }
101
102 NavigationSimulator::~NavigationSimulator() {}
103
104 void NavigationSimulator::Start() {
105 CHECK(state_ == INITIALIZATION)
106 << "NavigationSimulator::Start should only be called once.";
107 state_ = STARTED;
108
109 if (IsBrowserSideNavigationEnabled()) {
110 BeginNavigationParams begin_params(
111 std::string(), net::LOAD_NORMAL, true /* has_user_gesture */,
112 false /* skip_service_worker */, REQUEST_CONTEXT_TYPE_HYPERLINK,
113 blink::WebMixedContentContextType::Blockable, url::Origin());
114 CommonNavigationParams common_params;
115 common_params.url = navigation_url_;
116 common_params.referrer = referrer_;
117 common_params.transition = transition_;
118 common_params.navigation_type =
119 PageTransitionCoreTypeIs(transition_, ui::PAGE_TRANSITION_RELOAD)
120 ? FrameMsg_Navigate_Type::RELOAD
121 : FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT;
122 render_frame_host_->OnMessageReceived(FrameHostMsg_BeginNavigation(
123 render_frame_host_->GetRoutingID(), common_params, begin_params));
124 NavigationRequest* request =
125 render_frame_host_->frame_tree_node()->navigation_request();
126 DCHECK(request);
127 DCHECK_EQ(handle_, request->navigation_handle());
128 } else {
129 render_frame_host_->OnMessageReceived(
130 FrameHostMsg_DidStartLoading(render_frame_host_->GetRoutingID(), true));
131 render_frame_host_->OnMessageReceived(FrameHostMsg_DidStartProvisionalLoad(
132 render_frame_host_->GetRoutingID(), navigation_url_,
133 std::vector<GURL>(), base::TimeTicks::Now()));
134 DCHECK_EQ(handle_, render_frame_host_->navigation_handle());
135 handle_->WillStartRequest(
136 "GET", scoped_refptr<content::ResourceRequestBodyImpl>(), referrer_,
137 true /* user_gesture */, transition_, false /* is_external_protocol */,
138 REQUEST_CONTEXT_TYPE_LOCATION,
139 blink::WebMixedContentContextType::NotMixedContent,
140 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
141 }
142
143 CHECK(handle_);
144
145 // Make sure all NavigationThrottles have run.
146 // TODO(clamy): provide a non auto-advance mode if needed.
147 while (handle_->state_for_testing() == NavigationHandleImpl::DEFERRING_START)
148 handle_->Resume();
149
150 CHECK_EQ(1, num_did_start_navigation_called_);
151 CHECK_EQ(1, num_will_start_request_called_);
152 }
153
154 void NavigationSimulator::Redirect(const GURL& new_url) {
155 CHECK(state_ <= STARTED) << "NavigationSimulator::Redirect should be "
156 "called before Fail or Commit";
157 CHECK_EQ(0, num_did_finish_navigation_called_)
158 << "NavigationSimulator::Redirect cannot be called after the "
159 "navigation has finished";
160
161 if (state_ == INITIALIZATION)
162 Start();
163
164 navigation_url_ = new_url;
165
166 int previous_num_will_redirect_request_called =
167 num_will_redirect_request_called_;
168 int previous_did_redirect_navigation_called =
169 num_did_redirect_navigation_called_;
170
171 if (IsBrowserSideNavigationEnabled()) {
172 NavigationRequest* request =
173 render_frame_host_->frame_tree_node()->navigation_request();
174 TestNavigationURLLoader* url_loader =
175 static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
176 CHECK(url_loader);
177
178 net::RedirectInfo redirect_info;
179 redirect_info.status_code = 302;
180 redirect_info.new_method = "GET";
181 redirect_info.new_url = new_url;
182 redirect_info.new_first_party_for_cookies = new_url;
183 redirect_info.new_referrer = referrer_.url.spec();
184 redirect_info.new_referrer_policy =
185 Referrer::ReferrerPolicyForUrlRequest(referrer_);
186
187 url_loader->CallOnRequestRedirected(
188 redirect_info, scoped_refptr<ResourceResponse>(new ResourceResponse));
189 } else {
190 handle_->WillRedirectRequest(
191 new_url, "GET", referrer_.url, false /* is_external_protocol */,
192 scoped_refptr<net::HttpResponseHeaders>(),
193 net::HttpResponseInfo::ConnectionInfo(),
194 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
195 }
196
197 // Make sure all NavigationThrottles have run.
198 // TODO(clamy): provide a non auto-advance mode if needed.
199 while (handle_->state_for_testing() ==
200 NavigationHandleImpl::DEFERRING_REDIRECT) {
201 handle_->Resume();
202 }
203
204 CHECK_EQ(previous_num_will_redirect_request_called + 1,
205 num_will_redirect_request_called_);
206 CHECK_EQ(previous_did_redirect_navigation_called + 1,
207 num_did_redirect_navigation_called_);
208 }
209
210 void NavigationSimulator::Commit() {
211 CHECK_LE(state_, STARTED) << "NavigationSimulator::Commit can only be "
212 "called once, and cannot be called after "
213 "NavigationSimulator::Fail";
214 CHECK_EQ(0, num_did_finish_navigation_called_)
215 << "NavigationSimulator::Commit cannot be called after the "
216 "navigation has finished";
217
218 if (state_ == INITIALIZATION)
219 Start();
220
221 if (IsBrowserSideNavigationEnabled() &&
222 render_frame_host_->frame_tree_node()->navigation_request()) {
223 render_frame_host_->PrepareForCommit();
224 }
225
226 // Call NavigationHandle::WillProcessResponse if needed.
227 if (handle_->state_for_testing() <
228 NavigationHandleImpl::WILL_PROCESS_RESPONSE) {
229 handle_->WillProcessResponse(
230 render_frame_host_, scoped_refptr<net::HttpResponseHeaders>(),
231 net::HttpResponseInfo::ConnectionInfo(), SSLStatus(), GlobalRequestID(),
232 false /* should_replace_current_entry */, false /* is_download */,
233 false /* is_stream */, base::Closure(),
234 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
235 }
236
237 // Make sure all NavigationThrottles have run.
238 // TODO(clamy): provide a non auto-advance mode if needed.
239 while (handle_->state_for_testing() ==
240 NavigationHandleImpl::DEFERRING_RESPONSE) {
241 handle_->Resume();
242 }
243
244 CHECK_EQ(1, num_will_process_response_called_);
245 CHECK_EQ(1, num_ready_to_commit_called_);
246
247 // Update the RenderFrameHost now that we know which RenderFrameHost will
248 // commit the navigation.
249 TestRenderFrameHost* new_render_frame_host =
250 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost());
251 if (!IsBrowserSideNavigationEnabled() &&
252 new_render_frame_host != render_frame_host_) {
253 CHECK(handle_->is_transferring());
254 // Simulate the renderer transfer.
255 new_render_frame_host->OnMessageReceived(FrameHostMsg_DidStartLoading(
256 new_render_frame_host->GetRoutingID(), true));
257 new_render_frame_host->OnMessageReceived(
258 FrameHostMsg_DidStartProvisionalLoad(
259 new_render_frame_host->GetRoutingID(), navigation_url_,
260 std::vector<GURL>(), base::TimeTicks::Now()));
261 CHECK(!handle_->is_transferring());
262 }
263 render_frame_host_ = new_render_frame_host;
264
265 // Keep a pointer to the current RenderFrameHost that may be pending deletion
266 // after commit.
267 RenderFrameHostImpl* previous_rfh =
268 render_frame_host_->frame_tree_node()->current_frame_host();
269
270 FrameHostMsg_DidCommitProvisionalLoad_Params params;
271 params.nav_entry_id = 0;
272 params.url = navigation_url_;
273 params.origin = url::Origin(navigation_url_);
274 params.transition = transition_;
275 params.should_update_history = true;
276 params.did_create_new_entry =
277 !render_frame_host_->GetParent() ||
278 render_frame_host_->frame_tree_node()->has_committed_real_load();
279 params.gesture = NavigationGestureUser;
280 params.contents_mime_type = "text/html";
281 params.method = "GET";
282 params.http_status_code = 200;
283 params.socket_address.set_host("2001:db8::1");
284 params.socket_address.set_port(80);
285 params.history_list_was_cleared = false;
286 params.original_request_url = navigation_url_;
287 params.was_within_same_page = false;
288 params.page_state =
289 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr);
290
291 render_frame_host_->SendNavigateWithParams(&params);
292
293 // Simulate the UnloadACK in the old RenderFrameHost if it was swapped out at
294 // commit time.
295 if (previous_rfh != render_frame_host_) {
296 previous_rfh->OnMessageReceived(
297 FrameHostMsg_SwapOut_ACK(previous_rfh->GetRoutingID()));
298 }
299
300 state_ = FINISHED;
301
302 CHECK_EQ(1, num_did_finish_navigation_called_);
303 }
304
305 void NavigationSimulator::Fail(int error_code) {
306 CHECK_LE(state_, STARTED) << "NavigationSimulator::Fail can only be "
307 "called.";
308 CHECK_EQ(0, num_did_finish_navigation_called_)
309 << "NavigationSimulator::Fail cannot be called after the "
310 "navigation has finished";
311
312 if (state_ == INITIALIZATION)
313 Start();
314
315 state_ = FAILED;
316
317 bool should_result_in_error_page = error_code != net::ERR_ABORTED;
318 if (IsBrowserSideNavigationEnabled()) {
319 NavigationRequest* request =
320 render_frame_host_->frame_tree_node()->navigation_request();
321 CHECK(request);
322 TestNavigationURLLoader* url_loader =
323 static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
324 CHECK(url_loader);
325 url_loader->SimulateError(error_code);
326 } else {
327 FrameHostMsg_DidFailProvisionalLoadWithError_Params error_params;
328 error_params.error_code = error_code;
329 error_params.url = navigation_url_;
330 render_frame_host_->OnMessageReceived(
331 FrameHostMsg_DidFailProvisionalLoadWithError(
332 render_frame_host_->GetRoutingID(), error_params));
333 if (!should_result_in_error_page) {
334 render_frame_host_->OnMessageReceived(
335 FrameHostMsg_DidStopLoading(render_frame_host_->GetRoutingID()));
336 }
337 }
338
339 if (IsBrowserSideNavigationEnabled()) {
340 CHECK_EQ(1, num_ready_to_commit_called_);
341 if (should_result_in_error_page) {
342 // Update the RenderFrameHost now that we know which RenderFrameHost will
343 // commit the error page.
344 render_frame_host_ =
345 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost());
346 }
347 }
348
349 if (should_result_in_error_page)
350 CHECK_EQ(0, num_did_finish_navigation_called_);
351 else
352 CHECK_EQ(1, num_did_finish_navigation_called_);
353 }
354
355 void NavigationSimulator::CommitErrorPage() {
356 CHECK_EQ(FAILED, state_)
357 << "NavigationSimulator::CommitErrorPage can only be "
358 "called once, and should be called after Fail "
359 "has been called";
360 CHECK_EQ(0, num_did_finish_navigation_called_)
361 << "NavigationSimulator::CommitErrorPage cannot be called after the "
362 "navigation has finished";
363
364 // Keep a pointer to the current RenderFrameHost that may be pending deletion
365 // after commit.
366 RenderFrameHostImpl* previous_rfh =
367 render_frame_host_->frame_tree_node()->current_frame_host();
368
369 GURL error_url = GURL(kUnreachableWebDataURL);
370 render_frame_host_->OnMessageReceived(FrameHostMsg_DidStartProvisionalLoad(
371 render_frame_host_->GetRoutingID(), error_url, std::vector<GURL>(),
372 base::TimeTicks::Now()));
373 FrameHostMsg_DidCommitProvisionalLoad_Params params;
374 params.nav_entry_id = 0;
375 params.did_create_new_entry = true;
376 params.url = navigation_url_;
377 params.transition = transition_;
378 params.was_within_same_page = false;
379 params.url_is_unreachable = true;
380 params.page_state =
381 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr);
382 render_frame_host_->SendNavigateWithParams(&params);
383
384 // Simulate the UnloadACK in the old RenderFrameHost if it was swapped out at
385 // commit time.
386 if (previous_rfh != render_frame_host_) {
387 previous_rfh->OnMessageReceived(
388 FrameHostMsg_SwapOut_ACK(previous_rfh->GetRoutingID()));
389 }
390
391 state_ = FINISHED;
392
393 CHECK_EQ(1, num_did_finish_navigation_called_);
394 }
395
396 void NavigationSimulator::CommitSamePage() {
397 CHECK_EQ(INITIALIZATION, state_)
398 << "NavigationSimulator::CommitErrorPage should be the only "
399 "navigation event function called on the NavigationSimulator";
400
401 render_frame_host_->OnMessageReceived(
402 FrameHostMsg_DidStartLoading(render_frame_host_->GetRoutingID(), false));
403
404 FrameHostMsg_DidCommitProvisionalLoad_Params params;
405 params.nav_entry_id = 0;
406 params.url = navigation_url_;
407 params.origin = url::Origin(navigation_url_);
408 params.transition = transition_;
409 params.should_update_history = true;
410 params.did_create_new_entry = false;
411 params.gesture = NavigationGestureUser;
412 params.contents_mime_type = "text/html";
413 params.method = "GET";
414 params.http_status_code = 200;
415 params.socket_address.set_host("2001:db8::1");
416 params.socket_address.set_port(80);
417 params.history_list_was_cleared = false;
418 params.original_request_url = navigation_url_;
419 params.was_within_same_page = true;
420 params.page_state =
421 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr);
422
423 render_frame_host_->SendNavigateWithParams(&params);
424
425 render_frame_host_->OnMessageReceived(
426 FrameHostMsg_DidStopLoading(render_frame_host_->GetRoutingID()));
427
428 state_ = FINISHED;
429
430 CHECK_EQ(1, num_did_start_navigation_called_);
431 CHECK_EQ(0, num_will_start_request_called_);
432 CHECK_EQ(0, num_will_process_response_called_);
433 CHECK_EQ(0, num_ready_to_commit_called_);
434 CHECK_EQ(1, num_did_finish_navigation_called_);
435 }
436
437 void NavigationSimulator::SetTransition(ui::PageTransition transition) {
438 CHECK_EQ(INITIALIZATION, state_)
439 << "The transition cannot be set after the navigation has started";
440 transition_ = transition;
441 }
442
443 void NavigationSimulator::SetReferrer(const Referrer& referrer) {
444 CHECK_LE(state_, STARTED) << "The referrer cannot be set after the "
445 "navigation has committed or has failed";
446 referrer_ = referrer;
447 }
448
449 void NavigationSimulator::DidStartNavigation(
450 NavigationHandle* navigation_handle) {
451 // Check if this navigation is the one we're simulating.
452 if (handle_)
453 return;
454
455 if (navigation_handle->GetURL() != navigation_url_)
456 return;
457
458 NavigationHandleImpl* handle =
459 static_cast<NavigationHandleImpl*>(navigation_handle);
460
461 if (handle->frame_tree_node() != render_frame_host_->frame_tree_node())
462 return;
463
464 handle_ = handle;
465
466 num_did_start_navigation_called_++;
467
468 // Add a throttle to count NavigationThrottle calls count.
469 handle->RegisterThrottleForTesting(
470 base::MakeUnique<NavigationThrottleCallbackRunner>(
471 handle,
472 base::Bind(&NavigationSimulator::OnWillStartRequest,
473 weak_factory_.GetWeakPtr()),
474 base::Bind(&NavigationSimulator::OnWillRedirectRequest,
475 weak_factory_.GetWeakPtr()),
476 base::Bind(&NavigationSimulator::OnWillProcessResponse,
477 weak_factory_.GetWeakPtr())));
478 }
479
480 void NavigationSimulator::DidRedirectNavigation(
481 NavigationHandle* navigation_handle) {
482 if (navigation_handle == handle_)
483 num_did_redirect_navigation_called_++;
484 }
485
486 void NavigationSimulator::ReadyToCommitNavigation(
487 NavigationHandle* navigation_handle) {
488 if (navigation_handle == handle_)
489 num_ready_to_commit_called_++;
490 }
491
492 void NavigationSimulator::DidFinishNavigation(
493 NavigationHandle* navigation_handle) {
494 if (navigation_handle == handle_)
495 num_did_finish_navigation_called_++;
496 }
497
498 void NavigationSimulator::OnWillStartRequest() {
499 num_will_start_request_called_++;
500 }
501
502 void NavigationSimulator::OnWillRedirectRequest() {
503 num_will_redirect_request_called_++;
504 }
505
506 void NavigationSimulator::OnWillProcessResponse() {
507 num_will_process_response_called_++;
508 }
509
510 } // namespace content
OLDNEW
« no previous file with comments | « content/public/test/navigation_simulator.h ('k') | content/public/test/test_renderer_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698