Chromium Code Reviews| Index: content/browser/download/parallel_download_job_unittest.cc |
| diff --git a/content/browser/download/parallel_download_job_unittest.cc b/content/browser/download/parallel_download_job_unittest.cc |
| index 394da4163942f0276df755a842ca346cacf66c4c..14447fc22f4a477d9cd59e9eb3a6079ec022b210 100644 |
| --- a/content/browser/download/parallel_download_job_unittest.cc |
| +++ b/content/browser/download/parallel_download_job_unittest.cc |
| @@ -31,6 +31,26 @@ class MockDownloadRequestHandle : public DownloadRequestHandleInterface { |
| MOCK_CONST_METHOD0(DebugString, std::string()); |
| }; |
| +class DownloadWorkerForTest : public DownloadWorker { |
| + public: |
| + DownloadWorkerForTest(DownloadWorker::Delegate* delegate, |
| + int64_t offset, |
| + int64_t length) |
| + : DownloadWorker(delegate, offset, length) {} |
| + |
| + void MakeResponseReady( |
| + std::unique_ptr<MockDownloadRequestHandle> request_handle) { |
| + UrlDownloader::Delegate* delegate = |
| + static_cast<UrlDownloader::Delegate*>(this); |
| + std::unique_ptr<DownloadCreateInfo> create_info = |
| + base::MakeUnique<DownloadCreateInfo>(); |
| + create_info->request_handle = std::move(request_handle); |
| + delegate->OnUrlDownloaderStarted( |
| + std::move(create_info), std::unique_ptr<ByteStreamReader>(), |
| + DownloadUrlParameters::OnStartedCallback()); |
| + } |
| +}; |
| + |
| } // namespace |
| class ParallelDownloadJobForTest : public ParallelDownloadJob { |
| @@ -45,15 +65,31 @@ class ParallelDownloadJobForTest : public ParallelDownloadJob { |
| create_info), |
| request_count_(request_count) {} |
| + const std::vector<DownloadWorkerForTest*>& mock_workers() { |
| + return mock_workers_; |
| + } |
| + |
| void CreateRequest(int64_t offset, int64_t length) override { |
| - fake_tasks_.push_back(std::pair<int64_t, int64_t>(offset, length)); |
| + std::unique_ptr<DownloadWorkerForTest> mock_worker = |
| + base::MakeUnique<DownloadWorkerForTest>(this, offset, length); |
| + mock_workers_.push_back(mock_worker.get()); |
| + |
| + DCHECK(workers_.find(offset) == workers_.end()); |
| + workers_[offset] = std::move(mock_worker); |
| } |
| int GetParallelRequestCount() const override { return request_count_; } |
| - std::vector<std::pair<int64_t, int64_t>> fake_tasks_; |
| + void OnByteStreamReady( |
| + DownloadWorker* worker, |
| + std::unique_ptr<ByteStreamReader> stream_reader) override { |
| + CountOnByteStreamReady(); |
| + } |
| + |
| + MOCK_METHOD0(CountOnByteStreamReady, void()); |
| private: |
| + std::vector<DownloadWorkerForTest*> mock_workers_; |
|
qinmin
2017/03/22 05:50:29
looks like you only need to check the size of this
xingliu
2017/03/22 23:54:06
Done,
Good catch, this is no longer needed.
|
| int request_count_; |
| DISALLOW_COPY_AND_ASSIGN(ParallelDownloadJobForTest); |
| }; |
| @@ -70,23 +106,34 @@ class ParallelDownloadJobTest : public testing::Test { |
| DownloadCreateInfo info; |
| info.offset = offset; |
| info.total_bytes = content_length; |
| + std::unique_ptr<MockDownloadRequestHandle> request_handle = |
| + base::MakeUnique<MockDownloadRequestHandle>(); |
| + mock_request_handle_ = request_handle.get(); |
| job_ = base::MakeUnique<ParallelDownloadJobForTest>( |
| - download_item_.get(), base::MakeUnique<MockDownloadRequestHandle>(), |
| - info, request_count); |
| + download_item_.get(), std::move(request_handle), info, request_count); |
| } |
| void DestroyParallelJob() { |
| job_.reset(); |
| download_item_.reset(); |
| item_delegate_.reset(); |
| + mock_request_handle_ = nullptr; |
| } |
| void BuildParallelRequests() { job_->BuildParallelRequests(); } |
| + void VerifyWorker(int64_t offset, int64_t length) const { |
| + EXPECT_TRUE(job_->workers_.find(offset) != job_->workers_.end()); |
| + EXPECT_EQ(offset, job_->workers_[offset]->offset()); |
| + EXPECT_EQ(length, job_->workers_[offset]->length()); |
| + } |
| + |
| content::TestBrowserThreadBundle browser_threads_; |
| std::unique_ptr<DownloadItemImplDelegate> item_delegate_; |
| std::unique_ptr<MockDownloadItemImpl> download_item_; |
| std::unique_ptr<ParallelDownloadJobForTest> job_; |
| + // Request handle for the original request. |
| + MockDownloadRequestHandle* mock_request_handle_; |
| }; |
| // Test if parallel requests can be built correctly for a new download. |
| @@ -96,10 +143,8 @@ TEST_F(ParallelDownloadJobTest, CreateNewDownloadRequests) { |
| // Task 1: Range:50-, for 50 bytes. |
| CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); |
| BuildParallelRequests(); |
| - EXPECT_EQ(1, static_cast<int>(job_->fake_tasks_.size())); |
| - EXPECT_EQ(50, job_->fake_tasks_[0].first); |
| - EXPECT_EQ(0, job_->fake_tasks_[0].second); |
| - job_->fake_tasks_.clear(); |
| + EXPECT_EQ(1, static_cast<int>(job_->mock_workers().size())); |
| + VerifyWorker(50, 0); |
| DestroyParallelJob(); |
| // Totally 3 requests for 100 bytes. |
| @@ -108,12 +153,9 @@ TEST_F(ParallelDownloadJobTest, CreateNewDownloadRequests) { |
| // Task 2: Range:66-, for 34 bytes. |
| CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 3); |
| BuildParallelRequests(); |
| - EXPECT_EQ(2, static_cast<int>(job_->fake_tasks_.size())); |
| - EXPECT_EQ(33, job_->fake_tasks_[0].first); |
| - EXPECT_EQ(33, job_->fake_tasks_[0].second); |
| - EXPECT_EQ(66, job_->fake_tasks_[1].first); |
| - EXPECT_EQ(0, job_->fake_tasks_[1].second); |
| - job_->fake_tasks_.clear(); |
| + EXPECT_EQ(2, static_cast<int>(job_->mock_workers().size())); |
| + VerifyWorker(33, 33); |
| + VerifyWorker(66, 0); |
| DestroyParallelJob(); |
| // Totally 3 requests for 100 bytes. Start from the 17th byte. |
| @@ -122,34 +164,31 @@ TEST_F(ParallelDownloadJobTest, CreateNewDownloadRequests) { |
| // Task 2: Range:71-99, for 29 bytes. |
| CreateParallelJob(17, 83, DownloadItem::ReceivedSlices(), 3); |
| BuildParallelRequests(); |
| - EXPECT_EQ(2, static_cast<int>(job_->fake_tasks_.size())); |
| - EXPECT_EQ(44, job_->fake_tasks_[0].first); |
| - EXPECT_EQ(27, job_->fake_tasks_[0].second); |
| - EXPECT_EQ(71, job_->fake_tasks_[1].first); |
| - EXPECT_EQ(0, job_->fake_tasks_[1].second); |
| - job_->fake_tasks_.clear(); |
| + EXPECT_EQ(2, static_cast<int>(job_->mock_workers().size())); |
| + VerifyWorker(44, 27); |
| + VerifyWorker(71, 0); |
| DestroyParallelJob(); |
| // Less than 2 requests, do nothing. |
| CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 1); |
| BuildParallelRequests(); |
| - EXPECT_TRUE(job_->fake_tasks_.empty()); |
| + EXPECT_TRUE(job_->mock_workers().empty()); |
| DestroyParallelJob(); |
| CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 0); |
| BuildParallelRequests(); |
| - EXPECT_TRUE(job_->fake_tasks_.empty()); |
| + EXPECT_TRUE(job_->mock_workers().empty()); |
| DestroyParallelJob(); |
| // Content-length is 0, do nothing. |
| CreateParallelJob(100, 0, DownloadItem::ReceivedSlices(), 3); |
| BuildParallelRequests(); |
| - EXPECT_TRUE(job_->fake_tasks_.empty()); |
| + EXPECT_TRUE(job_->mock_workers().empty()); |
| DestroyParallelJob(); |
| CreateParallelJob(0, 0, DownloadItem::ReceivedSlices(), 3); |
| BuildParallelRequests(); |
| - EXPECT_TRUE(job_->fake_tasks_.empty()); |
| + EXPECT_TRUE(job_->mock_workers().empty()); |
| DestroyParallelJob(); |
| // 2 bytes left for 3 additional requests. Only 1 are built. |
| @@ -157,10 +196,108 @@ TEST_F(ParallelDownloadJobTest, CreateNewDownloadRequests) { |
| // Task 1: Range:99-, for 1 byte. |
| CreateParallelJob(98, 2, DownloadItem::ReceivedSlices(), 4); |
| BuildParallelRequests(); |
| - EXPECT_EQ(1, static_cast<int>(job_->fake_tasks_.size())); |
| - EXPECT_EQ(99, job_->fake_tasks_[0].first); |
| - EXPECT_EQ(0, job_->fake_tasks_[0].second); |
| - job_->fake_tasks_.clear(); |
| + EXPECT_EQ(1, static_cast<int>(job_->mock_workers().size())); |
| + VerifyWorker(99, 0); |
| + DestroyParallelJob(); |
| +} |
| + |
| +// Pause, cancel, resume can be called before or after the worker establish |
| +// the byte stream. |
| +// These tests ensure the states consistency between the job and workers. |
| + |
| +// Ensure cancel before building the requests will result in workers being |
| +// canceled. |
| +TEST_F(ParallelDownloadJobTest, EarlyCancelBeforeBuildRequests) { |
| + CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); |
| + EXPECT_CALL(*mock_request_handle_, CancelRequest()); |
| + |
| + // Job is canceled before building parallel requests. |
| + job_->Cancel(true); |
| + EXPECT_TRUE(job_->is_canceled()); |
| + |
| + BuildParallelRequests(); |
| + VerifyWorker(50, 0); |
| + |
| + for (auto* worker : job_->mock_workers()) { |
| + std::unique_ptr<MockDownloadRequestHandle> mock_handle = |
| + base::MakeUnique<MockDownloadRequestHandle>(); |
| + EXPECT_CALL(*mock_handle.get(), CancelRequest()); |
| + worker->MakeResponseReady(std::move(mock_handle)); |
| + } |
| + |
| + DestroyParallelJob(); |
| +} |
| + |
| +// Ensure cancel before adding the byte stream will result in workers being |
| +// canceled. |
| +TEST_F(ParallelDownloadJobTest, EarlyCancelBeforeByteStreamReady) { |
| + CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); |
| + EXPECT_CALL(*mock_request_handle_, CancelRequest()); |
| + |
| + BuildParallelRequests(); |
| + VerifyWorker(50, 0); |
| + |
| + // Job is canceled after building parallel requests and before byte streams |
| + // are added to the file sink. |
| + job_->Cancel(true); |
| + EXPECT_TRUE(job_->is_canceled()); |
| + |
| + for (auto* worker : job_->mock_workers()) { |
| + std::unique_ptr<MockDownloadRequestHandle> mock_handle = |
| + base::MakeUnique<MockDownloadRequestHandle>(); |
| + EXPECT_CALL(*mock_handle.get(), CancelRequest()); |
| + worker->MakeResponseReady(std::move(mock_handle)); |
| + } |
| + |
| + DestroyParallelJob(); |
| +} |
| + |
| +// Ensure pause before building the requests will result in workers being |
| +// paused. |
| +TEST_F(ParallelDownloadJobTest, EarlyPauseBeforeBuildRequests) { |
| + CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); |
| + EXPECT_CALL(*mock_request_handle_, PauseRequest()); |
| + |
| + // Job is paused before building parallel requests. |
| + job_->Pause(); |
| + EXPECT_TRUE(job_->is_paused()); |
| + |
| + BuildParallelRequests(); |
| + VerifyWorker(50, 0); |
| + |
| + for (auto* worker : job_->mock_workers()) { |
| + EXPECT_CALL(*job_.get(), CountOnByteStreamReady()); |
| + std::unique_ptr<MockDownloadRequestHandle> mock_handle = |
| + base::MakeUnique<MockDownloadRequestHandle>(); |
| + EXPECT_CALL(*mock_handle.get(), PauseRequest()); |
| + worker->MakeResponseReady(std::move(mock_handle)); |
| + } |
| + |
| + DestroyParallelJob(); |
| +} |
| + |
| +// Ensure pause before adding the byte stream will result in workers being |
| +// paused. |
| +TEST_F(ParallelDownloadJobTest, EarlyPauseBeforeByteStreamReady) { |
| + CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); |
| + EXPECT_CALL(*mock_request_handle_, PauseRequest()); |
| + |
| + BuildParallelRequests(); |
| + VerifyWorker(50, 0); |
| + |
| + // Job is paused after building parallel requests and before adding the byte |
| + // stream to the file sink. |
| + job_->Pause(); |
| + EXPECT_TRUE(job_->is_paused()); |
| + |
| + for (auto* worker : job_->mock_workers()) { |
| + EXPECT_CALL(*job_.get(), CountOnByteStreamReady()); |
| + std::unique_ptr<MockDownloadRequestHandle> mock_handle = |
| + base::MakeUnique<MockDownloadRequestHandle>(); |
| + EXPECT_CALL(*mock_handle.get(), PauseRequest()); |
| + worker->MakeResponseReady(std::move(mock_handle)); |
| + } |
| + |
| DestroyParallelJob(); |
| } |