NaCl docs: add sanitizers to GSoC ideas
[chromium-blink-merge.git] / chrome / browser / ui / browser_close_browsertest.cc
blobe9183c696516ae87582b551920ea2513c3695960
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 {
40 public:
41 // Structure defining test cases for DownloadsCloseCheck.
42 struct DownloadsCloseCheckCase {
43 std::string DebugString() const;
45 // Input
46 struct {
47 struct {
48 int windows;
49 int downloads;
50 } regular;
51 struct {
52 int windows;
53 int downloads;
54 } incognito;
55 } profile_a;
57 struct {
58 struct {
59 int windows;
60 int downloads;
61 } regular;
62 struct {
63 int windows;
64 int downloads;
65 } incognito;
66 } profile_b;
68 // We always probe a window in profile A.
69 enum { REGULAR = 0, INCOGNITO = 1 } window_to_probe;
71 // Output
72 Browser::DownloadClosePreventionType type;
74 // Unchecked if type == DOWNLOAD_CLOSE_OK.
75 int num_blocking;
78 protected:
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))
91 return NULL;
93 Profile* second_profile =
94 g_browser_process->profile_manager()->GetProfile(
95 second_profile_data_dir_.path());
96 if (!second_profile)
97 return NULL;
99 bool result = second_profile_downloads_dir_.CreateUniqueTempDir();
100 if (!result)
101 return NULL;
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)
117 return;
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,
125 num_downloads));
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);
134 // Wait for them.
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();
186 return new_browser;
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))
201 return false;
202 (*base_browser)->window()->Close();
203 *base_browser = 0;
204 return true;
207 // num_windows > 0
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);
214 return true;
217 int TotalUnclosedBrowsers() {
218 int count = 0;
219 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
220 if (!it->IsAttemptingToCloseBrowser())
221 count++;
223 return count;
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())
230 return *it;
232 return NULL;
235 bool SetupForDownloadCloseCheck() {
236 first_profile_ = browser()->profile();
238 bool result = first_profile_downloads_dir_.CreateUniqueTempDir();
239 EXPECT_TRUE(result);
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);
251 return true;
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)
272 return false;
274 Browser* entry_browser = FirstUnclosedBrowser();
275 EXPECT_EQ(first_profile_, entry_browser->profile());
276 if (first_profile_ != entry_browser->profile())
277 return false;
278 int total_download_count =
279 DownloadService::NonMaliciousDownloadCountAllProfiles();
280 EXPECT_EQ(0, total_download_count);
281 if (0 != total_download_count)
282 return false;
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
293 // as necessary.
294 chrome::HostDesktopType host_desktop_type =
295 entry_browser->host_desktop_type();
296 Browser* browser_a_regular(CreateBrowserOnProfile(first_profile_,
297 host_desktop_type));
298 Browser* browser_a_incognito(
299 CreateBrowserOnProfile(first_profile_incognito, host_desktop_type));
300 Browser* browser_b_regular(CreateBrowserOnProfile(second_profile_,
301 host_desktop_type));
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]);
332 EXPECT_TRUE(result);
333 if (!result)
334 return false;
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)))
347 return false;
349 int num_downloads_blocking;
350 Browser* browser_to_probe =
351 (check_case.window_to_probe == DownloadsCloseCheckCase::REGULAR ?
352 browser_a_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) {
368 if (!it->window()) {
369 ADD_FAILURE();
370 return false;
372 it->window()->Close();
375 content::RunAllPendingInMessageLoop();
377 return true;
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
434 // profile.
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
451 // active.
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 {
473 std::string result;
474 result += "{";
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" :
493 "Probe unknown");
494 result += "} -> ";
495 if (type == Browser::DOWNLOAD_CLOSE_OK) {
496 result += "No warning";
497 } else {
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"),
503 num_blocking);
505 return result;
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);