unload_browsertest.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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
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 = 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
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 = 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