Index: chrome/browser/download/download_browsertest.cc |
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc |
index 1dd19488aff2fbd9104d9c007afb2d962ee48e14..33121f60cd94685207761bcf39ac87468b3adaf1 100644 |
--- a/chrome/browser/download/download_browsertest.cc |
+++ b/chrome/browser/download/download_browsertest.cc |
@@ -2,6 +2,8 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <sstream> |
+ |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/file_path.h" |
@@ -54,6 +56,7 @@ |
#include "content/public/common/page_transition_types.h" |
#include "content/test/net/url_request_mock_http_job.h" |
#include "content/test/net/url_request_slow_download_job.h" |
+#include "content/test/test_file_error_injector.h" |
#include "content/test/test_navigation_observer.h" |
#include "net/base/net_util.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -253,6 +256,11 @@ class DownloadTest : public InProcessBrowserTest { |
bool should_redirect_to_documents; // True if we save it in "My Documents". |
}; |
+ struct FileErrorInjectInfo { |
+ DownloadInfo download_info; |
+ content::TestFileErrorInjector::FileErrorInfo error_info; |
+ }; |
+ |
DownloadTest() { |
EnableDOMAutomation(); |
} |
@@ -643,22 +651,41 @@ class DownloadTest : public InProcessBrowserTest { |
// Attempts to download a file, based on information in |download_info|. |
// If a Select File dialog opens, will automatically choose the default. |
- void DownloadFileCheckErrors(const DownloadInfo& download_info) { |
+ void DownloadFilesCheckErrorsSetup() { |
ASSERT_TRUE(test_server()->Start()); |
std::vector<DownloadItem*> download_items; |
GetDownloads(browser(), &download_items); |
ASSERT_TRUE(download_items.empty()); |
NullSelectFile(browser()); |
+ } |
+ |
+ void DownloadFilesCheckErrorsLoopBody(const DownloadInfo& download_info, |
+ size_t i) { |
+ std::stringstream s; |
+ s << " " << __FUNCTION__ << "()" |
+ << " index = " << i |
+ << " url = '" << download_info.url_name << "'" |
+ << " method = " |
+ << ((download_info.download_method == DOWNLOAD_DIRECT) ? |
+ "DOWNLOAD_DIRECT" : "DOWNLOAD_NAVIGATE") |
+ << " show_item = " << download_info.show_download_item |
+ << " reason = " |
+ << InterruptReasonDebugString(download_info.reason); |
+ |
+ std::vector<DownloadItem*> download_items; |
+ GetDownloads(browser(), &download_items); |
+ size_t downloads_expected = download_items.size(); |
std::string server_path = "files/downloads/"; |
server_path += download_info.url_name; |
GURL url = test_server()->GetURL(server_path); |
- ASSERT_TRUE(url.is_valid()); |
- |
- NullSelectFile(browser()); // Needed for read-only tests. |
+ ASSERT_TRUE(url.is_valid()) << s.str(); |
DownloadManager* download_manager = DownloadManagerForBrowser(browser()); |
+ WebContents* web_contents = browser()->GetSelectedWebContents(); |
+ ASSERT_TRUE(web_contents) << s.str(); |
+ |
scoped_ptr<DownloadTestObserver> observer( |
new DownloadTestObserverTerminal( |
download_manager, |
@@ -667,10 +694,9 @@ class DownloadTest : public InProcessBrowserTest { |
DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL)); |
if (download_info.download_method == DOWNLOAD_DIRECT) { |
- // Go directly to download. |
- WebContents* web_contents = browser()->GetSelectedWebContents(); |
- ASSERT_TRUE(web_contents); |
+ // Go directly to download. Don't wait for navigation. |
content::DownloadSaveInfo save_info; |
+ // NOTE: |prompt_for_save_location| may change during the download. |
save_info.prompt_for_save_location = false; |
scoped_refptr<DownloadTestItemCreationObserver> creation_observer( |
@@ -702,6 +728,7 @@ class DownloadTest : public InProcessBrowserTest { |
} |
if (download_info.show_download_item) { |
+ downloads_expected++; |
observer->WaitForFinished(); |
DownloadItem::DownloadState final_state = |
(download_info.reason == content::DOWNLOAD_INTERRUPT_REASON_NONE) ? |
@@ -710,17 +737,26 @@ class DownloadTest : public InProcessBrowserTest { |
EXPECT_EQ(1u, observer->NumDownloadsSeenInState(final_state)); |
} |
- // Validate that the correct file was downloaded. |
+ // Wait till the |DownloadFile|s are destroyed. |
+ ui_test_utils::RunAllPendingInMessageLoop(content::BrowserThread::FILE); |
+ ui_test_utils::RunAllPendingInMessageLoop(content::BrowserThread::UI); |
+ |
+ // Validate that the correct files were downloaded. |
download_items.clear(); |
GetDownloads(browser(), &download_items); |
- size_t item_count = download_info.show_download_item ? 1 : 0; |
- ASSERT_EQ(item_count, download_items.size()); |
+ ASSERT_EQ(downloads_expected, download_items.size()) << s.str(); |
if (download_info.show_download_item) { |
+ // Find the last download item. |
DownloadItem* item = download_items[0]; |
- ASSERT_EQ(url, item->GetOriginalUrl()); |
+ for (size_t d = 1; d < downloads_expected; ++d) { |
+ if (download_items[d]->GetStartTime() > item->GetStartTime()) |
+ item = download_items[d]; |
+ } |
+ |
+ ASSERT_EQ(url, item->GetOriginalUrl()) << s.str(); |
- ASSERT_EQ(download_info.reason, item->GetLastReason()); |
+ ASSERT_EQ(download_info.reason, item->GetLastReason()) << s.str(); |
if (item->GetState() == content::DownloadItem::COMPLETE) { |
// Clean up the file, in case it ended up in the My Documents folder. |
@@ -746,11 +782,75 @@ class DownloadTest : public InProcessBrowserTest { |
} |
} |
+ // Attempts to download a set of files, based on information in the |
+ // |download_info| array. |count| is the number of files. |
+ // If a Select File dialog appears, it will choose the default and return |
+ // immediately. |
+ void DownloadFilesCheckErrors(size_t count, DownloadInfo* download_info) { |
+ DownloadFilesCheckErrorsSetup(); |
+ |
+ for (size_t i = 0; i < count; ++i) { |
+ DownloadFilesCheckErrorsLoopBody(download_info[i], i); |
+ } |
+ } |
+ |
+ void DownloadInsertFilesErrorCheckErrorsLoopBody( |
+ scoped_refptr<content::TestFileErrorInjector> injector, |
+ const FileErrorInjectInfo& info, |
+ size_t i) { |
+ std::stringstream s; |
+ s << " " << __FUNCTION__ << "()" |
+ << " index = " << i |
+ << " url = " << info.error_info.url |
+ << " operation code = " << |
+ content::TestFileErrorInjector::DebugString( |
+ info.error_info.code) |
+ << " instance = " << info.error_info.operation_instance |
+ << " error = " << net::ErrorToString( |
+ info.error_info.net_error); |
+ |
+ injector->ClearErrors(); |
+ injector->AddError(info.error_info); |
+ |
+ injector->InjectErrors(); |
+ |
+ DownloadFilesCheckErrorsLoopBody(info.download_info, i); |
+ |
+ size_t expected_successes = info.download_info.show_download_item ? 1u : 0u; |
+ EXPECT_EQ(expected_successes, injector->TotalFileCount()) << s.str(); |
+ EXPECT_EQ(0u, injector->CurrentFileCount()) << s.str(); |
+ |
+ if (info.download_info.show_download_item) |
+ EXPECT_TRUE(injector->HadFile(GURL(info.error_info.url))) << s.str(); |
+ } |
+ |
+ void DownloadInsertFilesErrorCheckErrors(size_t count, |
+ FileErrorInjectInfo* info) { |
+ DownloadFilesCheckErrorsSetup(); |
+ |
+ // Set up file failures. |
+ scoped_refptr<content::TestFileErrorInjector> injector( |
+ content::TestFileErrorInjector::Create()); |
+ |
+ for (size_t i = 0; i < count; ++i) { |
+ // Set up the full URL, for download file tracking. |
+ std::string server_path = "files/downloads/"; |
+ server_path += info[i].download_info.url_name; |
+ GURL url = test_server()->GetURL(server_path); |
+ info[i].error_info.url = url.spec(); |
+ |
+ DownloadInsertFilesErrorCheckErrorsLoopBody(injector, info[i], i); |
+ } |
+ } |
+ |
// Attempts to download a file to a read-only folder, based on information |
// in |download_info|. |
- void DownloadFileToReadonlyFolder(const DownloadInfo& download_info) { |
+ void DownloadFilesToReadonlyFolder(size_t count, |
+ DownloadInfo* download_info) { |
ASSERT_TRUE(InitialSetup(false)); // Creates temporary download folder. |
+ DownloadFilesCheckErrorsSetup(); |
+ |
// Make the test folder unwritable. |
FilePath destination_folder = GetDownloadDirectory(browser()); |
DVLOG(1) << " " << __FUNCTION__ << "()" |
@@ -758,7 +858,9 @@ class DownloadTest : public InProcessBrowserTest { |
file_util::PermissionRestorer permission_restorer(destination_folder); |
EXPECT_TRUE(file_util::MakeFileUnwritable(destination_folder)); |
- DownloadFileCheckErrors(download_info); |
+ for (size_t i = 0; i < count; ++i) { |
+ DownloadFilesCheckErrorsLoopBody(download_info[i], i); |
+ } |
} |
bool EnsureNoPendingDownloads() { |
@@ -2071,112 +2173,254 @@ IN_PROC_BROWSER_TEST_F(DownloadTest, SavePageNonHTMLViaPost) { |
ASSERT_EQ(jpeg_url, download_items[1]->GetOriginalUrl()); |
} |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadNavigate) { |
- DownloadInfo download_info = { |
- "a_zip_file.zip", |
- DOWNLOAD_NAVIGATE, |
- content::DOWNLOAD_INTERRUPT_REASON_NONE, |
- true, |
- false |
- }; |
- |
- // Do initial setup. |
- ASSERT_TRUE(InitialSetup(false)); |
- DownloadFileCheckErrors(download_info); |
-} |
- |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadDirect) { |
- DownloadInfo download_info = { |
- "a_zip_file.zip", |
- DOWNLOAD_DIRECT, |
- content::DOWNLOAD_INTERRUPT_REASON_NONE, |
- true, |
- false |
- }; |
- |
- // Do initial setup. |
- ASSERT_TRUE(InitialSetup(false)); |
- DownloadFileCheckErrors(download_info); |
-} |
- |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadError404Direct) { |
- DownloadInfo download_info = { |
- "there_IS_no_spoon.zip", |
- DOWNLOAD_DIRECT, |
- content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT, |
- true, |
- false |
- }; |
- |
- // Do initial setup. |
- ASSERT_TRUE(InitialSetup(false)); |
- DownloadFileCheckErrors(download_info); |
-} |
- |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadError404Navigate) { |
- DownloadInfo download_info = { |
- "there_IS_no_spoon.zip", |
- DOWNLOAD_NAVIGATE, |
- content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT, |
- false, |
- false |
- }; |
- |
- // Do initial setup. |
- ASSERT_TRUE(InitialSetup(false)); |
- DownloadFileCheckErrors(download_info); |
-} |
- |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadError400Direct) { |
- DownloadInfo download_info = { |
- "zip_file_not_found.zip", |
- DOWNLOAD_DIRECT, |
- content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, |
- true, |
- false |
+IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadErrorsServer) { |
+ DownloadInfo download_info[] = { |
+ { // Normal navigated download. |
+ "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_NONE, |
+ true, |
+ false |
+ }, |
+ { // Normal direct download. |
+ "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_NONE, |
+ true, |
+ false |
+ }, |
+ { // Direct download with 404 error. |
+ "there_IS_no_spoon.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT, |
+ true, |
+ false |
+ }, |
+ { // Navigated download with 404 error. |
+ "there_IS_no_spoon.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT, |
+ false, |
+ false |
+ }, |
+ { // Direct download with 400 error. |
+ "zip_file_not_found.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, |
+ true, |
+ false |
+ }, |
+ { // Navigated download with 400 error. |
+ "zip_file_not_found.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, |
+ false, |
+ false |
+ } |
}; |
// Do initial setup. |
ASSERT_TRUE(InitialSetup(false)); |
- DownloadFileCheckErrors(download_info); |
-} |
- |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadError400Navigate) { |
- DownloadInfo download_info = { |
- "zip_file_not_found.zip", |
- DOWNLOAD_NAVIGATE, |
- content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, |
- false, |
- false |
- }; |
- // Do initial setup. |
- ASSERT_TRUE(InitialSetup(false)); |
- DownloadFileCheckErrors(download_info); |
+ DownloadFilesCheckErrors(ARRAYSIZE_UNSAFE(download_info), download_info); |
} |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadErrorReadonlyFolderDirect) { |
- DownloadInfo download_info = { |
- "a_zip_file.zip", |
- DOWNLOAD_DIRECT, |
- // This passes because we switch to the My Documents folder. |
- content::DOWNLOAD_INTERRUPT_REASON_NONE, |
- true, |
- true |
+IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadErrorsFile) { |
+ FileErrorInjectInfo error_info[] = { |
+ { // Navigated download with injected "Disk full" error in Initialize(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE, |
+ 0, |
+ net::ERR_FILE_NO_SPACE |
+ } |
+ }, |
+ { // Direct download with injected "Disk full" error in Initialize(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE, |
+ 0, |
+ net::ERR_FILE_NO_SPACE |
+ } |
+ }, |
+ { // Navigated download with injected "Disk full" error in Write(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_WRITE, |
+ 0, |
+ net::ERR_FILE_NO_SPACE |
+ } |
+ }, |
+ { // Direct download with injected "Disk full" error in Write(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_WRITE, |
+ 0, |
+ net::ERR_FILE_NO_SPACE |
+ } |
+ }, |
+ { // Navigated download with injected "Failed" error in Initialize(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE, |
+ 0, |
+ net::ERR_FAILED |
+ } |
+ }, |
+ { // Direct download with injected "Failed" error in Initialize(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE, |
+ 0, |
+ net::ERR_FAILED |
+ } |
+ }, |
+ { // Navigated download with injected "Failed" error in Write(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_WRITE, |
+ 0, |
+ net::ERR_FAILED |
+ } |
+ }, |
+ { // Direct download with injected "Failed" error in Write(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_WRITE, |
+ 0, |
+ net::ERR_FAILED |
+ } |
+ }, |
+ { // Navigated download with injected "Name too long" error in |
+ // Initialize(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE, |
+ 0, |
+ net::ERR_FILE_PATH_TOO_LONG |
+ } |
+ }, |
+ { // Direct download with injected "Name too long" error in Initialize(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE, |
+ 0, |
+ net::ERR_FILE_PATH_TOO_LONG |
+ } |
+ }, |
+ { // Navigated download with injected "Name too long" error in Write(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_WRITE, |
+ 0, |
+ net::ERR_INVALID_HANDLE |
+ } |
+ }, |
+ { // Direct download with injected "Name too long" error in Write(). |
+ { "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_WRITE, |
+ 0, |
+ net::ERR_INVALID_HANDLE |
+ } |
+ }, |
+ { // Direct download with injected "Disk full" error in 2nd Write(). |
+ { "06bESSE21Evolution.ppt", |
+ DOWNLOAD_DIRECT, |
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, |
+ 1 |
+ }, |
+ { |
+ "", |
+ content::TestFileErrorInjector::FILE_OPERATION_WRITE, |
+ 1, |
+ net::ERR_FILE_NO_SPACE |
+ } |
+ } |
}; |
- DownloadFileToReadonlyFolder(download_info); |
+ DownloadInsertFilesErrorCheckErrors(ARRAYSIZE_UNSAFE(error_info), error_info); |
} |
-IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadErrorReadonlyFolderNavigate) { |
- DownloadInfo download_info = { |
- "a_zip_file.zip", |
- DOWNLOAD_NAVIGATE, |
- // This passes because we switch to the My Documents folder. |
- content::DOWNLOAD_INTERRUPT_REASON_NONE, |
- true, |
- true |
+IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadErrorReadonlyFolder) { |
+ DownloadInfo download_info[] = { |
+ { |
+ "a_zip_file.zip", |
+ DOWNLOAD_DIRECT, |
+ // This passes because we switch to the My Documents folder. |
+ content::DOWNLOAD_INTERRUPT_REASON_NONE, |
+ true, |
+ true |
+ }, |
+ { |
+ "a_zip_file.zip", |
+ DOWNLOAD_NAVIGATE, |
+ // This passes because we switch to the My Documents folder. |
+ content::DOWNLOAD_INTERRUPT_REASON_NONE, |
+ true, |
+ true |
+ } |
}; |
- DownloadFileToReadonlyFolder(download_info); |
+ DownloadFilesToReadonlyFolder(ARRAYSIZE_UNSAFE(download_info), download_info); |
} |