| 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 <memory> | |
| 6 #include <utility> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 9 #include "base/command_line.h" | |
| 10 #include "base/compiler_specific.h" | |
| 11 #include "base/files/scoped_temp_dir.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/macros.h" | |
| 14 #include "base/memory/ptr_util.h" | |
| 15 #include "base/memory/weak_ptr.h" | |
| 16 #include "base/path_service.h" | |
| 17 #include "base/strings/stringprintf.h" | |
| 18 #include "base/strings/utf_string_conversions.h" | |
| 19 #include "base/synchronization/lock.h" | |
| 20 #include "build/build_config.h" | |
| 21 #include "chrome/browser/browsing_data/browsing_data_helper.h" | |
| 22 #include "chrome/browser/browsing_data/browsing_data_remover.h" | |
| 23 #include "chrome/browser/browsing_data/browsing_data_remover_factory.h" | |
| 24 #include "chrome/browser/net/net_error_diagnostics_dialog.h" | |
| 25 #include "chrome/browser/net/url_request_mock_util.h" | |
| 26 #include "chrome/browser/profiles/profile.h" | |
| 27 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h" | |
| 28 #include "chrome/browser/ui/browser.h" | |
| 29 #include "chrome/browser/ui/browser_commands.h" | |
| 30 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 31 #include "chrome/common/chrome_paths.h" | |
| 32 #include "chrome/common/chrome_switches.h" | |
| 33 #include "chrome/common/pref_names.h" | |
| 34 #include "chrome/test/base/in_process_browser_test.h" | |
| 35 #include "chrome/test/base/ui_test_utils.h" | |
| 36 #include "components/error_page/common/error_page_switches.h" | |
| 37 #include "components/google/core/browser/google_util.h" | |
| 38 #include "components/prefs/pref_service.h" | |
| 39 #include "components/strings/grit/components_strings.h" | |
| 40 #include "content/public/browser/browser_thread.h" | |
| 41 #include "content/public/browser/notification_service.h" | |
| 42 #include "content/public/browser/notification_types.h" | |
| 43 #include "content/public/browser/render_frame_host.h" | |
| 44 #include "content/public/browser/render_view_host.h" | |
| 45 #include "content/public/browser/web_contents.h" | |
| 46 #include "content/public/browser/web_contents_observer.h" | |
| 47 #include "content/public/test/browser_test_utils.h" | |
| 48 #include "content/public/test/test_navigation_observer.h" | |
| 49 #include "net/base/filename_util.h" | |
| 50 #include "net/base/net_errors.h" | |
| 51 #include "net/http/failing_http_transaction_factory.h" | |
| 52 #include "net/http/http_cache.h" | |
| 53 #include "net/test/embedded_test_server/embedded_test_server.h" | |
| 54 #include "net/test/url_request/url_request_failed_job.h" | |
| 55 #include "net/test/url_request/url_request_mock_http_job.h" | |
| 56 #include "net/url_request/url_request_context.h" | |
| 57 #include "net/url_request/url_request_context_getter.h" | |
| 58 #include "net/url_request/url_request_filter.h" | |
| 59 #include "net/url_request/url_request_interceptor.h" | |
| 60 #include "net/url_request/url_request_job.h" | |
| 61 #include "net/url_request/url_request_test_job.h" | |
| 62 #include "net/url_request/url_request_test_util.h" | |
| 63 #include "policy/policy_constants.h" | |
| 64 #include "ui/base/l10n/l10n_util.h" | |
| 65 | |
| 66 #if defined(OS_CHROMEOS) | |
| 67 #include "chrome/browser/browser_process.h" | |
| 68 #include "chrome/browser/chromeos/chrome_browser_main_chromeos.h" | |
| 69 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" | |
| 70 #include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h" | |
| 71 #include "components/policy/core/common/policy_types.h" | |
| 72 #else | |
| 73 #include "chrome/browser/policy/profile_policy_connector_factory.h" | |
| 74 #endif | |
| 75 #include "components/policy/core/common/mock_configuration_policy_provider.h" | |
| 76 | |
| 77 using content::BrowserThread; | |
| 78 using content::NavigationController; | |
| 79 using net::URLRequestFailedJob; | |
| 80 using net::URLRequestTestJob; | |
| 81 | |
| 82 namespace { | |
| 83 | |
| 84 // Returns true if |text| is displayed on the page |browser| is currently | |
| 85 // displaying. Uses "innerText", so will miss hidden text, and whitespace | |
| 86 // space handling may be weird. | |
| 87 bool WARN_UNUSED_RESULT IsDisplayingText(Browser* browser, | |
| 88 const std::string& text) { | |
| 89 std::string command = base::StringPrintf( | |
| 90 "var textContent = document.body.innerText;" | |
| 91 "var hasText = textContent.indexOf('%s') >= 0;" | |
| 92 "domAutomationController.send(hasText);", | |
| 93 text.c_str()); | |
| 94 bool result = false; | |
| 95 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( | |
| 96 browser->tab_strip_model()->GetActiveWebContents(), command, &result)); | |
| 97 return result; | |
| 98 } | |
| 99 | |
| 100 // Expands the more box on the currently displayed error page. | |
| 101 void ToggleHelpBox(Browser* browser) { | |
| 102 EXPECT_TRUE(content::ExecuteScript( | |
| 103 browser->tab_strip_model()->GetActiveWebContents(), | |
| 104 "document.getElementById('details-button').click();")); | |
| 105 } | |
| 106 | |
| 107 // Returns true if the diagnostics link suggestion is displayed. | |
| 108 bool WARN_UNUSED_RESULT IsDisplayingDiagnosticsLink(Browser* browser) { | |
| 109 std::string command = base::StringPrintf( | |
| 110 "var diagnose_link = document.getElementById('diagnose-link');" | |
| 111 "domAutomationController.send(diagnose_link != null);"); | |
| 112 bool result = false; | |
| 113 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( | |
| 114 browser->tab_strip_model()->GetActiveWebContents(), command, &result)); | |
| 115 return result; | |
| 116 } | |
| 117 | |
| 118 // Checks that the local error page is being displayed, without remotely | |
| 119 // retrieved navigation corrections, and with the specified error string. | |
| 120 void ExpectDisplayingLocalErrorPage(Browser* browser, | |
| 121 const std::string& error_string) { | |
| 122 EXPECT_TRUE(IsDisplayingText(browser, error_string)); | |
| 123 | |
| 124 // Locally generated error pages should not have navigation corrections. | |
| 125 EXPECT_FALSE(IsDisplayingText(browser, "http://mock.http/title2.html")); | |
| 126 | |
| 127 // Locally generated error pages should not have a link with search terms. | |
| 128 EXPECT_FALSE(IsDisplayingText(browser, "search query")); | |
| 129 } | |
| 130 | |
| 131 // Checks that the local error page is being displayed, without remotely | |
| 132 // retrieved navigation corrections, and with the specified error code. | |
| 133 void ExpectDisplayingLocalErrorPage(Browser* browser, net::Error error_code) { | |
| 134 ExpectDisplayingLocalErrorPage(browser, net::ErrorToShortString(error_code)); | |
| 135 } | |
| 136 | |
| 137 // Checks that an error page with information retrieved from the navigation | |
| 138 // correction service is being displayed, with the specified specified error | |
| 139 // string. | |
| 140 void ExpectDisplayingNavigationCorrections(Browser* browser, | |
| 141 const std::string& error_string) { | |
| 142 EXPECT_TRUE(IsDisplayingText(browser, error_string)); | |
| 143 | |
| 144 // Check that the mock navigation corrections are displayed. | |
| 145 EXPECT_TRUE(IsDisplayingText(browser, "http://mock.http/title2.html")); | |
| 146 | |
| 147 // Check that the search terms are displayed as a link. | |
| 148 EXPECT_TRUE(IsDisplayingText(browser, "search query")); | |
| 149 | |
| 150 // The diagnostics button isn't displayed when corrections were | |
| 151 // retrieved from a remote server. | |
| 152 EXPECT_FALSE(IsDisplayingDiagnosticsLink(browser)); | |
| 153 } | |
| 154 | |
| 155 // Checks that an error page with information retrieved from the navigation | |
| 156 // correction service is being displayed, with the specified specified error | |
| 157 // code. | |
| 158 void ExpectDisplayingNavigationCorrections(Browser* browser, | |
| 159 net::Error error_code) { | |
| 160 ExpectDisplayingNavigationCorrections(browser, | |
| 161 net::ErrorToShortString(error_code)); | |
| 162 } | |
| 163 | |
| 164 std::string GetShowSavedButtonLabel() { | |
| 165 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY); | |
| 166 } | |
| 167 | |
| 168 void AddInterceptorForURL(const GURL& url, | |
| 169 std::unique_ptr<net::URLRequestInterceptor> handler) { | |
| 170 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 171 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(url, | |
| 172 std::move(handler)); | |
| 173 } | |
| 174 | |
| 175 // An interceptor that fails a configurable number of requests, then succeeds | |
| 176 // all requests after that, keeping count of failures and successes. | |
| 177 class FailFirstNRequestsInterceptor : public net::URLRequestInterceptor { | |
| 178 public: | |
| 179 explicit FailFirstNRequestsInterceptor(int requests_to_fail) | |
| 180 : requests_(0), failures_(0), requests_to_fail_(requests_to_fail) {} | |
| 181 ~FailFirstNRequestsInterceptor() override {} | |
| 182 | |
| 183 // net::URLRequestInterceptor implementation | |
| 184 net::URLRequestJob* MaybeInterceptRequest( | |
| 185 net::URLRequest* request, | |
| 186 net::NetworkDelegate* network_delegate) const override { | |
| 187 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 188 requests_++; | |
| 189 if (failures_ < requests_to_fail_) { | |
| 190 failures_++; | |
| 191 // Note: net::ERR_CONNECTION_RESET does not summon the Link Doctor; see | |
| 192 // NetErrorHelperCore::GetErrorPageURL. | |
| 193 return new URLRequestFailedJob(request, | |
| 194 network_delegate, | |
| 195 net::ERR_CONNECTION_RESET); | |
| 196 } else { | |
| 197 return new URLRequestTestJob(request, network_delegate, | |
| 198 URLRequestTestJob::test_headers(), | |
| 199 URLRequestTestJob::test_data_1(), | |
| 200 true); | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 int requests() const { return requests_; } | |
| 205 int failures() const { return failures_; } | |
| 206 | |
| 207 private: | |
| 208 // These are mutable because MaybeCreateJob is const but we want this state | |
| 209 // for testing. | |
| 210 mutable int requests_; | |
| 211 mutable int failures_; | |
| 212 int requests_to_fail_; | |
| 213 | |
| 214 DISALLOW_COPY_AND_ASSIGN(FailFirstNRequestsInterceptor); | |
| 215 }; | |
| 216 | |
| 217 // An interceptor that serves LinkDoctor responses. It also allows waiting | |
| 218 // until a certain number of requests have been sent. | |
| 219 // TODO(mmenke): Wait until responses have been received instead. | |
| 220 class LinkDoctorInterceptor : public net::URLRequestInterceptor { | |
| 221 public: | |
| 222 LinkDoctorInterceptor() : num_requests_(0), | |
| 223 requests_to_wait_for_(-1), | |
| 224 weak_factory_(this) { | |
| 225 } | |
| 226 | |
| 227 ~LinkDoctorInterceptor() override {} | |
| 228 | |
| 229 // net::URLRequestInterceptor implementation | |
| 230 net::URLRequestJob* MaybeInterceptRequest( | |
| 231 net::URLRequest* request, | |
| 232 net::NetworkDelegate* network_delegate) const override { | |
| 233 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 234 | |
| 235 BrowserThread::PostTask( | |
| 236 BrowserThread::UI, FROM_HERE, | |
| 237 base::Bind(&LinkDoctorInterceptor::RequestCreated, | |
| 238 weak_factory_.GetWeakPtr())); | |
| 239 | |
| 240 base::FilePath root_http; | |
| 241 PathService::Get(chrome::DIR_TEST_DATA, &root_http); | |
| 242 return new net::URLRequestMockHTTPJob( | |
| 243 request, | |
| 244 network_delegate, | |
| 245 root_http.AppendASCII("mock-link-doctor.json"), | |
| 246 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( | |
| 247 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); | |
| 248 } | |
| 249 | |
| 250 void WaitForRequests(int requests_to_wait_for) { | |
| 251 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 252 DCHECK_EQ(-1, requests_to_wait_for_); | |
| 253 DCHECK(!run_loop_); | |
| 254 | |
| 255 if (requests_to_wait_for >= num_requests_) | |
| 256 return; | |
| 257 | |
| 258 requests_to_wait_for_ = requests_to_wait_for; | |
| 259 run_loop_.reset(new base::RunLoop()); | |
| 260 run_loop_->Run(); | |
| 261 run_loop_.reset(); | |
| 262 requests_to_wait_for_ = -1; | |
| 263 EXPECT_EQ(num_requests_, requests_to_wait_for); | |
| 264 } | |
| 265 | |
| 266 // It is up to the caller to wait until all relevant requests has been | |
| 267 // created, either through calling WaitForRequests or some other manner, | |
| 268 // before calling this method. | |
| 269 int num_requests() const { | |
| 270 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 271 return num_requests_; | |
| 272 } | |
| 273 | |
| 274 private: | |
| 275 void RequestCreated() { | |
| 276 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 277 | |
| 278 num_requests_++; | |
| 279 if (num_requests_ == requests_to_wait_for_) | |
| 280 run_loop_->Quit(); | |
| 281 } | |
| 282 | |
| 283 // These are only used on the UI thread. | |
| 284 int num_requests_; | |
| 285 int requests_to_wait_for_; | |
| 286 std::unique_ptr<base::RunLoop> run_loop_; | |
| 287 | |
| 288 // This prevents any risk of flake if any test doesn't wait for a request | |
| 289 // it sent. Mutable so it can be accessed from a const function. | |
| 290 mutable base::WeakPtrFactory<LinkDoctorInterceptor> weak_factory_; | |
| 291 | |
| 292 DISALLOW_COPY_AND_ASSIGN(LinkDoctorInterceptor); | |
| 293 }; | |
| 294 | |
| 295 void InstallMockInterceptors( | |
| 296 const GURL& search_url, | |
| 297 std::unique_ptr<net::URLRequestInterceptor> link_doctor_interceptor) { | |
| 298 chrome_browser_net::SetUrlRequestMocksEnabled(true); | |
| 299 | |
| 300 AddInterceptorForURL(google_util::LinkDoctorBaseURL(), | |
| 301 std::move(link_doctor_interceptor)); | |
| 302 | |
| 303 // Add a mock for the search engine the error page will use. | |
| 304 base::FilePath root_http; | |
| 305 PathService::Get(chrome::DIR_TEST_DATA, &root_http); | |
| 306 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( | |
| 307 search_url.scheme(), search_url.host(), | |
| 308 net::URLRequestMockHTTPJob::CreateInterceptorForSingleFile( | |
| 309 root_http.AppendASCII("title3.html"), | |
| 310 BrowserThread::GetBlockingPool())); | |
| 311 } | |
| 312 | |
| 313 class ErrorPageTest : public InProcessBrowserTest { | |
| 314 public: | |
| 315 enum HistoryNavigationDirection { | |
| 316 HISTORY_NAVIGATE_BACK, | |
| 317 HISTORY_NAVIGATE_FORWARD, | |
| 318 }; | |
| 319 | |
| 320 ErrorPageTest() : link_doctor_interceptor_(NULL) {} | |
| 321 ~ErrorPageTest() override {} | |
| 322 | |
| 323 // Navigates the active tab to a mock url created for the file at |file_path|. | |
| 324 // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests. | |
| 325 void SetUpCommandLine(base::CommandLine* command_line) override { | |
| 326 command_line->AppendSwitchASCII( | |
| 327 error_page::switches::kShowSavedCopy, | |
| 328 error_page::switches::kEnableShowSavedCopyPrimary); | |
| 329 } | |
| 330 | |
| 331 // Navigates the active tab to a mock url created for the file at |path|. | |
| 332 void NavigateToFileURL(const std::string& path) { | |
| 333 ui_test_utils::NavigateToURL(browser(), | |
| 334 net::URLRequestMockHTTPJob::GetMockUrl(path)); | |
| 335 } | |
| 336 | |
| 337 // Navigates to the given URL and waits for |num_navigations| to occur, and | |
| 338 // the title to change to |expected_title|. | |
| 339 void NavigateToURLAndWaitForTitle(const GURL& url, | |
| 340 const std::string& expected_title, | |
| 341 int num_navigations) { | |
| 342 content::TitleWatcher title_watcher( | |
| 343 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 344 base::ASCIIToUTF16(expected_title)); | |
| 345 | |
| 346 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 347 browser(), url, num_navigations); | |
| 348 | |
| 349 EXPECT_EQ(base::ASCIIToUTF16(expected_title), | |
| 350 title_watcher.WaitAndGetTitle()); | |
| 351 } | |
| 352 | |
| 353 // Navigates back in the history and waits for |num_navigations| to occur, and | |
| 354 // the title to change to |expected_title|. | |
| 355 void GoBackAndWaitForTitle(const std::string& expected_title, | |
| 356 int num_navigations) { | |
| 357 NavigateHistoryAndWaitForTitle(expected_title, | |
| 358 num_navigations, | |
| 359 HISTORY_NAVIGATE_BACK); | |
| 360 } | |
| 361 | |
| 362 // Navigates forward in the history and waits for |num_navigations| to occur, | |
| 363 // and the title to change to |expected_title|. | |
| 364 void GoForwardAndWaitForTitle(const std::string& expected_title, | |
| 365 int num_navigations) { | |
| 366 NavigateHistoryAndWaitForTitle(expected_title, | |
| 367 num_navigations, | |
| 368 HISTORY_NAVIGATE_FORWARD); | |
| 369 } | |
| 370 | |
| 371 void GoBackAndWaitForNavigations(int num_navigations) { | |
| 372 NavigateHistory(num_navigations, HISTORY_NAVIGATE_BACK); | |
| 373 } | |
| 374 | |
| 375 void GoForwardAndWaitForNavigations(int num_navigations) { | |
| 376 NavigateHistory(num_navigations, HISTORY_NAVIGATE_FORWARD); | |
| 377 } | |
| 378 | |
| 379 // Confirms that the javascript variable indicating whether or not we have | |
| 380 // a stale copy in the cache has been set to |expected|, and that the | |
| 381 // stale load button is or isn't there based on the same expectation. | |
| 382 testing::AssertionResult ProbeStaleCopyValue(bool expected) { | |
| 383 const char* js_cache_probe = | |
| 384 "try {\n" | |
| 385 " domAutomationController.send(\n" | |
| 386 " loadTimeData.valueExists('showSavedCopyButton') ?" | |
| 387 " 'yes' : 'no');\n" | |
| 388 "} catch (e) {\n" | |
| 389 " domAutomationController.send(e.message);\n" | |
| 390 "}\n"; | |
| 391 | |
| 392 std::string result; | |
| 393 bool ret = | |
| 394 content::ExecuteScriptAndExtractString( | |
| 395 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 396 js_cache_probe, | |
| 397 &result); | |
| 398 if (!ret) { | |
| 399 return testing::AssertionFailure() | |
| 400 << "Failing return from ExecuteScriptAndExtractString."; | |
| 401 } | |
| 402 | |
| 403 if ((expected && "yes" == result) || (!expected && "no" == result)) | |
| 404 return testing::AssertionSuccess(); | |
| 405 | |
| 406 return testing::AssertionFailure() << "Cache probe result is " << result; | |
| 407 } | |
| 408 | |
| 409 testing::AssertionResult ReloadStaleCopyFromCache() { | |
| 410 const char* js_reload_script = | |
| 411 "try {\n" | |
| 412 " document.getElementById('show-saved-copy-button').click();\n" | |
| 413 " domAutomationController.send('success');\n" | |
| 414 "} catch (e) {\n" | |
| 415 " domAutomationController.send(e.message);\n" | |
| 416 "}\n"; | |
| 417 | |
| 418 std::string result; | |
| 419 bool ret = content::ExecuteScriptAndExtractString( | |
| 420 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 421 js_reload_script, | |
| 422 &result); | |
| 423 EXPECT_TRUE(ret); | |
| 424 if (!ret) | |
| 425 return testing::AssertionFailure(); | |
| 426 return ("success" == result ? testing::AssertionSuccess() : | |
| 427 (testing::AssertionFailure() << "Exception message is " << result)); | |
| 428 } | |
| 429 | |
| 430 LinkDoctorInterceptor* link_doctor_interceptor() { | |
| 431 return link_doctor_interceptor_; | |
| 432 } | |
| 433 | |
| 434 protected: | |
| 435 void SetUpOnMainThread() override { | |
| 436 link_doctor_interceptor_ = new LinkDoctorInterceptor(); | |
| 437 std::unique_ptr<net::URLRequestInterceptor> owned_interceptor( | |
| 438 link_doctor_interceptor_); | |
| 439 // Ownership of the |interceptor_| is passed to an object the IO thread, but | |
| 440 // a pointer is kept in the test fixture. As soon as anything calls | |
| 441 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid. | |
| 442 UIThreadSearchTermsData search_terms_data(browser()->profile()); | |
| 443 BrowserThread::PostTask( | |
| 444 BrowserThread::IO, FROM_HERE, | |
| 445 base::Bind(&InstallMockInterceptors, | |
| 446 GURL(search_terms_data.GoogleBaseURLValue()), | |
| 447 base::Passed(&owned_interceptor))); | |
| 448 } | |
| 449 | |
| 450 // Returns a GURL that results in a DNS error. | |
| 451 GURL GetDnsErrorURL() const { | |
| 452 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED); | |
| 453 } | |
| 454 | |
| 455 // Returns true if the platform has support for a diagnostics tool, which | |
| 456 // can be launched from the error page. | |
| 457 bool PlatformSupportsDiagnosticsTool() { | |
| 458 #if defined(OS_CHROMEOS) | |
| 459 // ChromeOS uses an extension instead of a diagnostics dialog. | |
| 460 return true; | |
| 461 #else | |
| 462 return CanShowNetworkDiagnosticsDialog(); | |
| 463 #endif | |
| 464 } | |
| 465 | |
| 466 private: | |
| 467 // Navigates the browser the indicated direction in the history and waits for | |
| 468 // |num_navigations| to occur and the title to change to |expected_title|. | |
| 469 void NavigateHistoryAndWaitForTitle(const std::string& expected_title, | |
| 470 int num_navigations, | |
| 471 HistoryNavigationDirection direction) { | |
| 472 content::TitleWatcher title_watcher( | |
| 473 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 474 base::ASCIIToUTF16(expected_title)); | |
| 475 | |
| 476 NavigateHistory(num_navigations, direction); | |
| 477 | |
| 478 EXPECT_EQ(title_watcher.WaitAndGetTitle(), | |
| 479 base::ASCIIToUTF16(expected_title)); | |
| 480 } | |
| 481 | |
| 482 void NavigateHistory(int num_navigations, | |
| 483 HistoryNavigationDirection direction) { | |
| 484 content::TestNavigationObserver test_navigation_observer( | |
| 485 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 486 num_navigations); | |
| 487 if (direction == HISTORY_NAVIGATE_BACK) { | |
| 488 chrome::GoBack(browser(), CURRENT_TAB); | |
| 489 } else if (direction == HISTORY_NAVIGATE_FORWARD) { | |
| 490 chrome::GoForward(browser(), CURRENT_TAB); | |
| 491 } else { | |
| 492 FAIL(); | |
| 493 } | |
| 494 test_navigation_observer.Wait(); | |
| 495 } | |
| 496 | |
| 497 LinkDoctorInterceptor* link_doctor_interceptor_; | |
| 498 }; | |
| 499 | |
| 500 class TestFailProvisionalLoadObserver : public content::WebContentsObserver { | |
| 501 public: | |
| 502 explicit TestFailProvisionalLoadObserver(content::WebContents* contents) | |
| 503 : content::WebContentsObserver(contents) {} | |
| 504 ~TestFailProvisionalLoadObserver() override {} | |
| 505 | |
| 506 // This method is invoked when the provisional load failed. | |
| 507 void DidFailProvisionalLoad( | |
| 508 content::RenderFrameHost* render_frame_host, | |
| 509 const GURL& validated_url, | |
| 510 int error_code, | |
| 511 const base::string16& error_description, | |
| 512 bool was_ignored_by_handler) override { | |
| 513 fail_url_ = validated_url; | |
| 514 } | |
| 515 | |
| 516 const GURL& fail_url() const { return fail_url_; } | |
| 517 | |
| 518 private: | |
| 519 GURL fail_url_; | |
| 520 | |
| 521 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver); | |
| 522 }; | |
| 523 | |
| 524 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter, | |
| 525 net::Error error) { | |
| 526 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 527 net::HttpCache* cache( | |
| 528 getter->GetURLRequestContext()->http_transaction_factory()->GetCache()); | |
| 529 DCHECK(cache); | |
| 530 std::unique_ptr<net::HttpTransactionFactory> factory( | |
| 531 new net::FailingHttpTransactionFactory(cache->GetSession(), error)); | |
| 532 // Throw away old version; since this is a a browser test, we don't | |
| 533 // need to restore the old state. | |
| 534 cache->SetHttpNetworkTransactionFactoryForTesting(std::move(factory)); | |
| 535 } | |
| 536 | |
| 537 // Test an error with a file URL, and make sure it doesn't have a | |
| 538 // button to launch a network diagnostics tool. | |
| 539 IN_PROC_BROWSER_TEST_F(ErrorPageTest, FileNotFound) { | |
| 540 // Create an empty temp directory, to be sure there's no file in it. | |
| 541 base::ScopedTempDir temp_dir; | |
| 542 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 543 GURL non_existent_file_url = | |
| 544 net::FilePathToFileURL(temp_dir.path().AppendASCII("marmoset")); | |
| 545 | |
| 546 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 547 browser(), non_existent_file_url, 1); | |
| 548 | |
| 549 ExpectDisplayingLocalErrorPage(browser(), net::ERR_FILE_NOT_FOUND); | |
| 550 // Should not request Link Doctor corrections for local errors. | |
| 551 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 552 // Only errors on HTTP/HTTPS pages should display a diagnostics button. | |
| 553 EXPECT_FALSE(IsDisplayingDiagnosticsLink(browser())); | |
| 554 } | |
| 555 | |
| 556 // Check an network error page for ERR_FAILED. In particular, this should | |
| 557 // not trigger a link doctor error page. | |
| 558 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Failed) { | |
| 559 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 560 browser(), URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED), 1); | |
| 561 | |
| 562 ExpectDisplayingLocalErrorPage(browser(), net::ERR_FAILED); | |
| 563 // Should not request Link Doctor corrections for this error. | |
| 564 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 565 } | |
| 566 | |
| 567 // Test that a DNS error occuring in the main frame redirects to an error page. | |
| 568 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_Basic) { | |
| 569 // The first navigation should fail and load a blank page, while it fetches | |
| 570 // the Link Doctor response. The second navigation is the Link Doctor. | |
| 571 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 572 browser(), GetDnsErrorURL(), 2); | |
| 573 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 574 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 575 } | |
| 576 | |
| 577 // Test that a DNS error occuring in the main frame does not result in an | |
| 578 // additional session history entry. | |
| 579 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack1) { | |
| 580 NavigateToFileURL("title2.html"); | |
| 581 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 582 browser(), GetDnsErrorURL(), 2); | |
| 583 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 584 GoBackAndWaitForTitle("Title Of Awesomeness", 1); | |
| 585 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 586 } | |
| 587 | |
| 588 // Test that a DNS error occuring in the main frame does not result in an | |
| 589 // additional session history entry. | |
| 590 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) { | |
| 591 NavigateToFileURL("title2.html"); | |
| 592 | |
| 593 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 594 browser(), GetDnsErrorURL(), 2); | |
| 595 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 596 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 597 | |
| 598 NavigateToFileURL("title3.html"); | |
| 599 | |
| 600 GoBackAndWaitForNavigations(2); | |
| 601 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 602 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); | |
| 603 | |
| 604 GoBackAndWaitForTitle("Title Of Awesomeness", 1); | |
| 605 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); | |
| 606 } | |
| 607 | |
| 608 // Test that a DNS error occuring in the main frame does not result in an | |
| 609 // additional session history entry. | |
| 610 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) { | |
| 611 NavigateToFileURL("title2.html"); | |
| 612 | |
| 613 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 614 browser(), GetDnsErrorURL(), 2); | |
| 615 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 616 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 617 | |
| 618 NavigateToFileURL("title3.html"); | |
| 619 | |
| 620 GoBackAndWaitForNavigations(2); | |
| 621 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 622 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); | |
| 623 | |
| 624 GoBackAndWaitForTitle("Title Of Awesomeness", 1); | |
| 625 | |
| 626 GoForwardAndWaitForNavigations(2); | |
| 627 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 628 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); | |
| 629 } | |
| 630 | |
| 631 // Test that a DNS error occuring in the main frame does not result in an | |
| 632 // additional session history entry. | |
| 633 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) { | |
| 634 NavigateToFileURL("title3.html"); | |
| 635 | |
| 636 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 637 browser(), GetDnsErrorURL(), 2); | |
| 638 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 639 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 640 | |
| 641 NavigateToFileURL("title2.html"); | |
| 642 | |
| 643 GoBackAndWaitForNavigations(2); | |
| 644 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 645 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); | |
| 646 | |
| 647 GoBackAndWaitForTitle("Title Of More Awesomeness", 1); | |
| 648 | |
| 649 GoForwardAndWaitForNavigations(2); | |
| 650 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 651 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); | |
| 652 | |
| 653 GoForwardAndWaitForTitle("Title Of Awesomeness", 1); | |
| 654 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); | |
| 655 } | |
| 656 | |
| 657 // Test that the search link on a DNS error page works. | |
| 658 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoSearch) { | |
| 659 // The first navigation should fail, and the second one should be the error | |
| 660 // page. | |
| 661 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 662 browser(), GetDnsErrorURL(), 2); | |
| 663 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 664 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 665 | |
| 666 content::WebContents* web_contents = | |
| 667 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 668 | |
| 669 // Do a search and make sure the browser ends up at the right page. | |
| 670 content::TestNavigationObserver nav_observer(web_contents, 1); | |
| 671 content::TitleWatcher title_watcher( | |
| 672 web_contents, | |
| 673 base::ASCIIToUTF16("Title Of More Awesomeness")); | |
| 674 // Can't use content::ExecuteScript because it waits for scripts to send | |
| 675 // notification that they've run, and scripts that trigger a navigation may | |
| 676 // not send that notification. | |
| 677 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 678 base::ASCIIToUTF16("document.getElementById('search-link').click();")); | |
| 679 nav_observer.Wait(); | |
| 680 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"), | |
| 681 title_watcher.WaitAndGetTitle()); | |
| 682 | |
| 683 // There should have been another Link Doctor request, for tracking purposes. | |
| 684 // Have to wait for it, since the search page does not depend on having | |
| 685 // sent the tracking request. | |
| 686 link_doctor_interceptor()->WaitForRequests(2); | |
| 687 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); | |
| 688 | |
| 689 // Check the path and query string. | |
| 690 std::string url; | |
| 691 ASSERT_TRUE(content::ExecuteScriptAndExtractString( | |
| 692 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 693 "domAutomationController.send(window.location.href);", | |
| 694 &url)); | |
| 695 EXPECT_EQ("/search", GURL(url).path()); | |
| 696 EXPECT_EQ("q=search%20query", GURL(url).query()); | |
| 697 | |
| 698 // Go back to the error page, to make sure the history is correct. | |
| 699 GoBackAndWaitForNavigations(2); | |
| 700 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 701 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); | |
| 702 } | |
| 703 | |
| 704 // Test that the reload button on a DNS error page works. | |
| 705 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoReload) { | |
| 706 // The first navigation should fail, and the second one should be the error | |
| 707 // page. | |
| 708 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 709 browser(), GetDnsErrorURL(), 2); | |
| 710 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 711 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 712 | |
| 713 content::WebContents* web_contents = | |
| 714 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 715 | |
| 716 // Clicking the reload button should load the error page again, and there | |
| 717 // should be two commits, as before. | |
| 718 content::TestNavigationObserver nav_observer(web_contents, 2); | |
| 719 // Can't use content::ExecuteScript because it waits for scripts to send | |
| 720 // notification that they've run, and scripts that trigger a navigation may | |
| 721 // not send that notification. | |
| 722 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 723 base::ASCIIToUTF16("document.getElementById('reload-button').click();")); | |
| 724 nav_observer.Wait(); | |
| 725 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 726 | |
| 727 // There should have been two more requests to the correction service: One | |
| 728 // for the new error page, and one for tracking purposes. Have to make sure | |
| 729 // to wait for the tracking request, since the new error page does not depend | |
| 730 // on it. | |
| 731 link_doctor_interceptor()->WaitForRequests(3); | |
| 732 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); | |
| 733 } | |
| 734 | |
| 735 // Test that the reload button on a DNS error page works after a same page | |
| 736 // navigation on the error page. Error pages don't seem to do this, but some | |
| 737 // traces indicate this may actually happen. This test may hang on regression. | |
| 738 IN_PROC_BROWSER_TEST_F(ErrorPageTest, | |
| 739 DNSError_DoReloadAfterSamePageNavigation) { | |
| 740 // The first navigation should fail, and the second one should be the error | |
| 741 // page. | |
| 742 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 743 browser(), GetDnsErrorURL(), 2); | |
| 744 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 745 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 746 | |
| 747 content::WebContents* web_contents = | |
| 748 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 749 | |
| 750 // Do a same page navigation. | |
| 751 content::TestNavigationObserver nav_observer1(web_contents, 1); | |
| 752 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 753 base::ASCIIToUTF16("document.location='#';")); | |
| 754 // The same page navigation counts as a single navigation as far as the | |
| 755 // TestNavigationObserver is concerned. | |
| 756 nav_observer1.Wait(); | |
| 757 // Page being displayed should not change. | |
| 758 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 759 // No new requests should have been issued. | |
| 760 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 761 | |
| 762 // Clicking the reload button should load the error page again, and there | |
| 763 // should be two commits, as before. | |
| 764 content::TestNavigationObserver nav_observer2(web_contents, 2); | |
| 765 // Can't use content::ExecuteScript because it waits for scripts to send | |
| 766 // notification that they've run, and scripts that trigger a navigation may | |
| 767 // not send that notification. | |
| 768 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 769 base::ASCIIToUTF16("document.getElementById('reload-button').click();")); | |
| 770 nav_observer2.Wait(); | |
| 771 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 772 | |
| 773 // There should have been two more requests to the correction service: One | |
| 774 // for the new error page, and one for tracking purposes. Have to make sure | |
| 775 // to wait for the tracking request, since the new error page does not depend | |
| 776 // on it. | |
| 777 link_doctor_interceptor()->WaitForRequests(3); | |
| 778 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); | |
| 779 } | |
| 780 | |
| 781 // Test that clicking links on a DNS error page works. | |
| 782 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoClickLink) { | |
| 783 // The first navigation should fail, and the second one should be the error | |
| 784 // page. | |
| 785 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 786 browser(), GetDnsErrorURL(), 2); | |
| 787 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 788 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 789 | |
| 790 content::WebContents* web_contents = | |
| 791 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 792 | |
| 793 // Simulate a click on a link. | |
| 794 | |
| 795 content::TitleWatcher title_watcher( | |
| 796 web_contents, | |
| 797 base::ASCIIToUTF16("Title Of Awesomeness")); | |
| 798 std::string link_selector = | |
| 799 "document.querySelector('a[href=\"http://mock.http/title2.html\"]')"; | |
| 800 // The tracking request is triggered by onmousedown, so it catches middle | |
| 801 // mouse button clicks, as well as left clicks. | |
| 802 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 803 base::ASCIIToUTF16(link_selector + ".onmousedown();")); | |
| 804 // Can't use content::ExecuteScript because it waits for scripts to send | |
| 805 // notification that they've run, and scripts that trigger a navigation may | |
| 806 // not send that notification. | |
| 807 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 808 base::ASCIIToUTF16(link_selector + ".click();")); | |
| 809 EXPECT_EQ(base::ASCIIToUTF16("Title Of Awesomeness"), | |
| 810 title_watcher.WaitAndGetTitle()); | |
| 811 | |
| 812 // There should have been a tracking request to the correction service. Have | |
| 813 // to make sure to wait the tracking request, since the new page does not | |
| 814 // depend on it. | |
| 815 link_doctor_interceptor()->WaitForRequests(2); | |
| 816 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); | |
| 817 } | |
| 818 | |
| 819 // Test that a DNS error occuring in an iframe does not result in showing | |
| 820 // navigation corrections. | |
| 821 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) { | |
| 822 NavigateToURLAndWaitForTitle( | |
| 823 net::URLRequestMockHTTPJob::GetMockUrl("iframe_dns_error.html"), "Blah", | |
| 824 1); | |
| 825 // We expect to have two history entries, since we started off with navigation | |
| 826 // to "about:blank" and then navigated to "iframe_dns_error.html". | |
| 827 EXPECT_EQ(2, | |
| 828 browser()->tab_strip_model()->GetActiveWebContents()-> | |
| 829 GetController().GetEntryCount()); | |
| 830 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 831 } | |
| 832 | |
| 833 // This test fails regularly on win_rel trybots. See crbug.com/121540 | |
| 834 #if defined(OS_WIN) | |
| 835 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack | |
| 836 #else | |
| 837 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack | |
| 838 #endif | |
| 839 // Test that a DNS error occuring in an iframe does not result in an | |
| 840 // additional session history entry. | |
| 841 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) { | |
| 842 NavigateToFileURL("title2.html"); | |
| 843 NavigateToFileURL("iframe_dns_error.html"); | |
| 844 GoBackAndWaitForTitle("Title Of Awesomeness", 1); | |
| 845 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 846 } | |
| 847 | |
| 848 // This test fails regularly on win_rel trybots. See crbug.com/121540 | |
| 849 // | |
| 850 // This fails on linux_aura bringup: http://crbug.com/163931 | |
| 851 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(US
E_AURA)) | |
| 852 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndF
orward | |
| 853 #else | |
| 854 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward | |
| 855 #endif | |
| 856 // Test that a DNS error occuring in an iframe does not result in an | |
| 857 // additional session history entry. | |
| 858 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) { | |
| 859 NavigateToFileURL("title2.html"); | |
| 860 NavigateToFileURL("iframe_dns_error.html"); | |
| 861 GoBackAndWaitForTitle("Title Of Awesomeness", 1); | |
| 862 GoForwardAndWaitForTitle("Blah", 1); | |
| 863 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 864 } | |
| 865 | |
| 866 // Test that a DNS error occuring in an iframe, once the main document is | |
| 867 // completed loading, does not result in an additional session history entry. | |
| 868 // To ensure that the main document has completed loading, JavaScript is used to | |
| 869 // inject an iframe after loading is done. | |
| 870 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) { | |
| 871 content::WebContents* wc = | |
| 872 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 873 GURL fail_url = | |
| 874 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED); | |
| 875 | |
| 876 // Load a regular web page, in which we will inject an iframe. | |
| 877 NavigateToFileURL("title2.html"); | |
| 878 | |
| 879 // We expect to have two history entries, since we started off with navigation | |
| 880 // to "about:blank" and then navigated to "title2.html". | |
| 881 EXPECT_EQ(2, wc->GetController().GetEntryCount()); | |
| 882 | |
| 883 std::string script = "var frame = document.createElement('iframe');" | |
| 884 "frame.src = '" + fail_url.spec() + "';" | |
| 885 "document.body.appendChild(frame);"; | |
| 886 { | |
| 887 TestFailProvisionalLoadObserver fail_observer(wc); | |
| 888 content::WindowedNotificationObserver load_observer( | |
| 889 content::NOTIFICATION_LOAD_STOP, | |
| 890 content::Source<NavigationController>(&wc->GetController())); | |
| 891 wc->GetMainFrame()->ExecuteJavaScriptForTests(base::ASCIIToUTF16(script)); | |
| 892 load_observer.Wait(); | |
| 893 | |
| 894 // Ensure we saw the expected failure. | |
| 895 EXPECT_EQ(fail_url, fail_observer.fail_url()); | |
| 896 | |
| 897 // Failed initial navigation of an iframe shouldn't be adding any history | |
| 898 // entries. | |
| 899 EXPECT_EQ(2, wc->GetController().GetEntryCount()); | |
| 900 } | |
| 901 | |
| 902 // Do the same test, but with an iframe that doesn't have initial URL | |
| 903 // assigned. | |
| 904 script = "var frame = document.createElement('iframe');" | |
| 905 "frame.id = 'target_frame';" | |
| 906 "document.body.appendChild(frame);"; | |
| 907 { | |
| 908 content::WindowedNotificationObserver load_observer( | |
| 909 content::NOTIFICATION_LOAD_STOP, | |
| 910 content::Source<NavigationController>(&wc->GetController())); | |
| 911 wc->GetMainFrame()->ExecuteJavaScriptForTests(base::ASCIIToUTF16(script)); | |
| 912 load_observer.Wait(); | |
| 913 } | |
| 914 | |
| 915 script = "var f = document.getElementById('target_frame');" | |
| 916 "f.src = '" + fail_url.spec() + "';"; | |
| 917 { | |
| 918 TestFailProvisionalLoadObserver fail_observer(wc); | |
| 919 content::WindowedNotificationObserver load_observer( | |
| 920 content::NOTIFICATION_LOAD_STOP, | |
| 921 content::Source<NavigationController>(&wc->GetController())); | |
| 922 wc->GetMainFrame()->ExecuteJavaScriptForTests(base::ASCIIToUTF16(script)); | |
| 923 load_observer.Wait(); | |
| 924 | |
| 925 EXPECT_EQ(fail_url, fail_observer.fail_url()); | |
| 926 EXPECT_EQ(2, wc->GetController().GetEntryCount()); | |
| 927 } | |
| 928 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 929 } | |
| 930 | |
| 931 // Checks that navigation corrections are not loaded when we receive an actual | |
| 932 // 404 page. | |
| 933 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) { | |
| 934 NavigateToURLAndWaitForTitle( | |
| 935 net::URLRequestMockHTTPJob::GetMockUrl("page404.html"), "SUCCESS", 1); | |
| 936 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 937 } | |
| 938 | |
| 939 // Checks that navigation corrections are loaded in response to a 404 page with | |
| 940 // no body. | |
| 941 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Empty404) { | |
| 942 // The first navigation should fail and load a blank page, while it fetches | |
| 943 // the Link Doctor response. The second navigation is the Link Doctor. | |
| 944 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 945 browser(), | |
| 946 net::URLRequestMockHTTPJob::GetMockUrl("errorpage/empty404.html"), 2); | |
| 947 // This depends on the non-internationalized error ID string in | |
| 948 // localized_error.cc. | |
| 949 ExpectDisplayingNavigationCorrections(browser(), "HTTP ERROR 404"); | |
| 950 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); | |
| 951 } | |
| 952 | |
| 953 // Checks that a local error page is shown in response to a 500 error page | |
| 954 // without a body. | |
| 955 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Empty500) { | |
| 956 NavigateToFileURL("errorpage/empty500.html"); | |
| 957 // This depends on the non-internationalized error ID string in | |
| 958 // localized_error.cc. | |
| 959 ExpectDisplayingLocalErrorPage(browser(), "HTTP ERROR 500"); | |
| 960 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 961 } | |
| 962 | |
| 963 // Checks that when an error occurs, the stale cache status of the page | |
| 964 // is correctly transferred, and that stale cached copied can be loaded | |
| 965 // from the javascript. | |
| 966 IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) { | |
| 967 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 968 // Load cache with entry with "nocache" set, to create stale | |
| 969 // cache. | |
| 970 GURL test_url(embedded_test_server()->GetURL("/nocache.html")); | |
| 971 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1); | |
| 972 | |
| 973 // Reload same URL after forcing an error from the the network layer; | |
| 974 // confirm that the error page is told the cached copy exists. | |
| 975 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = | |
| 976 browser()->profile()->GetRequestContext(); | |
| 977 BrowserThread::PostTask( | |
| 978 BrowserThread::IO, FROM_HERE, | |
| 979 base::Bind(&InterceptNetworkTransactions, | |
| 980 base::RetainedRef(url_request_context_getter), | |
| 981 net::ERR_FAILED)); | |
| 982 | |
| 983 // With no navigation corrections to load, there's only one navigation. | |
| 984 ui_test_utils::NavigateToURL(browser(), test_url); | |
| 985 EXPECT_TRUE(ProbeStaleCopyValue(true)); | |
| 986 EXPECT_TRUE(IsDisplayingText(browser(), GetShowSavedButtonLabel())); | |
| 987 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"), | |
| 988 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); | |
| 989 | |
| 990 // Confirm that loading the stale copy from the cache works. | |
| 991 content::TestNavigationObserver same_tab_observer( | |
| 992 browser()->tab_strip_model()->GetActiveWebContents(), 1); | |
| 993 ASSERT_TRUE(ReloadStaleCopyFromCache()); | |
| 994 same_tab_observer.Wait(); | |
| 995 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"), | |
| 996 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); | |
| 997 | |
| 998 // Reload the same URL with a post request; confirm the error page is told | |
| 999 // that there is no cached copy. | |
| 1000 ui_test_utils::NavigateToURLWithPost(browser(), test_url); | |
| 1001 EXPECT_TRUE(ProbeStaleCopyValue(false)); | |
| 1002 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel())); | |
| 1003 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 1004 | |
| 1005 // Clear the cache and reload the same URL; confirm the error page is told | |
| 1006 // that there is no cached copy. | |
| 1007 BrowsingDataRemover* remover = | |
| 1008 BrowsingDataRemoverFactory::GetForBrowserContext(browser()->profile()); | |
| 1009 remover->Remove(BrowsingDataRemover::Unbounded(), | |
| 1010 BrowsingDataRemover::REMOVE_CACHE, | |
| 1011 BrowsingDataHelper::UNPROTECTED_WEB); | |
| 1012 ui_test_utils::NavigateToURL(browser(), test_url); | |
| 1013 EXPECT_TRUE(ProbeStaleCopyValue(false)); | |
| 1014 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel())); | |
| 1015 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); | |
| 1016 } | |
| 1017 | |
| 1018 // Check that the easter egg is present and initialised and is not disabled. | |
| 1019 IN_PROC_BROWSER_TEST_F(ErrorPageTest, CheckEasterEggIsNotDisabled) { | |
| 1020 ui_test_utils::NavigateToURL(browser(), | |
| 1021 URLRequestFailedJob::GetMockHttpUrl(net::ERR_INTERNET_DISCONNECTED)); | |
| 1022 | |
| 1023 content::WebContents* web_contents = | |
| 1024 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1025 | |
| 1026 // Check for no disabled message container. | |
| 1027 std::string command = base::StringPrintf( | |
| 1028 "var hasDisableContainer = document.querySelectorAll('.snackbar').length;" | |
| 1029 "domAutomationController.send(hasDisableContainer);"); | |
| 1030 int result; | |
| 1031 EXPECT_TRUE(content::ExecuteScriptAndExtractInt( | |
| 1032 web_contents, command, &result)); | |
| 1033 EXPECT_EQ(0, result); | |
| 1034 | |
| 1035 // Presence of the canvas container. | |
| 1036 command = base::StringPrintf( | |
| 1037 "var runnerCanvas = document.querySelectorAll('.runner-canvas').length;" | |
| 1038 "domAutomationController.send(runnerCanvas);"); | |
| 1039 EXPECT_TRUE(content::ExecuteScriptAndExtractInt( | |
| 1040 web_contents, command, &result)); | |
| 1041 EXPECT_EQ(1, result); | |
| 1042 } | |
| 1043 | |
| 1044 class ErrorPageAutoReloadTest : public InProcessBrowserTest { | |
| 1045 public: | |
| 1046 void SetUpCommandLine(base::CommandLine* command_line) override { | |
| 1047 command_line->AppendSwitch(switches::kEnableOfflineAutoReload); | |
| 1048 } | |
| 1049 | |
| 1050 void InstallInterceptor(const GURL& url, int requests_to_fail) { | |
| 1051 interceptor_ = new FailFirstNRequestsInterceptor(requests_to_fail); | |
| 1052 std::unique_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_); | |
| 1053 | |
| 1054 // Tests don't need to wait for this task to complete before using the | |
| 1055 // filter; any requests that might be affected by it will end up in the IO | |
| 1056 // thread's message loop after this posted task anyway. | |
| 1057 // | |
| 1058 // Ownership of the interceptor is passed to an object the IO thread, but a | |
| 1059 // pointer is kept in the test fixture. As soon as anything calls | |
| 1060 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid. | |
| 1061 BrowserThread::PostTask( | |
| 1062 BrowserThread::IO, FROM_HERE, | |
| 1063 base::Bind(&AddInterceptorForURL, url, | |
| 1064 base::Passed(&owned_interceptor))); | |
| 1065 } | |
| 1066 | |
| 1067 void NavigateToURLAndWaitForTitle(const GURL& url, | |
| 1068 const std::string& expected_title, | |
| 1069 int num_navigations) { | |
| 1070 content::TitleWatcher title_watcher( | |
| 1071 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 1072 base::ASCIIToUTF16(expected_title)); | |
| 1073 | |
| 1074 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 1075 browser(), url, num_navigations); | |
| 1076 | |
| 1077 EXPECT_EQ(base::ASCIIToUTF16(expected_title), | |
| 1078 title_watcher.WaitAndGetTitle()); | |
| 1079 } | |
| 1080 | |
| 1081 FailFirstNRequestsInterceptor* interceptor() { | |
| 1082 return interceptor_; | |
| 1083 } | |
| 1084 | |
| 1085 private: | |
| 1086 FailFirstNRequestsInterceptor* interceptor_; | |
| 1087 }; | |
| 1088 | |
| 1089 // Fails on official mac_trunk build. See crbug.com/465789. | |
| 1090 #if defined(OFFICIAL_BUILD) && defined(OS_MACOSX) | |
| 1091 #define MAYBE_AutoReload DISABLED_AutoReload | |
| 1092 #else | |
| 1093 #define MAYBE_AutoReload AutoReload | |
| 1094 #endif | |
| 1095 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, MAYBE_AutoReload) { | |
| 1096 GURL test_url("http://error.page.auto.reload"); | |
| 1097 const int kRequestsToFail = 2; | |
| 1098 InstallInterceptor(test_url, kRequestsToFail); | |
| 1099 NavigateToURLAndWaitForTitle(test_url, "Test One", kRequestsToFail + 1); | |
| 1100 // Note that the interceptor updates these variables on the IO thread, | |
| 1101 // but this function reads them on the main thread. The requests have to be | |
| 1102 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or | |
| 1103 // this becomes racey. | |
| 1104 EXPECT_EQ(kRequestsToFail, interceptor()->failures()); | |
| 1105 EXPECT_EQ(kRequestsToFail + 1, interceptor()->requests()); | |
| 1106 } | |
| 1107 | |
| 1108 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, ManualReloadNotSuppressed) { | |
| 1109 GURL test_url("http://error.page.auto.reload"); | |
| 1110 const int kRequestsToFail = 3; | |
| 1111 InstallInterceptor(test_url, kRequestsToFail); | |
| 1112 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 1113 browser(), test_url, 2); | |
| 1114 | |
| 1115 EXPECT_EQ(2, interceptor()->failures()); | |
| 1116 EXPECT_EQ(2, interceptor()->requests()); | |
| 1117 | |
| 1118 ToggleHelpBox(browser()); | |
| 1119 EXPECT_TRUE(IsDisplayingText(browser(), l10n_util::GetStringUTF8( | |
| 1120 IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_HEADER))); | |
| 1121 | |
| 1122 content::WebContents* web_contents = | |
| 1123 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1124 content::TestNavigationObserver nav_observer(web_contents, 1); | |
| 1125 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 1126 base::ASCIIToUTF16("document.getElementById('reload-button').click();")); | |
| 1127 nav_observer.Wait(); | |
| 1128 EXPECT_FALSE(IsDisplayingText(browser(), l10n_util::GetStringUTF8( | |
| 1129 IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_HEADER))); | |
| 1130 } | |
| 1131 | |
| 1132 // Make sure that a same page navigation does not cause issues with the | |
| 1133 // auto-reload timer. Note that this test was added due to this case causing | |
| 1134 // a crash. On regression, this test may hang due to a crashed renderer. | |
| 1135 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, IgnoresSamePageNavigation) { | |
| 1136 GURL test_url("http://error.page.auto.reload"); | |
| 1137 InstallInterceptor(test_url, 2); | |
| 1138 | |
| 1139 // Wait for the error page and first autoreload, which happens immediately. | |
| 1140 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 1141 browser(), test_url, 2); | |
| 1142 | |
| 1143 EXPECT_EQ(2, interceptor()->failures()); | |
| 1144 EXPECT_EQ(2, interceptor()->requests()); | |
| 1145 | |
| 1146 content::WebContents* web_contents = | |
| 1147 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1148 content::TestNavigationObserver observer(web_contents, 1); | |
| 1149 web_contents->GetMainFrame()->ExecuteJavaScriptForTests( | |
| 1150 base::ASCIIToUTF16("document.location='#';")); | |
| 1151 // The same page navigation counts as a navigation as far as the | |
| 1152 // TestNavigationObserver is concerned. | |
| 1153 observer.Wait(); | |
| 1154 | |
| 1155 // No new requests should have been issued. | |
| 1156 EXPECT_EQ(2, interceptor()->failures()); | |
| 1157 EXPECT_EQ(2, interceptor()->requests()); | |
| 1158 | |
| 1159 // Wait for the second auto reload, which succeeds. | |
| 1160 content::TestNavigationObserver observer2(web_contents, 1); | |
| 1161 observer2.Wait(); | |
| 1162 | |
| 1163 EXPECT_EQ(2, interceptor()->failures()); | |
| 1164 EXPECT_EQ(3, interceptor()->requests()); | |
| 1165 } | |
| 1166 | |
| 1167 // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE. | |
| 1168 class AddressUnreachableInterceptor : public net::URLRequestInterceptor { | |
| 1169 public: | |
| 1170 AddressUnreachableInterceptor() {} | |
| 1171 ~AddressUnreachableInterceptor() override {} | |
| 1172 | |
| 1173 // net::URLRequestInterceptor: | |
| 1174 net::URLRequestJob* MaybeInterceptRequest( | |
| 1175 net::URLRequest* request, | |
| 1176 net::NetworkDelegate* network_delegate) const override { | |
| 1177 return new URLRequestFailedJob(request, | |
| 1178 network_delegate, | |
| 1179 net::ERR_ADDRESS_UNREACHABLE); | |
| 1180 } | |
| 1181 | |
| 1182 private: | |
| 1183 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableInterceptor); | |
| 1184 }; | |
| 1185 | |
| 1186 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation | |
| 1187 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use | |
| 1188 // a different error for the correction service and the original page to | |
| 1189 // validate the right page is being displayed. | |
| 1190 class ErrorPageNavigationCorrectionsFailTest : public ErrorPageTest { | |
| 1191 public: | |
| 1192 // InProcessBrowserTest: | |
| 1193 void SetUpOnMainThread() override { | |
| 1194 BrowserThread::PostTask( | |
| 1195 BrowserThread::IO, FROM_HERE, | |
| 1196 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters)); | |
| 1197 } | |
| 1198 | |
| 1199 void TearDownOnMainThread() override { | |
| 1200 BrowserThread::PostTask( | |
| 1201 BrowserThread::IO, FROM_HERE, | |
| 1202 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters)); | |
| 1203 } | |
| 1204 | |
| 1205 private: | |
| 1206 // Adds a filter that causes all correction service requests to fail with | |
| 1207 // ERR_ADDRESS_UNREACHABLE. | |
| 1208 // | |
| 1209 // Also adds the net::URLRequestFailedJob filter. | |
| 1210 static void AddFilters() { | |
| 1211 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 1212 URLRequestFailedJob::AddUrlHandler(); | |
| 1213 | |
| 1214 net::URLRequestFilter::GetInstance()->AddUrlInterceptor( | |
| 1215 google_util::LinkDoctorBaseURL(), | |
| 1216 std::unique_ptr<net::URLRequestInterceptor>( | |
| 1217 new AddressUnreachableInterceptor())); | |
| 1218 } | |
| 1219 | |
| 1220 static void RemoveFilters() { | |
| 1221 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 1222 net::URLRequestFilter::GetInstance()->ClearHandlers(); | |
| 1223 } | |
| 1224 }; | |
| 1225 | |
| 1226 // Make sure that when corrections fail to load, the network error page is | |
| 1227 // successfully loaded. | |
| 1228 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest, | |
| 1229 FetchCorrectionsFails) { | |
| 1230 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 1231 browser(), | |
| 1232 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED), | |
| 1233 2); | |
| 1234 | |
| 1235 // Verify that the expected error page is being displayed. | |
| 1236 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED); | |
| 1237 | |
| 1238 // Diagnostics button should be displayed, if available on this platform. | |
| 1239 EXPECT_EQ(PlatformSupportsDiagnosticsTool(), | |
| 1240 IsDisplayingDiagnosticsLink(browser())); | |
| 1241 } | |
| 1242 | |
| 1243 // Checks that when an error occurs and a corrections fail to load, the stale | |
| 1244 // cache status of the page is correctly transferred, and we can load the | |
| 1245 // stale copy from the javascript. Most logic copied from StaleCacheStatus | |
| 1246 // above. | |
| 1247 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest, | |
| 1248 StaleCacheStatusFailedCorrections) { | |
| 1249 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 1250 // Load cache with entry with "nocache" set, to create stale | |
| 1251 // cache. | |
| 1252 GURL test_url(embedded_test_server()->GetURL("/nocache.html")); | |
| 1253 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1); | |
| 1254 | |
| 1255 // Reload same URL after forcing an error from the the network layer; | |
| 1256 // confirm that the error page is told the cached copy exists. | |
| 1257 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = | |
| 1258 browser()->profile()->GetRequestContext(); | |
| 1259 BrowserThread::PostTask( | |
| 1260 BrowserThread::IO, FROM_HERE, | |
| 1261 base::Bind(&InterceptNetworkTransactions, | |
| 1262 base::RetainedRef(url_request_context_getter), | |
| 1263 net::ERR_CONNECTION_FAILED)); | |
| 1264 | |
| 1265 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 1266 browser(), test_url, 2); | |
| 1267 EXPECT_TRUE(IsDisplayingText(browser(), GetShowSavedButtonLabel())); | |
| 1268 EXPECT_TRUE(ProbeStaleCopyValue(true)); | |
| 1269 | |
| 1270 // Confirm that loading the stale copy from the cache works. | |
| 1271 content::TestNavigationObserver same_tab_observer( | |
| 1272 browser()->tab_strip_model()->GetActiveWebContents(), 1); | |
| 1273 ASSERT_TRUE(ReloadStaleCopyFromCache()); | |
| 1274 same_tab_observer.Wait(); | |
| 1275 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"), | |
| 1276 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); | |
| 1277 | |
| 1278 // Clear the cache and reload the same URL; confirm the error page is told | |
| 1279 // that there is no cached copy. | |
| 1280 BrowsingDataRemover* remover = | |
| 1281 BrowsingDataRemoverFactory::GetForBrowserContext(browser()->profile()); | |
| 1282 remover->Remove(BrowsingDataRemover::Unbounded(), | |
| 1283 BrowsingDataRemover::REMOVE_CACHE, | |
| 1284 BrowsingDataHelper::UNPROTECTED_WEB); | |
| 1285 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | |
| 1286 browser(), test_url, 2); | |
| 1287 EXPECT_TRUE(ProbeStaleCopyValue(false)); | |
| 1288 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel())); | |
| 1289 } | |
| 1290 | |
| 1291 class ErrorPageOfflineTest : public ErrorPageTest { | |
| 1292 protected: | |
| 1293 | |
| 1294 void SetUpInProcessBrowserTestFixture() override { | |
| 1295 #if defined(OS_CHROMEOS) | |
| 1296 if (enroll_) { | |
| 1297 // Set up fake install attributes. | |
| 1298 std::unique_ptr<policy::StubEnterpriseInstallAttributes> attributes( | |
| 1299 new policy::StubEnterpriseInstallAttributes()); | |
| 1300 attributes->SetDomain("example.com"); | |
| 1301 attributes->SetRegistrationUser("user@example.com"); | |
| 1302 policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting( | |
| 1303 attributes.release()); | |
| 1304 } | |
| 1305 #endif | |
| 1306 | |
| 1307 // Sets up a mock policy provider for user and device policies. | |
| 1308 EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_)) | |
| 1309 .WillRepeatedly(testing::Return(true)); | |
| 1310 | |
| 1311 policy::PolicyMap policy_map; | |
| 1312 #if defined(OS_CHROMEOS) | |
| 1313 if (enroll_) | |
| 1314 SetEnterpriseUsersDefaults(&policy_map); | |
| 1315 #endif | |
| 1316 if (set_allow_dinosaur_easter_egg_) { | |
| 1317 policy_map.Set( | |
| 1318 policy::key::kAllowDinosaurEasterEgg, policy::POLICY_LEVEL_MANDATORY, | |
| 1319 policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, | |
| 1320 base::WrapUnique( | |
| 1321 new base::FundamentalValue(value_of_allow_dinosaur_easter_egg_)), | |
| 1322 nullptr); | |
| 1323 } | |
| 1324 policy_provider_.UpdateChromePolicy(policy_map); | |
| 1325 | |
| 1326 #if defined(OS_CHROMEOS) | |
| 1327 policy::BrowserPolicyConnector::SetPolicyProviderForTesting( | |
| 1328 &policy_provider_); | |
| 1329 #else | |
| 1330 policy::ProfilePolicyConnectorFactory::GetInstance() | |
| 1331 ->PushProviderForTesting(&policy_provider_); | |
| 1332 #endif | |
| 1333 | |
| 1334 ErrorPageTest::SetUpInProcessBrowserTestFixture(); | |
| 1335 } | |
| 1336 | |
| 1337 std::string NavigateToPageAndReadText() { | |
| 1338 #if defined(OS_CHROMEOS) | |
| 1339 // Check enterprise enrollment | |
| 1340 policy::BrowserPolicyConnectorChromeOS* connector = | |
| 1341 g_browser_process->platform_part() | |
| 1342 ->browser_policy_connector_chromeos(); | |
| 1343 EXPECT_EQ(enroll_, connector->IsEnterpriseManaged()); | |
| 1344 #endif | |
| 1345 | |
| 1346 ui_test_utils::NavigateToURL( | |
| 1347 browser(), | |
| 1348 URLRequestFailedJob::GetMockHttpUrl(net::ERR_INTERNET_DISCONNECTED)); | |
| 1349 | |
| 1350 content::WebContents* web_contents = | |
| 1351 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1352 | |
| 1353 std::string command = base::StringPrintf( | |
| 1354 "var hasText = document.querySelector('.snackbar');" | |
| 1355 "domAutomationController.send(hasText ? hasText.innerText : '');"); | |
| 1356 | |
| 1357 std::string result; | |
| 1358 EXPECT_TRUE( | |
| 1359 content::ExecuteScriptAndExtractString(web_contents, command, &result)); | |
| 1360 | |
| 1361 return result; | |
| 1362 } | |
| 1363 | |
| 1364 // Whether to set AllowDinosaurEasterEgg policy | |
| 1365 bool set_allow_dinosaur_easter_egg_ = false; | |
| 1366 | |
| 1367 // The value of AllowDinosaurEasterEgg policy we want to set | |
| 1368 bool value_of_allow_dinosaur_easter_egg_; | |
| 1369 | |
| 1370 #if defined(OS_CHROMEOS) | |
| 1371 // Whether to enroll this CrOS device | |
| 1372 bool enroll_ = true; | |
| 1373 #endif | |
| 1374 | |
| 1375 // Mock policy provider for both user and device policies. | |
| 1376 policy::MockConfigurationPolicyProvider policy_provider_; | |
| 1377 }; | |
| 1378 | |
| 1379 class ErrorPageOfflineTestWithAllowDinosaurTrue : public ErrorPageOfflineTest { | |
| 1380 protected: | |
| 1381 void SetUpInProcessBrowserTestFixture() override { | |
| 1382 set_allow_dinosaur_easter_egg_ = true; | |
| 1383 value_of_allow_dinosaur_easter_egg_ = true; | |
| 1384 ErrorPageOfflineTest::SetUpInProcessBrowserTestFixture(); | |
| 1385 } | |
| 1386 }; | |
| 1387 | |
| 1388 class ErrorPageOfflineTestWithAllowDinosaurFalse : public ErrorPageOfflineTest { | |
| 1389 protected: | |
| 1390 void SetUpInProcessBrowserTestFixture() override { | |
| 1391 set_allow_dinosaur_easter_egg_ = true; | |
| 1392 value_of_allow_dinosaur_easter_egg_ = false; | |
| 1393 ErrorPageOfflineTest::SetUpInProcessBrowserTestFixture(); | |
| 1394 } | |
| 1395 }; | |
| 1396 | |
| 1397 #if defined(OS_CHROMEOS) | |
| 1398 class ErrorPageOfflineTestUnEnrolledChromeOS : public ErrorPageOfflineTest { | |
| 1399 protected: | |
| 1400 void SetUpInProcessBrowserTestFixture() override { | |
| 1401 set_allow_dinosaur_easter_egg_ = false; | |
| 1402 enroll_ = false; | |
| 1403 ErrorPageOfflineTest::SetUpInProcessBrowserTestFixture(); | |
| 1404 } | |
| 1405 }; | |
| 1406 #endif | |
| 1407 | |
| 1408 IN_PROC_BROWSER_TEST_F(ErrorPageOfflineTestWithAllowDinosaurTrue, | |
| 1409 CheckEasterEggIsAllowed) { | |
| 1410 std::string result = NavigateToPageAndReadText(); | |
| 1411 EXPECT_EQ("", result); | |
| 1412 } | |
| 1413 | |
| 1414 IN_PROC_BROWSER_TEST_F(ErrorPageOfflineTestWithAllowDinosaurFalse, | |
| 1415 CheckEasterEggIsDisabled) { | |
| 1416 std::string result = NavigateToPageAndReadText(); | |
| 1417 std::string disabled_text = | |
| 1418 l10n_util::GetStringUTF8(IDS_ERRORPAGE_FUN_DISABLED); | |
| 1419 EXPECT_EQ(disabled_text, result); | |
| 1420 } | |
| 1421 | |
| 1422 #if defined(OS_CHROMEOS) | |
| 1423 IN_PROC_BROWSER_TEST_F(ErrorPageOfflineTest, CheckEasterEggIsDisabled) { | |
| 1424 std::string result = NavigateToPageAndReadText(); | |
| 1425 std::string disabled_text = | |
| 1426 l10n_util::GetStringUTF8(IDS_ERRORPAGE_FUN_DISABLED); | |
| 1427 EXPECT_EQ(disabled_text, result); | |
| 1428 } | |
| 1429 #else | |
| 1430 IN_PROC_BROWSER_TEST_F(ErrorPageOfflineTest, CheckEasterEggIsAllowed) { | |
| 1431 std::string result = NavigateToPageAndReadText(); | |
| 1432 EXPECT_EQ("", result); | |
| 1433 } | |
| 1434 #endif | |
| 1435 | |
| 1436 #if defined(OS_CHROMEOS) | |
| 1437 IN_PROC_BROWSER_TEST_F(ErrorPageOfflineTestUnEnrolledChromeOS, | |
| 1438 CheckEasterEggIsAllowed) { | |
| 1439 std::string result = NavigateToPageAndReadText(); | |
| 1440 std::string disabled_text = | |
| 1441 l10n_util::GetStringUTF8(IDS_ERRORPAGE_FUN_DISABLED); | |
| 1442 EXPECT_EQ("", result); | |
| 1443 } | |
| 1444 #endif | |
| 1445 | |
| 1446 // A test fixture that simulates failing requests for an IDN domain name. | |
| 1447 class ErrorPageForIDNTest : public InProcessBrowserTest { | |
| 1448 public: | |
| 1449 // Target hostname in different forms. | |
| 1450 static const char kHostname[]; | |
| 1451 static const char kHostnameJSUnicode[]; | |
| 1452 | |
| 1453 // InProcessBrowserTest: | |
| 1454 void SetUpOnMainThread() override { | |
| 1455 // Clear AcceptLanguages to force punycode decoding. | |
| 1456 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages, | |
| 1457 std::string()); | |
| 1458 BrowserThread::PostTask( | |
| 1459 BrowserThread::IO, FROM_HERE, | |
| 1460 base::Bind(&ErrorPageForIDNTest::AddFilters)); | |
| 1461 } | |
| 1462 | |
| 1463 void TearDownOnMainThread() override { | |
| 1464 BrowserThread::PostTask( | |
| 1465 BrowserThread::IO, FROM_HERE, | |
| 1466 base::Bind(&ErrorPageForIDNTest::RemoveFilters)); | |
| 1467 } | |
| 1468 | |
| 1469 private: | |
| 1470 static void AddFilters() { | |
| 1471 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 1472 URLRequestFailedJob::AddUrlHandlerForHostname(kHostname); | |
| 1473 } | |
| 1474 | |
| 1475 static void RemoveFilters() { | |
| 1476 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 1477 net::URLRequestFilter::GetInstance()->ClearHandlers(); | |
| 1478 } | |
| 1479 }; | |
| 1480 | |
| 1481 const char ErrorPageForIDNTest::kHostname[] = | |
| 1482 "xn--d1abbgf6aiiy.xn--p1ai"; | |
| 1483 const char ErrorPageForIDNTest::kHostnameJSUnicode[] = | |
| 1484 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442." | |
| 1485 "\\u0440\\u0444"; | |
| 1486 | |
| 1487 // Make sure error page shows correct unicode for IDN. | |
| 1488 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) { | |
| 1489 // ERR_UNSAFE_PORT will not trigger navigation corrections. | |
| 1490 ui_test_utils::NavigateToURL( | |
| 1491 browser(), | |
| 1492 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT, | |
| 1493 kHostname)); | |
| 1494 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode)); | |
| 1495 } | |
| 1496 | |
| 1497 } // namespace | |
| OLD | NEW |