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

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

Issue 2682313002: Introduce NavigationSimulator to use in unit tests (Closed)
Patch Set: Added same-page navigation simulation 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/url_request/redirect_info.h"
16
17 namespace content {
18
19 namespace {
20
21 class NavigationThrottleCallCounter : public NavigationThrottle {
nasko 2017/02/16 18:47:59 This class doesn't seem to count anything, so the
clamy 2017/02/17 17:34:52 Indeed. Renamed it.
22 public:
23 NavigationThrottleCallCounter(NavigationHandle* handle,
24 const base::Closure& on_will_start_request,
25 const base::Closure& on_will_redirect_request,
26 const base::Closure& on_will_process_response)
27 : NavigationThrottle(handle),
28 on_will_start_request_(on_will_start_request),
29 on_will_redirect_request_(on_will_redirect_request),
30 on_will_process_response_(on_will_process_response) {}
31
32 NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
33 on_will_start_request_.Run();
34 return NavigationThrottle::PROCEED;
35 }
36
37 NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override {
38 on_will_redirect_request_.Run();
39 return NavigationThrottle::PROCEED;
40 }
41
42 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
43 on_will_process_response_.Run();
44 return NavigationThrottle::PROCEED;
45 }
46
47 private:
48 base::Closure on_will_start_request_;
49 base::Closure on_will_redirect_request_;
50 base::Closure on_will_process_response_;
51 };
52
53 } // namespace
54
55 NavigationSimulatorImpl::NavigationSimulatorImpl(
56 const GURL& original_url,
57 TestRenderFrameHost* render_frame_host)
58 : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
59 state_(INITIALIZATION),
nasko 2017/02/16 18:47:59 With the newest C++11 goodies, we can initialize t
clamy 2017/02/17 17:34:52 Done.
60 render_frame_host_(render_frame_host),
61 handle_(nullptr),
62 navigation_url_(original_url),
63 transition_(ui::PAGE_TRANSITION_LINK),
64 num_did_start_navigation_called_(0),
65 num_will_start_request_called_(0),
66 num_will_redirect_request_called_(0),
67 num_did_redirect_navigation_called_(0),
68 num_will_process_response_called_(0),
69 num_ready_to_commit_called_(0),
70 num_did_finish_navigation_called_(0),
71 weak_factory_(this) {
72 if (render_frame_host->GetParent()) {
73 if (!render_frame_host->frame_tree_node()->has_committed_real_load())
74 transition_ = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
75 else
76 transition_ = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
77 }
78 }
79
80 NavigationSimulatorImpl::~NavigationSimulatorImpl() {}
81
82 void NavigationSimulatorImpl::Start() {
83 CHECK(state_ == INITIALIZATION)
84 << "NavigationSimulator::Start should only be called once.";
85 state_ = STARTED;
86
87 if (IsBrowserSideNavigationEnabled()) {
88 render_frame_host_->SendRendererInitiatedNavigationRequest(navigation_url_,
89 true);
90 NavigationRequest* request =
91 render_frame_host_->frame_tree_node()->navigation_request();
92 DCHECK(request);
93 handle_ = request->navigation_handle();
94 } else {
95 render_frame_host_->OnMessageReceived(
96 FrameHostMsg_DidStartLoading(render_frame_host_->GetRoutingID(), true));
97 render_frame_host_->OnMessageReceived(FrameHostMsg_DidStartProvisionalLoad(
98 render_frame_host_->GetRoutingID(), navigation_url_,
99 std::vector<GURL>(), base::TimeTicks::Now()));
100 handle_ = render_frame_host_->navigation_handle();
101 handle_->WillStartRequest(
102 "GET", scoped_refptr<content::ResourceRequestBodyImpl>(), referrer_,
103 true /* user_gesture */, transition_, false /* is_external_protocol */,
104 REQUEST_CONTEXT_TYPE_LOCATION,
105 blink::WebMixedContentContextType::NotMixedContent,
106 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
107 }
108
109 CHECK(handle_);
110
111 // Make sure all NavigationThrottles have run.
112 // TODO(clamy): provide a non auto-advance mode if needed.
113 while (handle_->state_for_testing() == NavigationHandleImpl::DEFERRING_START)
114 handle_->Resume();
115
116 CHECK_EQ(1, num_did_start_navigation_called_);
117 CHECK_EQ(1, num_will_start_request_called_);
118 }
119
120 void NavigationSimulatorImpl::Redirect(const GURL& new_url) {
121 CHECK(state_ == STARTED) << "NavigationSimulatorImpl::Redirect should be "
122 "called after Start but before Fail or Commit";
123 CHECK_EQ(0, num_did_finish_navigation_called_)
124 << "NavigationSimulatorImpl::Redirect cannot be called after the "
125 "navigation has finished";
126
127 navigation_url_ = new_url;
128
129 int previous_num_will_redirect_request_called =
130 num_will_redirect_request_called_;
131 int previous_did_redirect_navigation_called =
132 num_did_redirect_navigation_called_;
133
134 if (IsBrowserSideNavigationEnabled()) {
135 NavigationRequest* request =
136 render_frame_host_->frame_tree_node()->navigation_request();
137 TestNavigationURLLoader* url_loader =
138 static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
139 CHECK(url_loader);
140
141 net::RedirectInfo redirect_info;
142 redirect_info.status_code = 302;
143 redirect_info.new_method = "GET";
144 redirect_info.new_url = new_url;
145 redirect_info.new_first_party_for_cookies = new_url;
146 redirect_info.new_referrer = referrer_.url.spec();
147 redirect_info.new_referrer_policy =
148 Referrer::ReferrerPolicyForUrlRequest(referrer_);
149
150 url_loader->CallOnRequestRedirected(
151 redirect_info, scoped_refptr<ResourceResponse>(new ResourceResponse));
152 } else {
153 handle_->WillRedirectRequest(
154 new_url, "GET", referrer_.url, false /* is_external_protocol */,
155 scoped_refptr<net::HttpResponseHeaders>(),
156 net::HttpResponseInfo::ConnectionInfo(),
157 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
158 }
159
160 // Make sure all NavigationThrottles have run.
161 // TODO(clamy): provide a non auto-advance mode if needed.
162 while (handle_->state_for_testing() ==
163 NavigationHandleImpl::DEFERRING_REDIRECT) {
164 handle_->Resume();
165 }
166
167 CHECK_EQ(previous_num_will_redirect_request_called + 1,
168 num_will_redirect_request_called_);
169 CHECK_EQ(previous_did_redirect_navigation_called + 1,
170 num_did_redirect_navigation_called_);
171 }
172
173 void NavigationSimulatorImpl::Commit() {
174 CHECK_EQ(STARTED, state_) << "NavigationSimulatorImpl::Commit can only be "
175 "called once, and should be called after Start "
176 "has been called";
177 CHECK_EQ(0, num_did_finish_navigation_called_)
178 << "NavigationSimulatorImpl::Commit cannot be called after the "
179 "navigation has finished";
180
181 if (IsBrowserSideNavigationEnabled() &&
182 render_frame_host_->frame_tree_node()->navigation_request()) {
183 render_frame_host_->PrepareForCommit();
184 }
185
186 // Call NavigationHandle::WillProcessResponse if needed.
187 if (handle_->state_for_testing() <
188 NavigationHandleImpl::WILL_PROCESS_RESPONSE) {
189 handle_->WillProcessResponse(
190 render_frame_host_, scoped_refptr<net::HttpResponseHeaders>(),
191 net::HttpResponseInfo::ConnectionInfo(), SSLStatus(), GlobalRequestID(),
192 false /* should_replace_current_entry */, false /* is_download */,
193 false /* is_stream */, base::Closure(),
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_RESPONSE) {
201 handle_->Resume();
202 }
203
204 CHECK_EQ(1, num_will_process_response_called_);
205 CHECK_EQ(1, num_ready_to_commit_called_);
206
207 // Update the RenderFrameHost now that we know which RenderFrameHost will
208 // commit the navigation.
209 TestRenderFrameHost* new_render_frame_host =
210 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost());
211 if (!IsBrowserSideNavigationEnabled() &&
212 new_render_frame_host != render_frame_host_) {
213 CHECK(handle_->is_transferring());
214 // Simulate the renderer transfer.
215 new_render_frame_host->OnMessageReceived(FrameHostMsg_DidStartLoading(
216 new_render_frame_host->GetRoutingID(), true));
217 new_render_frame_host->OnMessageReceived(
218 FrameHostMsg_DidStartProvisionalLoad(
219 new_render_frame_host->GetRoutingID(), navigation_url_,
220 std::vector<GURL>(), base::TimeTicks::Now()));
221 CHECK(!handle_->is_transferring());
222 }
223 render_frame_host_ =
224 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost());
nasko 2017/02/16 18:47:59 Why do we need to call this again? Wouldn't assign
clamy 2017/02/17 17:34:52 Done.
225
226 FrameHostMsg_DidCommitProvisionalLoad_Params params;
227 params.nav_entry_id = 0;
228 params.url = navigation_url_;
229 params.origin = url::Origin(navigation_url_);
230 params.transition = transition_;
231 params.should_update_history = true;
232 params.did_create_new_entry =
233 render_frame_host_->GetParent() ||
234 render_frame_host_->frame_tree_node()->has_committed_real_load();
235 params.gesture = NavigationGestureUser;
236 params.contents_mime_type = "text/html";
237 params.method = "GET";
238 params.http_status_code = 200;
239 params.socket_address.set_host("2001:db8::1");
240 params.socket_address.set_port(80);
241 params.history_list_was_cleared = false;
242 params.original_request_url = navigation_url_;
243 params.was_within_same_page = false;
244 params.page_state =
245 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr);
246
247 render_frame_host_->SendNavigateWithParams(&params);
248
249 state_ = FINISHED;
250
251 CHECK_EQ(1, num_did_finish_navigation_called_);
252 }
253
254 void NavigationSimulatorImpl::Fail(int error_code) {
255 CHECK_EQ(STARTED, state_) << "NavigationSimulatorImpl::Fail can only be "
256 "called once, and should be called after Start "
257 "has been called";
258 CHECK_EQ(0, num_did_finish_navigation_called_)
259 << "NavigationSimulatorImpl::Fail cannot be called after the "
260 "navigation has finished";
261
262 state_ = FAILED;
263
264 bool should_result_in_error_page = error_code != net::ERR_ABORTED;
265 if (IsBrowserSideNavigationEnabled()) {
266 NavigationRequest* request =
267 render_frame_host_->frame_tree_node()->navigation_request();
268 CHECK(request);
269 TestNavigationURLLoader* url_loader =
270 static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
271 CHECK(url_loader);
272 url_loader->SimulateError(error_code);
273 } else {
274 FrameHostMsg_DidFailProvisionalLoadWithError_Params error_params;
275 error_params.error_code = error_code;
276 error_params.url = navigation_url_;
277 render_frame_host_->OnMessageReceived(
278 FrameHostMsg_DidFailProvisionalLoadWithError(
279 render_frame_host_->GetRoutingID(), error_params));
280 if (!should_result_in_error_page) {
281 render_frame_host_->OnMessageReceived(
282 FrameHostMsg_DidStopLoading(render_frame_host_->GetRoutingID()));
283 }
284 }
285
286 if (IsBrowserSideNavigationEnabled()) {
287 CHECK_EQ(1, num_ready_to_commit_called_);
288 if (should_result_in_error_page) {
289 // Update the RenderFrameHost now that we know which RenderFrameHost will
290 // commit the error page.
291 render_frame_host_ =
292 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost());
293 }
294 }
295
296 if (should_result_in_error_page)
297 CHECK_EQ(0, num_did_finish_navigation_called_);
298 else
299 CHECK_EQ(1, num_did_finish_navigation_called_);
300 }
301
302 void NavigationSimulatorImpl::CommitErrorPage() {
303 CHECK_EQ(FAILED, state_)
304 << "NavigationSimulatorImpl::CommitErrorPage can only be "
305 "called once, and should be called after Fail "
306 "has been called";
307 CHECK_EQ(0, num_did_finish_navigation_called_)
308 << "NavigationSimulatorImpl::CommitErrorPage cannot be called after the "
309 "navigation has finished";
310
311 GURL error_url = GURL(kUnreachableWebDataURL);
312 render_frame_host_->OnMessageReceived(FrameHostMsg_DidStartProvisionalLoad(
313 render_frame_host_->GetRoutingID(), error_url, std::vector<GURL>(),
314 base::TimeTicks::Now()));
315 FrameHostMsg_DidCommitProvisionalLoad_Params params;
316 params.nav_entry_id = 0;
317 params.did_create_new_entry = true;
318 params.url = navigation_url_;
319 params.transition = transition_;
320 params.was_within_same_page = false;
321 params.url_is_unreachable = true;
322 params.page_state =
323 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr);
324 render_frame_host_->SendNavigateWithParams(&params);
325
326 state_ = FINISHED;
327
328 CHECK_EQ(1, num_did_finish_navigation_called_);
329 }
330
331 void NavigationSimulatorImpl::CommitSamePage() {
332 CHECK_EQ(INITIALIZATION, state_)
333 << "NavigationSimulatorImpl::CommitErrorPage should be the only "
334 "navigation event function called on the NavigationSimulator";
335
336 render_frame_host_->OnMessageReceived(
337 FrameHostMsg_DidStartLoading(render_frame_host_->GetRoutingID(), false));
338
339 FrameHostMsg_DidCommitProvisionalLoad_Params params;
340 params.nav_entry_id = 0;
341 params.url = navigation_url_;
342 params.origin = url::Origin(navigation_url_);
343 params.transition = transition_;
344 params.should_update_history = true;
nasko 2017/02/16 18:47:59 Is this set to true for same page?
clamy 2017/02/17 17:34:52 I think so. See https://cs.chromium.org/chromium/s
345 params.did_create_new_entry =
nasko 2017/02/16 18:47:59 Why would we create a new entry for same page navi
clamy 2017/02/17 17:34:52 Done.
346 render_frame_host_->GetParent() ||
347 render_frame_host_->frame_tree_node()->has_committed_real_load();
348 params.gesture = NavigationGestureUser;
349 params.contents_mime_type = "text/html";
350 params.method = "GET";
351 params.http_status_code = 200;
352 params.socket_address.set_host("2001:db8::1");
353 params.socket_address.set_port(80);
354 params.history_list_was_cleared = false;
355 params.original_request_url = navigation_url_;
356 params.was_within_same_page = true;
357 params.page_state =
358 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr);
359
360 render_frame_host_->SendNavigateWithParams(&params);
361
362 render_frame_host_->OnMessageReceived(
363 FrameHostMsg_DidStopLoading(render_frame_host_->GetRoutingID()));
364
365 state_ = FINISHED;
366
367 CHECK_EQ(1, num_did_start_navigation_called_);
368 CHECK_EQ(0, num_will_start_request_called_);
369 CHECK_EQ(0, num_will_process_response_called_);
370 CHECK_EQ(0, num_ready_to_commit_called_);
371 CHECK_EQ(1, num_did_finish_navigation_called_);
372 }
373
374 void NavigationSimulatorImpl::SetTransition(ui::PageTransition transition) {
375 CHECK_EQ(INITIALIZATION, state_)
376 << "The transition cannot be set after the navigation has started";
377 transition_ = transition;
378 }
379
380 void NavigationSimulatorImpl::SetReferrer(const Referrer& referrer) {
381 CHECK_LE(state_, STARTED) << "The referrer cannot be set after the "
382 "navigation has committed or has failed";
383 referrer_ = referrer;
384 }
385
386 void NavigationSimulatorImpl::DidStartNavigation(
387 NavigationHandle* navigation_handle) {
388 // Check if this navigation is the one we're simulating.
389 if (state_ != STARTED)
390 return;
391
392 if (navigation_handle->GetURL() != navigation_url_)
393 return;
394
395 NavigationHandleImpl* handle =
396 static_cast<NavigationHandleImpl*>(navigation_handle);
397
398 if (handle->frame_tree_node() != render_frame_host_->frame_tree_node())
399 return;
400
401 num_did_start_navigation_called_++;
402
403 // Add a throttle to count NavigationThrottle calls count.
404 handle->RegisterThrottleForTesting(
405 base::MakeUnique<NavigationThrottleCallCounter>(
406 handle, base::Bind(&NavigationSimulatorImpl::OnWillStartRequest,
407 weak_factory_.GetWeakPtr()),
408 base::Bind(&NavigationSimulatorImpl::OnWillRedirectRequest,
409 weak_factory_.GetWeakPtr()),
410 base::Bind(&NavigationSimulatorImpl::OnWillProcessResponse,
411 weak_factory_.GetWeakPtr())));
412 }
413
414 void NavigationSimulatorImpl::DidRedirectNavigation(
415 NavigationHandle* navigation_handle) {
416 if (navigation_handle == handle_)
417 num_did_redirect_navigation_called_++;
418 }
419
420 void NavigationSimulatorImpl::ReadyToCommitNavigation(
421 NavigationHandle* navigation_handle) {
422 if (navigation_handle == handle_)
423 num_ready_to_commit_called_++;
424 }
425
426 void NavigationSimulatorImpl::DidFinishNavigation(
427 NavigationHandle* navigation_handle) {
428 if (navigation_handle == handle_)
429 num_did_finish_navigation_called_++;
430 }
431
432 void NavigationSimulatorImpl::OnWillStartRequest() {
433 num_will_start_request_called_++;
434 }
435
436 void NavigationSimulatorImpl::OnWillRedirectRequest() {
437 num_will_redirect_request_called_++;
438 }
439
440 void NavigationSimulatorImpl::OnWillProcessResponse() {
441 num_will_process_response_called_++;
442 }
443
444 } // 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