crash_recovery_browsertest.cc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. #include <utility>
  5. #include "base/base_switches.h"
  6. #include "base/bind.h"
  7. #include "base/command_line.h"
  8. #include "base/files/file_path.h"
  9. #include "base/strings/stringprintf.h"
  10. #include "build/build_config.h"
  11. #include "build/chromeos_buildflags.h"
  12. #include "chrome/browser/ui/browser.h"
  13. #include "chrome/browser/ui/browser_commands.h"
  14. #include "chrome/browser/ui/tabs/tab_strip_model.h"
  15. #include "chrome/common/url_constants.h"
  16. #include "chrome/test/base/in_process_browser_test.h"
  17. #include "chrome/test/base/ui_test_utils.h"
  18. #include "content/public/browser/navigation_controller.h"
  19. #include "content/public/browser/navigation_entry.h"
  20. #include "content/public/browser/notification_service.h"
  21. #include "content/public/browser/notification_types.h"
  22. #include "content/public/browser/render_frame_host.h"
  23. #include "content/public/browser/render_process_host.h"
  24. #include "content/public/browser/render_widget_host_view.h"
  25. #include "content/public/browser/web_contents.h"
  26. #include "content/public/test/browser_test.h"
  27. #include "content/public/test/browser_test_utils.h"
  28. #include "content/public/test/no_renderer_crashes_assertion.h"
  29. #include "net/test/embedded_test_server/embedded_test_server.h"
  30. #include "net/test/embedded_test_server/http_request.h"
  31. #include "net/test/embedded_test_server/http_response.h"
  32. #include "testing/gtest/include/gtest/gtest.h"
  33. #include "third_party/blink/public/common/chrome_debug_urls.h"
  34. #include "ui/base/page_transition_types.h"
  35. using content::OpenURLParams;
  36. using content::Referrer;
  37. using content::WebContents;
  38. // TODO(jam): http://crbug.com/350550
  39. #if !(BUILDFLAG(IS_CHROMEOS_ASH) && defined(ADDRESS_SANITIZER))
  40. namespace {
  41. void SimulateRendererCrash(Browser* browser) {
  42. content::RenderProcessHostWatcher crash_observer(
  43. browser->tab_strip_model()->GetActiveWebContents(),
  44. content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
  45. browser->OpenURL(OpenURLParams(GURL(blink::kChromeUICrashURL), Referrer(),
  46. WindowOpenDisposition::CURRENT_TAB,
  47. ui::PAGE_TRANSITION_TYPED, false));
  48. crash_observer.Wait();
  49. }
  50. // A request handler which returns a different result each time but stays fresh
  51. // into the far future.
  52. class CacheMaxAgeHandler {
  53. public:
  54. explicit CacheMaxAgeHandler(const std::string& path)
  55. : path_(path), request_count_(0) { }
  56. CacheMaxAgeHandler(const CacheMaxAgeHandler&) = delete;
  57. CacheMaxAgeHandler& operator=(const CacheMaxAgeHandler&) = delete;
  58. std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
  59. const net::test_server::HttpRequest& request) {
  60. if (request.relative_url != path_)
  61. return nullptr;
  62. request_count_++;
  63. std::unique_ptr<net::test_server::BasicHttpResponse> response(
  64. new net::test_server::BasicHttpResponse);
  65. response->set_content(base::StringPrintf("<title>%d</title>",
  66. request_count_));
  67. response->set_content_type("text/html");
  68. response->AddCustomHeader("Cache-Control", "max-age=99999");
  69. return std::move(response);
  70. }
  71. private:
  72. std::string path_;
  73. int request_count_;
  74. };
  75. class CrashRecoveryBrowserTest : public InProcessBrowserTest {
  76. protected:
  77. WebContents* GetActiveWebContents() {
  78. return browser()->tab_strip_model()->GetActiveWebContents();
  79. }
  80. private:
  81. void SetUpCommandLine(base::CommandLine* command_line) override {
  82. command_line->AppendSwitch(switches::kDisableBreakpad);
  83. }
  84. content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes_;
  85. };
  86. // Test that reload works after a crash.
  87. IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, Reload) {
  88. // The title of the active tab should change each time this URL is loaded.
  89. GURL url(
  90. "data:text/html,<script>document.title=new Date().valueOf()</script>");
  91. ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
  92. std::u16string title_before_crash;
  93. std::u16string title_after_crash;
  94. ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
  95. &title_before_crash));
  96. SimulateRendererCrash(browser());
  97. chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
  98. EXPECT_TRUE(content::WaitForLoadStop(GetActiveWebContents()));
  99. ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
  100. &title_after_crash));
  101. EXPECT_NE(title_before_crash, title_after_crash);
  102. ASSERT_TRUE(
  103. GetActiveWebContents()->GetPrimaryMainFrame()->GetView()->IsShowing());
  104. ASSERT_FALSE(GetActiveWebContents()
  105. ->GetPrimaryMainFrame()
  106. ->GetProcess()
  107. ->IsProcessBackgrounded());
  108. }
  109. // Test that reload after a crash forces a cache revalidation.
  110. IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, ReloadCacheRevalidate) {
  111. const char kTestPath[] = "/test";
  112. // Use the test server so as not to bypass cache behavior. The title of the
  113. // active tab should change only when this URL is reloaded.
  114. embedded_test_server()->RegisterRequestHandler(
  115. base::BindRepeating(&CacheMaxAgeHandler::HandleRequest,
  116. base::Owned(new CacheMaxAgeHandler(kTestPath))));
  117. ASSERT_TRUE(embedded_test_server()->Start());
  118. ASSERT_TRUE(ui_test_utils::NavigateToURL(
  119. browser(), embedded_test_server()->GetURL(kTestPath)));
  120. std::u16string title_before_crash;
  121. std::u16string title_after_crash;
  122. ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
  123. &title_before_crash));
  124. SimulateRendererCrash(browser());
  125. chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
  126. EXPECT_TRUE(content::WaitForLoadStop(GetActiveWebContents()));
  127. ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
  128. &title_after_crash));
  129. EXPECT_NE(title_before_crash, title_after_crash);
  130. }
  131. // Tests that loading a crashed page in a new tab correctly updates the title.
  132. // There was an earlier bug (1270510) in process-per-site in which the max page
  133. // ID of the RenderProcessHost was stale, so the NavigationEntry in the new tab
  134. // was not committed. This prevents regression of that bug.
  135. IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, LoadInNewTab) {
  136. const base::FilePath::CharType kTitle2File[] =
  137. FILE_PATH_LITERAL("title2.html");
  138. GURL url(ui_test_utils::GetTestUrl(
  139. base::FilePath(base::FilePath::kCurrentDirectory),
  140. base::FilePath(kTitle2File)));
  141. ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
  142. std::u16string title_before_crash;
  143. std::u16string title_after_crash;
  144. ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
  145. &title_before_crash));
  146. SimulateRendererCrash(browser());
  147. ASSERT_EQ(GURL(blink::kChromeUICrashURL), GetActiveWebContents()
  148. ->GetController()
  149. .GetVisibleEntry()
  150. ->GetVirtualURL());
  151. chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
  152. EXPECT_TRUE(content::WaitForLoadStop(GetActiveWebContents()));
  153. ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
  154. &title_after_crash));
  155. EXPECT_EQ(title_before_crash, title_after_crash);
  156. }
  157. // Tests that reloads of navigation errors behave correctly after a crash.
  158. // Regression test for http://crbug.com/348918
  159. IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, DoubleReloadWithError) {
  160. GURL url(content::GetWebUIURL("bogus"));
  161. ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
  162. ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
  163. SimulateRendererCrash(browser());
  164. chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
  165. EXPECT_FALSE(content::WaitForLoadStop(GetActiveWebContents()));
  166. ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
  167. chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
  168. EXPECT_FALSE(content::WaitForLoadStop(GetActiveWebContents()));
  169. ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
  170. }
  171. // Tests that a beforeunload handler doesn't run if user navigates to
  172. // chrome::crash.
  173. IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, BeforeUnloadNotRun) {
  174. const char* kBeforeUnloadHTML =
  175. "<html><body>"
  176. "<script>window.onbeforeunload=function(e){return 'foo'}</script>"
  177. "</body></html>";
  178. GURL url(std::string("data:text/html,") + kBeforeUnloadHTML);
  179. ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
  180. SimulateRendererCrash(browser());
  181. }
  182. } // namespace
  183. #endif