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 "content/test/net/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
;
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
,
182 GURL(url::kAboutBlankURL
),
183 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
);
184 content::WaitForLoadStop(
185 new_browser
->tab_strip_model()->GetActiveWebContents());
186 new_browser
->window()->Show();
190 // Adjust the number of browsers and associated windows up or down
191 // to |num_windows|. This routine assumes that there is only a single
192 // browser associated with the profile on entry. |*base_browser| contains
193 // this browser, and the profile is derived from that browser. On output,
194 // if |*base_browser| was destroyed (because |num_windows == 0|), NULL
195 // is assigned to that memory location.
196 bool AdjustBrowsersOnProfile(Browser
** base_browser
, int num_windows
) {
197 int num_downloads_blocking
;
198 if (num_windows
== 0) {
199 if (Browser::DOWNLOAD_CLOSE_OK
!=
200 (*base_browser
)->OkToCloseWithInProgressDownloads(
201 &num_downloads_blocking
))
203 (*base_browser
)->window()->Close();
209 Profile
* profile((*base_browser
)->profile());
210 chrome::HostDesktopType host_desktop_type
=
211 (*base_browser
)->host_desktop_type();
212 for (int w
= 1; w
< num_windows
; ++w
) {
213 CreateBrowserOnProfile(profile
, host_desktop_type
);
218 int TotalUnclosedBrowsers() {
220 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
221 if (!it
->IsAttemptingToCloseBrowser())
227 // Note that this is invalid to call if TotalUnclosedBrowsers() == 0.
228 Browser
* FirstUnclosedBrowser() {
229 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
230 if (!it
->IsAttemptingToCloseBrowser())
236 bool SetupForDownloadCloseCheck() {
237 first_profile_
= browser()->profile();
239 bool result
= first_profile_downloads_dir_
.CreateUniqueTempDir();
241 if (!result
) return false;
242 first_profile_
->GetPrefs()->SetFilePath(
243 prefs::kDownloadDefaultDirectory
,
244 first_profile_downloads_dir_
.path());
246 second_profile_
= CreateSecondProfile();
247 EXPECT_TRUE(second_profile_
);
248 if (!second_profile_
) return false;
250 DownloadTestFileActivityObserver(first_profile_
) .EnableFileChooser(false);
251 DownloadTestFileActivityObserver(second_profile_
).EnableFileChooser(false);
255 // Test a specific DownloadsCloseCheckCase. Returns false if
256 // an assertion has failed and the test should be aborted.
257 bool ExecuteDownloadCloseCheckCase(size_t i
) {
258 const DownloadsCloseCheckCase
& check_case(download_close_check_cases
[i
]);
259 SCOPED_TRACE(testing::Message() << "Case" << i
260 << ": " << check_case
.DebugString());
262 // Test invariant: so that we don't actually try and close the browser,
263 // we always enter the function with a single browser window open on the
264 // main profile. That means we need to exit the function the same way.
265 // So we setup everything except for the |first_profile_| regular, and then
266 // flip the bit on the main window.
267 // Note that this means that browser() is unreliable in the context
268 // of this function or its callers; we'll be killing that main window
269 // and recreating it fairly frequently.
270 int unclosed_browsers
= TotalUnclosedBrowsers();
271 EXPECT_EQ(1, unclosed_browsers
);
272 if (1 != unclosed_browsers
)
275 Browser
* entry_browser
= FirstUnclosedBrowser();
276 EXPECT_EQ(first_profile_
, entry_browser
->profile());
277 if (first_profile_
!= entry_browser
->profile())
279 int total_download_count
=
280 DownloadService::NonMaliciousDownloadCountAllProfiles();
281 EXPECT_EQ(0, total_download_count
);
282 if (0 != total_download_count
)
284 Profile
* first_profile_incognito
= first_profile_
->GetOffTheRecordProfile();
285 Profile
* second_profile_incognito
=
286 second_profile_
->GetOffTheRecordProfile();
287 DownloadTestFileActivityObserver(first_profile_incognito
)
288 .EnableFileChooser(false);
289 DownloadTestFileActivityObserver(second_profile_incognito
)
290 .EnableFileChooser(false);
292 // For simplicty of coding, we create a window on each profile so that
293 // we can easily create downloads, then we destroy or create windows
295 chrome::HostDesktopType host_desktop_type
=
296 entry_browser
->host_desktop_type();
297 Browser
* browser_a_regular(CreateBrowserOnProfile(first_profile_
,
299 Browser
* browser_a_incognito(
300 CreateBrowserOnProfile(first_profile_incognito
, host_desktop_type
));
301 Browser
* browser_b_regular(CreateBrowserOnProfile(second_profile_
,
303 Browser
* browser_b_incognito(
304 CreateBrowserOnProfile(second_profile_incognito
, host_desktop_type
));
306 // Kill our entry browser.
307 entry_browser
->window()->Close();
308 entry_browser
= NULL
;
310 // Create all downloads needed.
311 CreateStalledDownloads(
312 browser_a_regular
, check_case
.profile_a
.regular
.downloads
);
313 CreateStalledDownloads(
314 browser_a_incognito
, check_case
.profile_a
.incognito
.downloads
);
315 CreateStalledDownloads(
316 browser_b_regular
, check_case
.profile_b
.regular
.downloads
);
317 CreateStalledDownloads(
318 browser_b_incognito
, check_case
.profile_b
.incognito
.downloads
);
320 // Adjust the windows
321 Browser
** browsers
[] = {
322 &browser_a_regular
, &browser_a_incognito
,
323 &browser_b_regular
, &browser_b_incognito
325 int window_counts
[] = {
326 check_case
.profile_a
.regular
.windows
,
327 check_case
.profile_a
.incognito
.windows
,
328 check_case
.profile_b
.regular
.windows
,
329 check_case
.profile_b
.incognito
.windows
,
331 for (size_t j
= 0; j
< arraysize(browsers
); ++j
) {
332 bool result
= AdjustBrowsersOnProfile(browsers
[j
], window_counts
[j
]);
337 content::RunAllPendingInMessageLoop();
339 // All that work, for this one little test.
340 EXPECT_TRUE((check_case
.window_to_probe
==
341 DownloadsCloseCheckCase::REGULAR
) ||
342 (check_case
.window_to_probe
==
343 DownloadsCloseCheckCase::INCOGNITO
));
344 if (!((check_case
.window_to_probe
==
345 DownloadsCloseCheckCase::REGULAR
) ||
346 (check_case
.window_to_probe
==
347 DownloadsCloseCheckCase::INCOGNITO
)))
350 int num_downloads_blocking
;
351 Browser
* browser_to_probe
=
352 (check_case
.window_to_probe
== DownloadsCloseCheckCase::REGULAR
?
354 browser_a_incognito
);
355 Browser::DownloadClosePreventionType type
=
356 browser_to_probe
->OkToCloseWithInProgressDownloads(
357 &num_downloads_blocking
);
358 EXPECT_EQ(check_case
.type
, type
);
359 if (type
!= Browser::DOWNLOAD_CLOSE_OK
)
360 EXPECT_EQ(check_case
.num_blocking
, num_downloads_blocking
);
362 // Release all the downloads.
363 CompleteAllDownloads(browser_to_probe
);
365 // Create a new main window and kill everything else.
366 entry_browser
= CreateBrowserOnProfile(first_profile_
, host_desktop_type
);
367 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
368 if ((*it
) != entry_browser
) {
373 it
->window()->Close();
376 content::RunAllPendingInMessageLoop();
381 static const DownloadsCloseCheckCase download_close_check_cases
[];
383 // DownloadCloseCheck variables.
384 Profile
* first_profile_
;
385 Profile
* second_profile_
;
387 base::ScopedTempDir first_profile_downloads_dir_
;
388 base::ScopedTempDir second_profile_data_dir_
;
389 base::ScopedTempDir second_profile_downloads_dir_
;
392 const BrowserCloseTest::DownloadsCloseCheckCase
393 BrowserCloseTest::download_close_check_cases
[] = {
394 // Top level nesting is {profile_a, profile_b}
395 // Second level nesting is {regular, incognito
396 // Third level (inner) nesting is {windows, downloads}
398 // Last window (incognito) triggers browser close warning.
399 {{{0, 0}, {1, 1}}, {{0, 0}, {0, 0}},
400 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
401 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
403 // Last incognito window triggers incognito close warning.
404 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
405 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
406 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
, 1},
408 // Last incognito window with no downloads triggers no warning.
409 {{{0, 0}, {1, 0}}, {{0, 0}, {0, 0}},
410 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
411 Browser::DOWNLOAD_CLOSE_OK
},
413 // Last incognito window with window+download on another incognito profile
414 // triggers no warning.
415 {{{0, 0}, {1, 0}}, {{0, 0}, {1, 1}},
416 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
417 Browser::DOWNLOAD_CLOSE_OK
},
419 // Non-last incognito window triggers no warning.
420 {{{0, 0}, {2, 1}}, {{0, 0}, {0, 0}},
421 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
422 Browser::DOWNLOAD_CLOSE_OK
},
424 // Non-last regular window triggers no warning.
425 {{{2, 1}, {0, 0}}, {{0, 0}, {0, 0}},
426 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
427 Browser::DOWNLOAD_CLOSE_OK
},
429 // Last regular window triggers browser close.
430 {{{1, 1}, {0, 0}}, {{0, 0}, {0, 0}},
431 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
432 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
434 // Last regular window triggers browser close for download on different
436 {{{1, 0}, {0, 0}}, {{0, 1}, {0, 0}},
437 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
438 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 1},
440 // Last regular window triggers no warning if incognito
441 // active (http://crbug.com/61257).
442 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
443 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
444 Browser::DOWNLOAD_CLOSE_OK
},
446 // Last regular window triggers no warning if other profile window active.
447 {{{1, 1}, {0, 0}}, {{1, 0}, {0, 0}},
448 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
449 Browser::DOWNLOAD_CLOSE_OK
},
451 // Last regular window triggers no warning if other incognito window
453 {{{1, 0}, {0, 0}}, {{0, 0}, {1, 1}},
454 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
455 Browser::DOWNLOAD_CLOSE_OK
},
457 // Last regular window triggers no warning if incognito active.
458 {{{1, 1}, {1, 0}}, {{0, 0}, {0, 0}},
459 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
460 Browser::DOWNLOAD_CLOSE_OK
},
462 // Test plural for regular.
463 {{{1, 2}, {0, 0}}, {{0, 0}, {0, 0}},
464 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR
,
465 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
, 2},
467 // Test plural for incognito.
468 {{{1, 0}, {1, 2}}, {{0, 0}, {0, 0}},
469 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO
,
470 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
, 2},
473 std::string
BrowserCloseTest::DownloadsCloseCheckCase::DebugString() const {
476 if (profile_a
.regular
.windows
|| profile_a
.regular
.downloads
)
477 result
+= base::StringPrintf("Regular profile A: (%d w, %d d), ",
478 profile_a
.regular
.windows
,
479 profile_a
.regular
.downloads
);
480 if (profile_a
.incognito
.windows
|| profile_a
.incognito
.downloads
)
481 result
+= base::StringPrintf("Incognito profile A: (%d w, %d d), ",
482 profile_a
.incognito
.windows
,
483 profile_a
.incognito
.downloads
);
484 if (profile_b
.regular
.windows
|| profile_b
.regular
.downloads
)
485 result
+= base::StringPrintf("Regular profile B: (%d w, %d d), ",
486 profile_b
.regular
.windows
,
487 profile_b
.regular
.downloads
);
488 if (profile_b
.incognito
.windows
|| profile_b
.incognito
.downloads
)
489 result
+= base::StringPrintf("Incognito profile B: (%d w, %d d), ",
490 profile_b
.incognito
.windows
,
491 profile_b
.incognito
.downloads
);
492 result
+= (window_to_probe
== REGULAR
? "Probe regular" :
493 window_to_probe
== INCOGNITO
? "Probe incognito" :
496 if (type
== Browser::DOWNLOAD_CLOSE_OK
) {
497 result
+= "No warning";
499 result
+= base::StringPrintf(
500 "%s (%d downloads) warning",
501 (type
== Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
? "Browser shutdown" :
502 type
== Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE
?
503 "Incognito close" : "Unknown"),
509 // The following test is split into six chunks to reduce the chance
510 // of hitting the 25s timeout.
512 // This test is timing out very often under AddressSanitizer.
513 // http://crbug.com/111914 and http://crbug.com/103371.
514 // Crashing on Linux. http://crbug.com/100566
515 // Timing out on XP debug. http://crbug.com/111914
516 // Timing out, http://crbug.com/159449 .
518 #define MAYBE_DownloadsCloseCheck_0 DISABLED_DownloadsCloseCheck_0
519 #define MAYBE_DownloadsCloseCheck_1 DISABLED_DownloadsCloseCheck_1
520 #define MAYBE_DownloadsCloseCheck_2 DISABLED_DownloadsCloseCheck_2
521 #define MAYBE_DownloadsCloseCheck_3 DISABLED_DownloadsCloseCheck_3
522 #define MAYBE_DownloadsCloseCheck_4 DISABLED_DownloadsCloseCheck_4
523 #define MAYBE_DownloadsCloseCheck_5 DISABLED_DownloadsCloseCheck_5
525 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_0
) {
526 ASSERT_TRUE(SetupForDownloadCloseCheck());
527 for (size_t i
= 0; i
< arraysize(download_close_check_cases
) / 6; ++i
) {
528 ExecuteDownloadCloseCheckCase(i
);
532 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_1
) {
533 ASSERT_TRUE(SetupForDownloadCloseCheck());
534 for (size_t i
= arraysize(download_close_check_cases
) / 6;
535 i
< 2 * arraysize(download_close_check_cases
) / 6; ++i
) {
536 ExecuteDownloadCloseCheckCase(i
);
540 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_2
) {
541 ASSERT_TRUE(SetupForDownloadCloseCheck());
542 for (size_t i
= 2 * arraysize(download_close_check_cases
) / 6;
543 i
< 3 * arraysize(download_close_check_cases
) / 6; ++i
) {
544 ExecuteDownloadCloseCheckCase(i
);
548 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_3
) {
549 ASSERT_TRUE(SetupForDownloadCloseCheck());
550 for (size_t i
= 3 * arraysize(download_close_check_cases
) / 6;
551 i
< 4 * arraysize(download_close_check_cases
) / 6; ++i
) {
552 ExecuteDownloadCloseCheckCase(i
);
556 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_4
) {
557 ASSERT_TRUE(SetupForDownloadCloseCheck());
558 for (size_t i
= 4 * arraysize(download_close_check_cases
) / 6;
559 i
< 5 * arraysize(download_close_check_cases
) / 6; ++i
) {
560 ExecuteDownloadCloseCheckCase(i
);
564 IN_PROC_BROWSER_TEST_F(BrowserCloseTest
, MAYBE_DownloadsCloseCheck_5
) {
565 ASSERT_TRUE(SetupForDownloadCloseCheck());
566 for (size_t i
= 5 * arraysize(download_close_check_cases
) / 6;
567 i
< 6 * arraysize(download_close_check_cases
) / 6; ++i
) {
568 ExecuteDownloadCloseCheckCase(i
);