| Index: content/browser/download/download_file_unittest.cc
|
| diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
|
| index 2e8df324f0ebb164fae83acc2af352d829d123cc..c199b64f1f6e53f47aa922ded61cb3019f9f2984 100644
|
| --- a/content/browser/download/download_file_unittest.cc
|
| +++ b/content/browser/download/download_file_unittest.cc
|
| @@ -6,14 +6,17 @@
|
| #include "base/message_loop.h"
|
| #include "base/string_number_conversions.h"
|
| #include "content/browser/browser_thread_impl.h"
|
| +#include "content/browser/download/byte_stream.h"
|
| #include "content/browser/download/download_create_info.h"
|
| #include "content/browser/download/download_file_impl.h"
|
| #include "content/browser/download/download_request_handle.h"
|
| #include "content/browser/power_save_blocker.h"
|
| +#include "content/public/browser/download_interrupt_reasons.h"
|
| #include "content/public/browser/download_manager.h"
|
| #include "content/test/mock_download_manager.h"
|
| #include "net/base/file_stream.h"
|
| #include "net/base/net_errors.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| using content::BrowserThread;
|
| @@ -21,9 +24,28 @@ using content::BrowserThreadImpl;
|
| using content::DownloadFile;
|
| using content::DownloadId;
|
| using content::DownloadManager;
|
| -using testing::_;
|
| -using testing::AnyNumber;
|
| -using testing::StrictMock;
|
| +using ::testing::_;
|
| +using ::testing::AnyNumber;
|
| +using ::testing::DoAll;
|
| +using ::testing::Return;
|
| +using ::testing::SetArgPointee;
|
| +using ::testing::StrictMock;
|
| +
|
| +namespace {
|
| +
|
| +class MockByteStreamOutput : public content::ByteStreamOutput {
|
| + public:
|
| + MockByteStreamOutput() {}
|
| + ~MockByteStreamOutput() {}
|
| +
|
| + // ByteStream functions
|
| + MOCK_METHOD2(Read, content::ByteStreamOutput::StreamState(
|
| + scoped_refptr<net::IOBuffer>*, size_t*));
|
| + MOCK_CONST_METHOD0(GetStatus, content::DownloadInterruptReason());
|
| + MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
|
| +};
|
| +
|
| +} // namespace
|
|
|
| DownloadId::Domain kValidIdDomain = "valid DownloadId::Domain";
|
|
|
| @@ -77,45 +99,125 @@ class DownloadFileTest : public testing::Test {
|
| ui_thread_.message_loop()->RunAllPending();
|
| }
|
|
|
| - virtual void CreateDownloadFile(scoped_ptr<DownloadFile>* file,
|
| - int offset,
|
| - bool calculate_hash) {
|
| + // Mock calls to this function are forwarded here.
|
| + void RegisterCallback(base::Closure sink_callback) {
|
| + sink_callback_ = sink_callback;
|
| + }
|
| +
|
| + virtual bool CreateDownloadFile(int offset, bool calculate_hash) {
|
| + // There can be only one.
|
| + DCHECK(!download_file_.get());
|
| +
|
| + input_pipe_ = new StrictMock<MockByteStreamOutput>();
|
| +
|
| + // TODO: Need to actually create a function that'll set the variables
|
| + // based on the inputs from the callback.
|
| + EXPECT_CALL(*input_pipe_, RegisterCallback(_))
|
| + .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
|
| + .RetiresOnSaturation();
|
| +
|
| DownloadCreateInfo info;
|
| info.download_id = DownloadId(kValidIdDomain, kDummyDownloadId + offset);
|
| // info.request_handle default constructed to null.
|
| info.save_info.file_stream = file_stream_;
|
| - file->reset(
|
| - new DownloadFileImpl(&info, new DownloadRequestHandle(),
|
| - download_manager_, calculate_hash,
|
| - scoped_ptr<PowerSaveBlocker>(NULL).Pass(),
|
| - net::BoundNetLog()));
|
| + download_file_.reset(
|
| + new DownloadFileImpl(
|
| + &info,
|
| + scoped_ptr<content::ByteStreamOutput>(input_pipe_).Pass(),
|
| + new DownloadRequestHandle(),
|
| + download_manager_, calculate_hash,
|
| + scoped_ptr<PowerSaveBlocker>(NULL).Pass(),
|
| + net::BoundNetLog()));
|
| +
|
| + EXPECT_CALL(*input_pipe_, Read(_, _))
|
| + .WillOnce(Return(content::ByteStreamOutput::STREAM_EMPTY))
|
| + .RetiresOnSaturation();
|
| + net::Error result = download_file_->Initialize();
|
| + ::testing::Mock::VerifyAndClearExpectations(input_pipe_);
|
| + return result == net::OK;
|
| }
|
|
|
| - virtual void DestroyDownloadFile(scoped_ptr<DownloadFile>* file, int offset) {
|
| - EXPECT_EQ(kDummyDownloadId + offset, (*file)->Id());
|
| - EXPECT_EQ(download_manager_, (*file)->GetDownloadManager());
|
| - EXPECT_FALSE((*file)->InProgress());
|
| + virtual void DestroyDownloadFile(int offset) {
|
| + EXPECT_EQ(kDummyDownloadId + offset, download_file_->Id());
|
| + EXPECT_EQ(download_manager_, download_file_->GetDownloadManager());
|
| + EXPECT_FALSE(download_file_->InProgress());
|
| EXPECT_EQ(static_cast<int64>(expected_data_.size()),
|
| - (*file)->BytesSoFar());
|
| + download_file_->BytesSoFar());
|
|
|
| // Make sure the data has been properly written to disk.
|
| std::string disk_data;
|
| - EXPECT_TRUE(file_util::ReadFileToString((*file)->FullPath(),
|
| + EXPECT_TRUE(file_util::ReadFileToString(download_file_->FullPath(),
|
| &disk_data));
|
| EXPECT_EQ(expected_data_, disk_data);
|
|
|
| // Make sure the Browser and File threads outlive the DownloadFile
|
| // to satisfy thread checks inside it.
|
| - file->reset();
|
| + EXPECT_CALL(*input_pipe_, RegisterCallback(_))
|
| + .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
|
| + .RetiresOnSaturation();
|
| + download_file_.reset();
|
| }
|
|
|
| - void AppendDataToFile(scoped_ptr<DownloadFile>* file,
|
| - const std::string& data) {
|
| - EXPECT_TRUE((*file)->InProgress());
|
| - (*file)->AppendDataToFile(data.data(), data.size());
|
| - expected_data_ += data;
|
| - EXPECT_EQ(static_cast<int64>(expected_data_.size()),
|
| - (*file)->BytesSoFar());
|
| + // Setup the pipe to do be a data append; don't actually trigger
|
| + // the callback or do verifications.
|
| + void SetupDataAppend(const char **data_chunks, size_t num_chunks,
|
| + ::testing::Sequence s) {
|
| + DCHECK(input_pipe_);
|
| + for (size_t i = 0; i < num_chunks; i++) {
|
| + const char *source_data = data_chunks[i];
|
| + size_t length = strlen(source_data);
|
| + scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length);
|
| + memcpy(data->data(), source_data, length);
|
| + EXPECT_CALL(*input_pipe_, Read(_, _))
|
| + .InSequence(s)
|
| + .WillOnce(DoAll(SetArgPointee<0>(data),
|
| + SetArgPointee<1>(length),
|
| + Return(content::ByteStreamOutput::STREAM_HAS_DATA)))
|
| + .RetiresOnSaturation();
|
| + expected_data_ += source_data;
|
| + }
|
| + }
|
| +
|
| + void VerifyPipeAndSize() {
|
| + ::testing::Mock::VerifyAndClearExpectations(input_pipe_);
|
| + int64 size;
|
| + EXPECT_TRUE(file_util::GetFileSize(download_file_->FullPath(), &size));
|
| + EXPECT_EQ(expected_data_.size(), static_cast<size_t>(size));
|
| + }
|
| +
|
| + // TODO(rdsmith): Manage full percentage issues properly.
|
| + void AppendDataToFile(const char **data_chunks, size_t num_chunks) {
|
| + ::testing::Sequence s1;
|
| + SetupDataAppend(data_chunks, num_chunks, s1);
|
| + EXPECT_CALL(*input_pipe_, Read(_, _))
|
| + .InSequence(s1)
|
| + .WillOnce(Return(content::ByteStreamOutput::STREAM_EMPTY))
|
| + .RetiresOnSaturation();
|
| + sink_callback_.Run();
|
| + VerifyPipeAndSize();
|
| + }
|
| +
|
| + void SetupFinishPipe(content::DownloadInterruptReason interrupt_reason,
|
| + ::testing::Sequence s) {
|
| + EXPECT_CALL(*input_pipe_, Read(_, _))
|
| + .InSequence(s)
|
| + .WillOnce(Return(content::ByteStreamOutput::STREAM_COMPLETE))
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*input_pipe_, GetStatus())
|
| + .InSequence(s)
|
| + .WillOnce(Return(interrupt_reason))
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*input_pipe_, RegisterCallback(_))
|
| + .InSequence(s)
|
| + .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
|
| + .RetiresOnSaturation();
|
| + }
|
| +
|
| + void FinishPipe(content::DownloadInterruptReason interrupt_reason) {
|
| + ::testing::Sequence s1;
|
| + SetupFinishPipe(interrupt_reason, s1);
|
| + sink_callback_.Run();
|
| + VerifyPipeAndSize();
|
| }
|
|
|
| protected:
|
| @@ -126,6 +228,13 @@ class DownloadFileTest : public testing::Test {
|
| // DownloadFile instance we are testing.
|
| scoped_ptr<DownloadFile> download_file_;
|
|
|
| + // Pipe for sending data into the download file.
|
| + // Owned by download_file_; will be alive for lifetime of download_file_.
|
| + StrictMock<MockByteStreamOutput>* input_pipe_;
|
| +
|
| + // Sink callback data for pipe.
|
| + base::Closure sink_callback_;
|
| +
|
| // Latest update sent to the download manager.
|
| int64 bytes_;
|
| int64 bytes_per_sec_;
|
| @@ -157,7 +266,7 @@ const int DownloadFileTest::kDummyRequestId = 67;
|
| // Rename the file before any data is downloaded, after some has, after it all
|
| // has, and after it's closed.
|
| TEST_F(DownloadFileTest, RenameFileFinal) {
|
| - CreateDownloadFile(&download_file_, 0, true);
|
| + CreateDownloadFile(0, true);
|
| ASSERT_EQ(net::OK, download_file_->Initialize());
|
| FilePath initial_path(download_file_->FullPath());
|
| EXPECT_TRUE(file_util::PathExists(initial_path));
|
| @@ -176,8 +285,8 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
|
| EXPECT_TRUE(file_util::PathExists(path_1));
|
|
|
| // Download the data.
|
| - AppendDataToFile(&download_file_, kTestData1);
|
| - AppendDataToFile(&download_file_, kTestData2);
|
| + const char* chunks1[] = { kTestData1, kTestData2 };
|
| + AppendDataToFile(chunks1, 2);
|
|
|
| // Rename the file after downloading some data.
|
| EXPECT_EQ(net::OK, download_file_->Rename(path_2));
|
| @@ -188,7 +297,8 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
|
| EXPECT_FALSE(file_util::PathExists(path_1));
|
| EXPECT_TRUE(file_util::PathExists(path_2));
|
|
|
| - AppendDataToFile(&download_file_, kTestData3);
|
| + const char* chunks2[] = { kTestData3 };
|
| + AppendDataToFile(chunks2, 1);
|
|
|
| // Rename the file after downloading all the data.
|
| EXPECT_EQ(net::OK, download_file_->Rename(path_3));
|
| @@ -202,8 +312,7 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
|
| // Should not be able to get the hash until the file is closed.
|
| std::string hash;
|
| EXPECT_FALSE(download_file_->GetHash(&hash));
|
| -
|
| - download_file_->Finish();
|
| + FinishPipe(content::DOWNLOAD_INTERRUPT_REASON_NONE);
|
|
|
| // Rename the file after downloading all the data and closing the file.
|
| EXPECT_EQ(net::OK, download_file_->Rename(path_4));
|
| @@ -218,17 +327,94 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
|
| EXPECT_TRUE(download_file_->GetHash(&hash));
|
| EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
|
|
|
| - DestroyDownloadFile(&download_file_, 0);
|
| + DestroyDownloadFile(0);
|
| +}
|
| +
|
| +// Various tests of the PipeActive method.
|
| +TEST_F(DownloadFileTest, PipeEmptySuccess) {
|
| + ASSERT_TRUE(CreateDownloadFile(0, true));
|
| + FilePath initial_path(download_file_->FullPath());
|
| + EXPECT_TRUE(file_util::PathExists(initial_path));
|
| +
|
| + // Test that calling the sink_callback_ on an empty pipe shouldn't
|
| + // do anything.
|
| + AppendDataToFile(NULL, 0);
|
| + ::testing::Mock::VerifyAndClearExpectations(download_manager_.get());
|
| +
|
| + // Finish the download this way and make sure we see it on the
|
| + // DownloadManager.
|
| + EXPECT_CALL(*(download_manager_.get()),
|
| + OnResponseCompleted(DownloadId(kValidIdDomain,
|
| + kDummyDownloadId + 0).local(),
|
| + 0, _));
|
| + FinishPipe(content::DOWNLOAD_INTERRUPT_REASON_NONE);
|
| +
|
| + DestroyDownloadFile(0);
|
| +}
|
| +
|
| +TEST_F(DownloadFileTest, PipeEmptyError) {
|
| + ASSERT_TRUE(CreateDownloadFile(0, true));
|
| + FilePath initial_path(download_file_->FullPath());
|
| + EXPECT_TRUE(file_util::PathExists(initial_path));
|
| +
|
| + // Finish the download in error and make sure we see it on the
|
| + // DownloadManager.
|
| + EXPECT_CALL(*(download_manager_.get()),
|
| + OnDownloadInterrupted(
|
| + DownloadId(kValidIdDomain, kDummyDownloadId + 0).local(),
|
| + 0, _,
|
| + content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED));
|
| + FinishPipe(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED);
|
| +
|
| + DestroyDownloadFile(0);
|
| +}
|
| +
|
| +TEST_F(DownloadFileTest, PipeNonEmptySuccess) {
|
| + ASSERT_TRUE(CreateDownloadFile(0, true));
|
| + FilePath initial_path(download_file_->FullPath());
|
| + EXPECT_TRUE(file_util::PathExists(initial_path));
|
| +
|
| + const char* chunks1[] = { kTestData1, kTestData2 };
|
| + ::testing::Sequence s1;
|
| + SetupDataAppend(chunks1, 2, s1);
|
| + SetupFinishPipe(content::DOWNLOAD_INTERRUPT_REASON_NONE, s1);
|
| + EXPECT_CALL(*(download_manager_.get()),
|
| + OnResponseCompleted(DownloadId(kValidIdDomain,
|
| + kDummyDownloadId + 0).local(),
|
| + strlen(kTestData1) + strlen(kTestData2),
|
| + _));
|
| + sink_callback_.Run();
|
| + VerifyPipeAndSize();
|
| + DestroyDownloadFile(0);
|
| +}
|
| +
|
| +TEST_F(DownloadFileTest, PipeNonEmptyError) {
|
| + ASSERT_TRUE(CreateDownloadFile(0, true));
|
| + FilePath initial_path(download_file_->FullPath());
|
| + EXPECT_TRUE(file_util::PathExists(initial_path));
|
| +
|
| + const char* chunks1[] = { kTestData1, kTestData2 };
|
| + ::testing::Sequence s1;
|
| + SetupDataAppend(chunks1, 2, s1);
|
| + SetupFinishPipe(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
|
| + EXPECT_CALL(*(download_manager_.get()),
|
| + OnDownloadInterrupted(
|
| + DownloadId(kValidIdDomain, kDummyDownloadId + 0).local(),
|
| + strlen(kTestData1) + strlen(kTestData2), _,
|
| + content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED));
|
| + sink_callback_.Run();
|
| + VerifyPipeAndSize();
|
| + DestroyDownloadFile(0);
|
| }
|
|
|
| // Send some data, wait 3/4s of a second, run the message loop, and
|
| // confirm the values the DownloadManager received are correct.
|
| TEST_F(DownloadFileTest, ConfirmUpdate) {
|
| - CreateDownloadFile(&download_file_, 0, true);
|
| + CreateDownloadFile(0, true);
|
| ASSERT_EQ(net::OK, download_file_->Initialize());
|
|
|
| - AppendDataToFile(&download_file_, kTestData1);
|
| - AppendDataToFile(&download_file_, kTestData2);
|
| + const char* chunks1[] = { kTestData1, kTestData2 };
|
| + AppendDataToFile(chunks1, 2);
|
|
|
| // Run the message loops for 750ms and check for results.
|
| loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
|
| @@ -239,6 +425,6 @@ TEST_F(DownloadFileTest, ConfirmUpdate) {
|
| bytes_);
|
| EXPECT_EQ(download_file_->GetHashState(), hash_state_);
|
|
|
| - download_file_->Finish();
|
| - DestroyDownloadFile(&download_file_, 0);
|
| + FinishPipe(content::DOWNLOAD_INTERRUPT_REASON_NONE);
|
| + DestroyDownloadFile(0);
|
| }
|
|
|