1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/base_switches.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/functional/bind.h"
11 #include "base/strings/stringprintf.h"
12 #include "build/build_config.h"
13 #include "build/chromeos_buildflags.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/url_constants.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/navigation_controller.h"
21 #include "content/public/browser/navigation_entry.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"
36 using content::OpenURLParams;
37 using content::Referrer;
38 using content::WebContents;
40 // TODO(jam): http://crbug.com/350550
41 #if !(BUILDFLAG(IS_CHROMEOS_ASH) && defined(ADDRESS_SANITIZER))
45 void SimulateRendererCrash(Browser* browser) {
46 content::RenderProcessHostWatcher crash_observer(
47 browser->tab_strip_model()->GetActiveWebContents(),
48 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
49 browser->OpenURL(OpenURLParams(GURL(blink::kChromeUICrashURL), Referrer(),
50 WindowOpenDisposition::CURRENT_TAB,
51 ui::PAGE_TRANSITION_TYPED, false));
52 crash_observer.Wait();
55 // A request handler which returns a different result each time but stays fresh
56 // into the far future.
57 class CacheMaxAgeHandler {
59 explicit CacheMaxAgeHandler(const std::string& path)
60 : path_(path), request_count_(0) { }
62 CacheMaxAgeHandler(const CacheMaxAgeHandler&) = delete;
63 CacheMaxAgeHandler& operator=(const CacheMaxAgeHandler&) = delete;
65 std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
66 const net::test_server::HttpRequest& request) {
67 if (request.relative_url != path_)
71 std::unique_ptr<net::test_server::BasicHttpResponse> response(
72 new net::test_server::BasicHttpResponse);
73 response->set_content(base::StringPrintf("<title>%d</title>",
75 response->set_content_type("text/html");
76 response->AddCustomHeader("Cache-Control", "max-age=99999");
77 return std::move(response);
84 class CrashRecoveryBrowserTest : public InProcessBrowserTest {
86 WebContents* GetActiveWebContents() {
87 return browser()->tab_strip_model()->GetActiveWebContents();
91 void SetUpCommandLine(base::CommandLine* command_line) override {
92 command_line->AppendSwitch(switches::kDisableBreakpad);
95 content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes_;
98 // Test that reload works after a crash.
99 IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, Reload) {
100 // The title of the active tab should change each time this URL is loaded.
102 "data:text/html,<script>document.title=new Date().valueOf()</script>");
103 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
105 std::u16string title_before_crash;
106 std::u16string title_after_crash;
108 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
109 &title_before_crash));
110 SimulateRendererCrash(browser());
111 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
112 EXPECT_TRUE(content::WaitForLoadStop(GetActiveWebContents()));
113 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
114 &title_after_crash));
115 EXPECT_NE(title_before_crash, title_after_crash);
117 GetActiveWebContents()->GetPrimaryMainFrame()->GetView()->IsShowing());
118 ASSERT_FALSE(GetActiveWebContents()
119 ->GetPrimaryMainFrame()
121 ->IsProcessBackgrounded());
124 // Test that reload after a crash forces a cache revalidation.
125 IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, ReloadCacheRevalidate) {
126 const char kTestPath[] = "/test";
128 // Use the test server so as not to bypass cache behavior. The title of the
129 // active tab should change only when this URL is reloaded.
130 embedded_test_server()->RegisterRequestHandler(
131 base::BindRepeating(&CacheMaxAgeHandler::HandleRequest,
132 base::Owned(new CacheMaxAgeHandler(kTestPath))));
133 ASSERT_TRUE(embedded_test_server()->Start());
134 ASSERT_TRUE(ui_test_utils::NavigateToURL(
135 browser(), embedded_test_server()->GetURL(kTestPath)));
137 std::u16string title_before_crash;
138 std::u16string title_after_crash;
140 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
141 &title_before_crash));
142 SimulateRendererCrash(browser());
143 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
144 EXPECT_TRUE(content::WaitForLoadStop(GetActiveWebContents()));
145 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
146 &title_after_crash));
147 EXPECT_NE(title_before_crash, title_after_crash);
150 // Tests that loading a crashed page in a new tab correctly updates the title.
151 // There was an earlier bug (1270510) in process-per-site in which the max page
152 // ID of the RenderProcessHost was stale, so the NavigationEntry in the new tab
153 // was not committed. This prevents regression of that bug.
154 IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, LoadInNewTab) {
155 const base::FilePath::CharType kTitle2File[] =
156 FILE_PATH_LITERAL("title2.html");
158 GURL url(ui_test_utils::GetTestUrl(
159 base::FilePath(base::FilePath::kCurrentDirectory),
160 base::FilePath(kTitle2File)));
161 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
163 std::u16string title_before_crash;
164 std::u16string title_after_crash;
166 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
167 &title_before_crash));
168 SimulateRendererCrash(browser());
169 ASSERT_EQ(GURL(blink::kChromeUICrashURL), GetActiveWebContents()
173 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
174 EXPECT_TRUE(content::WaitForLoadStop(GetActiveWebContents()));
175 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
176 &title_after_crash));
177 EXPECT_EQ(title_before_crash, title_after_crash);
180 // Tests that reloads of navigation errors behave correctly after a crash.
181 // Regression test for http://crbug.com/348918
182 IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, DoubleReloadWithError) {
183 GURL url(content::GetWebUIURL("bogus"));
184 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
185 ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
187 SimulateRendererCrash(browser());
189 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
190 EXPECT_FALSE(content::WaitForLoadStop(GetActiveWebContents()));
191 ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
193 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
194 EXPECT_FALSE(content::WaitForLoadStop(GetActiveWebContents()));
195 ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
198 // Tests that a beforeunload handler doesn't run if user navigates to
200 IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, BeforeUnloadNotRun) {
201 const char* kBeforeUnloadHTML =
203 "<script>window.onbeforeunload=function(e){return 'foo'}</script>"
205 GURL url(std::string("data:text/html,") + kBeforeUnloadHTML);
206 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
207 SimulateRendererCrash(browser());