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

Unified Diff: chrome/browser/download/download_manager_unittest.cc

Issue 7646025: Detect file system errors during downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merged with trunk. Created 9 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | content/browser/download/base_file.h » ('j') | content/browser/download/base_file_unittest.cc » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/download/download_manager_unittest.cc
diff --git a/chrome/browser/download/download_manager_unittest.cc b/chrome/browser/download/download_manager_unittest.cc
index 58c39fa36df05fc6b64bca79419515ae2768b082..4938db0ea1e76fca82df45f77fb588f22c1ffa26 100644
--- a/chrome/browser/download/download_manager_unittest.cc
+++ b/chrome/browser/download/download_manager_unittest.cc
@@ -30,6 +30,8 @@
#include "content/browser/download/download_status_updater.h"
#include "content/browser/download/mock_download_manager.h"
#include "grit/generated_resources.h"
+#include "net/base/io_buffer.h"
+#include "net/base/mock_file_stream.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -67,8 +69,9 @@ class DownloadManagerTest : public testing::Test {
file_manager()->downloads_[id] = download_file;
}
- void OnAllDataSaved(int32 download_id, int64 size, const std::string& hash) {
- download_manager_->OnAllDataSaved(download_id, size, hash);
+ void OnResponseCompleted(int32 download_id, int64 size,
+ const std::string& hash) {
+ download_manager_->OnResponseCompleted(download_id, size, hash);
}
void FileSelected(const FilePath& path, void* params) {
@@ -79,6 +82,31 @@ class DownloadManagerTest : public testing::Test {
download_manager_->ContinueDownloadWithPath(download, path);
}
+ void UpdateData(int32 id, const void* data, size_t length) {
cbentzel 2011/08/29 15:05:27 Should |data| be const char* to be consistent with
ahendrickson 2011/08/29 16:30:53 I don't have a strong opinion about this. Changed
+ // We are passing ownership of this buffer to the download file manager.
+ net::IOBuffer* io_buffer = new net::IOBuffer(length);
+ // We need |AddRef()| because io_buffer is not a |scoped_refptr|, and we
cbentzel 2011/08/29 15:05:27 This comment isn't quite correct. If io_buffer wer
ahendrickson 2011/08/29 16:30:53 Yeah, it's funky. Changed.
+ // will do a |Release()| in |UpdateDownload()|.
+ io_buffer->AddRef();
+ memcpy(io_buffer->data(), data, length);
+
+ {
+ base::AutoLock auto_lock(download_buffer_.lock);
cbentzel 2011/08/29 15:05:27 This is kinda gross, although it already existed.
ahendrickson 2011/08/29 16:30:53 I think that's outside the scope of this CL.
Randy Smith (Not in Mondays) 2011/08/29 16:57:57 Agreed with both points (suggested refactor, and t
+
+ download_buffer_.contents.push_back(
+ std::make_pair(io_buffer, length));
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(file_manager_.get(),
+ &DownloadFileManager::UpdateDownload,
+ id,
+ &download_buffer_));
+
+ message_loop_.RunAllPending();
cbentzel 2011/08/29 15:05:27 Why do you need to do this inside of UpdateData?
ahendrickson 2011/08/29 16:30:53 For other operations. Most tests don't need to us
+ }
+
void OnDownloadError(int32 download_id, int64 size, int os_error) {
download_manager_->OnDownloadError(download_id, size, os_error);
}
@@ -99,6 +127,7 @@ class DownloadManagerTest : public testing::Test {
MessageLoopForUI message_loop_;
BrowserThread ui_thread_;
BrowserThread file_thread_;
+ DownloadBuffer download_buffer_;
DownloadFileManager* file_manager() {
if (!file_manager_) {
@@ -126,6 +155,35 @@ const char* DownloadManagerTest::kTestData = "a;sdlfalsdfjalsdkfjad";
const size_t DownloadManagerTest::kTestDataLen =
strlen(DownloadManagerTest::kTestData);
+// A DownloadFile that we can inject errors into. Uses MockFileStream.
+// Note: This can't be in an anonymous namespace because it must be declared
+// as a friend of |DownloadFile| in order to access its private members.
cbentzel 2011/08/29 15:05:27 Could you just add a DownloadFile constructor whic
ahendrickson 2011/08/29 16:30:53 It needs more information than just the file strea
+class DownloadFileWithMockStream : public DownloadFile {
+ public:
+ DownloadFileWithMockStream(DownloadCreateInfo* info,
+ DownloadManager* manager,
+ testing::MockFileStream* stream)
+ : DownloadFile(info, manager) {
+ DCHECK(file_stream_ == NULL);
+ file_stream_.reset(stream);
+ }
+ virtual ~DownloadFileWithMockStream() {
+ }
+
+ void SetForcedError(int error)
+ {
+ testing::MockFileStream* mock_stream =
Randy Smith (Not in Mondays) 2011/08/28 22:14:03 Please put in a comment as to why the upcast is ok
ahendrickson 2011/08/29 16:30:53 Done.
+ static_cast<testing::MockFileStream *>(file_stream_.get());
+ mock_stream->set_forced_error(error);
+ }
+
+ protected:
+ // This version creates a |MockFileStream| instead of a |FileStream|.
+ virtual void CreateFileStream() {
cbentzel 2011/08/29 15:05:27 OVERRIDE
cbentzel 2011/08/29 15:05:27 Is this expected to be called?
ahendrickson 2011/08/29 16:30:53 Yes, from Open().
ahendrickson 2011/08/29 16:30:53 Done.
cbentzel 2011/08/29 17:27:55 Well, it could be called from Open(), but that onl
ahendrickson 2011/08/29 17:51:37 No, the rename operation does a Close() (which res
+ file_stream_.reset(new testing::MockFileStream);
+ }
+};
+
namespace {
const struct {
@@ -384,13 +442,13 @@ TEST_F(DownloadManagerTest, DownloadRenameTest) {
int32* id_ptr = new int32;
*id_ptr = i; // Deleted in FileSelected().
if (kDownloadRenameCases[i].finish_before_rename) {
- OnAllDataSaved(i, 1024, std::string("fake_hash"));
+ OnResponseCompleted(i, 1024, std::string("fake_hash"));
message_loop_.RunAllPending();
FileSelected(new_path, id_ptr);
} else {
FileSelected(new_path, id_ptr);
message_loop_.RunAllPending();
- OnAllDataSaved(i, 1024, std::string("fake_hash"));
+ OnResponseCompleted(i, 1024, std::string("fake_hash"));
}
message_loop_.RunAllPending();
@@ -482,6 +540,91 @@ TEST_F(DownloadManagerTest, DownloadInterruptTest) {
EXPECT_EQ(download->total_bytes(), static_cast<int64>(kTestDataLen));
}
+// Test the behavior of DownloadFileManager and DownloadManager in the event
+// of a file error while writing the download to disk.
+TEST_F(DownloadManagerTest, DownloadFileErrorTest) {
+ // Create a temporary file and a mock stream.
+ FilePath path;
+ ASSERT_TRUE(file_util::CreateTemporaryFile(&path));
+
+ // This file stream will be used, until the first rename occurs.
+ testing::MockFileStream* mock_stream = new testing::MockFileStream;
+ ASSERT_EQ(0, mock_stream->Open(
+ path,
+ base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE));
+
+ // Normally, the download system takes ownership of info, and is
+ // responsible for deleting it. In these unit tests, however, we
+ // don't call the function that deletes it, so we can use a stack variable.
cbentzel 2011/08/29 15:05:27 Looks like other tests use scoped_ptr. I'd either
ahendrickson 2011/08/29 16:30:53 DownloadFileManager::CreateDownloadFile() normally
Randy Smith (Not in Mondays) 2011/08/29 16:57:57 I'm cool with shifting back to scoped_ptr; I agree
ahendrickson 2011/08/29 17:51:37 Done.
+ DownloadCreateInfo info;
+ int32 id = 0;
+ info.download_id = id;
+ info.prompt_user_for_save_location = false;
+ info.url_chain.push_back(GURL());
+ info.total_bytes = static_cast<int64>(kTestDataLen * 3);
+ info.save_info.file_path = path;
+
+ // Create a download file that we can insert errors into.
+ DownloadFileWithMockStream* download_file(new DownloadFileWithMockStream(
+ &info, download_manager_, mock_stream));
+ AddDownloadToFileManager(id, download_file);
+
+ // |download_file| is owned by DownloadFileManager.
+ ::testing::Mock::AllowLeak(download_file);
Randy Smith (Not in Mondays) 2011/08/28 22:14:03 Why does the leak occur? Shouldn't it be cleaned
ahendrickson 2011/08/29 16:30:53 Hmm, thinking about it, due to recent refactorings
+ download_manager_->CreateDownloadItem(&info);
+
+ DownloadItem* download = GetActiveDownloadItem(0);
+ ASSERT_TRUE(download != NULL);
+ // This will keep track of what should be displayed on the shelf.
+ scoped_ptr<DownloadItemModel> download_item_model(
+ new DownloadItemModel(download));
+
+ EXPECT_EQ(DownloadItem::IN_PROGRESS, download->state());
+ scoped_ptr<ItemObserver> observer(new ItemObserver(download));
+
+ // Add some data before finalizing the file name.
+ UpdateData(id, kTestData, kTestDataLen);
+
+ // Finalize the file name.
+ ContinueDownloadWithPath(download, path);
+ message_loop_.RunAllPending();
+ EXPECT_TRUE(GetActiveDownloadItem(0) != NULL);
+
+ // Add more data.
+ UpdateData(id, kTestData, kTestDataLen);
+
+ // Add more data, but an error occurs.
+ download_file->SetForcedError(net::ERR_FAILED);
+ UpdateData(id, kTestData, kTestDataLen);
+
+ // Check the state. The download should have been interrupted.
+ EXPECT_TRUE(GetActiveDownloadItem(0) == NULL);
+ EXPECT_TRUE(observer->hit_state(DownloadItem::IN_PROGRESS));
+ EXPECT_TRUE(observer->hit_state(DownloadItem::INTERRUPTED));
+ EXPECT_FALSE(observer->hit_state(DownloadItem::COMPLETE));
+ EXPECT_FALSE(observer->hit_state(DownloadItem::CANCELLED));
+ EXPECT_FALSE(observer->hit_state(DownloadItem::REMOVING));
+ EXPECT_TRUE(observer->was_updated());
+ EXPECT_FALSE(observer->was_opened());
+ EXPECT_FALSE(download->file_externally_removed());
+ EXPECT_EQ(DownloadItem::INTERRUPTED, download->state());
+
+ // Check the download shelf's information.
+ size_t error_size = kTestDataLen * 3;
+ ui::DataUnits amount_units = ui::GetByteDisplayUnits(kTestDataLen);
+ string16 simple_size =
+ ui::FormatBytesWithUnits(error_size, amount_units, false);
+ string16 simple_total = base::i18n::GetDisplayStringInLTRDirectionality(
+ ui::FormatBytesWithUnits(error_size, amount_units, true));
+ EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_INTERRUPTED,
+ simple_size,
+ simple_total),
+ download_item_model->GetStatusText());
+
+ // Clean up.
+ download->Cancel(true);
+}
+
TEST_F(DownloadManagerTest, DownloadCancelTest) {
using ::testing::_;
using ::testing::CreateFunctor;
@@ -609,7 +752,7 @@ TEST_F(DownloadManagerTest, DownloadOverwriteTest) {
download_file->AppendDataToFile(kTestData, kTestDataLen);
// Finish the download.
- OnAllDataSaved(0, kTestDataLen, "");
+ OnResponseCompleted(0, kTestDataLen, "");
message_loop_.RunAllPending();
// Download is complete.
@@ -685,7 +828,7 @@ TEST_F(DownloadManagerTest, DownloadRemoveTest) {
download_file->AppendDataToFile(kTestData, kTestDataLen);
// Finish the download.
- OnAllDataSaved(0, kTestDataLen, "");
+ OnResponseCompleted(0, kTestDataLen, "");
message_loop_.RunAllPending();
// Download is complete.
« no previous file with comments | « no previous file | content/browser/download/base_file.h » ('j') | content/browser/download/base_file_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698