browser_uitest.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2006-2008 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/base_paths.h"
6#include "base/file_path.h"
7#include "base/file_util.h"
8#include "base/path_service.h"
9#include "base/string_util.h"
10#include "base/sys_info.h"
11#include "base/test/test_file_util.h"
12#include "base/values.h"
13#include "chrome/app/chrome_command_ids.h"
14#include "chrome/browser/platform_util.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/common/chrome_switches.h"
17#include "chrome/common/chrome_constants.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/test/automation/browser_proxy.h"
20#include "chrome/test/automation/tab_proxy.h"
21#include "chrome/test/automation/window_proxy.h"
22#include "chrome/test/ui/ui_test.h"
23#include "gfx/native_widget_types.h"
24#include "grit/chromium_strings.h"
25#include "grit/generated_resources.h"
26#include "net/base/net_util.h"
27#include "net/test/test_server.h"
28
29namespace {
30
31class BrowserTest : public UITest {
32};
33
34class VisibleBrowserTest : public UITest {
35 protected:
36  VisibleBrowserTest() : UITest() {
37    show_window_ = true;
38  }
39};
40
41#if defined(OS_WIN)
42// The browser should quit quickly if it receives a WM_ENDSESSION message.
43TEST_F(BrowserTest, WindowsSessionEnd) {
44#elif defined(OS_POSIX)
45// The browser should quit gracefully and quickly if it receives a SIGTERM.
46TEST_F(BrowserTest, PosixSessionEnd) {
47#endif
48  FilePath test_file(test_data_directory_);
49  test_file = test_file.AppendASCII("title1.html");
50
51  NavigateToURL(net::FilePathToFileURL(test_file));
52  TerminateBrowser();
53  ASSERT_FALSE(IsBrowserRunning());
54
55  // Make sure the UMA metrics say we didn't crash.
56  scoped_ptr<DictionaryValue> local_prefs(GetLocalState());
57  bool exited_cleanly;
58  ASSERT_TRUE(local_prefs.get());
59  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilityExitedCleanly,
60                                      &exited_cleanly));
61  ASSERT_TRUE(exited_cleanly);
62
63  // And that session end was successful.
64  bool session_end_completed;
65  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilitySessionEndCompleted,
66                                      &session_end_completed));
67  ASSERT_TRUE(session_end_completed);
68
69  // Make sure session restore says we didn't crash.
70  scoped_ptr<DictionaryValue> profile_prefs(GetDefaultProfilePreferences());
71  ASSERT_TRUE(profile_prefs.get());
72  ASSERT_TRUE(profile_prefs->GetBoolean(prefs::kSessionExitedCleanly,
73                                        &exited_cleanly));
74  ASSERT_TRUE(exited_cleanly);
75}
76
77// Test that scripts can fork a new renderer process for a tab in a particular
78// case (which matches following a link in Gmail).  The script must open a new
79// tab, set its window.opener to null, and redirect it to a cross-site URL.
80// (Bug 1115708)
81// This test can only run if V8 is in use, and not KJS, because KJS will not
82// set window.opener to null properly.
83#ifdef CHROME_V8
84TEST_F(BrowserTest, NullOpenerRedirectForksProcess) {
85  // This test only works in multi-process mode
86  if (ProxyLauncher::in_process_renderer())
87    return;
88
89  net::TestServer test_server(net::TestServer::TYPE_HTTP,
90                              FilePath(FILE_PATH_LITERAL("chrome/test/data")));
91  ASSERT_TRUE(test_server.Start());
92
93  FilePath test_file(test_data_directory_);
94  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
95  ASSERT_TRUE(window.get());
96  scoped_refptr<TabProxy> tab(window->GetActiveTab());
97  ASSERT_TRUE(tab.get());
98
99  // Start with a file:// url
100  test_file = test_file.AppendASCII("title2.html");
101  tab->NavigateToURL(net::FilePathToFileURL(test_file));
102  int orig_tab_count = -1;
103  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
104  int orig_process_count = GetBrowserProcessCount();
105  ASSERT_GE(orig_process_count, 1);
106
107  // Use JavaScript URL to "fork" a new tab, just like Gmail.  (Open tab to a
108  // blank page, set its opener to null, and redirect it cross-site.)
109  std::wstring url_prefix(L"javascript:(function(){w=window.open();");
110  GURL fork_url(url_prefix +
111      L"w.opener=null;w.document.location=\"http://localhost:1337\";})()");
112
113  // Make sure that a new tab has been created and that we have a new renderer
114  // process for it.
115  ASSERT_TRUE(tab->NavigateToURLAsync(fork_url));
116  PlatformThread::Sleep(sleep_timeout_ms());
117  ASSERT_EQ(orig_process_count + 1, GetBrowserProcessCount());
118  int new_tab_count = -1;
119  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
120  ASSERT_EQ(orig_tab_count + 1, new_tab_count);
121}
122#endif  // CHROME_V8
123
124// This test fails on ChromeOS (it has never been known to work on it).
125// Currently flaky on Windows - it has crashed a couple of times.
126// http://crbug.com/32799
127#if defined(OS_CHROMEOS)
128#define MAYBE_OtherRedirectsDontForkProcess DISABLED_OtherRedirectsDontForkProcess
129#else
130#define MAYBE_OtherRedirectsDontForkProcess FLAKY_OtherRedirectsDontForkProcess
131#endif
132
133// Tests that non-Gmail-like script redirects (i.e., non-null window.opener) or
134// a same-page-redirect) will not fork a new process.
135TEST_F(BrowserTest, MAYBE_OtherRedirectsDontForkProcess) {
136  // This test only works in multi-process mode
137  if (ProxyLauncher::in_process_renderer())
138    return;
139
140  net::TestServer test_server(net::TestServer::TYPE_HTTP,
141                              FilePath(FILE_PATH_LITERAL("chrome/test/data")));
142  ASSERT_TRUE(test_server.Start());
143
144  FilePath test_file(test_data_directory_);
145  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
146  ASSERT_TRUE(window.get());
147  scoped_refptr<TabProxy> tab(window->GetActiveTab());
148  ASSERT_TRUE(tab.get());
149
150  // Start with a file:// url
151  test_file = test_file.AppendASCII("title2.html");
152  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
153            tab->NavigateToURL(net::FilePathToFileURL(test_file)));
154  int orig_tab_count = -1;
155  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
156  int orig_process_count = GetBrowserProcessCount();
157  ASSERT_GE(orig_process_count, 1);
158
159  // Use JavaScript URL to almost fork a new tab, but not quite.  (Leave the
160  // opener non-null.)  Should not fork a process.
161  std::string url_str = "javascript:(function(){w=window.open(); ";
162  url_str += "w.document.location=\"";
163  url_str += test_server.GetURL("").spec();
164  url_str += "\";})()";
165  GURL dont_fork_url(url_str);
166
167  // Make sure that a new tab but not new process has been created.
168  ASSERT_TRUE(tab->NavigateToURLAsync(dont_fork_url));
169  base::PlatformThread::Sleep(sleep_timeout_ms());
170  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
171  int new_tab_count = -1;
172  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
173  ASSERT_EQ(orig_tab_count + 1, new_tab_count);
174
175  // Same thing if the current tab tries to redirect itself.
176  url_str = "javascript:(function(){w=window.open(); ";
177  url_str += "document.location=\"";
178  url_str += test_server.GetURL("").spec();
179  url_str += "\";})()";
180  GURL dont_fork_url2(url_str);
181
182  // Make sure that no new process has been created.
183  ASSERT_TRUE(tab->NavigateToURLAsync(dont_fork_url2));
184  base::PlatformThread::Sleep(sleep_timeout_ms());
185  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
186}
187
188TEST_F(VisibleBrowserTest, WindowOpenClose) {
189  FilePath test_file(test_data_directory_);
190  test_file = test_file.AppendASCII("window.close.html");
191
192  NavigateToURLBlockUntilNavigationsComplete(
193      net::FilePathToFileURL(test_file), 2);
194  EXPECT_EQ(L"Title Of Awesomeness", GetActiveTabTitle());
195}
196
197class ShowModalDialogTest : public UITest {
198 public:
199  ShowModalDialogTest() {
200    launch_arguments_.AppendSwitch(switches::kDisablePopupBlocking);
201  }
202};
203
204// Flakiness returned. Re-opened crbug.com/17806
205TEST_F(ShowModalDialogTest, FLAKY_BasicTest) {
206  FilePath test_file(test_data_directory_);
207  test_file = test_file.AppendASCII("showmodaldialog.html");
208
209  // This navigation should show a modal dialog that will be immediately
210  // closed, but the fact that it was shown should be recorded.
211  NavigateToURL(net::FilePathToFileURL(test_file));
212
213  // At this point the modal dialog should not be showing.
214  int window_count = 0;
215  EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
216  EXPECT_EQ(1, window_count);
217
218  // Verify that we set a mark on successful dialog show.
219  scoped_refptr<BrowserProxy> browser = automation()->GetBrowserWindow(0);
220  ASSERT_TRUE(browser.get());
221  scoped_refptr<TabProxy> tab = browser->GetActiveTab();
222  ASSERT_TRUE(tab.get());
223  std::wstring title;
224  ASSERT_TRUE(tab->GetTabTitle(&title));
225  ASSERT_EQ(L"SUCCESS", title);
226}
227
228class SecurityTest : public UITest {
229};
230
231TEST_F(SecurityTest, DisallowFileUrlUniversalAccessTest) {
232  scoped_refptr<TabProxy> tab(GetActiveTab());
233  ASSERT_TRUE(tab.get());
234
235  FilePath test_file(test_data_directory_);
236  test_file = test_file.AppendASCII("fileurl_universalaccess.html");
237
238  GURL url = net::FilePathToFileURL(test_file);
239  ASSERT_TRUE(tab->NavigateToURL(url));
240
241  std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
242        "status", action_max_timeout_ms());
243  ASSERT_STREQ("Disallowed", value.c_str());
244}
245
246#if !defined(OS_MACOSX)
247class KioskModeTest : public UITest {
248 public:
249  KioskModeTest() {
250    launch_arguments_.AppendSwitch(switches::kKioskMode);
251  }
252};
253
254TEST_F(KioskModeTest, EnableKioskModeTest) {
255  // Load a local file.
256  FilePath test_file(test_data_directory_);
257  test_file = test_file.AppendASCII("title1.html");
258
259  // Verify that the window is present.
260  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
261  ASSERT_TRUE(browser.get());
262
263  // Check if browser is in fullscreen mode.
264  bool is_visible;
265  ASSERT_TRUE(browser->IsFullscreen(&is_visible));
266  EXPECT_TRUE(is_visible);
267  ASSERT_TRUE(browser->IsFullscreenBubbleVisible(&is_visible));
268  EXPECT_FALSE(is_visible);
269}
270#endif  // !defined(OS_MACOSX)
271
272#if defined(OS_WIN)
273// This test verifies that Chrome can be launched with a user-data-dir path
274// which contains non ASCII characters.
275class LaunchBrowserWithNonAsciiUserDatadir : public UITest {
276public:
277  void SetUp() {
278    PathService::Get(base::DIR_TEMP, &tmp_profile_);
279    tmp_profile_ = tmp_profile_.AppendASCII("tmp_profile");
280    tmp_profile_ = tmp_profile_.Append(L"Test Chrome G�raldine");
281
282    // Create a fresh, empty copy of this directory.
283    file_util::Delete(tmp_profile_, true);
284    file_util::CreateDirectory(tmp_profile_);
285
286    launch_arguments_.AppendSwitchPath(switches::kUserDataDir, tmp_profile_);
287  }
288
289  bool LaunchAppWithProfile() {
290    UITest::SetUp();
291    return true;
292  }
293
294  void TearDown() {
295    UITest::TearDown();
296    EXPECT_TRUE(file_util::DieFileDie(tmp_profile_, true));
297  }
298
299public:
300  FilePath tmp_profile_;
301};
302
303TEST_F(LaunchBrowserWithNonAsciiUserDatadir, TestNonAsciiUserDataDir) {
304  ASSERT_TRUE(LaunchAppWithProfile());
305  // Verify that the window is present.
306  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
307  ASSERT_TRUE(browser.get());
308}
309#endif  // defined(OS_WIN)
310
311class AppModeTest : public UITest {
312 public:
313  AppModeTest() {
314    // Load a local file.
315    FilePath test_file(test_data_directory_);
316    test_file = test_file.AppendASCII("title1.html");
317    GURL test_file_url(net::FilePathToFileURL(test_file));
318
319    launch_arguments_.AppendSwitchASCII(switches::kApp, test_file_url.spec());
320  }
321};
322
323TEST_F(AppModeTest, EnableAppModeTest) {
324  // Test that an application browser window loads correctly.
325
326  // Verify that the window is present.
327  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
328  ASSERT_TRUE(browser.get());
329
330  // Verify the browser is an application.
331  Browser::Type type;
332  ASSERT_TRUE(browser->GetType(&type));
333  EXPECT_EQ(Browser::TYPE_APP, type);
334}
335
336// Tests to ensure that the browser continues running in the background after
337// the last window closes.
338class RunInBackgroundTest : public UITest {
339 public:
340  RunInBackgroundTest() {
341    launch_arguments_.AppendSwitch(switches::kKeepAliveForTest);
342  }
343};
344
345TEST_F(RunInBackgroundTest, RunInBackgroundBasicTest) {
346  // Close the browser window, then open a new one - the browser should keep
347  // running.
348  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
349  ASSERT_TRUE(browser.get());
350  int window_count;
351  ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
352  EXPECT_EQ(1, window_count);
353  ASSERT_TRUE(browser->RunCommand(IDC_CLOSE_WINDOW));
354  ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
355  EXPECT_EQ(0, window_count);
356  ASSERT_TRUE(IsBrowserRunning());
357  ASSERT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_NORMAL, true));
358  ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
359  EXPECT_EQ(1, window_count);
360}
361
362// Tests to ensure that the browser continues running in the background after
363// the last window closes.
364class NoStartupWindowTest : public UITest {
365 public:
366  NoStartupWindowTest() {
367    launch_arguments_.AppendSwitch(switches::kNoStartupWindow);
368    launch_arguments_.AppendSwitch(switches::kKeepAliveForTest);
369  }
370};
371
372TEST_F(NoStartupWindowTest, NoStartupWindowBasicTest) {
373  // No browser window should be started by default.
374  int window_count;
375  ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
376  EXPECT_EQ(0, window_count);
377
378  // Starting a browser window should work just fine.
379  ASSERT_TRUE(IsBrowserRunning());
380  ASSERT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_NORMAL, true));
381  ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
382  EXPECT_EQ(1, window_count);
383}
384
385}  // namespace
386