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 "base/command_line.h"
6#include "base/files/file_path.h"
7#include "base/strings/stringprintf.h"
8#include "chrome/browser/ui/browser.h"
9#include "chrome/browser/ui/browser_commands.h"
10#include "chrome/browser/ui/tabs/tab_strip_model.h"
11#include "chrome/common/chrome_switches.h"
12#include "chrome/common/url_constants.h"
13#include "chrome/test/base/in_process_browser_test.h"
14#include "chrome/test/base/ui_test_utils.h"
15#include "content/public/browser/notification_service.h"
16#include "content/public/browser/notification_types.h"
17#include "content/public/browser/web_contents.h"
18#include "content/public/test/browser_test_utils.h"
19#include "net/test/embedded_test_server/embedded_test_server.h"
20#include "net/test/embedded_test_server/http_request.h"
21#include "net/test/embedded_test_server/http_response.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "ui/base/page_transition_types.h"
24
25using content::OpenURLParams;
26using content::Referrer;
27using content::WebContents;
28
29// TODO(jam): http://crbug.com/350550
30#if !(defined(OS_CHROMEOS) && defined(ADDRESS_SANITIZER))
31
32namespace {
33
34void SimulateRendererCrash(Browser* browser) {
35  content::WindowedNotificationObserver observer(
36      content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
37      content::NotificationService::AllSources());
38  browser->OpenURL(OpenURLParams(
39      GURL(content::kChromeUICrashURL), Referrer(), CURRENT_TAB,
40      ui::PAGE_TRANSITION_TYPED, false));
41  observer.Wait();
42}
43
44// A request handler which returns a different result each time but stays fresh
45// into the far future.
46class CacheMaxAgeHandler {
47 public:
48  explicit CacheMaxAgeHandler(const std::string& path)
49      : path_(path), request_count_(0) { }
50
51  scoped_ptr<net::test_server::HttpResponse> HandleRequest(
52      const net::test_server::HttpRequest& request) {
53    if (request.relative_url != path_)
54      return scoped_ptr<net::test_server::HttpResponse>();
55
56    request_count_++;
57    scoped_ptr<net::test_server::BasicHttpResponse> response(
58        new net::test_server::BasicHttpResponse);
59    response->set_content(base::StringPrintf("<title>%d</title>",
60                                             request_count_));
61    response->set_content_type("text/html");
62    response->AddCustomHeader("Cache-Control", "max-age=99999");
63    return response.PassAs<net::test_server::HttpResponse>();
64  }
65 private:
66  std::string path_;
67  int request_count_;
68
69  DISALLOW_COPY_AND_ASSIGN(CacheMaxAgeHandler);
70};
71
72class CrashRecoveryBrowserTest : public InProcessBrowserTest {
73 protected:
74  WebContents* GetActiveWebContents() {
75    return browser()->tab_strip_model()->GetActiveWebContents();
76  }
77
78 private:
79  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
80    command_line->AppendSwitch(switches::kDisableBreakpad);
81  }
82};
83
84// Test that reload works after a crash.
85// Disabled, http://crbug.com/29331 , http://crbug.com/69637 .
86IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, Reload) {
87  // The title of the active tab should change each time this URL is loaded.
88  GURL url(
89      "data:text/html,<script>document.title=new Date().valueOf()</script>");
90  ui_test_utils::NavigateToURL(browser(), url);
91
92  base::string16 title_before_crash;
93  base::string16 title_after_crash;
94
95  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
96                                                &title_before_crash));
97  SimulateRendererCrash(browser());
98  chrome::Reload(browser(), CURRENT_TAB);
99  content::WaitForLoadStop(GetActiveWebContents());
100  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
101                                                &title_after_crash));
102  EXPECT_NE(title_before_crash, title_after_crash);
103}
104
105// Test that reload after a crash forces a cache revalidation.
106IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, ReloadCacheRevalidate) {
107  const char kTestPath[] = "/test";
108
109  // Use the test server so as not to bypass cache behavior. The title of the
110  // active tab should change only when this URL is reloaded.
111  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
112  embedded_test_server()->RegisterRequestHandler(
113      base::Bind(&CacheMaxAgeHandler::HandleRequest,
114                 base::Owned(new CacheMaxAgeHandler(kTestPath))));
115  ui_test_utils::NavigateToURL(browser(),
116                               embedded_test_server()->GetURL(kTestPath));
117
118  base::string16 title_before_crash;
119  base::string16 title_after_crash;
120
121  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
122                                                &title_before_crash));
123  SimulateRendererCrash(browser());
124  chrome::Reload(browser(), CURRENT_TAB);
125  content::WaitForLoadStop(GetActiveWebContents());
126  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
127                                                &title_after_crash));
128  EXPECT_NE(title_before_crash, title_after_crash);
129}
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.
135IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, LoadInNewTab) {
136  const base::FilePath::CharType kTitle2File[] =
137      FILE_PATH_LITERAL("title2.html");
138
139  ui_test_utils::NavigateToURL(
140      browser(), ui_test_utils::GetTestUrl(
141                     base::FilePath(base::FilePath::kCurrentDirectory),
142                     base::FilePath(kTitle2File)));
143
144  base::string16 title_before_crash;
145  base::string16 title_after_crash;
146
147  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
148                                                &title_before_crash));
149  SimulateRendererCrash(browser());
150  chrome::Reload(browser(), CURRENT_TAB);
151  content::WaitForLoadStop(GetActiveWebContents());
152  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
153                                                &title_after_crash));
154  EXPECT_EQ(title_before_crash, title_after_crash);
155}
156
157// Tests that reloads of navigation errors behave correctly after a crash.
158// Regression test for http://crbug.com/348918
159IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, DoubleReloadWithError) {
160  GURL url("chrome://bogus");
161  ui_test_utils::NavigateToURL(browser(), url);
162  ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
163
164  SimulateRendererCrash(browser());
165
166  chrome::Reload(browser(), CURRENT_TAB);
167  content::WaitForLoadStop(GetActiveWebContents());
168  ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
169
170  chrome::Reload(browser(), CURRENT_TAB);
171  content::WaitForLoadStop(GetActiveWebContents());
172  ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
173}
174
175}  // namespace
176
177#endif
178