OLD | NEW |
---|---|
(Empty) | |
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 "chrome/browser/prerender/prerender_test_utils.h" | |
6 | |
7 #include "base/command_line.h" | |
8 #include "chrome/browser/prerender/prerender_manager.h" | |
9 #include "chrome/browser/prerender/prerender_manager_factory.h" | |
10 #include "chrome/browser/profiles/profile.h" | |
11 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate. h" | |
12 #include "chrome/browser/safe_browsing/local_database_manager.h" | |
13 #include "chrome/browser/ui/browser.h" | |
14 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
15 #include "chrome/common/pref_names.h" | |
16 #include "components/prefs/pref_service.h" | |
17 #include "content/public/browser/notification_details.h" | |
18 #include "content/public/browser/notification_source.h" | |
19 #include "content/public/browser/notification_types.h" | |
20 #include "content/public/browser/render_view_host.h" | |
21 #include "content/public/common/content_switches.h" | |
22 #include "content/public/common/url_constants.h" | |
23 #include "content/public/test/ppapi_test_utils.h" | |
24 #include "ppapi/shared_impl/ppapi_switches.h" | |
25 #include "testing/gtest/include/gtest/gtest.h" | |
26 | |
27 using content::BrowserThread; | |
28 using content::RenderViewHost; | |
29 | |
30 namespace prerender { | |
31 | |
32 namespace test_utils { | |
33 | |
34 namespace { | |
droger
2016/09/02 14:33:54
nit: blank line after this.
I believe the recomme
mattcary
2016/09/02 15:02:07
Done.
| |
35 // Wrapper over URLRequestMockHTTPJob that exposes extra callbacks. | |
36 class MockHTTPJob : public net::URLRequestMockHTTPJob { | |
37 public: | |
38 MockHTTPJob(net::URLRequest* request, | |
39 net::NetworkDelegate* delegate, | |
40 const base::FilePath& file) | |
41 : net::URLRequestMockHTTPJob( | |
42 request, | |
43 delegate, | |
44 file, | |
45 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( | |
46 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {} | |
47 | |
48 void set_start_callback(const base::Closure& start_callback) { | |
49 start_callback_ = start_callback; | |
50 } | |
51 | |
52 void Start() override { | |
53 if (!start_callback_.is_null()) | |
54 start_callback_.Run(); | |
55 net::URLRequestMockHTTPJob::Start(); | |
56 } | |
57 | |
58 private: | |
59 ~MockHTTPJob() override {} | |
60 | |
61 base::Closure start_callback_; | |
62 }; | |
63 | |
64 // Protocol handler which counts the number of requests that start. | |
65 class CountingInterceptor : public net::URLRequestInterceptor { | |
66 public: | |
67 CountingInterceptor(const base::FilePath& file, | |
68 const base::WeakPtr<RequestCounter>& counter) | |
69 : file_(file), counter_(counter), weak_factory_(this) {} | |
70 ~CountingInterceptor() override {} | |
71 | |
72 net::URLRequestJob* MaybeInterceptRequest( | |
73 net::URLRequest* request, | |
74 net::NetworkDelegate* network_delegate) const override { | |
75 MockHTTPJob* job = new MockHTTPJob(request, network_delegate, file_); | |
76 job->set_start_callback(base::Bind(&CountingInterceptor::RequestStarted, | |
77 weak_factory_.GetWeakPtr())); | |
78 return job; | |
79 } | |
80 | |
81 void RequestStarted() { | |
82 content::BrowserThread::PostTask( | |
83 content::BrowserThread::UI, FROM_HERE, | |
84 base::Bind(&RequestCounter::RequestStarted, counter_)); | |
85 } | |
86 | |
87 private: | |
88 base::FilePath file_; | |
89 base::WeakPtr<RequestCounter> counter_; | |
90 mutable base::WeakPtrFactory<CountingInterceptor> weak_factory_; | |
91 }; | |
92 | |
93 // An ExternalProtocolHandler that blocks everything and asserts it never is | |
94 // called. | |
95 class NeverRunsExternalProtocolHandlerDelegate | |
96 : public ExternalProtocolHandler::Delegate { | |
97 public: | |
98 scoped_refptr<shell_integration::DefaultProtocolClientWorker> | |
99 CreateShellWorker( | |
100 const shell_integration::DefaultWebClientWorkerCallback& callback, | |
101 const std::string& protocol) override { | |
102 NOTREACHED(); | |
103 // This will crash, but it shouldn't get this far with BlockState::BLOCK | |
104 // anyway. | |
105 return nullptr; | |
106 } | |
107 | |
108 ExternalProtocolHandler::BlockState GetBlockState( | |
109 const std::string& scheme) override { | |
110 // Block everything and fail the test. | |
111 ADD_FAILURE(); | |
112 return ExternalProtocolHandler::BLOCK; | |
113 } | |
114 | |
115 void BlockRequest() override {} | |
116 | |
117 void RunExternalProtocolDialog(const GURL& url, | |
118 int render_process_host_id, | |
119 int routing_id, | |
120 ui::PageTransition page_transition, | |
121 bool has_user_gesture) override { | |
122 NOTREACHED(); | |
123 } | |
124 | |
125 void LaunchUrlWithoutSecurityCheck(const GURL& url) override { NOTREACHED(); } | |
126 | |
127 void FinishedProcessingCheck() override { NOTREACHED(); } | |
128 }; | |
129 | |
130 } // namespace | |
131 | |
132 RequestCounter::RequestCounter() : count_(0), expected_count_(-1) {} | |
133 | |
134 RequestCounter::~RequestCounter() {} | |
135 | |
136 void RequestCounter::RequestStarted() { | |
137 count_++; | |
138 if (loop_ && count_ == expected_count_) | |
139 loop_->Quit(); | |
140 } | |
141 | |
142 void RequestCounter::WaitForCount(int expected_count) { | |
143 ASSERT_TRUE(!loop_); | |
144 ASSERT_EQ(-1, expected_count_); | |
145 if (count_ < expected_count) { | |
146 expected_count_ = expected_count; | |
147 loop_.reset(new base::RunLoop); | |
148 loop_->Run(); | |
149 expected_count_ = -1; | |
150 loop_.reset(); | |
151 } | |
152 | |
153 EXPECT_EQ(expected_count, count_); | |
154 } | |
155 | |
156 FakeSafeBrowsingDatabaseManager::FakeSafeBrowsingDatabaseManager() {} | |
157 | |
158 bool FakeSafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& gurl, | |
159 Client* client) { | |
160 if (bad_urls_.find(gurl.spec()) == bad_urls_.end() || | |
161 bad_urls_[gurl.spec()] == safe_browsing::SB_THREAT_TYPE_SAFE) { | |
162 return true; | |
163 } | |
164 | |
165 content::BrowserThread::PostTask( | |
166 content::BrowserThread::IO, FROM_HERE, | |
167 base::Bind(&FakeSafeBrowsingDatabaseManager::OnCheckBrowseURLDone, this, | |
168 gurl, client)); | |
169 return false; | |
170 } | |
171 | |
172 bool FakeSafeBrowsingDatabaseManager::IsSupported() const { | |
173 return true; | |
174 } | |
175 | |
176 bool FakeSafeBrowsingDatabaseManager::ChecksAreAlwaysAsync() const { | |
177 return false; | |
178 } | |
179 | |
180 bool FakeSafeBrowsingDatabaseManager::CanCheckResourceType( | |
181 content::ResourceType /* resource_type */) const { | |
182 return true; | |
183 } | |
184 | |
185 bool FakeSafeBrowsingDatabaseManager::CheckExtensionIDs( | |
186 const std::set<std::string>& extension_ids, | |
187 Client* client) { | |
188 return true; | |
189 } | |
190 | |
191 FakeSafeBrowsingDatabaseManager::~FakeSafeBrowsingDatabaseManager() {} | |
192 | |
193 void FakeSafeBrowsingDatabaseManager::OnCheckBrowseURLDone(const GURL& gurl, | |
194 Client* client) { | |
195 std::vector<safe_browsing::SBThreatType> expected_threats; | |
196 expected_threats.push_back(safe_browsing::SB_THREAT_TYPE_URL_MALWARE); | |
197 expected_threats.push_back(safe_browsing::SB_THREAT_TYPE_URL_PHISHING); | |
198 // TODO(nparker): Replace SafeBrowsingCheck w/ a call to | |
199 // client->OnCheckBrowseUrlResult() | |
200 safe_browsing::LocalSafeBrowsingDatabaseManager::SafeBrowsingCheck sb_check( | |
201 std::vector<GURL>(1, gurl), std::vector<safe_browsing::SBFullHash>(), | |
202 client, safe_browsing::MALWARE, expected_threats); | |
203 sb_check.url_results[0] = bad_urls_[gurl.spec()]; | |
204 sb_check.OnSafeBrowsingResult(); | |
205 } | |
206 | |
207 TestPrerenderContents::TestPrerenderContents( | |
208 PrerenderManager* prerender_manager, | |
209 Profile* profile, | |
210 const GURL& url, | |
211 const content::Referrer& referrer, | |
212 Origin origin, | |
213 FinalStatus expected_final_status) | |
214 : PrerenderContents(prerender_manager, profile, url, referrer, origin), | |
215 expected_final_status_(expected_final_status), | |
216 new_render_view_host_(nullptr), | |
217 was_hidden_(false), | |
218 was_shown_(false), | |
219 should_be_shown_(expected_final_status == FINAL_STATUS_USED), | |
220 skip_final_checks_(false) {} | |
221 | |
222 TestPrerenderContents::~TestPrerenderContents() { | |
223 if (skip_final_checks_) | |
224 return; | |
225 | |
226 EXPECT_EQ(expected_final_status_, final_status()) | |
227 << " when testing URL " << prerender_url().path() | |
228 << " (Expected: " << NameFromFinalStatus(expected_final_status_) | |
229 << ", Actual: " << NameFromFinalStatus(final_status()) << ")"; | |
230 | |
231 // Prerendering RenderViewHosts should be hidden before the first | |
232 // navigation, so this should be happen for every PrerenderContents for | |
233 // which a RenderViewHost is created, regardless of whether or not it's | |
234 // used. | |
235 if (new_render_view_host_) | |
236 EXPECT_TRUE(was_hidden_); | |
237 | |
238 // A used PrerenderContents will only be destroyed when we swap out | |
239 // WebContents, at the end of a navigation caused by a call to | |
240 // NavigateToURLImpl(). | |
241 if (final_status() == FINAL_STATUS_USED) | |
242 EXPECT_TRUE(new_render_view_host_); | |
243 | |
244 EXPECT_EQ(should_be_shown_, was_shown_); | |
245 } | |
246 | |
247 void TestPrerenderContents::RenderProcessGone( | |
248 base::TerminationStatus status) { | |
249 // On quit, it's possible to end up here when render processes are closed | |
250 // before the PrerenderManager is destroyed. As a result, it's possible to | |
251 // get either FINAL_STATUS_APP_TERMINATING or FINAL_STATUS_RENDERER_CRASHED | |
252 // on quit. | |
253 // | |
254 // It's also possible for this to be called after we've been notified of | |
255 // app termination, but before we've been deleted, which is why the second | |
256 // check is needed. | |
257 if (expected_final_status_ == FINAL_STATUS_APP_TERMINATING && | |
258 final_status() != expected_final_status_) { | |
259 expected_final_status_ = FINAL_STATUS_RENDERER_CRASHED; | |
260 } | |
261 | |
262 PrerenderContents::RenderProcessGone(status); | |
263 } | |
264 | |
265 bool TestPrerenderContents::CheckURL(const GURL& url) { | |
266 // Prevent FINAL_STATUS_UNSUPPORTED_SCHEME when navigating to about:crash in | |
267 // the PrerenderRendererCrash test. | |
268 if (url.spec() != content::kChromeUICrashURL) | |
269 return PrerenderContents::CheckURL(url); | |
270 return true; | |
271 } | |
272 | |
273 void TestPrerenderContents::OnRenderViewHostCreated( | |
274 RenderViewHost* new_render_view_host) { | |
275 // Used to make sure the RenderViewHost is hidden and, if used, | |
276 // subsequently shown. | |
277 notification_registrar().Add( | |
278 this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, | |
279 content::Source<content::RenderWidgetHost>( | |
280 new_render_view_host->GetWidget())); | |
281 | |
282 new_render_view_host_ = new_render_view_host; | |
283 | |
284 PrerenderContents::OnRenderViewHostCreated(new_render_view_host); | |
285 } | |
286 | |
287 void TestPrerenderContents::Observe( | |
288 int type, | |
289 const content::NotificationSource& source, | |
290 const content::NotificationDetails& details) { | |
291 if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) { | |
292 EXPECT_EQ(new_render_view_host_->GetWidget(), | |
293 content::Source<content::RenderWidgetHost>(source).ptr()); | |
294 bool is_visible = *content::Details<bool>(details).ptr(); | |
295 | |
296 if (!is_visible) { | |
297 was_hidden_ = true; | |
298 } else if (is_visible && was_hidden_) { | |
299 // Once hidden, a prerendered RenderViewHost should only be shown after | |
300 // being removed from the PrerenderContents for display. | |
301 EXPECT_FALSE(GetRenderViewHost()); | |
302 was_shown_ = true; | |
303 } | |
304 return; | |
305 } | |
306 PrerenderContents::Observe(type, source, details); | |
307 } | |
308 | |
309 TestPrerender::TestPrerender() | |
310 : contents_(nullptr), number_of_loads_(0), expected_number_of_loads_(0) {} | |
311 | |
312 TestPrerender::~TestPrerender() { | |
313 if (contents_) | |
314 contents_->RemoveObserver(this); | |
315 } | |
316 | |
317 void TestPrerender::WaitForLoads(int expected_number_of_loads) { | |
318 DCHECK(!load_waiter_); | |
319 DCHECK(!expected_number_of_loads_); | |
320 if (number_of_loads_ < expected_number_of_loads) { | |
321 load_waiter_.reset(new base::RunLoop); | |
322 expected_number_of_loads_ = expected_number_of_loads; | |
323 load_waiter_->Run(); | |
324 load_waiter_.reset(); | |
325 expected_number_of_loads_ = 0; | |
326 } | |
327 EXPECT_LE(expected_number_of_loads, number_of_loads_); | |
328 } | |
329 | |
330 void TestPrerender::OnPrerenderCreated(TestPrerenderContents* contents) { | |
331 DCHECK(!contents_); | |
332 contents_ = contents; | |
333 contents_->AddObserver(this); | |
334 create_loop_.Quit(); | |
335 } | |
336 | |
337 void TestPrerender::OnPrerenderStart(PrerenderContents* contents) { | |
338 start_loop_.Quit(); | |
339 } | |
340 | |
341 void TestPrerender::OnPrerenderStopLoading(PrerenderContents* contents) { | |
342 number_of_loads_++; | |
343 if (load_waiter_ && number_of_loads_ >= expected_number_of_loads_) | |
344 load_waiter_->Quit(); | |
345 } | |
346 | |
347 void TestPrerender::OnPrerenderStop(PrerenderContents* contents) { | |
348 DCHECK(contents_); | |
349 contents_ = nullptr; | |
350 stop_loop_.Quit(); | |
351 // If there is a WaitForLoads call and it has yet to see the expected number | |
352 // of loads, stop the loop so the test fails instead of timing out. | |
353 if (load_waiter_) | |
354 load_waiter_->Quit(); | |
355 } | |
356 | |
357 TestPrerenderContentsFactory::TestPrerenderContentsFactory() {} | |
358 | |
359 TestPrerenderContentsFactory::~TestPrerenderContentsFactory() { | |
360 EXPECT_TRUE(expected_contents_queue_.empty()); | |
361 } | |
362 | |
363 std::unique_ptr<TestPrerender> | |
364 TestPrerenderContentsFactory::ExpectPrerenderContents( | |
365 FinalStatus final_status) { | |
366 std::unique_ptr<TestPrerender> handle(new TestPrerender()); | |
367 expected_contents_queue_.push_back( | |
368 ExpectedContents(final_status, handle->AsWeakPtr())); | |
369 return handle; | |
370 } | |
371 | |
372 PrerenderContents* TestPrerenderContentsFactory::CreatePrerenderContents( | |
373 PrerenderManager* prerender_manager, | |
374 Profile* profile, | |
375 const GURL& url, | |
376 const content::Referrer& referrer, | |
377 Origin origin) { | |
378 ExpectedContents expected; | |
379 if (!expected_contents_queue_.empty()) { | |
380 expected = expected_contents_queue_.front(); | |
381 expected_contents_queue_.pop_front(); | |
382 } | |
383 TestPrerenderContents* contents = new TestPrerenderContents( | |
384 prerender_manager, profile, url, referrer, origin, expected.final_status); | |
385 if (expected.handle) | |
386 expected.handle->OnPrerenderCreated(contents); | |
387 return contents; | |
388 } | |
389 | |
390 TestPrerenderContentsFactory::ExpectedContents::ExpectedContents() | |
391 : final_status(FINAL_STATUS_MAX) {} | |
392 | |
393 TestPrerenderContentsFactory::ExpectedContents::ExpectedContents( | |
394 const ExpectedContents& other) = default; | |
395 | |
396 TestPrerenderContentsFactory::ExpectedContents::ExpectedContents( | |
397 FinalStatus final_status, | |
398 const base::WeakPtr<TestPrerender>& handle) | |
399 : final_status(final_status), handle(handle) {} | |
400 | |
401 TestPrerenderContentsFactory::ExpectedContents::~ExpectedContents() {} | |
402 | |
403 PrerenderInProcessBrowserTest::PrerenderInProcessBrowserTest() | |
404 : external_protocol_handler_delegate_( | |
405 base::MakeUnique<NeverRunsExternalProtocolHandlerDelegate>()), | |
406 safe_browsing_factory_( | |
407 base::MakeUnique<safe_browsing::TestSafeBrowsingServiceFactory>()), | |
408 prerender_contents_factory_(nullptr), | |
409 explicitly_set_browser_(nullptr), | |
410 autostart_test_server_(true) {} | |
411 | |
412 PrerenderInProcessBrowserTest::~PrerenderInProcessBrowserTest() {} | |
413 | |
414 void PrerenderInProcessBrowserTest::SetUpCommandLine( | |
415 base::CommandLine* command_line) { | |
416 command_line->AppendSwitch(switches::kEnablePepperTesting); | |
417 command_line->AppendSwitchASCII(switches::kOverridePluginPowerSaverForTesting, | |
418 "ignore-list"); | |
419 ASSERT_TRUE(ppapi::RegisterPowerSaverTestPlugin(command_line)); | |
420 } | |
421 | |
422 | |
423 void PrerenderInProcessBrowserTest::TearDownInProcessBrowserTestFixture() { | |
424 safe_browsing::SafeBrowsingService::RegisterFactory(nullptr); | |
425 } | |
426 | |
427 content::SessionStorageNamespace* | |
428 PrerenderInProcessBrowserTest::GetSessionStorageNamespace() const { | |
429 content::WebContents* web_contents = GetActiveWebContents(); | |
430 if (!web_contents) | |
431 return nullptr; | |
432 return web_contents->GetController().GetDefaultSessionStorageNamespace(); | |
433 } | |
434 | |
435 bool PrerenderInProcessBrowserTest::UrlIsInPrerenderManager( | |
436 const std::string& html_file) const { | |
437 return UrlIsInPrerenderManager(embedded_test_server()->GetURL(html_file)); | |
438 } | |
439 | |
440 bool PrerenderInProcessBrowserTest::UrlIsInPrerenderManager( | |
441 const GURL& url) const { | |
442 return GetPrerenderManager()->FindPrerenderData( | |
443 url, GetSessionStorageNamespace()) != nullptr; | |
444 } | |
445 | |
446 content::WebContents* PrerenderInProcessBrowserTest::GetActiveWebContents() | |
447 const { | |
448 return current_browser()->tab_strip_model()->GetActiveWebContents(); | |
449 } | |
450 | |
451 PrerenderManager* PrerenderInProcessBrowserTest::GetPrerenderManager() const { | |
452 return PrerenderManagerFactory::GetForProfile(current_browser()->profile()); | |
453 } | |
454 | |
455 TestPrerenderContents* PrerenderInProcessBrowserTest::GetPrerenderContentsFor( | |
456 const GURL& url) const { | |
457 PrerenderManager::PrerenderData* prerender_data = | |
458 GetPrerenderManager()->FindPrerenderData(url, nullptr); | |
459 return static_cast<TestPrerenderContents*>( | |
460 prerender_data ? prerender_data->contents() : nullptr); | |
461 } | |
462 | |
463 void PrerenderInProcessBrowserTest::SetUpInProcessBrowserTestFixture() { | |
464 safe_browsing_factory_->SetTestDatabaseManager( | |
465 new test_utils::FakeSafeBrowsingDatabaseManager()); | |
466 safe_browsing::SafeBrowsingService::RegisterFactory( | |
467 safe_browsing_factory_.get()); | |
468 } | |
469 | |
470 void PrerenderInProcessBrowserTest::SetUpOnMainThread() { | |
471 // Increase the memory allowed in a prerendered page above normal settings. | |
472 // Debug build bots occasionally run against the default limit, and tests | |
473 // were failing because the prerender was canceled due to memory exhaustion. | |
474 // http://crbug.com/93076 | |
475 GetPrerenderManager()->mutable_config().max_bytes = 2000 * 1024 * 1024; | |
476 | |
477 current_browser()->profile()->GetPrefs()->SetBoolean( | |
478 prefs::kPromptForDownload, false); | |
479 if (autostart_test_server_) | |
480 ASSERT_TRUE(embedded_test_server()->Start()); | |
481 ChromeResourceDispatcherHostDelegate:: | |
482 SetExternalProtocolHandlerDelegateForTesting( | |
483 external_protocol_handler_delegate_.get()); | |
484 | |
485 PrerenderManager* prerender_manager = GetPrerenderManager(); | |
486 ASSERT_TRUE(prerender_manager); | |
487 prerender_manager->mutable_config().rate_limit_enabled = false; | |
488 ASSERT_FALSE(prerender_contents_factory_); | |
489 prerender_contents_factory_ = new TestPrerenderContentsFactory; | |
490 prerender_manager->SetPrerenderContentsFactoryForTest( | |
491 prerender_contents_factory_); | |
492 ASSERT_TRUE(safe_browsing_factory_->test_safe_browsing_service()); | |
493 } | |
494 | |
495 void CreateCountingInterceptorOnIO( | |
496 const GURL& url, | |
497 const base::FilePath& file, | |
498 const base::WeakPtr<RequestCounter>& counter) { | |
499 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
500 std::unique_ptr<net::URLRequestInterceptor> request_interceptor( | |
501 new CountingInterceptor(file, counter)); | |
502 net::URLRequestFilter::GetInstance()->AddUrlInterceptor( | |
503 url, std::move(request_interceptor)); | |
504 } | |
505 | |
506 void CreateMockInterceptorOnIO(const GURL& url, const base::FilePath& file) { | |
507 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
508 net::URLRequestFilter::GetInstance()->AddUrlInterceptor( | |
509 url, | |
510 net::URLRequestMockHTTPJob::CreateInterceptorForSingleFile( | |
511 file, content::BrowserThread::GetBlockingPool())); | |
512 } | |
513 | |
514 } // namespace test_utils | |
515 | |
516 } // namespace prerender | |
OLD | NEW |