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

Side by Side Diff: content/test/navigation_simulator_impl.cc

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

Powered by Google App Engine
This is Rietveld 408576698