Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: chrome/browser/ui/browser_close_browsertest.cc

Issue 7466033: Fix warning prompting on closing a window that will cancel downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merged up to latest (mostly around DownloadService changes. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 #include "base/command_line.h"
6 #include "base/logging.h"
7 #include "base/path_service.h"
8 #include "base/string_number_conversions.h"
9 #include "base/string_util.h"
10 #include "base/stringprintf.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/download/download_service.h"
13 #include "chrome/browser/download/download_service_factory.h"
14 #include "chrome/browser/download/download_test_observer.h"
15 #include "chrome/browser/net/url_request_mock_util.h"
16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/webui/active_downloads_ui.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/test/base/in_process_browser_test.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "content/browser/download/download_item.h"
27 #include "content/browser/net/url_request_slow_download_job.h"
28 #include "content/browser/tab_contents/tab_contents.h"
29 #include "content/common/url_constants.h"
30 #include "content/public/common/page_transition_types.h"
31
32 class BrowserCloseTest : public InProcessBrowserTest {
33 public:
34 // Structure defining test cases for DownloadsCloseCheck.
35 struct DownloadsCloseCheckCase {
36 std::string DebugString() const;
37
38 // Input
39 struct {
40 struct {
41 int windows;
42 int downloads;
43 } regular;
44 struct {
45 int windows;
46 int downloads;
47 } incognito;
48 } profile_a;
49
50 struct {
51 struct {
52 int windows;
53 int downloads;
54 } regular;
55 struct {
56 int windows;
57 int downloads;
58 } incognito;
59 } profile_b;
60
61 // We always probe a window in profile A.
62 enum { REGULAR = 0, INCOGNITO = 1 } window_to_probe;
63
64 // Output
65 Browser::DownloadClosePreventionType type;
66
67 // Unchecked if type == DOWNLOAD_CLOSE_OK.
68 int num_blocking;
69 };
70
71 protected:
72 void SetUpOnMainThread() OVERRIDE {
achuithb 2011/10/13 23:05:08 virtual?
Randy Smith (Not in Mondays) 2011/10/14 00:37:41 Done.
73 BrowserThread::PostTask(
74 BrowserThread::IO, FROM_HERE,
75 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
76 }
77
78 // Create a second profile to work within multi-profile.
79 Profile* CreateSecondProfile() {
80 FilePath user_data_dir;
81 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
82
83 if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
84 return NULL;
85
86 return g_browser_process->profile_manager()->GetProfile(
87 second_profile_data_dir_.path());
88 }
89
90 // Create |num_downloads| number of downloads that are stalled
91 // (will quickly get to a place where the server won't
92 // provide any more data) so that we can test closing the
93 // browser with active downloads.
94 void CreateStalledDownloads(Browser* browser, int num_downloads) {
95 GURL url(URLRequestSlowDownloadJob::kKnownSizeUrl);
96
97 if (num_downloads == 0)
98 return;
99
100 // Setup an observer waiting for the given number of downloads
101 // to get to IN_PROGRESS.
102 DownloadManager* download_manager =
103 browser->profile()->GetDownloadManager();
104 scoped_ptr<DownloadTestObserver> observer(
105 new DownloadTestObserver(
106 download_manager, num_downloads,
107 DownloadItem::IN_PROGRESS,
108 true, // Bail on select file.
109 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL));
110
111 // Set of that number of downloads.
112 while (num_downloads--)
113 ui_test_utils::NavigateToURLWithDisposition(
114 browser, url, NEW_BACKGROUND_TAB,
115 ui_test_utils::BROWSER_TEST_NONE);
116
117 // Wait for them.
118 observer->WaitForFinished();
119 }
120
121 // All all downloads created in CreateStalledDownloads() to
122 // complete, and block in this routine until they do complete.
123 void CompleteAllDownloads(Browser* browser) {
124 GURL finish_url(URLRequestSlowDownloadJob::kFinishDownloadUrl);
125 ui_test_utils::NavigateToURL(browser, finish_url);
126
127 // Go through and, for every single profile, wait until there are
128 // no active downloads on that download manager.
129 std::vector<Profile*> profiles(
130 g_browser_process->profile_manager()->GetLoadedProfiles());
131 for (std::vector<Profile*>::const_iterator pit = profiles.begin();
132 pit != profiles.end(); ++pit) {
133 DownloadService* download_service =
134 DownloadServiceFactory::GetForProfile(*pit);
135 if (download_service->HasCreatedDownloadManager()) {
136 DownloadManager *mgr = download_service->GetDownloadManager();
137 scoped_refptr<DownloadTestFlushObserver> observer(
138 new DownloadTestFlushObserver(mgr));
139 observer->WaitForFlush();
140 }
141 if ((*pit)->HasOffTheRecordProfile()) {
142 DownloadService* incognito_download_service =
143 DownloadServiceFactory::GetForProfile(
144 (*pit)->GetOffTheRecordProfile());
145 if (incognito_download_service->HasCreatedDownloadManager()) {
146 DownloadManager *mgr =
147 incognito_download_service->GetDownloadManager();
148 scoped_refptr<DownloadTestFlushObserver> observer(
149 new DownloadTestFlushObserver(mgr));
150 observer->WaitForFlush();
151 }
152 }
153 }
154 }
155
156 // Create a Browser (with associated window) on the specified profile.
157 Browser* CreateBrowserOnProfile(Profile* profile) {
158 Browser* new_browser = Browser::Create(profile);
159 new_browser->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL),
160 content::PAGE_TRANSITION_START_PAGE);
161 ui_test_utils::WaitForNavigation(
162 &new_browser->GetSelectedTabContents()->controller());
163 new_browser->window()->Show();
164 return new_browser;
165 }
166
167 // Adjust the number of browsers and associated windows up or down
168 // to |num_windows|. This routine assumes that there is only a single
169 // browser associated with the profile on entry. |*base_browser| contains
170 // this browser, and the profile is derived from that browser. On output,
171 // if |*base_browser| was destroyed (because |num_windows == 0|), NULL
172 // is assigned to that memory location.
173 bool AdjustBrowsersOnProfile(Browser** base_browser, int num_windows) {
174 int num_downloads_blocking;
175 if (num_windows == 0) {
176 if (Browser::DOWNLOAD_CLOSE_OK !=
177 (*base_browser)->OkToCloseWithInProgressDownloads(
178 &num_downloads_blocking))
179 return false;
180 (*base_browser)->window()->Close();
181 *base_browser = 0;
182 return true;
183 }
184
185 // num_windows > 0
186 Profile* profile((*base_browser)->profile());
187 for (int w = 1; w < num_windows; ++w) {
188 CreateBrowserOnProfile(profile);
189 }
190 return true;
191 }
192
193 int TotalUnclosedBrowsers() {
194 int count = 0;
195 for (BrowserList::const_iterator iter = BrowserList::begin();
196 iter != BrowserList::end(); ++iter)
197 if (!(*iter)->IsAttemptingToCloseBrowser()) {
198 LOG(WARNING) << "TotalUnclosedBrowsers: counted browser " << (*iter);
achuithb 2011/10/13 23:05:08 Is this logging supposed to be here?
Randy Smith (Not in Mondays) 2011/10/14 00:37:41 Oh, goodness. No, it's not; I thought I had gotte
199 count++;
200 }
201 return count;
202 }
203
204 // Note that this is invalid to call if TotalUnclosedBrowsers() == 0.
205 Browser* FirstUnclosedBrowser() {
206 for (BrowserList::const_iterator iter = BrowserList::begin();
207 iter != BrowserList::end(); ++iter)
208 if (!(*iter)->IsAttemptingToCloseBrowser())
209 return (*iter);
210 return NULL;
211 }
212
213 bool SetupForDownloadCloseCheck() {
214 first_profile_ = browser()->profile();
215
216 bool result = first_profile_data_dir_.CreateUniqueTempDir();
217 EXPECT_TRUE(result);
218 if (!result) return false;
219 first_profile_->GetPrefs()->SetFilePath(
220 prefs::kDownloadDefaultDirectory,
221 first_profile_data_dir_.path());
222
223 second_profile_ = CreateSecondProfile();
224 EXPECT_TRUE(second_profile_);
225 if (!second_profile_) return false;
226
227 return true;
228 }
229
230 // Test a specific DownloadsCloseCheckCase. Returns false if
231 // an assertion has failed and the test should be aborted.
232 bool ExecuteDownloadCloseCheckCase(size_t i) {
233 const DownloadsCloseCheckCase& check_case(download_close_check_cases[i]);
234
235 // Debugging hack to make it easy to run a single case from the
achuithb 2011/10/13 23:05:08 Are you checking this in?
Randy Smith (Not in Mondays) 2011/10/14 00:37:41 Right, thanks for pointing this out; I wanted to g
236 // command line.
237 CommandLine* command_line = CommandLine::ForCurrentProcess();
238 if (command_line->HasSwitch("test_argument")) {
239 std::string value =
240 command_line->GetSwitchValueASCII("test_argument");
241 std::vector<std::string> cases;
242 Tokenize(value, ",", &cases);
243 std::vector<std::string>::iterator it = cases.begin();
244 for (; it != cases.end(); ++it) {
245 int test_case_int;
246 base::StringToInt(*it, &test_case_int);
247 if (i == static_cast<size_t>(test_case_int))
248 break;
249 }
250 if (it == cases.end())
251 return true;
252 }
253
254 // Test invariant: so that we don't actually try and close the browser,
255 // we always enter the function with a single browser window open on the
256 // main profile. That means we need to exit the function the same way.
257 // So we setup everything except for the |first_profile_| regular, and then
258 // flip the bit on the main window.
259 // Note that this means that browser() is unreliable in the context
260 // of this function or its callers; we'll be killing that main window
261 // and recreating it fairly frequently.
262 int unclosed_browsers = TotalUnclosedBrowsers();
263 EXPECT_EQ(1, unclosed_browsers);
264 if (1 != unclosed_browsers)
265 return false;
266
267 Browser* entry_browser = FirstUnclosedBrowser();
268 EXPECT_EQ(first_profile_, entry_browser->profile())
269 << "Case" << i
270 << ": " << check_case.DebugString();
271 if (first_profile_ != entry_browser->profile())
272 return false;
273 int total_download_count = DownloadService::TotalDownloadCount();
274 EXPECT_EQ(0, total_download_count)
275 << "Case " << i
276 << ": " << check_case.DebugString();
277 if (0 != total_download_count)
278 return false;
279
280 Profile* first_profile_incognito = first_profile_->GetOffTheRecordProfile();
281 Profile* second_profile_incognito =
282 second_profile_->GetOffTheRecordProfile();
283
284 // For simplicty of coding, we create a window on each profile so that
285 // we can easily create downloads, then we destroy or create windows
286 // as necessary.
287 Browser* browser_a_regular(CreateBrowserOnProfile(first_profile_));
288 Browser* browser_a_incognito(
289 CreateBrowserOnProfile(first_profile_incognito));
290 Browser* browser_b_regular(CreateBrowserOnProfile(second_profile_));
291 Browser* browser_b_incognito(
292 CreateBrowserOnProfile(second_profile_incognito));
293
294 // Kill our entry browser.
295 entry_browser->window()->Close();
296 entry_browser = NULL;
297
298 // Create all downloads needed.
299 CreateStalledDownloads(
300 browser_a_regular, check_case.profile_a.regular.downloads);
301 CreateStalledDownloads(
302 browser_a_incognito, check_case.profile_a.incognito.downloads);
303 CreateStalledDownloads(
304 browser_b_regular, check_case.profile_b.regular.downloads);
305 CreateStalledDownloads(
306 browser_b_incognito, check_case.profile_b.incognito.downloads);
307
308 // Adjust the windows
309 Browser** browsers[] = {
310 &browser_a_regular, &browser_a_incognito,
311 &browser_b_regular, &browser_b_incognito
312 };
313 int window_counts[] = {
314 check_case.profile_a.regular.windows,
315 check_case.profile_a.incognito.windows,
316 check_case.profile_b.regular.windows,
317 check_case.profile_b.incognito.windows,
318 };
319 for (size_t j = 0; j < arraysize(browsers); ++j) {
320 bool result = AdjustBrowsersOnProfile(browsers[j], window_counts[j]);
321 EXPECT_TRUE(result);
322 if (!result)
323 return false;
324 }
325 ui_test_utils::RunAllPendingInMessageLoop();
326
327 #if defined(OS_CHROMEOS)
328 // Get rid of downloads panel on ChromeOS
329 Browser* panel = ActiveDownloadsUI::GetPopup();
330 if (panel)
331 panel->CloseWindow();
332 ui_test_utils::RunAllPendingInMessageLoop();
333 #endif
334
335 // All that work, for this one little test.
336 EXPECT_TRUE((check_case.window_to_probe ==
337 DownloadsCloseCheckCase::REGULAR) ||
338 (check_case.window_to_probe ==
339 DownloadsCloseCheckCase::INCOGNITO));
340 if (!((check_case.window_to_probe ==
341 DownloadsCloseCheckCase::REGULAR) ||
342 (check_case.window_to_probe ==
343 DownloadsCloseCheckCase::INCOGNITO)))
344 return false;
345
346 int num_downloads_blocking;
347 Browser* browser_to_probe =
348 (check_case.window_to_probe == DownloadsCloseCheckCase::REGULAR ?
349 browser_a_regular :
350 browser_a_incognito);
351 Browser::DownloadClosePreventionType type =
352 browser_to_probe->OkToCloseWithInProgressDownloads(
353 &num_downloads_blocking);
354 EXPECT_EQ(check_case.type, type) << "Case " << i
355 << ": " << check_case.DebugString();
356 if (type != Browser::DOWNLOAD_CLOSE_OK)
357 EXPECT_EQ(check_case.num_blocking, num_downloads_blocking)
358 << "Case " << i
359 << ": " << check_case.DebugString();
360
361 // Release all the downloads.
362 CompleteAllDownloads(browser_to_probe);
363
364 // Create a new main window and kill everything else.
365 entry_browser = CreateBrowserOnProfile(first_profile_);
366 for (BrowserList::const_iterator bit = BrowserList::begin();
367 bit != BrowserList::end(); ++bit) {
368 if ((*bit) != entry_browser) {
369 EXPECT_TRUE((*bit)->window());
370 if (!(*bit)->window())
371 return false;
372 (*bit)->window()->Close();
373 }
374 }
375 ui_test_utils::RunAllPendingInMessageLoop();
376
377 return true;
378 }
379
380 static const DownloadsCloseCheckCase download_close_check_cases[];
381
382 // DownloadCloseCheck variables.
383 Profile* first_profile_;
384 Profile* second_profile_;
385
386 ScopedTempDir first_profile_data_dir_;
387 ScopedTempDir second_profile_data_dir_;
388 };
389
390 const BrowserCloseTest::DownloadsCloseCheckCase
391 BrowserCloseTest::download_close_check_cases[] = {
392 // Top level nesting is {profile_a, profile_b}
393 // Second level nesting is {regular, incognito
394 // Third level (inner) nesting is {windows, downloads}
395
396 // Last window (incognito) triggers browser close warning.
397 {{{0, 0}, {1, 1}}, {{0, 0}, {0, 0}},
398 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
399 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 1},
400
401 // Last incognito window triggers incognito close warning.
402 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
403 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
404 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE, 1},
405
406 // Last incognito window with no downloads triggers no warning.
407 {{{0, 0}, {1, 0}}, {{0, 0}, {0, 0}},
408 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
409 Browser::DOWNLOAD_CLOSE_OK},
410
411 // Last incognito window with window+download on another incognito profile
412 // triggers no warning.
413 {{{0, 0}, {1, 0}}, {{0, 0}, {1, 1}},
414 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
415 Browser::DOWNLOAD_CLOSE_OK},
416
417 // Non-last incognito window triggers no warning.
418 {{{0, 0}, {2, 1}}, {{0, 0}, {0, 0}},
419 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
420 Browser::DOWNLOAD_CLOSE_OK},
421
422 // Non-last regular window triggers no warning.
423 {{{2, 1}, {0, 0}}, {{0, 0}, {0, 0}},
424 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
425 Browser::DOWNLOAD_CLOSE_OK},
426
427 // Last regular window triggers browser close.
428 {{{1, 1}, {0, 0}}, {{0, 0}, {0, 0}},
429 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
430 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 1},
431
432 // Last regular window triggers browser close for download on different
433 // profile.
434 {{{1, 0}, {0, 0}}, {{0, 1}, {0, 0}},
435 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
436 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 1},
437
438 // Last regular window triggers no warning if incognito
439 // active (http://crbug.com/61257).
440 {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
441 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
442 Browser::DOWNLOAD_CLOSE_OK},
443
444 // Last regular window triggers no warning if other profile window active.
445 {{{1, 1}, {0, 0}}, {{1, 0}, {0, 0}},
446 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
447 Browser::DOWNLOAD_CLOSE_OK},
448
449 // Last regular window triggers no warning if other incognito window
450 // active.
451 {{{1, 0}, {0, 0}}, {{0, 0}, {1, 1}},
452 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
453 Browser::DOWNLOAD_CLOSE_OK},
454
455 // Last regular window triggers no warning if incognito active.
456 {{{1, 1}, {1, 0}}, {{0, 0}, {0, 0}},
457 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
458 Browser::DOWNLOAD_CLOSE_OK},
459
460 // Test plural for regular.
461 {{{1, 2}, {0, 0}}, {{0, 0}, {0, 0}},
462 BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
463 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 2},
464
465 // Test plural for incognito.
466 {{{1, 0}, {1, 2}}, {{0, 0}, {0, 0}},
467 BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
468 Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE, 2},
469 };
470
471 std::string BrowserCloseTest::DownloadsCloseCheckCase::DebugString() const {
472 std::string result;
473 result += "{";
474 if (profile_a.regular.windows || profile_a.regular.downloads)
475 result += base::StringPrintf("Regular profile A: (%d w, %d d), ",
476 profile_a.regular.windows,
477 profile_a.regular.downloads);
478 if (profile_a.incognito.windows || profile_a.incognito.downloads)
479 result += base::StringPrintf("Incognito profile A: (%d w, %d d), ",
480 profile_a.incognito.windows,
481 profile_a.incognito.downloads);
482 if (profile_b.regular.windows || profile_b.regular.downloads)
483 result += base::StringPrintf("Regular profile B: (%d w, %d d), ",
484 profile_b.regular.windows,
485 profile_b.regular.downloads);
486 if (profile_b.incognito.windows || profile_b.incognito.downloads)
487 result += base::StringPrintf("Incognito profile B: (%d w, %d d), ",
488 profile_b.incognito.windows,
489 profile_b.incognito.downloads);
490 result += (window_to_probe == REGULAR ? "Probe regular" :
491 window_to_probe == INCOGNITO ? "Probe incognito" :
492 "Probe unknown");
493 result += "} -> ";
494 if (type == Browser::DOWNLOAD_CLOSE_OK) {
495 result += "No warning";
496 } else {
497 result += base::StringPrintf(
498 "%s (%d downloads) warning",
499 (type == Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN ? "Browser shutdown" :
500 type == Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE ?
501 "Incognito close" : "Unknown"),
502 num_blocking);
503 }
504 return result;
505 }
506
507 // The following test is split into three chunks to reduce the chance
508 // of hitting the 25s timeout.
509
510 IN_PROC_BROWSER_TEST_F(BrowserCloseTest, DownloadsCloseCheck_0) {
511 ASSERT_TRUE(SetupForDownloadCloseCheck());
512 for (size_t i = 0; i < arraysize(download_close_check_cases) / 3; ++i) {
513 ExecuteDownloadCloseCheckCase(i);
514 }
515 }
516
517 IN_PROC_BROWSER_TEST_F(BrowserCloseTest, DownloadsCloseCheck_1) {
518 ASSERT_TRUE(SetupForDownloadCloseCheck());
519 for (size_t i = arraysize(download_close_check_cases) / 3;
520 i < 2 * arraysize(download_close_check_cases) / 3; ++i) {
521 ExecuteDownloadCloseCheckCase(i);
522 }
523 }
524
525 IN_PROC_BROWSER_TEST_F(BrowserCloseTest, DownloadsCloseCheck_2) {
526 ASSERT_TRUE(SetupForDownloadCloseCheck());
527 for (size_t i = 2 * arraysize(download_close_check_cases) / 3;
528 i < arraysize(download_close_check_cases); ++i) {
529 ExecuteDownloadCloseCheckCase(i);
530 }
531 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698