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 "net/test/url_request/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 35using base::TimeDelta; 36using content::BrowserThread; 37 38const std::string NOLISTENERS_HTML = 39 "<html><head><title>nolisteners</title></head><body></body></html>"; 40 41const std::string UNLOAD_HTML = 42 "<html><head><title>unload</title></head><body>" 43 "<script>window.onunload=function(e){}</script></body></html>"; 44 45const 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 51const 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 59const 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 67const 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 72const 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 77const 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 84const 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 91const 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 99const 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 107const 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 114class 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 = base::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(net::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(net::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 197IN_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. 210IN_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 225IN_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. 239IN_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. 250IN_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 256IN_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. 262IN_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 276IN_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 = base::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) 301IN_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 310IN_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. 323IN_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. 330IN_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 340IN_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 351IN_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. 362IN_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. 374IN_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. 380IN_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. 390IN_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 417class 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 456class 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 491IN_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. 519IN_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). 535IN_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. 547IN_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). 567IN_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. 583IN_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 623IN_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