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/test/browser_test_utils.h"
30 #include "content/public/test/download_test_observer.h"
31 #include "net/test/url_request/url_request_slow_download_job.h"
32 #include "ui/base/page_transition_types.h"
34 using content::BrowserContext
;
35 using content::BrowserThread
;
36 using content::DownloadItem
;
37 using content::DownloadManager
;
39 class BrowserCloseTest
: public InProcessBrowserTest
{
41 // Structure defining test cases for DownloadsCloseCheck.
42 struct DownloadsCloseCheckCase
{
43 std::string
DebugString() const;
68 // We always probe a window in profile A.
69 enum { REGULAR
= 0, INCOGNITO
= 1 } window_to_probe
;
72 Browser::DownloadClosePreventionType type
;
74 // Unchecked if type == DOWNLOAD_CLOSE_OK.
79 void SetUpOnMainThread() override
{
80 BrowserThread::PostTask(
81 BrowserThread::IO
, FROM_HERE
,
82 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled
, true));
85 // Create a second profile to work within multi-profile.
86 Profile
* CreateSecondProfile() {
87 base::FilePath user_data_dir
;
88 PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir
);
90 if (!second_profile_data_dir_
.CreateUniqueTempDirUnderPath(user_data_dir
))
93 Profile
* second_profile
=
94 g_browser_process
->profile_manager()->GetProfile(
95 second_profile_data_dir_
.path());
99 bool result
= second_profile_downloads_dir_
.CreateUniqueTempDir();
102 second_profile
->GetPrefs()->SetFilePath(
103 prefs::kDownloadDefaultDirectory
,
104 second_profile_downloads_dir_
.path());
106 return second_profile
;
109 // Create |num_downloads| number of downloads that are stalled
110 // (will quickly get to a place where the server won't
111 // provide any more data) so that we can test closing the
112 // browser with active downloads.
113 void CreateStalledDownloads(Browser
* browser
, int num_downloads
) {
114 GURL
url(net::URLRequestSlowDownloadJob::kKnownSizeUrl
);
116 if (num_downloads
== 0)
119 // Setup an observer waiting for the given number of downloads
120 // to get to IN_PROGRESS.
121 DownloadManager
* download_manager
=
122 BrowserContext::GetDownloadManager(browser
->profile());
123 scoped_ptr
<content::DownloadTestObserver
> observer(
124 new content::DownloadTestObserverInProgress(download_manager
,
127 // Set of that number of downloads.
128 size_t count_downloads
= num_downloads
;
129 while (num_downloads
--)
130 ui_test_utils::NavigateToURLWithDisposition(
131 browser
, url
, NEW_BACKGROUND_TAB
,
132 ui_test_utils::BROWSER_TEST_NONE
);
135 observer
->WaitForFinished();
136 EXPECT_EQ(count_downloads
,
137 observer
->NumDownloadsSeenInState(DownloadItem::IN_PROGRESS
));
140 // All all downloads created in CreateStalledDownloads() to
141 // complete, and block in this routine until they do complete.
142 void CompleteAllDownloads(Browser
* browser
) {
143 GURL
finish_url(net::URLRequestSlowDownloadJob::kFinishDownloadUrl
);
144 ui_test_utils::NavigateToURL(browser
, finish_url
);
146 // Go through and, for every single profile, wait until there are
147 // no active downloads on that download manager.
148 std::vector
<Profile
*> profiles(
149 g_browser_process
->profile_manager()->GetLoadedProfiles());
150 for (std::vector
<Profile
*>::const_iterator pit
= profiles
.begin();
151 pit
!= profiles
.end(); ++pit
) {
152 DownloadService
* download_service
=
153 DownloadServiceFactory::GetForBrowserContext(*pit
);
154 if (download_service
->HasCreatedDownloadManager()) {
155 DownloadManager
*mgr
= BrowserContext::GetDownloadManager(*pit
);
156 scoped_refptr
<content::DownloadTestFlushObserver
> observer(
157 new content::DownloadTestFlushObserver(mgr
));
158 observer
->WaitForFlush();
160 if ((*pit
)->HasOffTheRecordProfile()) {
161 DownloadService
* incognito_download_service
=
162 DownloadServiceFactory::GetForBrowserContext(
163 (*pit
)->GetOffTheRecordProfile());
164 if (incognito_download_service
->HasCreatedDownloadManager()) {
165 DownloadManager
*mgr
= BrowserContext::GetDownloadManager(
166 (*pit
)->GetOffTheRecordProfile());
167 scoped_refptr
<content::DownloadTestFlushObserver
> observer(
168 new content::DownloadTestFlushObserver(mgr
));
169 observer
->WaitForFlush();
175 // Create a Browser (with associated window) on the specified profile.
176 Browser
* CreateBrowserOnProfile(Profile
* profile
,
177 chrome::HostDesktopType host_desktop_type
) {
178 Browser
* new_browser
=
179 new Browser(Browser::CreateParams(profile
, host_desktop_type
));
180 chrome::AddSelectedTabWithURL(new_browser
,
181 GURL(url::kAboutBlankURL
),
182 ui::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
]);
258 SCOPED_TRACE(testing::Message() << "Case" << i
259 << ": " << check_case
.DebugString());
261 // Test invariant: so that we don't actually try and close the browser,
262 // we always enter the function with a single browser window open on the
263 // main profile. That means we need to exit the function the same way.
264 // So we setup everything except for the |first_profile_| regular, and then
265 // flip the bit on the main window.
266 // Note that this means that browser() is unreliable in the context
267 // of this function or its callers; we'll be killing that main window
268 // and recreating it fairly frequently.
269 int unclosed_browsers
= TotalUnclosedBrowsers();
270 EXPECT_EQ(1, unclosed_browsers
);
271 if (1 != unclosed_browsers
)
274 Browser
* entry_browser
= FirstUnclosedBrowser();
275 EXPECT_EQ(first_profile_
, entry_browser
->profile());
276 if (first_profile_
!= entry_browser
->profile())
278 int total_download_count
=
279 DownloadService::NonMaliciousDownloadCountAllProfiles();
280 EXPECT_EQ(0, total_download_count
);
281 if (0 != total_download_count
)
283 Profile
* first_profile_incognito
= first_profile_
->GetOffTheRecordProfile();
284 Profile
* second_profile_incognito
=
285 second_profile_
->GetOffTheRecordProfile();
286 DownloadTestFileActivityObserver(first_profile_incognito
)
287 .EnableFileChooser(false);
288 DownloadTestFileActivityObserver(second_profile_incognito
)
289 .EnableFileChooser(false);
291 // For simplicty of coding, we create a window on each profile so that
292 // we can easily create downloads, then we destroy or create windows
294 chrome::HostDesktopType host_desktop_type
=
295 entry_browser
->host_desktop_type();
296 Browser
* browser_a_regular(CreateBrowserOnProfile(first_profile_
,
298 Browser
* browser_a_incognito(
299 CreateBrowserOnProfile(first_profile_incognito
, host_desktop_type
));
300 Browser
* browser_b_regular(CreateBrowserOnProfile(second_profile_
,
302 Browser
* browser_b_incognito(
303 CreateBrowserOnProfile(second_profile_incognito
, host_desktop_type
));
305 // Kill our entry browser.
306 entry_browser
->window()->Close();
307 entry_browser
= NULL
;
309 // Create all downloads needed.
310 CreateStalledDownloads(
311 browser_a_regular
, check_case
.profile_a
.regular
.downloads
);
312 CreateStalledDownloads(
313 browser_a_incognito
, check_case
.profile_a
.incognito
.downloads
);
314 CreateStalledDownloads(
315 browser_b_regular
, check_case
.profile_b
.regular
.downloads
);
316 CreateStalledDownloads(
317 browser_b_incognito
, check_case
.profile_b
.incognito
.downloads
);
319 // Adjust the windows
320 Browser
** browsers
[] = {
321 &browser_a_regular
, &browser_a_incognito
,
322 &browser_b_regular
, &browser_b_incognito
324 int window_counts
[] = {
325 check_case
.profile_a
.regular
.windows
,
326 check_case
.profile_a
.incognito
.windows
,
327 check_case
.profile_b
.regular
.windows
,
328 check_case
.profile_b
.incognito
.windows
,
330 for (size_t j
= 0; j
< arraysize(browsers
); ++j
) {
331 bool result
= AdjustBrowsersOnProfile(browsers
[j
], window_counts
[j
]);
336 content::RunAllPendingInMessageLoop();
338 // All that work, for this one little test.
339 EXPECT_TRUE((check_case
.window_to_probe
==
340 DownloadsCloseCheckCase::REGULAR
) ||
341 (check_case
.window_to_probe
==
342 DownloadsCloseCheckCase::INCOGNITO
));
343 if (!((check_case
.window_to_probe
==
344 DownloadsCloseCheckCase::REGULAR
) ||
345 (check_case
.window_to_probe
==
346 DownloadsCloseCheckCase::INCOGNITO
)))
349 int num_downloads_blocking
;
350 Browser
* browser_to_probe
=
351 (check_case
.window_to_probe
== DownloadsCloseCheckCase::REGULAR
?
353 browser_a_incognito
);
354 Browser::DownloadClosePreventionType type
=
355 browser_to_probe
->OkToCloseWithInProgressDownloads(
356 &num_downloads_blocking
);
357 EXPECT_EQ(check_case
.type
, type
);
358 if (type
!= Browser::DOWNLOAD_CLOSE_OK
)
359 EXPECT_EQ(check_case
.num_blocking
, num_downloads_blocking
);
361 // Release all the downloads.
362 CompleteAllDownloads(browser_to_probe
);
364 // Create a new main window and kill everything else.
365 entry_browser
= CreateBrowserOnProfile(first_profile_
, host_desktop_type
);
366 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
367 if ((*it
) != entry_browser
) {
372 it
->window()->Close();
375 content::RunAllPendingInMessageLoop();
380 static const DownloadsCloseCheckCase download_close_check_cases
[];
382 // DownloadCloseCheck variables.
383 Profile
* first_profile_
;
384 Profile
* second_profile_
;
386 base::ScopedTempDir first_profile_downloads_dir_
;
387 base::ScopedTempDir second_profile_data_dir_
;
388 base::ScopedTempDir second_profile_downloads_dir_
;
391 const BrowserCloseTest::DownloadsCloseCheckCase
392 BrowserCloseTest::download_close_check_cases
[] = {
393 // Top level nesting is {profile_a, profile_b}
394 // Second level nesting is {regular, incognito
395 // Third level (inner) nesting is {windows, downloads}
397 // Last window (incognito) triggers browser close warning.
398 {{{0, 0}, {1, 1}}, {{0, 0}, {0, 0}},
399 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
400 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
402 // Last incognito window triggers incognito close warning.
403 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
404 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
405 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
, 1},
407 // Last incognito window with no downloads triggers no warning.
408 {{{0, 0}, {1, 0}}, {{0, 0}, {0, 0}},
409 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
410 Browser::DOWNLOAD_CLOSE_OK
},
412 // Last incognito window with window+download on another incognito profile
413 // triggers no warning.
414 {{{0, 0}, {1, 0}}, {{0, 0}, {1, 1}},
415 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
416 Browser::DOWNLOAD_CLOSE_OK
},
418 // Non-last incognito window triggers no warning.
419 {{{0, 0}, {2, 1}}, {{0, 0}, {0, 0}},
420 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
421 Browser::DOWNLOAD_CLOSE_OK
},
423 // Non-last regular window triggers no warning.
424 {{{2, 1}, {0, 0}}, {{0, 0}, {0, 0}},
425 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
426 Browser::DOWNLOAD_CLOSE_OK
},
428 // Last regular window triggers browser close.
429 {{{1, 1}, {0, 0}}, {{0, 0}, {0, 0}},
430 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
431 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
433 // Last regular window triggers browser close for download on different
435 {{{1, 0}, {0, 0}}, {{0, 1}, {0, 0}},
436 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
437 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
439 // Last regular window triggers no warning if incognito
440 // active (http://crbug.com/61257).
441 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
442 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
443 Browser::DOWNLOAD_CLOSE_OK
},
445 // Last regular window triggers no warning if other profile window active.
446 {{{1, 1}, {0, 0}}, {{1, 0}, {0, 0}},
447 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
448 Browser::DOWNLOAD_CLOSE_OK
},
450 // Last regular window triggers no warning if other incognito window
452 {{{1, 0}, {0, 0}}, {{0, 0}, {1, 1}},
453 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
454 Browser::DOWNLOAD_CLOSE_OK
},
456 // Last regular window triggers no warning if incognito active.
457 {{{1, 1}, {1, 0}}, {{0, 0}, {0, 0}},
458 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
459 Browser::DOWNLOAD_CLOSE_OK
},
461 // Test plural for regular.
462 {{{1, 2}, {0, 0}}, {{0, 0}, {0, 0}},
463 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
464 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 2},
466 // Test plural for incognito.
467 {{{1, 0}, {1, 2}}, {{0, 0}, {0, 0}},
468 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
469 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
, 2},
472 std::string
BrowserCloseTest::DownloadsCloseCheckCase::DebugString() const {
475 if (profile_a
.regular
.windows
|| profile_a
.regular
.downloads
)
476 result
+= base::StringPrintf("Regular profile A: (%d w, %d d), ",
477 profile_a
.regular
.windows
,
478 profile_a
.regular
.downloads
);
479 if (profile_a
.incognito
.windows
|| profile_a
.incognito
.downloads
)
480 result
+= base::StringPrintf("Incognito profile A: (%d w, %d d), ",
481 profile_a
.incognito
.windows
,
482 profile_a
.incognito
.downloads
);
483 if (profile_b
.regular
.windows
|| profile_b
.regular
.downloads
)
484 result
+= base::StringPrintf("Regular profile B: (%d w, %d d), ",
485 profile_b
.regular
.windows
,
486 profile_b
.regular
.downloads
);
487 if (profile_b
.incognito
.windows
|| profile_b
.incognito
.downloads
)
488 result
+= base::StringPrintf("Incognito profile B: (%d w, %d d), ",
489 profile_b
.incognito
.windows
,
490 profile_b
.incognito
.downloads
);
491 result
+= (window_to_probe
== REGULAR
? "Probe regular" :
492 window_to_probe
== INCOGNITO
? "Probe incognito" :
495 if (type
== Browser::DOWNLOAD_CLOSE_OK
) {
496 result
+= "No warning";
498 result
+= base::StringPrintf(
499 "%s (%d downloads) warning",
500 (type
== Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
? "Browser shutdown" :
501 type
== Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
?
502 "Incognito close" : "Unknown"),
508 // The following test is split into six chunks to reduce the chance
509 // of hitting the 25s timeout.
511 // This test is timing out very often under AddressSanitizer.
512 // http://crbug.com/111914 and http://crbug.com/103371.
513 // Crashing on Linux. http://crbug.com/100566
514 // Timing out on XP debug. http://crbug.com/111914
515 // Timing out, http://crbug.com/159449 .
517 #define MAYBE_DownloadsCloseCheck_0 DISABLED_DownloadsCloseCheck_0
518 #define MAYBE_DownloadsCloseCheck_1 DISABLED_DownloadsCloseCheck_1
519 #define MAYBE_DownloadsCloseCheck_2 DISABLED_DownloadsCloseCheck_2
520 #define MAYBE_DownloadsCloseCheck_3 DISABLED_DownloadsCloseCheck_3
521 #define MAYBE_DownloadsCloseCheck_4 DISABLED_DownloadsCloseCheck_4
522 #define MAYBE_DownloadsCloseCheck_5 DISABLED_DownloadsCloseCheck_5
524 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_0
) {
525 ASSERT_TRUE(SetupForDownloadCloseCheck());
526 for (size_t i
= 0; i
< arraysize(download_close_check_cases
) / 6; ++i
) {
527 ExecuteDownloadCloseCheckCase(i
);
531 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_1
) {
532 ASSERT_TRUE(SetupForDownloadCloseCheck());
533 for (size_t i
= arraysize(download_close_check_cases
) / 6;
534 i
< 2 * arraysize(download_close_check_cases
) / 6; ++i
) {
535 ExecuteDownloadCloseCheckCase(i
);
539 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_2
) {
540 ASSERT_TRUE(SetupForDownloadCloseCheck());
541 for (size_t i
= 2 * arraysize(download_close_check_cases
) / 6;
542 i
< 3 * arraysize(download_close_check_cases
) / 6; ++i
) {
543 ExecuteDownloadCloseCheckCase(i
);
547 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_3
) {
548 ASSERT_TRUE(SetupForDownloadCloseCheck());
549 for (size_t i
= 3 * arraysize(download_close_check_cases
) / 6;
550 i
< 4 * arraysize(download_close_check_cases
) / 6; ++i
) {
551 ExecuteDownloadCloseCheckCase(i
);
555 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_4
) {
556 ASSERT_TRUE(SetupForDownloadCloseCheck());
557 for (size_t i
= 4 * arraysize(download_close_check_cases
) / 6;
558 i
< 5 * arraysize(download_close_check_cases
) / 6; ++i
) {
559 ExecuteDownloadCloseCheckCase(i
);
563 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_5
) {
564 ASSERT_TRUE(SetupForDownloadCloseCheck());
565 for (size_t i
= 5 * arraysize(download_close_check_cases
) / 6;
566 i
< 6 * arraysize(download_close_check_cases
) / 6; ++i
) {
567 ExecuteDownloadCloseCheckCase(i
);