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 #if defined(OS_POSIX) 6 #include <signal.h> 7 #endif 8 9 #include "base/command_line.h" 10 #include "base/logging.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "chrome/browser/chrome_notification_types.h" 13 #include "chrome/browser/net/url_request_mock_util.h" 14 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h" 15 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h" 16 #include "chrome/browser/ui/browser.h" 17 #include "chrome/browser/ui/browser_commands.h" 18 #include "chrome/browser/ui/browser_list.h" 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" 20 #include "chrome/common/chrome_switches.h" 21 #include "chrome/test/base/in_process_browser_test.h" 22 #include "chrome/test/base/ui_test_utils.h" 23 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/notification_service.h" 25 #include "content/public/browser/web_contents.h" 26 #include "content/public/test/browser_test_utils.h" 27 #include "content/test/net/url_request_mock_http_job.h" 28 #include "net/url_request/url_request_test_util.h" 29 30 #if defined(OS_WIN) 31 // For version specific disabled tests below (http://crbug.com/267597). 32 #include "base/win/windows_version.h" 33 #endif 34 35 using base::TimeDelta; 36 using content::BrowserThread; 37 38 const std::string NOLISTENERS_HTML = 39 "<html><head><title>nolisteners</title></head><body></body></html>"; 40 41 const std::string UNLOAD_HTML = 42 "<html><head><title>unload</title></head><body>" 43 "<script>window.onunload=function(e){}</script></body></html>"; 44 45 const std::string BEFORE_UNLOAD_HTML = 46 "<html><head><title>beforeunload</title></head><body>" 47 "<script>window.onbeforeunload=function(e){" 48 "setTimeout('document.title=\"cancelled\"', 0);return 'foo'}</script>" 49 "</body></html>"; 50 51 const std::string INNER_FRAME_WITH_FOCUS_HTML = 52 "<html><head><title>innerframewithfocus</title></head><body>" 53 "<script>window.onbeforeunload=function(e){return 'foo'}</script>" 54 "<iframe src=\"data:text/html,<html><head><script>window.onload=" 55 "function(){document.getElementById('box').focus()}</script>" 56 "<body><input id='box'></input></body></html>\"></iframe>" 57 "</body></html>"; 58 59 const std::string TWO_SECOND_BEFORE_UNLOAD_HTML = 60 "<html><head><title>twosecondbeforeunload</title></head><body>" 61 "<script>window.onbeforeunload=function(e){" 62 "var start = new Date().getTime();" 63 "while(new Date().getTime() - start < 2000){}" 64 "return 'foo';" 65 "}</script></body></html>"; 66 67 const std::string INFINITE_UNLOAD_HTML = 68 "<html><head><title>infiniteunload</title></head><body>" 69 "<script>window.onunload=function(e){while(true){}}</script>" 70 "</body></html>"; 71 72 const std::string INFINITE_BEFORE_UNLOAD_HTML = 73 "<html><head><title>infinitebeforeunload</title></head><body>" 74 "<script>window.onbeforeunload=function(e){while(true){}}</script>" 75 "</body></html>"; 76 77 const std::string INFINITE_UNLOAD_ALERT_HTML = 78 "<html><head><title>infiniteunloadalert</title></head><body>" 79 "<script>window.onunload=function(e){" 80 "while(true){}" 81 "alert('foo');" 82 "}</script></body></html>"; 83 84 const std::string INFINITE_BEFORE_UNLOAD_ALERT_HTML = 85 "<html><head><title>infinitebeforeunloadalert</title></head><body>" 86 "<script>window.onbeforeunload=function(e){" 87 "while(true){}" 88 "alert('foo');" 89 "}</script></body></html>"; 90 91 const std::string TWO_SECOND_UNLOAD_ALERT_HTML = 92 "<html><head><title>twosecondunloadalert</title></head><body>" 93 "<script>window.onunload=function(e){" 94 "var start = new Date().getTime();" 95 "while(new Date().getTime() - start < 2000){}" 96 "alert('foo');" 97 "}</script></body></html>"; 98 99 const std::string TWO_SECOND_BEFORE_UNLOAD_ALERT_HTML = 100 "<html><head><title>twosecondbeforeunloadalert</title></head><body>" 101 "<script>window.onbeforeunload=function(e){" 102 "var start = new Date().getTime();" 103 "while(new Date().getTime() - start < 2000){}" 104 "alert('foo');" 105 "}</script></body></html>"; 106 107 const std::string CLOSE_TAB_WHEN_OTHER_TAB_HAS_LISTENER = 108 "<html><head><title>only_one_unload</title></head>" 109 "<body onclick=\"window.open('data:text/html," 110 "<html><head><title>popup</title></head></body>')\" " 111 "onbeforeunload='return;'>" 112 "</body></html>"; 113 114 class UnloadTest : public InProcessBrowserTest { 115 public: 116 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 117 const testing::TestInfo* const test_info = 118 testing::UnitTest::GetInstance()->current_test_info(); 119 if (strcmp(test_info->name(), 120 "BrowserCloseTabWhenOtherTabHasListener") == 0) { 121 command_line->AppendSwitch(switches::kDisablePopupBlocking); 122 } else if (strcmp(test_info->name(), "BrowserTerminateBeforeUnload") == 0) { 123 #if defined(OS_POSIX) 124 DisableSIGTERMHandling(); 125 #endif 126 } 127 } 128 129 virtual void SetUpOnMainThread() OVERRIDE { 130 BrowserThread::PostTask( 131 BrowserThread::IO, FROM_HERE, 132 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); 133 } 134 135 void CheckTitle(const char* expected_title) { 136 base::string16 expected = ASCIIToUTF16(expected_title); 137 EXPECT_EQ(expected, 138 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 139 } 140 141 void NavigateToDataURL(const std::string& html_content, 142 const char* expected_title) { 143 ui_test_utils::NavigateToURL(browser(), 144 GURL("data:text/html," + html_content)); 145 CheckTitle(expected_title); 146 } 147 148 void NavigateToNolistenersFileTwice() { 149 GURL url(content::URLRequestMockHTTPJob::GetMockUrl( 150 base::FilePath(FILE_PATH_LITERAL("title2.html")))); 151 ui_test_utils::NavigateToURL(browser(), url); 152 CheckTitle("Title Of Awesomeness"); 153 ui_test_utils::NavigateToURL(browser(), url); 154 CheckTitle("Title Of Awesomeness"); 155 } 156 157 // Navigates to a URL asynchronously, then again synchronously. The first 158 // load is purposely async to test the case where the user loads another 159 // page without waiting for the first load to complete. 160 void NavigateToNolistenersFileTwiceAsync() { 161 GURL url(content::URLRequestMockHTTPJob::GetMockUrl( 162 base::FilePath(FILE_PATH_LITERAL("title2.html")))); 163 ui_test_utils::NavigateToURLWithDisposition(browser(), url, CURRENT_TAB, 0); 164 ui_test_utils::NavigateToURL(browser(), url); 165 CheckTitle("Title Of Awesomeness"); 166 } 167 168 void LoadUrlAndQuitBrowser(const std::string& html_content, 169 const char* expected_title) { 170 NavigateToDataURL(html_content, expected_title); 171 content::WindowedNotificationObserver window_observer( 172 chrome::NOTIFICATION_BROWSER_CLOSED, 173 content::NotificationService::AllSources()); 174 chrome::CloseWindow(browser()); 175 window_observer.Wait(); 176 } 177 178 // If |accept| is true, simulates user clicking OK, otherwise simulates 179 // clicking Cancel. 180 void ClickModalDialogButton(bool accept) { 181 AppModalDialog* dialog = ui_test_utils::WaitForAppModalDialog(); 182 ASSERT_TRUE(dialog->IsJavaScriptModalDialog()); 183 JavaScriptAppModalDialog* js_dialog = 184 static_cast<JavaScriptAppModalDialog*>(dialog); 185 if (accept) 186 js_dialog->native_dialog()->AcceptAppModalDialog(); 187 else 188 js_dialog->native_dialog()->CancelAppModalDialog(); 189 } 190 }; 191 192 // Navigate to a page with an infinite unload handler. 193 // Then two async crosssite requests to ensure 194 // we don't get confused and think we're closing the tab. 195 // 196 // This test is flaky on the valgrind UI bots. http://crbug.com/39057 197 IN_PROC_BROWSER_TEST_F(UnloadTest, CrossSiteInfiniteUnloadAsync) { 198 // Tests makes no sense in single-process mode since the renderer is hung. 199 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 200 return; 201 202 NavigateToDataURL(INFINITE_UNLOAD_HTML, "infiniteunload"); 203 // Must navigate to a non-data URL to trigger cross-site codepath. 204 NavigateToNolistenersFileTwiceAsync(); 205 } 206 207 // Navigate to a page with an infinite unload handler. 208 // Then two sync crosssite requests to ensure 209 // we correctly nav to each one. 210 IN_PROC_BROWSER_TEST_F(UnloadTest, CrossSiteInfiniteUnloadSync) { 211 // Tests makes no sense in single-process mode since the renderer is hung. 212 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 213 return; 214 215 NavigateToDataURL(INFINITE_UNLOAD_HTML, "infiniteunload"); 216 // Must navigate to a non-data URL to trigger cross-site codepath. 217 NavigateToNolistenersFileTwice(); 218 } 219 220 // Navigate to a page with an infinite beforeunload handler. 221 // Then two two async crosssite requests to ensure 222 // we don't get confused and think we're closing the tab. 223 // This test is flaky on the valgrind UI bots. http://crbug.com/39057 and 224 // http://crbug.com/86469 225 IN_PROC_BROWSER_TEST_F(UnloadTest, CrossSiteInfiniteBeforeUnloadAsync) { 226 // Tests makes no sense in single-process mode since the renderer is hung. 227 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 228 return; 229 230 NavigateToDataURL(INFINITE_BEFORE_UNLOAD_HTML, "infinitebeforeunload"); 231 // Must navigate to a non-data URL to trigger cross-site codepath. 232 NavigateToNolistenersFileTwiceAsync(); 233 } 234 235 // Navigate to a page with an infinite beforeunload handler. 236 // Then two two sync crosssite requests to ensure 237 // we correctly nav to each one. 238 // If this flakes, see bug http://crbug.com/86469. 239 IN_PROC_BROWSER_TEST_F(UnloadTest, CrossSiteInfiniteBeforeUnloadSync) { 240 // Tests makes no sense in single-process mode since the renderer is hung. 241 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 242 return; 243 244 NavigateToDataURL(INFINITE_BEFORE_UNLOAD_HTML, "infinitebeforeunload"); 245 // Must navigate to a non-data URL to trigger cross-site codepath. 246 NavigateToNolistenersFileTwice(); 247 } 248 249 // Tests closing the browser on a page with no unload listeners registered. 250 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseNoUnloadListeners) { 251 LoadUrlAndQuitBrowser(NOLISTENERS_HTML, "nolisteners"); 252 } 253 254 // Tests closing the browser on a page with an unload listener registered. 255 // Test marked as flaky in http://crbug.com/51698 256 IN_PROC_BROWSER_TEST_F(UnloadTest, DISABLED_BrowserCloseUnload) { 257 LoadUrlAndQuitBrowser(UNLOAD_HTML, "unload"); 258 } 259 260 // Tests closing the browser with a beforeunload handler and clicking 261 // OK in the beforeunload confirm dialog. 262 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseBeforeUnloadOK) { 263 NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload"); 264 265 content::WindowedNotificationObserver window_observer( 266 chrome::NOTIFICATION_BROWSER_CLOSED, 267 content::NotificationService::AllSources()); 268 chrome::CloseWindow(browser()); 269 ClickModalDialogButton(true); 270 window_observer.Wait(); 271 } 272 273 // Tests closing the browser with a beforeunload handler and clicking 274 // CANCEL in the beforeunload confirm dialog. 275 // If this test flakes, reopen http://crbug.com/123110 276 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseBeforeUnloadCancel) { 277 NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload"); 278 chrome::CloseWindow(browser()); 279 280 // We wait for the title to change after cancelling the popup to ensure that 281 // in-flight IPCs from the renderer reach the browser. Otherwise the browser 282 // won't put up the beforeunload dialog because it's waiting for an ack from 283 // the renderer. 284 base::string16 expected_title = ASCIIToUTF16("cancelled"); 285 content::TitleWatcher title_watcher( 286 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); 287 ClickModalDialogButton(false); 288 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 289 290 content::WindowedNotificationObserver window_observer( 291 chrome::NOTIFICATION_BROWSER_CLOSED, 292 content::NotificationService::AllSources()); 293 chrome::CloseWindow(browser()); 294 ClickModalDialogButton(true); 295 window_observer.Wait(); 296 } 297 298 // Tests terminating the browser with a beforeunload handler. 299 // Currently only ChromeOS shuts down gracefully. 300 #if defined(OS_CHROMEOS) 301 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserTerminateBeforeUnload) { 302 NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload"); 303 EXPECT_EQ(kill(base::GetCurrentProcessHandle(), SIGTERM), 0); 304 } 305 #endif 306 307 // Tests closing the browser and clicking OK in the beforeunload confirm dialog 308 // if an inner frame has the focus. 309 // If this flakes, use http://crbug.com/32615 and http://crbug.com/45675 310 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseWithInnerFocusedFrame) { 311 NavigateToDataURL(INNER_FRAME_WITH_FOCUS_HTML, "innerframewithfocus"); 312 313 content::WindowedNotificationObserver window_observer( 314 chrome::NOTIFICATION_BROWSER_CLOSED, 315 content::NotificationService::AllSources()); 316 chrome::CloseWindow(browser()); 317 ClickModalDialogButton(true); 318 window_observer.Wait(); 319 } 320 321 // Tests closing the browser with a beforeunload handler that takes 322 // two seconds to run. 323 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTwoSecondBeforeUnload) { 324 LoadUrlAndQuitBrowser(TWO_SECOND_BEFORE_UNLOAD_HTML, 325 "twosecondbeforeunload"); 326 } 327 328 // Tests closing the browser on a page with an unload listener registered where 329 // the unload handler has an infinite loop. 330 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseInfiniteUnload) { 331 // Tests makes no sense in single-process mode since the renderer is hung. 332 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 333 return; 334 335 LoadUrlAndQuitBrowser(INFINITE_UNLOAD_HTML, "infiniteunload"); 336 } 337 338 // Tests closing the browser with a beforeunload handler that hangs. 339 // If this flakes, use http://crbug.com/78803 and http://crbug.com/86469 340 IN_PROC_BROWSER_TEST_F(UnloadTest, DISABLED_BrowserCloseInfiniteBeforeUnload) { 341 // Tests makes no sense in single-process mode since the renderer is hung. 342 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 343 return; 344 345 LoadUrlAndQuitBrowser(INFINITE_BEFORE_UNLOAD_HTML, "infinitebeforeunload"); 346 } 347 348 // Tests closing the browser on a page with an unload listener registered where 349 // the unload handler has an infinite loop followed by an alert. 350 // If this flakes, use http://crbug.com/86469 351 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseInfiniteUnloadAlert) { 352 // Tests makes no sense in single-process mode since the renderer is hung. 353 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 354 return; 355 356 LoadUrlAndQuitBrowser(INFINITE_UNLOAD_ALERT_HTML, "infiniteunloadalert"); 357 } 358 359 // Tests closing the browser with a beforeunload handler that hangs then 360 // pops up an alert. 361 // If this flakes, use http://crbug.com/78803 and http://crbug.com/86469. 362 IN_PROC_BROWSER_TEST_F(UnloadTest, 363 DISABLED_BrowserCloseInfiniteBeforeUnloadAlert) { 364 // Tests makes no sense in single-process mode since the renderer is hung. 365 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 366 return; 367 368 LoadUrlAndQuitBrowser(INFINITE_BEFORE_UNLOAD_ALERT_HTML, 369 "infinitebeforeunloadalert"); 370 } 371 372 // Tests closing the browser on a page with an unload listener registered where 373 // the unload handler has an 2 second long loop followed by an alert. 374 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTwoSecondUnloadAlert) { 375 LoadUrlAndQuitBrowser(TWO_SECOND_UNLOAD_ALERT_HTML, "twosecondunloadalert"); 376 } 377 378 // Tests closing the browser with a beforeunload handler that takes 379 // two seconds to run then pops up an alert. 380 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTwoSecondBeforeUnloadAlert) { 381 LoadUrlAndQuitBrowser(TWO_SECOND_BEFORE_UNLOAD_ALERT_HTML, 382 "twosecondbeforeunloadalert"); 383 } 384 385 // Tests that if there's a renderer process with two tabs, one of which has an 386 // unload handler, and the other doesn't, the tab that doesn't have an unload 387 // handler can be closed. 388 // If this flakes, see http://crbug.com/45162, http://crbug.com/45281 and 389 // http://crbug.com/86769. 390 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTabWhenOtherTabHasListener) { 391 NavigateToDataURL(CLOSE_TAB_WHEN_OTHER_TAB_HAS_LISTENER, "only_one_unload"); 392 393 // Simulate a click to force user_gesture to true; if we don't, the resulting 394 // popup will be constrained, which isn't what we want to test. 395 396 content::WindowedNotificationObserver observer( 397 chrome::NOTIFICATION_TAB_ADDED, 398 content::NotificationService::AllSources()); 399 content::WindowedNotificationObserver load_stop_observer( 400 content::NOTIFICATION_LOAD_STOP, 401 content::NotificationService::AllSources()); 402 content::SimulateMouseClick( 403 browser()->tab_strip_model()->GetActiveWebContents(), 0, 404 blink::WebMouseEvent::ButtonLeft); 405 observer.Wait(); 406 load_stop_observer.Wait(); 407 CheckTitle("popup"); 408 409 content::WebContentsDestroyedWatcher destroyed_watcher( 410 browser()->tab_strip_model()->GetActiveWebContents()); 411 chrome::CloseTab(browser()); 412 destroyed_watcher.Wait(); 413 414 CheckTitle("only_one_unload"); 415 } 416 417 class FastUnloadTest : public UnloadTest { 418 public: 419 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 420 UnloadTest::SetUpCommandLine(command_line); 421 command_line->AppendSwitch(switches::kEnableFastUnload); 422 } 423 424 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 425 ASSERT_TRUE(test_server()->Start()); 426 } 427 428 virtual void TearDownInProcessBrowserTestFixture() OVERRIDE { 429 test_server()->Stop(); 430 } 431 432 GURL GetUrl(const std::string& name) { 433 return GURL(test_server()->GetURL( 434 "files/fast_tab_close/" + name + ".html")); 435 } 436 437 void NavigateToPage(const char* name) { 438 ui_test_utils::NavigateToURL(browser(), GetUrl(name)); 439 CheckTitle(name); 440 } 441 442 void NavigateToPageInNewTab(const char* name) { 443 ui_test_utils::NavigateToURLWithDisposition( 444 browser(), GetUrl(name), NEW_FOREGROUND_TAB, 445 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); 446 CheckTitle(name); 447 } 448 449 std::string GetCookies(const char* name) { 450 content::WebContents* contents = 451 browser()->tab_strip_model()->GetActiveWebContents(); 452 return content::GetCookies(contents->GetBrowserContext(), GetUrl(name)); 453 } 454 }; 455 456 class FastTabCloseTabStripModelObserver : public TabStripModelObserver { 457 public: 458 FastTabCloseTabStripModelObserver(TabStripModel* model, 459 base::RunLoop* run_loop) 460 : model_(model), 461 run_loop_(run_loop) { 462 model_->AddObserver(this); 463 } 464 465 virtual ~FastTabCloseTabStripModelObserver() { 466 model_->RemoveObserver(this); 467 } 468 469 // TabStripModelObserver: 470 virtual void TabDetachedAt(content::WebContents* contents, 471 int index) OVERRIDE { 472 run_loop_->Quit(); 473 } 474 475 private: 476 TabStripModel* const model_; 477 base::RunLoop* const run_loop_; 478 }; 479 480 481 // Test that fast-tab-close works when closing a tab with an unload handler 482 // (http://crbug.com/142458). 483 // Flaky on Windows bots (http://crbug.com/267597). 484 #if defined(OS_WIN) 485 #define MAYBE_UnloadHidden \ 486 DISABLED_UnloadHidden 487 #else 488 #define MAYBE_UnloadHidden \ 489 UnloadHidden 490 #endif 491 IN_PROC_BROWSER_TEST_F(FastUnloadTest, MAYBE_UnloadHidden) { 492 NavigateToPage("no_listeners"); 493 NavigateToPageInNewTab("unload_sets_cookie"); 494 EXPECT_EQ("", GetCookies("no_listeners")); 495 496 content::WebContentsDestroyedWatcher destroyed_watcher( 497 browser()->tab_strip_model()->GetActiveWebContents()); 498 499 { 500 base::RunLoop run_loop; 501 FastTabCloseTabStripModelObserver observer( 502 browser()->tab_strip_model(), &run_loop); 503 chrome::CloseTab(browser()); 504 run_loop.Run(); 505 } 506 507 // Check that the browser only has the original tab. 508 CheckTitle("no_listeners"); 509 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 510 511 // Wait for the actual destruction. 512 destroyed_watcher.Wait(); 513 514 // Verify that the destruction had the desired effect. 515 EXPECT_EQ("unloaded=ohyeah", GetCookies("no_listeners")); 516 } 517 518 // Test that fast-tab-close does not break a solo tab. 519 IN_PROC_BROWSER_TEST_F(FastUnloadTest, PRE_ClosingLastTabFinishesUnload) { 520 // The unload handler sleeps before setting the cookie to catch cases when 521 // unload handlers are not allowed to run to completion. (For example, 522 // using the detached handler for the tab and then closing the browser.) 523 NavigateToPage("unload_sleep_before_cookie"); 524 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 525 EXPECT_EQ("", GetCookies("unload_sleep_before_cookie")); 526 527 content::WindowedNotificationObserver window_observer( 528 chrome::NOTIFICATION_BROWSER_CLOSED, 529 content::NotificationService::AllSources()); 530 chrome::CloseTab(browser()); 531 window_observer.Wait(); 532 } 533 534 // Fails on Mac, Linux, Win7 (http://crbug.com/301173). 535 IN_PROC_BROWSER_TEST_F(FastUnloadTest, DISABLED_ClosingLastTabFinishesUnload) { 536 #if defined(OS_WIN) 537 // Flaky on Win7+ bots (http://crbug.com/267597). 538 if (base::win::GetVersion() >= base::win::VERSION_WIN7) 539 return; 540 #endif 541 // Check for cookie set in unload handler of PRE_ test. 542 NavigateToPage("no_listeners"); 543 EXPECT_EQ("unloaded=ohyeah", GetCookies("no_listeners")); 544 } 545 546 // Test that fast-tab-close does not break window close. 547 IN_PROC_BROWSER_TEST_F(FastUnloadTest, PRE_WindowCloseFinishesUnload) { 548 NavigateToPage("no_listeners"); 549 550 // The unload handler sleeps before setting the cookie to catch cases when 551 // unload handlers are not allowed to run to completion. Without the sleep, 552 // the cookie can get set even if the browser does not wait for 553 // the unload handler to finish. 554 NavigateToPageInNewTab("unload_sleep_before_cookie"); 555 EXPECT_EQ(2, browser()->tab_strip_model()->count()); 556 EXPECT_EQ("", GetCookies("no_listeners")); 557 558 content::WindowedNotificationObserver window_observer( 559 chrome::NOTIFICATION_BROWSER_CLOSED, 560 content::NotificationService::AllSources()); 561 chrome::CloseWindow(browser()); 562 window_observer.Wait(); 563 } 564 565 // Flaky on Windows bots (http://crbug.com/279267) and fails on Mac / Linux bots 566 // (http://crbug.com/301173). 567 IN_PROC_BROWSER_TEST_F(FastUnloadTest, DISABLED_WindowCloseFinishesUnload) { 568 // Check for cookie set in unload during PRE_ test. 569 NavigateToPage("no_listeners"); 570 EXPECT_EQ("unloaded=ohyeah", GetCookies("no_listeners")); 571 } 572 573 // Test that a tab crash during unload does not break window close. 574 // 575 // Hits assertion on Linux and Mac: 576 // [FATAL:profile_destroyer.cc(46)] Check failed: 577 // hosts.empty() || 578 // profile->IsOffTheRecord() || 579 // content::RenderProcessHost::run_renderer_in_process(). 580 // More details: The renderer process host matches the closed, crashed tab. 581 // The |UnloadController| receives |NOTIFICATION_WEB_CONTENTS_DISCONNECTED| 582 // and proceeds with the close. 583 IN_PROC_BROWSER_TEST_F(FastUnloadTest, DISABLED_WindowCloseAfterUnloadCrash) { 584 NavigateToPage("no_listeners"); 585 NavigateToPageInNewTab("unload_sets_cookie"); 586 content::WebContents* unload_contents = 587 browser()->tab_strip_model()->GetActiveWebContents(); 588 EXPECT_EQ("", GetCookies("no_listeners")); 589 590 { 591 base::RunLoop run_loop; 592 FastTabCloseTabStripModelObserver observer( 593 browser()->tab_strip_model(), &run_loop); 594 chrome::CloseTab(browser()); 595 run_loop.Run(); 596 } 597 598 // Check that the browser only has the original tab. 599 CheckTitle("no_listeners"); 600 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 601 602 CrashTab(unload_contents); 603 604 // Check that the browser only has the original tab. 605 CheckTitle("no_listeners"); 606 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 607 608 content::WindowedNotificationObserver window_observer( 609 chrome::NOTIFICATION_BROWSER_CLOSED, 610 content::NotificationService::AllSources()); 611 chrome::CloseWindow(browser()); 612 window_observer.Wait(); 613 } 614 615 // Times out on Windows and Linux. 616 #if defined(OS_WIN) || defined(OS_LINUX) 617 #define MAYBE_WindowCloseAfterBeforeUnloadCrash \ 618 DISABLED_WindowCloseAfterBeforeUnloadCrash 619 #else 620 #define MAYBE_WindowCloseAfterBeforeUnloadCrash \ 621 WindowCloseAfterBeforeUnloadCrash 622 #endif 623 IN_PROC_BROWSER_TEST_F(FastUnloadTest, 624 MAYBE_WindowCloseAfterBeforeUnloadCrash) { 625 // Tests makes no sense in single-process mode since the renderer is hung. 626 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 627 return; 628 629 NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload"); 630 content::WebContents* beforeunload_contents = 631 browser()->tab_strip_model()->GetActiveWebContents(); 632 633 content::WindowedNotificationObserver window_observer( 634 chrome::NOTIFICATION_BROWSER_CLOSED, 635 content::NotificationService::AllSources()); 636 chrome::CloseWindow(browser()); 637 CrashTab(beforeunload_contents); 638 window_observer.Wait(); 639 } 640 641 // TODO(ojan): Add tests for unload/beforeunload that have multiple tabs 642 // and multiple windows. 643