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