Index: chrome/browser/ui/browser_close_browsertest.cc |
diff --git a/chrome/browser/ui/browser_close_browsertest.cc b/chrome/browser/ui/browser_close_browsertest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b61682c4303b2053b327feb8dfe23a1a754195e4 |
--- /dev/null |
+++ b/chrome/browser/ui/browser_close_browsertest.cc |
@@ -0,0 +1,338 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/logging.h" |
+#include "base/stringprintf.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/download/download_item.h" |
+#include "chrome/browser/download/download_test_observer.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/profiles/profile_manager.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/browser_window.h" |
+#include "chrome/test/in_process_browser_test.h" |
+#include "chrome/test/ui_test_utils.h" |
+#include "content/browser/net/url_request_slow_download_job.h" |
+#include "content/browser/tab_contents/tab_contents.h" |
+#include "content/common/page_transition_types.h" |
+#include "content/common/url_constants.h" |
+ |
+class BrowserCloseTest : public InProcessBrowserTest { |
+ protected: |
+ Profile* CreateNewProfile() { |
sky
2011/07/21 20:08:11
Why is this here?
Randy Smith (Not in Mondays)
2011/07/21 21:36:31
See my answer to the question about the disabled t
|
+ NOTREACHED(); |
+ return NULL; |
+ } |
+ |
+ void CreateStalledDownload(Browser* browser, int num_downloads) { |
sky
2011/07/21 20:08:11
Please add descriptions for the methods that aren'
Randy Smith (Not in Mondays)
2011/07/21 21:36:31
Done.
|
+ GURL url(URLRequestSlowDownloadJob::kKnownSizeUrl); |
+ |
+ if (num_downloads == 0) |
+ return; |
+ |
+ // Setup an observer waiting for the given number of downloads |
+ // to get to IN_PROGRESS. |
+ DownloadManager* download_manager = |
+ browser->profile()->GetDownloadManager(); |
+ scoped_ptr<DownloadTestObserver> observer( |
+ new DownloadTestObserver( |
+ download_manager, num_downloads, |
+ DownloadItem::IN_PROGRESS, |
+ true, // Bail on select file |
+ DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL)); |
+ |
+ // Set of that number of downloads. |
+ while (num_downloads--) |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser, url, NEW_BACKGROUND_TAB, |
+ ui_test_utils::BROWSER_TEST_NONE); |
+ |
+ // Wait for them. |
+ observer->WaitForFinished(); |
+ } |
+ |
+ void CompleteAllDownloads() { |
+ GURL finish_url(URLRequestSlowDownloadJob::kFinishDownloadUrl); |
+ ui_test_utils::NavigateToURL(browser(), finish_url); |
+ |
+ // Go through and, for every single profile, wait until there are |
+ // no active downloads on that download manager. |
+ std::vector<Profile*> profiles( |
+ g_browser_process->profile_manager()->GetLoadedProfiles()); |
+ for (std::vector<Profile*>::const_iterator pit = profiles.begin(); |
+ pit != profiles.end(); ++pit) { |
+ if ((*pit)->HasCreatedDownloadManager()) { |
+ DownloadManager *mgr = (*pit)->GetDownloadManager(); |
+ scoped_refptr<DownloadTestFlushObserver> observer( |
+ new DownloadTestFlushObserver(mgr)); |
+ observer->WaitForFlush(); |
+ } |
+ } |
+ } |
+ |
+ Browser* CreateBrowserOnProfile(Profile* profile) { |
+ Browser* new_browser = Browser::Create(profile); |
+ new_browser->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL), |
+ PageTransition::START_PAGE); |
+ ui_test_utils::WaitForNavigation( |
+ &new_browser->GetSelectedTabContents()->controller()); |
+ new_browser->window()->Show(); |
+ return new_browser; |
+ } |
+ |
+ // Assumes a single browser on the profile passed in in *base_browser. |
+ bool AdjustBrowsersOnProfile(Browser** base_browser, int num_windows) { |
+ Browser::DownloadClosePreventionType type; |
+ int num_downloads_blocking; |
+ if (num_windows == 0) { |
+ if (!(*base_browser)->OkToCloseWithInProgressDownloads( |
+ &type, &num_downloads_blocking)) |
+ return false; |
+ (*base_browser)->window()->Close(); |
+ *base_browser = 0; |
+ return true; |
+ } |
+ |
+ // num_windows > 0 |
+ Profile* profile((*base_browser)->profile()); |
+ for (int w = 1; w < num_windows; w++) { |
+ CreateBrowserOnProfile(profile); |
+ } |
+ return true; |
+ } |
+ |
+}; |
+ |
+struct DownloadsCloseCheckCase { |
+ std::string DebugString() const; |
+ |
+ // Input |
+ struct { |
+ struct { |
+ int windows; |
+ int downloads; |
+ } regular; |
+ struct { |
+ int windows; |
+ int downloads; |
+ } incognito; |
+ } profile_a; |
+ |
+ struct { |
+ struct { |
+ int windows; |
+ int downloads; |
+ } regular; |
+ struct { |
+ int windows; |
+ int downloads; |
+ } incognito; |
+ } profile_b; |
+ |
+ // We always probe a window in profile A. |
+ enum { REGULAR = 0, INCOGNITO = 1 } window_to_probe; |
sky
2011/07/21 20:08:11
enums should be first.
Randy Smith (Not in Mondays)
2011/07/21 21:36:31
This line declares a member variable window_to_pro
sky
2011/07/22 03:00:40
Fair enough. Leave it.
Randy Smith (Not in Mondays)
2011/07/22 20:41:30
Done.
|
+ |
+ // Output |
+ bool warn; // Controlling; if we don't warn, the rest aren't checked. |
+ |
+ Browser::DownloadClosePreventionType type; |
+ int num_blocking; |
+}; |
+ |
+std::string DownloadsCloseCheckCase::DebugString() const { |
+ std::string result; |
+ result += "Case: {"; |
+ if (profile_a.regular.windows || profile_a.regular.downloads) |
+ result += base::StringPrintf("Regular profile A: (%d w, %d d), ", |
+ profile_a.regular.windows, |
+ profile_a.regular.downloads); |
+ if (profile_a.incognito.windows || profile_a.incognito.downloads) |
+ result += base::StringPrintf("Incognito profile A: (%d w, %d d), ", |
+ profile_a.incognito.windows, |
+ profile_a.incognito.downloads); |
+ if (profile_b.regular.windows || profile_b.regular.downloads) |
+ result += base::StringPrintf("Regular profile B: (%d w, %d d), ", |
+ profile_b.regular.windows, |
+ profile_b.regular.downloads); |
+ if (profile_b.incognito.windows || profile_b.incognito.downloads) |
+ result += base::StringPrintf("Incognito profile B: (%d w, %d d), ", |
+ profile_b.incognito.windows, |
+ profile_b.incognito.downloads); |
+ result += (window_to_probe == REGULAR ? "Probe regular" : |
+ window_to_probe == INCOGNITO ? "Probe incognito" : |
+ "Probe unknown"); |
+ result += "} -> "; |
+ if (!warn) { |
+ result += "No warning"; |
+ } else { |
+ result += base::StringPrintf( |
+ "%s (%d downloads) warning", |
+ (type == Browser::BROWSER_SHUTDOWN ? "Browser shutdown" : |
+ type == Browser::LAST_WINDOW_IN_INCOGNITO_PROFILE ? "Incognito close" : |
+ "Unknown"), num_blocking); |
+ } |
+ return result; |
+} |
+ |
+static const DownloadsCloseCheckCase download_close_check_cases[] = { |
+ // Top level nesting is {profile_a, profile_b} |
+ // Second level nesting is {regular, incognito |
+ // Third level (inner) nesting is {windows, downloads} |
+ |
+ // Last window (incognito) triggers browser close warning. |
+ {{{0, 0}, {1, 1}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::INCOGNITO, |
+ true, Browser::BROWSER_SHUTDOWN, 1}, |
+ |
+ // Last incognito window triggers incognito close warning. |
+ {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::INCOGNITO, |
+ true, Browser::LAST_WINDOW_IN_INCOGNITO_PROFILE, 1}, |
+ |
+ // Last incognito window with no downloads triggers no warning. |
+ {{{0, 0}, {1, 0}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::INCOGNITO, |
+ 1}, |
+ |
+ // Last incognito window with window+download on another incognito profile |
+ // triggers no warning. |
+ {{{0, 0}, {1, 0}}, {{0, 0}, {1, 1}}, DownloadsCloseCheckCase::INCOGNITO, |
+ 1}, |
+ |
+ // Non-last incognito window triggers no warning. |
+ {{{0, 0}, {2, 1}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::INCOGNITO, |
+ 1}, |
+ |
+ // Non-last regular window triggers no warning. |
+ {{{2, 1}, {0, 0}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::REGULAR, |
+ 1}, |
+ |
+ // Last regular window triggers browser close. |
+ {{{1, 1}, {0, 0}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::REGULAR, |
+ true, Browser::BROWSER_SHUTDOWN, 1}, |
+ |
+ // Last regular window triggers browser close for download on different |
+ // profile. |
+ {{{1, 0}, {0, 0}}, {{0, 1}, {0, 0}}, DownloadsCloseCheckCase::REGULAR, |
+ true, Browser::BROWSER_SHUTDOWN, 1}, |
+ |
+ // Last regular window triggers no warning if incognito |
+ // active (http://crbug.com/61257). |
+ {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::REGULAR, |
+ 1}, |
+ |
+ // Last regular window triggers no warning if other profile window active. |
+ {{{1, 1}, {0, 0}}, {{1, 0}, {0, 0}}, DownloadsCloseCheckCase::REGULAR, |
+ 1}, |
+ |
+ // Last regular window triggers no warning if other incognito window |
+ // active. |
+ {{{1, 0}, {0, 0}}, {{0, 0}, {1, 1}}, DownloadsCloseCheckCase::REGULAR, |
+ 1}, |
+ |
+ // Last regular window triggers no warning if incognito active. |
+ {{{1, 1}, {1, 0}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::REGULAR, |
+ 1}, |
+ |
+ // Test plural for regular. |
+ {{{1, 2}, {0, 0}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::REGULAR, |
+ true, Browser::BROWSER_SHUTDOWN, 2}, |
+ |
+ // Test plural for incognito. |
+ {{{1, 0}, {1, 2}}, {{0, 0}, {0, 0}}, DownloadsCloseCheckCase::INCOGNITO, |
+ true, Browser::LAST_WINDOW_IN_INCOGNITO_PROFILE, 2}, |
+}; |
+ |
+IN_PROC_BROWSER_TEST_F(BrowserCloseTest, DISABLED_DownloadsCloseCheck) { |
sky
2011/07/21 20:08:11
How come you're checking in a test that's disabled
Randy Smith (Not in Mondays)
2011/07/21 21:36:31
So if you'd like me to make that a separate CL, I'
sky
2011/07/22 03:00:40
My vote goes for separate cl with test in it.
Randy Smith (Not in Mondays)
2011/07/22 20:41:30
The postponement of multi-profile has made committ
|
+ Profile* profile_a = browser()->profile(); |
+ Profile* profile_b = CreateNewProfile(); |
+ |
+ for (size_t i = 0; i < arraysize(download_close_check_cases); ++i) { |
+ const DownloadsCloseCheckCase& check_case(download_close_check_cases[i]); |
+ |
+ // Loop invariant; so that we don't actually try and close the browser, |
+ // we always enter the loop with a single browser window open on the |
+ // main profile. That means we need to exit the loop the same way. |
+ // So we setup everything except for the profile_a regular, and then |
+ // flip the bit on the main window. |
+ // Note that this means that browser() is unreliable in the context |
+ // of this function; we'll be killing that main window and recreating |
+ // it fairly frequently. |
+ |
+ ASSERT_EQ(1u, BrowserList::size()); |
+ Browser* entry_browser = *BrowserList::begin(); |
+ ASSERT_EQ(profile_a, entry_browser->profile()); |
+ int total_downloads = 0; |
+ int profile_downloads = 0; |
+ entry_browser->CheckDownloadsInProgress( |
+ &total_downloads, &profile_downloads); |
+ ASSERT_EQ(0, total_downloads); |
+ |
+ Profile* profile_a_incognito = profile_a->GetOffTheRecordProfile(); |
+ Profile* profile_b_incognito = profile_b->GetOffTheRecordProfile(); |
+ |
+ // For simplicty of coding, we create a window on each profile so that |
+ // we can easily create downloads, then we destroy or create windows |
+ // as necessary. |
+ Browser* browser_a_regular(CreateBrowserOnProfile(profile_a)); |
+ Browser* browser_a_incognito(CreateBrowserOnProfile(profile_a_incognito)); |
+ Browser* browser_b_regular(CreateBrowserOnProfile(profile_b)); |
+ Browser* browser_b_incognito(CreateBrowserOnProfile(profile_b_incognito)); |
+ |
+ // Kill our entry browser. |
+ entry_browser->window()->Close(); |
+ entry_browser = NULL; |
+ |
+ // Create all downloads needed. |
+ CreateStalledDownload( |
+ browser_a_regular, check_case.profile_a.regular.downloads); |
+ CreateStalledDownload( |
+ browser_a_incognito, check_case.profile_a.incognito.downloads); |
+ CreateStalledDownload( |
+ browser_b_regular, check_case.profile_b.regular.downloads); |
+ CreateStalledDownload( |
+ browser_b_incognito, check_case.profile_b.incognito.downloads); |
+ |
+ // Adjust the windows |
+ ASSERT_TRUE(AdjustBrowsersOnProfile( |
+ &browser_a_regular, check_case.profile_a.regular.windows)); |
+ ASSERT_TRUE(AdjustBrowsersOnProfile( |
+ &browser_a_incognito, check_case.profile_a.incognito.windows)); |
+ ASSERT_TRUE(AdjustBrowsersOnProfile( |
+ &browser_b_regular, check_case.profile_b.regular.windows)); |
+ ASSERT_TRUE(AdjustBrowsersOnProfile( |
+ &browser_b_incognito, check_case.profile_b.incognito.windows)); |
+ |
+ // All that work, for this one little test. |
+ ASSERT_TRUE((check_case.window_to_probe == |
+ DownloadsCloseCheckCase::REGULAR) || |
+ (check_case.window_to_probe == |
+ DownloadsCloseCheckCase::INCOGNITO)); |
+ |
+ Browser::DownloadClosePreventionType type; |
+ int num_downloads_blocking; |
+ bool result = |
+ (check_case.window_to_probe == DownloadsCloseCheckCase::REGULAR ? |
+ browser_a_regular : |
+ browser_a_incognito)->OkToCloseWithInProgressDownloads( |
+ &type, &num_downloads_blocking); |
+ EXPECT_EQ(check_case.warn, result) << check_case.DebugString(); |
+ if (!result) { |
+ EXPECT_EQ(check_case.type, type) << check_case.DebugString(); |
+ EXPECT_EQ(check_case.num_blocking, num_downloads_blocking) |
+ << check_case.DebugString(); |
+ } |
+ |
+ // Release and all the downloads |
+ CompleteAllDownloads(); |
+ |
+ // Create a new main window and kill everything else. |
+ entry_browser = CreateBrowserOnProfile(profile_a); |
+ if (browser_a_regular) |
+ browser_a_regular->window()->Close(); |
+ if (browser_a_incognito) |
+ browser_a_incognito->window()->Close(); |
+ if (browser_b_regular) |
+ browser_b_regular->window()->Close(); |
+ if (browser_b_incognito) |
+ browser_b_incognito->window()->Close(); |
+ } |
+} |