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.
5 #include "base/command_line.h"
6 #include "base/logging.h"
7 #include "base/path_service.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/download/download_service.h"
12 #include "chrome/browser/download/download_service_factory.h"
13 #include "chrome/browser/download/download_test_file_activity_observer.h"
14 #include "chrome/browser/net/url_request_mock_util.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_iterator.h"
19 #include "chrome/browser/ui/browser_tabstrip.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/host_desktop.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "chrome/common/chrome_paths.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "chrome/test/base/in_process_browser_test.h"
27 #include "chrome/test/base/ui_test_utils.h"
28 #include "content/public/browser/download_item.h"
29 #include "content/public/common/page_transition_types.h"
30 #include "content/public/test/browser_test_utils.h"
31 #include "content/public/test/download_test_observer.h"
32 #include "content/test/net/url_request_slow_download_job.h"
34 using content::BrowserContext
;
35 using content::BrowserThread
;
36 using content::DownloadItem
;
37 using content::DownloadManager
;
38 using content::URLRequestSlowDownloadJob
;
40 class BrowserCloseTest
: public InProcessBrowserTest
{
42 // Structure defining test cases for DownloadsCloseCheck.
43 struct DownloadsCloseCheckCase
{
44 std::string
DebugString() const;
69 // We always probe a window in profile A.
70 enum { REGULAR
= 0, INCOGNITO
= 1 } window_to_probe
;
73 Browser::DownloadClosePreventionType type
;
75 // Unchecked if type == DOWNLOAD_CLOSE_OK.
80 virtual void SetUpOnMainThread() OVERRIDE
{
81 BrowserThread::PostTask(
82 BrowserThread::IO
, FROM_HERE
,
83 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled
, true));
86 // Create a second profile to work within multi-profile.
87 Profile
* CreateSecondProfile() {
88 base::FilePath user_data_dir
;
89 PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir
);
91 if (!second_profile_data_dir_
.CreateUniqueTempDirUnderPath(user_data_dir
))
94 Profile
* second_profile
=
95 g_browser_process
->profile_manager()->GetProfile(
96 second_profile_data_dir_
.path());
100 bool result
= second_profile_downloads_dir_
.CreateUniqueTempDir();
103 second_profile
->GetPrefs()->SetFilePath(
104 prefs::kDownloadDefaultDirectory
,
105 second_profile_downloads_dir_
.path());
107 return second_profile
;
110 // Create |num_downloads| number of downloads that are stalled
111 // (will quickly get to a place where the server won't
112 // provide any more data) so that we can test closing the
113 // browser with active downloads.
114 void CreateStalledDownloads(Browser
* browser
, int num_downloads
) {
115 GURL
url(URLRequestSlowDownloadJob::kKnownSizeUrl
);
117 if (num_downloads
== 0)
120 // Setup an observer waiting for the given number of downloads
121 // to get to IN_PROGRESS.
122 DownloadManager
* download_manager
=
123 BrowserContext::GetDownloadManager(browser
->profile());
124 scoped_ptr
<content::DownloadTestObserver
> observer(
125 new content::DownloadTestObserverInProgress(download_manager
,
128 // Set of that number of downloads.
129 size_t count_downloads
= num_downloads
;
130 while (num_downloads
--)
131 ui_test_utils::NavigateToURLWithDisposition(
132 browser
, url
, NEW_BACKGROUND_TAB
,
133 ui_test_utils::BROWSER_TEST_NONE
);
136 observer
->WaitForFinished();
137 EXPECT_EQ(count_downloads
,
138 observer
->NumDownloadsSeenInState(DownloadItem::IN_PROGRESS
));
141 // All all downloads created in CreateStalledDownloads() to
142 // complete, and block in this routine until they do complete.
143 void CompleteAllDownloads(Browser
* browser
) {
144 GURL
finish_url(URLRequestSlowDownloadJob::kFinishDownloadUrl
);
145 ui_test_utils::NavigateToURL(browser
, finish_url
);
147 // Go through and, for every single profile, wait until there are
148 // no active downloads on that download manager.
149 std::vector
<Profile
*> profiles(
150 g_browser_process
->profile_manager()->GetLoadedProfiles());
151 for (std::vector
<Profile
*>::const_iterator pit
= profiles
.begin();
152 pit
!= profiles
.end(); ++pit
) {
153 DownloadService
* download_service
=
154 DownloadServiceFactory::GetForBrowserContext(*pit
);
155 if (download_service
->HasCreatedDownloadManager()) {
156 DownloadManager
*mgr
= BrowserContext::GetDownloadManager(*pit
);
157 scoped_refptr
<content::DownloadTestFlushObserver
> observer(
158 new content::DownloadTestFlushObserver(mgr
));
159 observer
->WaitForFlush();
161 if ((*pit
)->HasOffTheRecordProfile()) {
162 DownloadService
* incognito_download_service
=
163 DownloadServiceFactory::GetForBrowserContext(
164 (*pit
)->GetOffTheRecordProfile());
165 if (incognito_download_service
->HasCreatedDownloadManager()) {
166 DownloadManager
*mgr
= BrowserContext::GetDownloadManager(
167 (*pit
)->GetOffTheRecordProfile());
168 scoped_refptr
<content::DownloadTestFlushObserver
> observer(
169 new content::DownloadTestFlushObserver(mgr
));
170 observer
->WaitForFlush();
176 // Create a Browser (with associated window) on the specified profile.
177 Browser
* CreateBrowserOnProfile(Profile
* profile
,
178 chrome::HostDesktopType host_desktop_type
) {
179 Browser
* new_browser
=
180 new Browser(Browser::CreateParams(profile
, host_desktop_type
));
181 chrome::AddSelectedTabWithURL(new_browser
, GURL(content::kAboutBlankURL
),
182 content::PAGE_TRANSITION_AUTO_TOPLEVEL
);
183 content::WaitForLoadStop(
184 new_browser
->tab_strip_model()->GetActiveWebContents());
185 new_browser
->window()->Show();
189 // Adjust the number of browsers and associated windows up or down
190 // to |num_windows|. This routine assumes that there is only a single
191 // browser associated with the profile on entry. |*base_browser| contains
192 // this browser, and the profile is derived from that browser. On output,
193 // if |*base_browser| was destroyed (because |num_windows == 0|), NULL
194 // is assigned to that memory location.
195 bool AdjustBrowsersOnProfile(Browser
** base_browser
, int num_windows
) {
196 int num_downloads_blocking
;
197 if (num_windows
== 0) {
198 if (Browser::DOWNLOAD_CLOSE_OK
!=
199 (*base_browser
)->OkToCloseWithInProgressDownloads(
200 &num_downloads_blocking
))
202 (*base_browser
)->window()->Close();
208 Profile
* profile((*base_browser
)->profile());
209 chrome::HostDesktopType host_desktop_type
=
210 (*base_browser
)->host_desktop_type();
211 for (int w
= 1; w
< num_windows
; ++w
) {
212 CreateBrowserOnProfile(profile
, host_desktop_type
);
217 int TotalUnclosedBrowsers() {
219 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
220 if (!it
->IsAttemptingToCloseBrowser())
226 // Note that this is invalid to call if TotalUnclosedBrowsers() == 0.
227 Browser
* FirstUnclosedBrowser() {
228 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
229 if (!it
->IsAttemptingToCloseBrowser())
235 bool SetupForDownloadCloseCheck() {
236 first_profile_
= browser()->profile();
238 bool result
= first_profile_downloads_dir_
.CreateUniqueTempDir();
240 if (!result
) return false;
241 first_profile_
->GetPrefs()->SetFilePath(
242 prefs::kDownloadDefaultDirectory
,
243 first_profile_downloads_dir_
.path());
245 second_profile_
= CreateSecondProfile();
246 EXPECT_TRUE(second_profile_
);
247 if (!second_profile_
) return false;
249 DownloadTestFileActivityObserver(first_profile_
) .EnableFileChooser(false);
250 DownloadTestFileActivityObserver(second_profile_
).EnableFileChooser(false);
254 // Test a specific DownloadsCloseCheckCase. Returns false if
255 // an assertion has failed and the test should be aborted.
256 bool ExecuteDownloadCloseCheckCase(size_t i
) {
257 const DownloadsCloseCheckCase
& check_case(download_close_check_cases
[i
]);
259 // Test invariant: so that we don't actually try and close the browser,
260 // we always enter the function with a single browser window open on the
261 // main profile. That means we need to exit the function the same way.
262 // So we setup everything except for the |first_profile_| regular, and then
263 // flip the bit on the main window.
264 // Note that this means that browser() is unreliable in the context
265 // of this function or its callers; we'll be killing that main window
266 // and recreating it fairly frequently.
267 int unclosed_browsers
= TotalUnclosedBrowsers();
268 EXPECT_EQ(1, unclosed_browsers
);
269 if (1 != unclosed_browsers
)
272 Browser
* entry_browser
= FirstUnclosedBrowser();
273 EXPECT_EQ(first_profile_
, entry_browser
->profile())
275 << ": " << check_case
.DebugString();
276 if (first_profile_
!= entry_browser
->profile())
278 int total_download_count
= DownloadService::DownloadCountAllProfiles();
279 EXPECT_EQ(0, total_download_count
)
281 << ": " << check_case
.DebugString();
282 if (0 != total_download_count
)
285 Profile
* first_profile_incognito
= first_profile_
->GetOffTheRecordProfile();
286 Profile
* second_profile_incognito
=
287 second_profile_
->GetOffTheRecordProfile();
288 DownloadTestFileActivityObserver(first_profile_incognito
)
289 .EnableFileChooser(false);
290 DownloadTestFileActivityObserver(second_profile_incognito
)
291 .EnableFileChooser(false);
293 // For simplicty of coding, we create a window on each profile so that
294 // we can easily create downloads, then we destroy or create windows
296 chrome::HostDesktopType host_desktop_type
=
297 entry_browser
->host_desktop_type();
298 Browser
* browser_a_regular(CreateBrowserOnProfile(first_profile_
,
300 Browser
* browser_a_incognito(
301 CreateBrowserOnProfile(first_profile_incognito
, host_desktop_type
));
302 Browser
* browser_b_regular(CreateBrowserOnProfile(second_profile_
,
304 Browser
* browser_b_incognito(
305 CreateBrowserOnProfile(second_profile_incognito
, host_desktop_type
));
307 // Kill our entry browser.
308 entry_browser
->window()->Close();
309 entry_browser
= NULL
;
311 // Create all downloads needed.
312 CreateStalledDownloads(
313 browser_a_regular
, check_case
.profile_a
.regular
.downloads
);
314 CreateStalledDownloads(
315 browser_a_incognito
, check_case
.profile_a
.incognito
.downloads
);
316 CreateStalledDownloads(
317 browser_b_regular
, check_case
.profile_b
.regular
.downloads
);
318 CreateStalledDownloads(
319 browser_b_incognito
, check_case
.profile_b
.incognito
.downloads
);
321 // Adjust the windows
322 Browser
** browsers
[] = {
323 &browser_a_regular
, &browser_a_incognito
,
324 &browser_b_regular
, &browser_b_incognito
326 int window_counts
[] = {
327 check_case
.profile_a
.regular
.windows
,
328 check_case
.profile_a
.incognito
.windows
,
329 check_case
.profile_b
.regular
.windows
,
330 check_case
.profile_b
.incognito
.windows
,
332 for (size_t j
= 0; j
< arraysize(browsers
); ++j
) {
333 bool result
= AdjustBrowsersOnProfile(browsers
[j
], window_counts
[j
]);
338 content::RunAllPendingInMessageLoop();
340 // All that work, for this one little test.
341 EXPECT_TRUE((check_case
.window_to_probe
==
342 DownloadsCloseCheckCase::REGULAR
) ||
343 (check_case
.window_to_probe
==
344 DownloadsCloseCheckCase::INCOGNITO
));
345 if (!((check_case
.window_to_probe
==
346 DownloadsCloseCheckCase::REGULAR
) ||
347 (check_case
.window_to_probe
==
348 DownloadsCloseCheckCase::INCOGNITO
)))
351 int num_downloads_blocking
;
352 Browser
* browser_to_probe
=
353 (check_case
.window_to_probe
== DownloadsCloseCheckCase::REGULAR
?
355 browser_a_incognito
);
356 Browser::DownloadClosePreventionType type
=
357 browser_to_probe
->OkToCloseWithInProgressDownloads(
358 &num_downloads_blocking
);
359 EXPECT_EQ(check_case
.type
, type
) << "Case " << i
360 << ": " << check_case
.DebugString();
361 if (type
!= Browser::DOWNLOAD_CLOSE_OK
)
362 EXPECT_EQ(check_case
.num_blocking
, num_downloads_blocking
)
364 << ": " << check_case
.DebugString();
366 // Release all the downloads.
367 CompleteAllDownloads(browser_to_probe
);
369 // Create a new main window and kill everything else.
370 entry_browser
= CreateBrowserOnProfile(first_profile_
, host_desktop_type
);
371 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
372 if ((*it
) != entry_browser
) {
377 it
->window()->Close();
380 content::RunAllPendingInMessageLoop();
385 static const DownloadsCloseCheckCase download_close_check_cases
[];
387 // DownloadCloseCheck variables.
388 Profile
* first_profile_
;
389 Profile
* second_profile_
;
391 base::ScopedTempDir first_profile_downloads_dir_
;
392 base::ScopedTempDir second_profile_data_dir_
;
393 base::ScopedTempDir second_profile_downloads_dir_
;
396 const BrowserCloseTest::DownloadsCloseCheckCase
397 BrowserCloseTest::download_close_check_cases
[] = {
398 // Top level nesting is {profile_a, profile_b}
399 // Second level nesting is {regular, incognito
400 // Third level (inner) nesting is {windows, downloads}
402 // Last window (incognito) triggers browser close warning.
403 {{{0, 0}, {1, 1}}, {{0, 0}, {0, 0}},
404 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
405 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
407 // Last incognito window triggers incognito close warning.
408 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
409 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
410 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
, 1},
412 // Last incognito window with no downloads triggers no warning.
413 {{{0, 0}, {1, 0}}, {{0, 0}, {0, 0}},
414 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
415 Browser::DOWNLOAD_CLOSE_OK
},
417 // Last incognito window with window+download on another incognito profile
418 // triggers no warning.
419 {{{0, 0}, {1, 0}}, {{0, 0}, {1, 1}},
420 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
421 Browser::DOWNLOAD_CLOSE_OK
},
423 // Non-last incognito window triggers no warning.
424 {{{0, 0}, {2, 1}}, {{0, 0}, {0, 0}},
425 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
426 Browser::DOWNLOAD_CLOSE_OK
},
428 // Non-last regular window triggers no warning.
429 {{{2, 1}, {0, 0}}, {{0, 0}, {0, 0}},
430 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
431 Browser::DOWNLOAD_CLOSE_OK
},
433 // Last regular window triggers browser close.
434 {{{1, 1}, {0, 0}}, {{0, 0}, {0, 0}},
435 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
436 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
438 // Last regular window triggers browser close for download on different
440 {{{1, 0}, {0, 0}}, {{0, 1}, {0, 0}},
441 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
442 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
444 // Last regular window triggers no warning if incognito
445 // active (http://crbug.com/61257).
446 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
447 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
448 Browser::DOWNLOAD_CLOSE_OK
},
450 // Last regular window triggers no warning if other profile window active.
451 {{{1, 1}, {0, 0}}, {{1, 0}, {0, 0}},
452 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
453 Browser::DOWNLOAD_CLOSE_OK
},
455 // Last regular window triggers no warning if other incognito window
457 {{{1, 0}, {0, 0}}, {{0, 0}, {1, 1}},
458 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
459 Browser::DOWNLOAD_CLOSE_OK
},
461 // Last regular window triggers no warning if incognito active.
462 {{{1, 1}, {1, 0}}, {{0, 0}, {0, 0}},
463 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
464 Browser::DOWNLOAD_CLOSE_OK
},
466 // Test plural for regular.
467 {{{1, 2}, {0, 0}}, {{0, 0}, {0, 0}},
468 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
469 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 2},
471 // Test plural for incognito.
472 {{{1, 0}, {1, 2}}, {{0, 0}, {0, 0}},
473 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
474 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
, 2},
477 std::string
BrowserCloseTest::DownloadsCloseCheckCase::DebugString() const {
480 if (profile_a
.regular
.windows
|| profile_a
.regular
.downloads
)
481 result
+= base::StringPrintf("Regular profile A: (%d w, %d d), ",
482 profile_a
.regular
.windows
,
483 profile_a
.regular
.downloads
);
484 if (profile_a
.incognito
.windows
|| profile_a
.incognito
.downloads
)
485 result
+= base::StringPrintf("Incognito profile A: (%d w, %d d), ",
486 profile_a
.incognito
.windows
,
487 profile_a
.incognito
.downloads
);
488 if (profile_b
.regular
.windows
|| profile_b
.regular
.downloads
)
489 result
+= base::StringPrintf("Regular profile B: (%d w, %d d), ",
490 profile_b
.regular
.windows
,
491 profile_b
.regular
.downloads
);
492 if (profile_b
.incognito
.windows
|| profile_b
.incognito
.downloads
)
493 result
+= base::StringPrintf("Incognito profile B: (%d w, %d d), ",
494 profile_b
.incognito
.windows
,
495 profile_b
.incognito
.downloads
);
496 result
+= (window_to_probe
== REGULAR
? "Probe regular" :
497 window_to_probe
== INCOGNITO
? "Probe incognito" :
500 if (type
== Browser::DOWNLOAD_CLOSE_OK
) {
501 result
+= "No warning";
503 result
+= base::StringPrintf(
504 "%s (%d downloads) warning",
505 (type
== Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
? "Browser shutdown" :
506 type
== Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
?
507 "Incognito close" : "Unknown"),
513 // The following test is split into six chunks to reduce the chance
514 // of hitting the 25s timeout.
516 // This test is timing out very often under AddressSanitizer.
517 // http://crbug.com/111914 and http://crbug.com/103371.
518 // Crashing on Linux. http://crbug.com/100566
519 // Timing out on XP debug. http://crbug.com/111914
520 // Timing out, http://crbug.com/159449 .
522 #define MAYBE_DownloadsCloseCheck_0 DISABLED_DownloadsCloseCheck_0
523 #define MAYBE_DownloadsCloseCheck_1 DISABLED_DownloadsCloseCheck_1
524 #define MAYBE_DownloadsCloseCheck_2 DISABLED_DownloadsCloseCheck_2
525 #define MAYBE_DownloadsCloseCheck_3 DISABLED_DownloadsCloseCheck_3
526 #define MAYBE_DownloadsCloseCheck_4 DISABLED_DownloadsCloseCheck_4
527 #define MAYBE_DownloadsCloseCheck_5 DISABLED_DownloadsCloseCheck_5
529 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_0
) {
530 ASSERT_TRUE(SetupForDownloadCloseCheck());
531 for (size_t i
= 0; i
< arraysize(download_close_check_cases
) / 6; ++i
) {
532 ExecuteDownloadCloseCheckCase(i
);
536 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_1
) {
537 ASSERT_TRUE(SetupForDownloadCloseCheck());
538 for (size_t i
= arraysize(download_close_check_cases
) / 6;
539 i
< 2 * arraysize(download_close_check_cases
) / 6; ++i
) {
540 ExecuteDownloadCloseCheckCase(i
);
544 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_2
) {
545 ASSERT_TRUE(SetupForDownloadCloseCheck());
546 for (size_t i
= 2 * arraysize(download_close_check_cases
) / 6;
547 i
< 3 * arraysize(download_close_check_cases
) / 6; ++i
) {
548 ExecuteDownloadCloseCheckCase(i
);
552 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_3
) {
553 ASSERT_TRUE(SetupForDownloadCloseCheck());
554 for (size_t i
= 3 * arraysize(download_close_check_cases
) / 6;
555 i
< 4 * arraysize(download_close_check_cases
) / 6; ++i
) {
556 ExecuteDownloadCloseCheckCase(i
);
560 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_4
) {
561 ASSERT_TRUE(SetupForDownloadCloseCheck());
562 for (size_t i
= 4 * arraysize(download_close_check_cases
) / 6;
563 i
< 5 * arraysize(download_close_check_cases
) / 6; ++i
) {
564 ExecuteDownloadCloseCheckCase(i
);
568 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_5
) {
569 ASSERT_TRUE(SetupForDownloadCloseCheck());
570 for (size_t i
= 5 * arraysize(download_close_check_cases
) / 6;
571 i
< 6 * arraysize(download_close_check_cases
) / 6; ++i
) {
572 ExecuteDownloadCloseCheckCase(i
);