Add link to OSX's diagnostic tool on error page.
[chromium-blink-merge.git] / chrome / browser / errorpage_browsertest.cc
blobf47a5854549ca09392693ce844dbcd9e2a846d17
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/command_line.h"
7 #include "base/compiler_specific.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/path_service.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/synchronization/lock.h"
17 #include "chrome/browser/browsing_data/browsing_data_helper.h"
18 #include "chrome/browser/browsing_data/browsing_data_remover.h"
19 #include "chrome/browser/net/net_error_diagnostics_dialog.h"
20 #include "chrome/browser/net/url_request_mock_util.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_commands.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/grit/generated_resources.h"
30 #include "chrome/test/base/in_process_browser_test.h"
31 #include "chrome/test/base/ui_test_utils.h"
32 #include "components/google/core/browser/google_util.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_service.h"
35 #include "content/public/browser/notification_types.h"
36 #include "content/public/browser/render_frame_host.h"
37 #include "content/public/browser/render_view_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_observer.h"
40 #include "content/public/test/browser_test_utils.h"
41 #include "content/public/test/test_navigation_observer.h"
42 #include "net/base/filename_util.h"
43 #include "net/base/net_errors.h"
44 #include "net/base/net_util.h"
45 #include "net/http/failing_http_transaction_factory.h"
46 #include "net/http/http_cache.h"
47 #include "net/test/spawned_test_server/spawned_test_server.h"
48 #include "net/test/url_request/url_request_failed_job.h"
49 #include "net/test/url_request/url_request_mock_http_job.h"
50 #include "net/url_request/url_request_context.h"
51 #include "net/url_request/url_request_context_getter.h"
52 #include "net/url_request/url_request_filter.h"
53 #include "net/url_request/url_request_interceptor.h"
54 #include "net/url_request/url_request_job.h"
55 #include "net/url_request/url_request_test_job.h"
56 #include "net/url_request/url_request_test_util.h"
57 #include "ui/base/l10n/l10n_util.h"
59 #if defined(OS_CHROMEOS)
60 #include "chrome/browser/browser_process.h"
61 #include "chrome/browser/chromeos/chrome_browser_main_chromeos.h"
62 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
63 #include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
64 #include "chrome/grit/generated_resources.h"
65 #include "components/policy/core/common/mock_configuration_policy_provider.h"
66 #include "components/policy/core/common/policy_types.h"
67 #include "content/public/test/browser_test_utils.h"
68 #include "ui/base/l10n/l10n_util.h"
69 #endif
71 using content::BrowserThread;
72 using content::NavigationController;
73 using net::URLRequestFailedJob;
74 using net::URLRequestTestJob;
76 namespace {
78 // Returns true if |text| is displayed on the page |browser| is currently
79 // displaying. Uses "innerText", so will miss hidden text, and whitespace
80 // space handling may be weird.
81 bool WARN_UNUSED_RESULT IsDisplayingText(Browser* browser,
82 const std::string& text) {
83 std::string command = base::StringPrintf(
84 "var textContent = document.body.innerText;"
85 "var hasText = textContent.indexOf('%s') >= 0;"
86 "domAutomationController.send(hasText);",
87 text.c_str());
88 bool result = false;
89 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
90 browser->tab_strip_model()->GetActiveWebContents(), command, &result));
91 return result;
94 // Expands the more box on the currently displayed error page.
95 void ToggleHelpBox(Browser* browser) {
96 EXPECT_TRUE(content::ExecuteScript(
97 browser->tab_strip_model()->GetActiveWebContents(),
98 "document.getElementById('details-button').click();"));
101 // Returns true if |browser| is displaying the text representation of
102 // |error_code| on the current page.
103 bool WARN_UNUSED_RESULT IsDisplayingNetError(Browser* browser,
104 net::Error error_code) {
105 return IsDisplayingText(browser, net::ErrorToShortString(error_code));
108 // Returns true if the diagnostics button is displayed.
109 bool WARN_UNUSED_RESULT IsDisplayingDiagnosticsButton(Browser* browser) {
110 std::string command = base::StringPrintf(
111 "var diagnose_button = document.getElementById('diagnose-button');"
112 "domAutomationController.send(diagnose_button.style.display != 'none');");
113 bool result = false;
114 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
115 browser->tab_strip_model()->GetActiveWebContents(), command, &result));
116 return result;
119 // Checks that the local error page is being displayed, without remotely
120 // retrieved navigation corrections, and with the specified error code.
121 void ExpectDisplayingLocalErrorPage(Browser* browser, net::Error error_code) {
122 // Expand the help box so innerText will include text below the fold.
123 ToggleHelpBox(browser);
125 EXPECT_TRUE(IsDisplayingNetError(browser, error_code));
127 // Locally generated error pages should not have navigation corrections.
128 EXPECT_FALSE(IsDisplayingText(browser, "http://correction1/"));
129 EXPECT_FALSE(IsDisplayingText(browser, "http://correction2/"));
131 // Locally generated error pages should not have a populated search box.
132 bool search_box_populated = false;
133 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
134 browser->tab_strip_model()->GetActiveWebContents(),
135 "var searchText = document.getElementById('search-box').value;"
136 "domAutomationController.send(searchText == 'search query');",
137 &search_box_populated));
138 EXPECT_FALSE(search_box_populated);
141 // Checks that an error page with information retrieved from the navigation
142 // correction service is being displayed, with the specified specified error
143 // code.
144 void ExpectDisplayingNavigationCorrections(Browser* browser,
145 net::Error error_code) {
146 // Expand the help box so innerText will include text below the fold.
147 ToggleHelpBox(browser);
149 EXPECT_TRUE(IsDisplayingNetError(browser, error_code));
151 // Check that the mock navigation corrections are displayed.
152 EXPECT_TRUE(IsDisplayingText(browser, "http://correction1/"));
153 EXPECT_TRUE(IsDisplayingText(browser, "http://correction2/"));
155 // Check that the search box is populated correctly.
156 bool search_box_populated = false;
157 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
158 browser->tab_strip_model()->GetActiveWebContents(),
159 "var searchText = document.getElementById('search-box').value;"
160 "domAutomationController.send(searchText == 'search query');",
161 &search_box_populated));
162 EXPECT_TRUE(search_box_populated);
164 // The diagnostics button isn't displayed when corrections were
165 // retrieved from a remote server.
166 EXPECT_FALSE(IsDisplayingDiagnosticsButton(browser));
169 std::string GetShowSavedButtonLabel() {
170 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY);
173 void AddInterceptorForURL(
174 const GURL& url,
175 scoped_ptr<net::URLRequestInterceptor> handler) {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
177 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
178 url, handler.Pass());
181 // An interceptor that fails a configurable number of requests, then succeeds
182 // all requests after that, keeping count of failures and successes.
183 class FailFirstNRequestsInterceptor : public net::URLRequestInterceptor {
184 public:
185 explicit FailFirstNRequestsInterceptor(int requests_to_fail)
186 : requests_(0), failures_(0), requests_to_fail_(requests_to_fail) {}
187 ~FailFirstNRequestsInterceptor() override {}
189 // net::URLRequestInterceptor implementation
190 net::URLRequestJob* MaybeInterceptRequest(
191 net::URLRequest* request,
192 net::NetworkDelegate* network_delegate) const override {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
194 requests_++;
195 if (failures_ < requests_to_fail_) {
196 failures_++;
197 // Note: net::ERR_CONNECTION_RESET does not summon the Link Doctor; see
198 // NetErrorHelperCore::GetErrorPageURL.
199 return new URLRequestFailedJob(request,
200 network_delegate,
201 net::ERR_CONNECTION_RESET);
202 } else {
203 return new URLRequestTestJob(request, network_delegate,
204 URLRequestTestJob::test_headers(),
205 URLRequestTestJob::test_data_1(),
206 true);
210 int requests() const { return requests_; }
211 int failures() const { return failures_; }
213 private:
214 // These are mutable because MaybeCreateJob is const but we want this state
215 // for testing.
216 mutable int requests_;
217 mutable int failures_;
218 int requests_to_fail_;
220 DISALLOW_COPY_AND_ASSIGN(FailFirstNRequestsInterceptor);
223 // An interceptor that serves LinkDoctor responses. It also allows waiting
224 // until a certain number of requests have been sent.
225 // TODO(mmenke): Wait until responses have been received instead.
226 class LinkDoctorInterceptor : public net::URLRequestInterceptor {
227 public:
228 LinkDoctorInterceptor() : num_requests_(0),
229 requests_to_wait_for_(-1),
230 weak_factory_(this) {
233 ~LinkDoctorInterceptor() override {}
235 // net::URLRequestInterceptor implementation
236 net::URLRequestJob* MaybeInterceptRequest(
237 net::URLRequest* request,
238 net::NetworkDelegate* network_delegate) const override {
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241 BrowserThread::PostTask(
242 BrowserThread::UI, FROM_HERE,
243 base::Bind(&LinkDoctorInterceptor::RequestCreated,
244 weak_factory_.GetWeakPtr()));
246 base::FilePath root_http;
247 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
248 return new net::URLRequestMockHTTPJob(
249 request,
250 network_delegate,
251 root_http.AppendASCII("mock-link-doctor.json"),
252 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
253 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
256 void WaitForRequests(int requests_to_wait_for) {
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
258 DCHECK_EQ(-1, requests_to_wait_for_);
259 DCHECK(!run_loop_);
261 if (requests_to_wait_for >= num_requests_)
262 return;
264 requests_to_wait_for_ = requests_to_wait_for;
265 run_loop_.reset(new base::RunLoop());
266 run_loop_->Run();
267 run_loop_.reset();
268 requests_to_wait_for_ = -1;
269 EXPECT_EQ(num_requests_, requests_to_wait_for);
272 // It is up to the caller to wait until all relevant requests has been
273 // created, either through calling WaitForRequests or some other manner,
274 // before calling this method.
275 int num_requests() const {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
277 return num_requests_;
280 private:
281 void RequestCreated() {
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284 num_requests_++;
285 if (num_requests_ == requests_to_wait_for_)
286 run_loop_->Quit();
289 // These are only used on the UI thread.
290 int num_requests_;
291 int requests_to_wait_for_;
292 scoped_ptr<base::RunLoop> run_loop_;
294 // This prevents any risk of flake if any test doesn't wait for a request
295 // it sent. Mutable so it can be accessed from a const function.
296 mutable base::WeakPtrFactory<LinkDoctorInterceptor> weak_factory_;
298 DISALLOW_COPY_AND_ASSIGN(LinkDoctorInterceptor);
301 void InstallMockInterceptors(
302 const GURL& search_url,
303 scoped_ptr<net::URLRequestInterceptor> link_doctor_interceptor) {
304 chrome_browser_net::SetUrlRequestMocksEnabled(true);
306 AddInterceptorForURL(google_util::LinkDoctorBaseURL(),
307 link_doctor_interceptor.Pass());
309 // Add a mock for the search engine the error page will use.
310 base::FilePath root_http;
311 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
312 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
313 search_url.scheme(), search_url.host(),
314 net::URLRequestMockHTTPJob::CreateInterceptorForSingleFile(
315 root_http.AppendASCII("title3.html"),
316 BrowserThread::GetBlockingPool()));
319 class ErrorPageTest : public InProcessBrowserTest {
320 public:
321 enum HistoryNavigationDirection {
322 HISTORY_NAVIGATE_BACK,
323 HISTORY_NAVIGATE_FORWARD,
326 ErrorPageTest() : link_doctor_interceptor_(NULL) {}
327 ~ErrorPageTest() override {}
329 // Navigates the active tab to a mock url created for the file at |file_path|.
330 // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests.
331 void SetUpCommandLine(base::CommandLine* command_line) override {
332 command_line->AppendSwitchASCII(switches::kShowSavedCopy,
333 switches::kEnableShowSavedCopyPrimary);
336 // Navigates the active tab to a mock url created for the file at |file_path|.
337 void NavigateToFileURL(const base::FilePath::StringType& file_path) {
338 ui_test_utils::NavigateToURL(
339 browser(),
340 net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path)));
343 // Navigates to the given URL and waits for |num_navigations| to occur, and
344 // the title to change to |expected_title|.
345 void NavigateToURLAndWaitForTitle(const GURL& url,
346 const std::string& expected_title,
347 int num_navigations) {
348 content::TitleWatcher title_watcher(
349 browser()->tab_strip_model()->GetActiveWebContents(),
350 base::ASCIIToUTF16(expected_title));
352 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
353 browser(), url, num_navigations);
355 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
356 title_watcher.WaitAndGetTitle());
359 // Navigates back in the history and waits for |num_navigations| to occur, and
360 // the title to change to |expected_title|.
361 void GoBackAndWaitForTitle(const std::string& expected_title,
362 int num_navigations) {
363 NavigateHistoryAndWaitForTitle(expected_title,
364 num_navigations,
365 HISTORY_NAVIGATE_BACK);
368 // Navigates forward in the history and waits for |num_navigations| to occur,
369 // and the title to change to |expected_title|.
370 void GoForwardAndWaitForTitle(const std::string& expected_title,
371 int num_navigations) {
372 NavigateHistoryAndWaitForTitle(expected_title,
373 num_navigations,
374 HISTORY_NAVIGATE_FORWARD);
377 void GoBackAndWaitForNavigations(int num_navigations) {
378 NavigateHistory(num_navigations, HISTORY_NAVIGATE_BACK);
381 void GoForwardAndWaitForNavigations(int num_navigations) {
382 NavigateHistory(num_navigations, HISTORY_NAVIGATE_FORWARD);
385 // Confirms that the javascript variable indicating whether or not we have
386 // a stale copy in the cache has been set to |expected|, and that the
387 // stale load button is or isn't there based on the same expectation.
388 testing::AssertionResult ProbeStaleCopyValue(bool expected) {
389 const char* js_cache_probe =
390 "try {\n"
391 " domAutomationController.send(\n"
392 " loadTimeData.valueExists('showSavedCopyButton') ?"
393 " 'yes' : 'no');\n"
394 "} catch (e) {\n"
395 " domAutomationController.send(e.message);\n"
396 "}\n";
398 std::string result;
399 bool ret =
400 content::ExecuteScriptAndExtractString(
401 browser()->tab_strip_model()->GetActiveWebContents(),
402 js_cache_probe,
403 &result);
404 if (!ret) {
405 return testing::AssertionFailure()
406 << "Failing return from ExecuteScriptAndExtractString.";
409 if ((expected && "yes" == result) || (!expected && "no" == result))
410 return testing::AssertionSuccess();
412 return testing::AssertionFailure() << "Cache probe result is " << result;
415 testing::AssertionResult ReloadStaleCopyFromCache() {
416 const char* js_reload_script =
417 "try {\n"
418 " document.getElementById('show-saved-copy-button').click();\n"
419 " domAutomationController.send('success');\n"
420 "} catch (e) {\n"
421 " domAutomationController.send(e.message);\n"
422 "}\n";
424 std::string result;
425 bool ret = content::ExecuteScriptAndExtractString(
426 browser()->tab_strip_model()->GetActiveWebContents(),
427 js_reload_script,
428 &result);
429 EXPECT_TRUE(ret);
430 if (!ret)
431 return testing::AssertionFailure();
432 return ("success" == result ? testing::AssertionSuccess() :
433 (testing::AssertionFailure() << "Exception message is " << result));
436 LinkDoctorInterceptor* link_doctor_interceptor() {
437 return link_doctor_interceptor_;
440 protected:
441 void SetUpOnMainThread() override {
442 link_doctor_interceptor_ = new LinkDoctorInterceptor();
443 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(
444 link_doctor_interceptor_);
445 // Ownership of the |interceptor_| is passed to an object the IO thread, but
446 // a pointer is kept in the test fixture. As soon as anything calls
447 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
448 UIThreadSearchTermsData search_terms_data(browser()->profile());
449 BrowserThread::PostTask(
450 BrowserThread::IO, FROM_HERE,
451 base::Bind(&InstallMockInterceptors,
452 GURL(search_terms_data.GoogleBaseURLValue()),
453 base::Passed(&owned_interceptor)));
456 // Returns a GURL that results in a DNS error.
457 GURL GetDnsErrorURL() const {
458 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
461 // Returns true if the platform has support for a diagnostics tool, which
462 // can be launched from the error page.
463 bool PlatformSupportsDiagnosticsTool() {
464 #if defined(OS_CHROMEOS)
465 // ChromeOS uses an extension instead of a diagnostics dialog.
466 return true;
467 #else
468 return CanShowNetworkDiagnosticsDialog();
469 #endif
472 private:
473 // Navigates the browser the indicated direction in the history and waits for
474 // |num_navigations| to occur and the title to change to |expected_title|.
475 void NavigateHistoryAndWaitForTitle(const std::string& expected_title,
476 int num_navigations,
477 HistoryNavigationDirection direction) {
478 content::TitleWatcher title_watcher(
479 browser()->tab_strip_model()->GetActiveWebContents(),
480 base::ASCIIToUTF16(expected_title));
482 NavigateHistory(num_navigations, direction);
484 EXPECT_EQ(title_watcher.WaitAndGetTitle(),
485 base::ASCIIToUTF16(expected_title));
488 void NavigateHistory(int num_navigations,
489 HistoryNavigationDirection direction) {
490 content::TestNavigationObserver test_navigation_observer(
491 browser()->tab_strip_model()->GetActiveWebContents(),
492 num_navigations);
493 if (direction == HISTORY_NAVIGATE_BACK) {
494 chrome::GoBack(browser(), CURRENT_TAB);
495 } else if (direction == HISTORY_NAVIGATE_FORWARD) {
496 chrome::GoForward(browser(), CURRENT_TAB);
497 } else {
498 FAIL();
500 test_navigation_observer.Wait();
503 LinkDoctorInterceptor* link_doctor_interceptor_;
506 class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
507 public:
508 explicit TestFailProvisionalLoadObserver(content::WebContents* contents)
509 : content::WebContentsObserver(contents) {}
510 ~TestFailProvisionalLoadObserver() override {}
512 // This method is invoked when the provisional load failed.
513 void DidFailProvisionalLoad(
514 content::RenderFrameHost* render_frame_host,
515 const GURL& validated_url,
516 int error_code,
517 const base::string16& error_description,
518 bool was_ignored_by_handler) override {
519 fail_url_ = validated_url;
522 const GURL& fail_url() const { return fail_url_; }
524 private:
525 GURL fail_url_;
527 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
530 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter,
531 net::Error error) {
532 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
533 net::HttpCache* cache(
534 getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
535 DCHECK(cache);
536 scoped_ptr<net::HttpTransactionFactory> factory(
537 new net::FailingHttpTransactionFactory(cache->GetSession(), error));
538 // Throw away old version; since this is a a browser test, we don't
539 // need to restore the old state.
540 cache->SetHttpNetworkTransactionFactoryForTesting(factory.Pass());
543 // Test an error with a file URL, and make sure it doesn't have a
544 // button to launch a network diagnostics tool.
545 IN_PROC_BROWSER_TEST_F(ErrorPageTest, FileNotFound) {
546 // Create an empty temp directory, to be sure there's no file in it.
547 base::ScopedTempDir temp_dir;
548 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
549 GURL non_existent_file_url =
550 net::FilePathToFileURL(temp_dir.path().AppendASCII("marmoset"));
552 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
553 browser(), non_existent_file_url, 1);
555 ExpectDisplayingLocalErrorPage(browser(), net::ERR_FILE_NOT_FOUND);
556 // Should not request Link Doctor corrections for local errors.
557 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
558 // Only errors on HTTP/HTTPS pages should display a diagnostics button.
559 EXPECT_FALSE(IsDisplayingDiagnosticsButton(browser()));
562 // Check an network error page for ERR_FAILED. In particular, this should
563 // not trigger a link doctor error page, and should have a diagnostics
564 // button, if available on the current platform.
565 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Failed) {
566 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
567 browser(), URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED), 1);
569 ExpectDisplayingLocalErrorPage(browser(), net::ERR_FAILED);
570 // Should not request Link Doctor corrections for this error.
571 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
573 EXPECT_EQ(PlatformSupportsDiagnosticsTool(),
574 IsDisplayingDiagnosticsButton(browser()));
577 // Test that a DNS error occuring in the main frame redirects to an error page.
578 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_Basic) {
579 // The first navigation should fail and load a blank page, while it fetches
580 // the Link Doctor response. The second navigation is the Link Doctor.
581 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
582 browser(), GetDnsErrorURL(), 2);
583 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
584 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
587 // Test that a DNS error occuring in the main frame does not result in an
588 // additional session history entry.
589 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack1) {
590 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
591 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
592 browser(), GetDnsErrorURL(), 2);
593 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
594 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
595 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
598 // Test that a DNS error occuring in the main frame does not result in an
599 // additional session history entry.
600 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) {
601 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
603 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
604 browser(), GetDnsErrorURL(), 2);
605 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
606 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
608 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
610 GoBackAndWaitForNavigations(2);
611 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
612 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
614 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
615 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
618 // Test that a DNS error occuring in the main frame does not result in an
619 // additional session history entry.
620 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
621 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
623 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
624 browser(), GetDnsErrorURL(), 2);
625 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
626 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
628 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
630 GoBackAndWaitForNavigations(2);
631 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
632 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
634 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
636 GoForwardAndWaitForNavigations(2);
637 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
638 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
641 // Test that a DNS error occuring in the main frame does not result in an
642 // additional session history entry.
643 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
644 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
646 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
647 browser(), GetDnsErrorURL(), 2);
648 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
649 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
651 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
653 GoBackAndWaitForNavigations(2);
654 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
655 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
657 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
659 GoForwardAndWaitForNavigations(2);
660 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
661 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
663 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
664 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
667 // Test that the search button on a DNS error page works.
668 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoSearch) {
669 // The first navigation should fail, and the second one should be the error
670 // page.
671 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
672 browser(), GetDnsErrorURL(), 2);
673 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
674 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
676 content::WebContents* web_contents =
677 browser()->tab_strip_model()->GetActiveWebContents();
679 // Do a search and make sure the browser ends up at the right page.
680 content::TestNavigationObserver nav_observer(web_contents, 1);
681 content::TitleWatcher title_watcher(
682 web_contents,
683 base::ASCIIToUTF16("Title Of More Awesomeness"));
684 // Can't use content::ExecuteScript because it waits for scripts to send
685 // notification that they've run, and scripts that trigger a navigation may
686 // not send that notification.
687 web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
688 base::ASCIIToUTF16("document.getElementById('search-button').click();"));
689 nav_observer.Wait();
690 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"),
691 title_watcher.WaitAndGetTitle());
693 // There should have been another Link Doctor request, for tracking purposes.
694 // Have to wait for it, since the search page does not depend on having
695 // sent the tracking request.
696 link_doctor_interceptor()->WaitForRequests(2);
697 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
699 // Check the path and query string.
700 std::string url;
701 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
702 browser()->tab_strip_model()->GetActiveWebContents(),
703 "domAutomationController.send(window.location.href);",
704 &url));
705 EXPECT_EQ("/search", GURL(url).path());
706 EXPECT_EQ("q=search%20query", GURL(url).query());
708 // Go back to the error page, to make sure the history is correct.
709 GoBackAndWaitForNavigations(2);
710 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
711 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
714 // Test that the reload button on a DNS error page works.
715 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoReload) {
716 // The first navigation should fail, and the second one should be the error
717 // page.
718 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
719 browser(), GetDnsErrorURL(), 2);
720 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
721 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
723 content::WebContents* web_contents =
724 browser()->tab_strip_model()->GetActiveWebContents();
726 // Clicking the reload button should load the error page again, and there
727 // should be two commits, as before.
728 content::TestNavigationObserver nav_observer(web_contents, 2);
729 // Can't use content::ExecuteScript because it waits for scripts to send
730 // notification that they've run, and scripts that trigger a navigation may
731 // not send that notification.
732 web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
733 base::ASCIIToUTF16("document.getElementById('reload-button').click();"));
734 nav_observer.Wait();
735 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
737 // There should have two more requests to the correction service: One for the
738 // new error page, and one for tracking purposes. Have to make sure to wait
739 // for the tracking request, since the new error page does not depend on it.
740 link_doctor_interceptor()->WaitForRequests(3);
741 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
744 // Test that clicking links on a DNS error page works.
745 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoClickLink) {
746 // The first navigation should fail, and the second one should be the error
747 // page.
748 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
749 browser(), GetDnsErrorURL(), 2);
750 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
751 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
753 content::WebContents* web_contents =
754 browser()->tab_strip_model()->GetActiveWebContents();
756 // Simulate a click on a link.
758 content::TitleWatcher title_watcher(
759 web_contents,
760 base::ASCIIToUTF16("Title Of Awesomeness"));
761 std::string link_selector =
762 "document.querySelector('a[href=\"http://mock.http/title2.html\"]')";
763 // The tracking request is triggered by onmousedown, so it catches middle
764 // mouse button clicks, as well as left clicks.
765 web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
766 base::ASCIIToUTF16(link_selector + ".onmousedown();"));
767 // Can't use content::ExecuteScript because it waits for scripts to send
768 // notification that they've run, and scripts that trigger a navigation may
769 // not send that notification.
770 web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
771 base::ASCIIToUTF16(link_selector + ".click();"));
772 EXPECT_EQ(base::ASCIIToUTF16("Title Of Awesomeness"),
773 title_watcher.WaitAndGetTitle());
775 // There should have been a tracking request to the correction service. Have
776 // to make sure to wait the tracking request, since the new page does not
777 // depend on it.
778 link_doctor_interceptor()->WaitForRequests(2);
779 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
782 // Test that a DNS error occuring in an iframe does not result in showing
783 // navigation corrections.
784 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
785 NavigateToURLAndWaitForTitle(
786 net::URLRequestMockHTTPJob::GetMockUrl(
787 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
788 "Blah",
790 // We expect to have two history entries, since we started off with navigation
791 // to "about:blank" and then navigated to "iframe_dns_error.html".
792 EXPECT_EQ(2,
793 browser()->tab_strip_model()->GetActiveWebContents()->
794 GetController().GetEntryCount());
795 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
798 // This test fails regularly on win_rel trybots. See crbug.com/121540
799 #if defined(OS_WIN)
800 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
801 #else
802 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
803 #endif
804 // Test that a DNS error occuring in an iframe does not result in an
805 // additional session history entry.
806 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) {
807 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
808 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
809 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
810 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
813 // This test fails regularly on win_rel trybots. See crbug.com/121540
815 // This fails on linux_aura bringup: http://crbug.com/163931
816 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
817 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
818 #else
819 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
820 #endif
821 // Test that a DNS error occuring in an iframe does not result in an
822 // additional session history entry.
823 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) {
824 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
825 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
826 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
827 GoForwardAndWaitForTitle("Blah", 1);
828 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
831 // Test that a DNS error occuring in an iframe, once the main document is
832 // completed loading, does not result in an additional session history entry.
833 // To ensure that the main document has completed loading, JavaScript is used to
834 // inject an iframe after loading is done.
835 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) {
836 content::WebContents* wc =
837 browser()->tab_strip_model()->GetActiveWebContents();
838 GURL fail_url =
839 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
841 // Load a regular web page, in which we will inject an iframe.
842 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
844 // We expect to have two history entries, since we started off with navigation
845 // to "about:blank" and then navigated to "title2.html".
846 EXPECT_EQ(2, wc->GetController().GetEntryCount());
848 std::string script = "var frame = document.createElement('iframe');"
849 "frame.src = '" + fail_url.spec() + "';"
850 "document.body.appendChild(frame);";
852 TestFailProvisionalLoadObserver fail_observer(wc);
853 content::WindowedNotificationObserver load_observer(
854 content::NOTIFICATION_LOAD_STOP,
855 content::Source<NavigationController>(&wc->GetController()));
856 wc->GetMainFrame()->ExecuteJavaScriptForTests(base::ASCIIToUTF16(script));
857 load_observer.Wait();
859 // Ensure we saw the expected failure.
860 EXPECT_EQ(fail_url, fail_observer.fail_url());
862 // Failed initial navigation of an iframe shouldn't be adding any history
863 // entries.
864 EXPECT_EQ(2, wc->GetController().GetEntryCount());
867 // Do the same test, but with an iframe that doesn't have initial URL
868 // assigned.
869 script = "var frame = document.createElement('iframe');"
870 "frame.id = 'target_frame';"
871 "document.body.appendChild(frame);";
873 content::WindowedNotificationObserver load_observer(
874 content::NOTIFICATION_LOAD_STOP,
875 content::Source<NavigationController>(&wc->GetController()));
876 wc->GetMainFrame()->ExecuteJavaScriptForTests(base::ASCIIToUTF16(script));
877 load_observer.Wait();
880 script = "var f = document.getElementById('target_frame');"
881 "f.src = '" + fail_url.spec() + "';";
883 TestFailProvisionalLoadObserver fail_observer(wc);
884 content::WindowedNotificationObserver load_observer(
885 content::NOTIFICATION_LOAD_STOP,
886 content::Source<NavigationController>(&wc->GetController()));
887 wc->GetMainFrame()->ExecuteJavaScriptForTests(base::ASCIIToUTF16(script));
888 load_observer.Wait();
890 EXPECT_EQ(fail_url, fail_observer.fail_url());
891 EXPECT_EQ(2, wc->GetController().GetEntryCount());
893 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
896 // Checks that navigation corrections are not loaded when we receive an actual
897 // 404 page.
898 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
899 NavigateToURLAndWaitForTitle(
900 net::URLRequestMockHTTPJob::GetMockUrl(
901 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
902 "SUCCESS",
904 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
907 // Checks that when an error occurs, the stale cache status of the page
908 // is correctly transferred, and that stale cached copied can be loaded
909 // from the javascript.
910 IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) {
911 ASSERT_TRUE(test_server()->Start());
912 // Load cache with entry with "nocache" set, to create stale
913 // cache.
914 GURL test_url(test_server()->GetURL("files/nocache.html"));
915 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
917 // Reload same URL after forcing an error from the the network layer;
918 // confirm that the error page is told the cached copy exists.
919 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
920 browser()->profile()->GetRequestContext();
921 BrowserThread::PostTask(
922 BrowserThread::IO, FROM_HERE,
923 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
924 net::ERR_FAILED));
926 // With no navigation corrections to load, there's only one navigation.
927 ui_test_utils::NavigateToURL(browser(), test_url);
928 EXPECT_TRUE(ProbeStaleCopyValue(true));
929 EXPECT_TRUE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
930 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"),
931 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
933 // Confirm that loading the stale copy from the cache works.
934 content::TestNavigationObserver same_tab_observer(
935 browser()->tab_strip_model()->GetActiveWebContents(), 1);
936 ASSERT_TRUE(ReloadStaleCopyFromCache());
937 same_tab_observer.Wait();
938 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
939 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
941 // Reload the same URL with a post request; confirm the error page is told
942 // that there is no cached copy.
943 ui_test_utils::NavigateToURLWithPost(browser(), test_url);
944 EXPECT_TRUE(ProbeStaleCopyValue(false));
945 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
946 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
948 // Clear the cache and reload the same URL; confirm the error page is told
949 // that there is no cached copy.
950 BrowsingDataRemover* remover =
951 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
952 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
953 BrowsingDataHelper::UNPROTECTED_WEB);
954 ui_test_utils::NavigateToURL(browser(), test_url);
955 EXPECT_TRUE(ProbeStaleCopyValue(false));
956 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
957 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
960 // Check that the easter egg is present and initialised and is not disabled.
961 IN_PROC_BROWSER_TEST_F(ErrorPageTest, CheckEasterEggIsNotDisabled) {
962 ui_test_utils::NavigateToURL(browser(),
963 URLRequestFailedJob::GetMockHttpUrl(net::ERR_INTERNET_DISCONNECTED));
965 content::WebContents* web_contents =
966 browser()->tab_strip_model()->GetActiveWebContents();
968 // Check for no disabled message container.
969 std::string command = base::StringPrintf(
970 "var hasDisableContainer = document.querySelectorAll('.snackbar').length;"
971 "domAutomationController.send(hasDisableContainer);");
972 int result;
973 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
974 web_contents, command, &result));
975 EXPECT_EQ(0, result);
977 // Presence of the canvas container.
978 command = base::StringPrintf(
979 "var runnerCanvas = document.querySelectorAll('.runner-canvas').length;"
980 "domAutomationController.send(runnerCanvas);");
981 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
982 web_contents, command, &result));
983 EXPECT_EQ(1, result);
986 class ErrorPageAutoReloadTest : public InProcessBrowserTest {
987 public:
988 void SetUpCommandLine(base::CommandLine* command_line) override {
989 command_line->AppendSwitch(switches::kEnableOfflineAutoReload);
992 void InstallInterceptor(const GURL& url, int requests_to_fail) {
993 interceptor_ = new FailFirstNRequestsInterceptor(requests_to_fail);
994 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_);
996 // Tests don't need to wait for this task to complete before using the
997 // filter; any requests that might be affected by it will end up in the IO
998 // thread's message loop after this posted task anyway.
1000 // Ownership of the interceptor is passed to an object the IO thread, but a
1001 // pointer is kept in the test fixture. As soon as anything calls
1002 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
1003 BrowserThread::PostTask(
1004 BrowserThread::IO, FROM_HERE,
1005 base::Bind(&AddInterceptorForURL, url,
1006 base::Passed(&owned_interceptor)));
1009 void NavigateToURLAndWaitForTitle(const GURL& url,
1010 const std::string& expected_title,
1011 int num_navigations) {
1012 content::TitleWatcher title_watcher(
1013 browser()->tab_strip_model()->GetActiveWebContents(),
1014 base::ASCIIToUTF16(expected_title));
1016 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1017 browser(), url, num_navigations);
1019 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
1020 title_watcher.WaitAndGetTitle());
1023 FailFirstNRequestsInterceptor* interceptor() {
1024 return interceptor_;
1027 private:
1028 FailFirstNRequestsInterceptor* interceptor_;
1031 // Fails on official mac_trunk build. See crbug.com/465789.
1032 #if defined(OFFICIAL_BUILD) && defined(OS_MACOSX)
1033 #define MAYBE_AutoReload DISABLED_AutoReload
1034 #else
1035 #define MAYBE_AutoReload AutoReload
1036 #endif
1037 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, MAYBE_AutoReload) {
1038 GURL test_url("http://error.page.auto.reload");
1039 const int kRequestsToFail = 2;
1040 InstallInterceptor(test_url, kRequestsToFail);
1041 NavigateToURLAndWaitForTitle(test_url, "Test One", kRequestsToFail + 1);
1042 // Note that the interceptor updates these variables on the IO thread,
1043 // but this function reads them on the main thread. The requests have to be
1044 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or
1045 // this becomes racey.
1046 EXPECT_EQ(kRequestsToFail, interceptor()->failures());
1047 EXPECT_EQ(kRequestsToFail + 1, interceptor()->requests());
1050 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, ManualReloadNotSuppressed) {
1051 GURL test_url("http://error.page.auto.reload");
1052 const int kRequestsToFail = 3;
1053 InstallInterceptor(test_url, kRequestsToFail);
1054 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1055 browser(), test_url, 2);
1057 EXPECT_EQ(2, interceptor()->failures());
1058 EXPECT_EQ(2, interceptor()->requests());
1060 ToggleHelpBox(browser());
1061 EXPECT_TRUE(IsDisplayingText(browser(), "error.page.auto.reload"));
1063 content::WebContents* web_contents =
1064 browser()->tab_strip_model()->GetActiveWebContents();
1065 content::TestNavigationObserver nav_observer(web_contents, 1);
1066 web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
1067 base::ASCIIToUTF16("document.getElementById('reload-button').click();"));
1068 nav_observer.Wait();
1069 EXPECT_FALSE(IsDisplayingText(browser(), "error.page.auto.reload"));
1072 // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
1073 class AddressUnreachableInterceptor : public net::URLRequestInterceptor {
1074 public:
1075 AddressUnreachableInterceptor() {}
1076 ~AddressUnreachableInterceptor() override {}
1078 // net::URLRequestInterceptor:
1079 net::URLRequestJob* MaybeInterceptRequest(
1080 net::URLRequest* request,
1081 net::NetworkDelegate* network_delegate) const override {
1082 return new URLRequestFailedJob(request,
1083 network_delegate,
1084 net::ERR_ADDRESS_UNREACHABLE);
1087 private:
1088 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableInterceptor);
1091 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation
1092 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use
1093 // a different error for the correction service and the original page to
1094 // validate the right page is being displayed.
1095 class ErrorPageNavigationCorrectionsFailTest : public ErrorPageTest {
1096 public:
1097 // InProcessBrowserTest:
1098 void SetUpOnMainThread() override {
1099 BrowserThread::PostTask(
1100 BrowserThread::IO, FROM_HERE,
1101 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters));
1104 void TearDownOnMainThread() override {
1105 BrowserThread::PostTask(
1106 BrowserThread::IO, FROM_HERE,
1107 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters));
1110 private:
1111 // Adds a filter that causes all correction service requests to fail with
1112 // ERR_ADDRESS_UNREACHABLE.
1114 // Also adds the net::URLRequestFailedJob filter.
1115 static void AddFilters() {
1116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1117 URLRequestFailedJob::AddUrlHandler();
1119 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
1120 google_util::LinkDoctorBaseURL(),
1121 scoped_ptr<net::URLRequestInterceptor>(
1122 new AddressUnreachableInterceptor()));
1125 static void RemoveFilters() {
1126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1127 net::URLRequestFilter::GetInstance()->ClearHandlers();
1131 // Make sure that when corrections fail to load, the network error page is
1132 // successfully loaded.
1133 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
1134 FetchCorrectionsFails) {
1135 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1136 browser(),
1137 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
1140 // Verify that the expected error page is being displayed.
1141 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED);
1143 // Diagnostics button should be displayed, if avilable on this platform.
1144 EXPECT_EQ(PlatformSupportsDiagnosticsTool(),
1145 IsDisplayingDiagnosticsButton(browser()));
1148 // Checks that when an error occurs and a corrections fail to load, the stale
1149 // cache status of the page is correctly transferred, and we can load the
1150 // stale copy from the javascript. Most logic copied from StaleCacheStatus
1151 // above.
1152 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
1153 StaleCacheStatusFailedCorrections) {
1154 ASSERT_TRUE(test_server()->Start());
1155 // Load cache with entry with "nocache" set, to create stale
1156 // cache.
1157 GURL test_url(test_server()->GetURL("files/nocache.html"));
1158 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
1160 // Reload same URL after forcing an error from the the network layer;
1161 // confirm that the error page is told the cached copy exists.
1162 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
1163 browser()->profile()->GetRequestContext();
1164 BrowserThread::PostTask(
1165 BrowserThread::IO, FROM_HERE,
1166 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
1167 net::ERR_CONNECTION_FAILED));
1169 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1170 browser(), test_url, 2);
1171 EXPECT_TRUE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
1172 EXPECT_TRUE(ProbeStaleCopyValue(true));
1174 // Confirm that loading the stale copy from the cache works.
1175 content::TestNavigationObserver same_tab_observer(
1176 browser()->tab_strip_model()->GetActiveWebContents(), 1);
1177 ASSERT_TRUE(ReloadStaleCopyFromCache());
1178 same_tab_observer.Wait();
1179 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
1180 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
1182 // Clear the cache and reload the same URL; confirm the error page is told
1183 // that there is no cached copy.
1184 BrowsingDataRemover* remover =
1185 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
1186 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1187 BrowsingDataHelper::UNPROTECTED_WEB);
1188 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1189 browser(), test_url, 2);
1190 EXPECT_TRUE(ProbeStaleCopyValue(false));
1191 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
1194 #if defined(OS_CHROMEOS)
1195 class ErrorPageOfflineTest : public ErrorPageTest {
1196 protected:
1197 // Mock policy provider for both user and device policies.
1198 policy::MockConfigurationPolicyProvider policy_provider_;
1200 void SetUpInProcessBrowserTestFixture() override {
1201 // Set up fake install attributes.
1202 scoped_ptr<policy::StubEnterpriseInstallAttributes> attributes(
1203 new policy::StubEnterpriseInstallAttributes());
1204 attributes->SetDomain("example.com");
1205 attributes->SetRegistrationUser("user@example.com");
1206 policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
1207 attributes.release());
1209 // Sets up a mock policy provider for user and device policies.
1210 EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_))
1211 .WillRepeatedly(testing::Return(true));
1212 policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
1213 &policy_provider_);
1215 ErrorPageTest::SetUpInProcessBrowserTestFixture();
1219 IN_PROC_BROWSER_TEST_F(ErrorPageOfflineTest, CheckEasterEggIsDisabled) {
1220 // Check for enterprise enrollment.
1221 policy::BrowserPolicyConnectorChromeOS* connector =
1222 g_browser_process->platform_part()->browser_policy_connector_chromeos();
1223 EXPECT_TRUE(connector->IsEnterpriseManaged());
1225 ui_test_utils::NavigateToURL(browser(),
1226 URLRequestFailedJob::GetMockHttpUrl(net::ERR_INTERNET_DISCONNECTED));
1228 content::WebContents* web_contents =
1229 browser()->tab_strip_model()->GetActiveWebContents();
1231 std::string command = base::StringPrintf(
1232 "var hasText = document.querySelector('.snackbar').innerText;"
1233 "domAutomationController.send(hasText);");
1234 std::string result = "";
1235 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1236 web_contents, command, &result));
1238 std::string disabled_text =
1239 l10n_util::GetStringUTF8(IDS_ERRORPAGE_FUN_DISABLED);
1240 EXPECT_EQ(disabled_text, result);
1242 #endif
1244 // A test fixture that simulates failing requests for an IDN domain name.
1245 class ErrorPageForIDNTest : public InProcessBrowserTest {
1246 public:
1247 // Target hostname in different forms.
1248 static const char kHostname[];
1249 static const char kHostnameJSUnicode[];
1251 // InProcessBrowserTest:
1252 void SetUpOnMainThread() override {
1253 // Clear AcceptLanguages to force punycode decoding.
1254 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages,
1255 std::string());
1256 BrowserThread::PostTask(
1257 BrowserThread::IO, FROM_HERE,
1258 base::Bind(&ErrorPageForIDNTest::AddFilters));
1261 void TearDownOnMainThread() override {
1262 BrowserThread::PostTask(
1263 BrowserThread::IO, FROM_HERE,
1264 base::Bind(&ErrorPageForIDNTest::RemoveFilters));
1267 private:
1268 static void AddFilters() {
1269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1270 URLRequestFailedJob::AddUrlHandlerForHostname(kHostname);
1273 static void RemoveFilters() {
1274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1275 net::URLRequestFilter::GetInstance()->ClearHandlers();
1279 const char ErrorPageForIDNTest::kHostname[] =
1280 "xn--d1abbgf6aiiy.xn--p1ai";
1281 const char ErrorPageForIDNTest::kHostnameJSUnicode[] =
1282 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
1283 "\\u0440\\u0444";
1285 // Make sure error page shows correct unicode for IDN.
1286 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) {
1287 // ERR_UNSAFE_PORT will not trigger navigation corrections.
1288 ui_test_utils::NavigateToURL(
1289 browser(),
1290 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
1291 kHostname));
1293 ToggleHelpBox(browser());
1294 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode));
1297 } // namespace