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