Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/download/parallel_download_job.h" | 5 #include "content/browser/download/parallel_download_job.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 class MockDownloadRequestHandle : public DownloadRequestHandleInterface { | 24 class MockDownloadRequestHandle : public DownloadRequestHandleInterface { |
| 25 public: | 25 public: |
| 26 MOCK_CONST_METHOD0(GetWebContents, WebContents*()); | 26 MOCK_CONST_METHOD0(GetWebContents, WebContents*()); |
| 27 MOCK_CONST_METHOD0(GetDownloadManager, DownloadManager*()); | 27 MOCK_CONST_METHOD0(GetDownloadManager, DownloadManager*()); |
| 28 MOCK_CONST_METHOD0(PauseRequest, void()); | 28 MOCK_CONST_METHOD0(PauseRequest, void()); |
| 29 MOCK_CONST_METHOD0(ResumeRequest, void()); | 29 MOCK_CONST_METHOD0(ResumeRequest, void()); |
| 30 MOCK_CONST_METHOD0(CancelRequest, void()); | 30 MOCK_CONST_METHOD0(CancelRequest, void()); |
| 31 MOCK_CONST_METHOD0(DebugString, std::string()); | 31 MOCK_CONST_METHOD0(DebugString, std::string()); |
| 32 }; | 32 }; |
| 33 | 33 |
| 34 class DownloadWorkerForTest : public DownloadWorker { | |
| 35 public: | |
| 36 DownloadWorkerForTest(DownloadWorker::Delegate* delegate, | |
| 37 int64_t offset, | |
| 38 int64_t length) | |
| 39 : DownloadWorker(delegate, offset, length) {} | |
| 40 | |
| 41 void MakeResponseReady( | |
| 42 std::unique_ptr<MockDownloadRequestHandle> request_handle) { | |
| 43 UrlDownloader::Delegate* delegate = | |
| 44 static_cast<UrlDownloader::Delegate*>(this); | |
| 45 std::unique_ptr<DownloadCreateInfo> create_info = | |
| 46 base::MakeUnique<DownloadCreateInfo>(); | |
| 47 create_info->request_handle = std::move(request_handle); | |
| 48 delegate->OnUrlDownloaderStarted( | |
| 49 std::move(create_info), std::unique_ptr<ByteStreamReader>(), | |
| 50 DownloadUrlParameters::OnStartedCallback()); | |
| 51 } | |
| 52 }; | |
| 53 | |
| 34 } // namespace | 54 } // namespace |
| 35 | 55 |
| 36 class ParallelDownloadJobForTest : public ParallelDownloadJob { | 56 class ParallelDownloadJobForTest : public ParallelDownloadJob { |
| 37 public: | 57 public: |
| 38 ParallelDownloadJobForTest( | 58 ParallelDownloadJobForTest( |
| 39 DownloadItemImpl* download_item, | 59 DownloadItemImpl* download_item, |
| 40 std::unique_ptr<DownloadRequestHandleInterface> request_handle, | 60 std::unique_ptr<DownloadRequestHandleInterface> request_handle, |
| 41 const DownloadCreateInfo& create_info, | 61 const DownloadCreateInfo& create_info, |
| 42 int request_count) | 62 int request_count) |
| 43 : ParallelDownloadJob(download_item, | 63 : ParallelDownloadJob(download_item, |
| 44 std::move(request_handle), | 64 std::move(request_handle), |
| 45 create_info), | 65 create_info), |
| 46 request_count_(request_count) {} | 66 request_count_(request_count) {} |
| 47 | 67 |
| 68 const std::vector<DownloadWorkerForTest*>& mock_workers() { | |
| 69 return mock_workers_; | |
| 70 } | |
| 71 | |
| 48 void CreateRequest(int64_t offset, int64_t length) override { | 72 void CreateRequest(int64_t offset, int64_t length) override { |
| 49 fake_tasks_.push_back(std::pair<int64_t, int64_t>(offset, length)); | 73 std::unique_ptr<DownloadWorkerForTest> mock_worker = |
| 74 base::MakeUnique<DownloadWorkerForTest>(this, offset, length); | |
| 75 mock_workers_.push_back(mock_worker.get()); | |
| 76 | |
| 77 DCHECK(workers_.find(offset) == workers_.end()); | |
| 78 workers_[offset] = std::move(mock_worker); | |
| 50 } | 79 } |
| 51 | 80 |
| 52 int GetParallelRequestCount() const override { return request_count_; } | 81 int GetParallelRequestCount() const override { return request_count_; } |
| 53 | 82 |
| 54 std::vector<std::pair<int64_t, int64_t>> fake_tasks_; | 83 void OnByteStreamReady( |
| 84 DownloadWorker* worker, | |
| 85 std::unique_ptr<ByteStreamReader> stream_reader) override { | |
| 86 CountOnByteStreamReady(); | |
| 87 } | |
| 88 | |
| 89 MOCK_METHOD0(CountOnByteStreamReady, void()); | |
| 55 | 90 |
| 56 private: | 91 private: |
| 92 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.
| |
| 57 int request_count_; | 93 int request_count_; |
| 58 DISALLOW_COPY_AND_ASSIGN(ParallelDownloadJobForTest); | 94 DISALLOW_COPY_AND_ASSIGN(ParallelDownloadJobForTest); |
| 59 }; | 95 }; |
| 60 | 96 |
| 61 class ParallelDownloadJobTest : public testing::Test { | 97 class ParallelDownloadJobTest : public testing::Test { |
| 62 public: | 98 public: |
| 63 void CreateParallelJob(int64_t offset, | 99 void CreateParallelJob(int64_t offset, |
| 64 int64_t content_length, | 100 int64_t content_length, |
| 65 const DownloadItem::ReceivedSlices& slices, | 101 const DownloadItem::ReceivedSlices& slices, |
| 66 int request_count) { | 102 int request_count) { |
| 67 item_delegate_ = base::MakeUnique<DownloadItemImplDelegate>(); | 103 item_delegate_ = base::MakeUnique<DownloadItemImplDelegate>(); |
| 68 download_item_ = base::MakeUnique<NiceMock<MockDownloadItemImpl>>( | 104 download_item_ = base::MakeUnique<NiceMock<MockDownloadItemImpl>>( |
| 69 item_delegate_.get(), slices); | 105 item_delegate_.get(), slices); |
| 70 DownloadCreateInfo info; | 106 DownloadCreateInfo info; |
| 71 info.offset = offset; | 107 info.offset = offset; |
| 72 info.total_bytes = content_length; | 108 info.total_bytes = content_length; |
| 109 std::unique_ptr<MockDownloadRequestHandle> request_handle = | |
| 110 base::MakeUnique<MockDownloadRequestHandle>(); | |
| 111 mock_request_handle_ = request_handle.get(); | |
| 73 job_ = base::MakeUnique<ParallelDownloadJobForTest>( | 112 job_ = base::MakeUnique<ParallelDownloadJobForTest>( |
| 74 download_item_.get(), base::MakeUnique<MockDownloadRequestHandle>(), | 113 download_item_.get(), std::move(request_handle), info, request_count); |
| 75 info, request_count); | |
| 76 } | 114 } |
| 77 | 115 |
| 78 void DestroyParallelJob() { | 116 void DestroyParallelJob() { |
| 79 job_.reset(); | 117 job_.reset(); |
| 80 download_item_.reset(); | 118 download_item_.reset(); |
| 81 item_delegate_.reset(); | 119 item_delegate_.reset(); |
| 120 mock_request_handle_ = nullptr; | |
| 82 } | 121 } |
| 83 | 122 |
| 84 void BuildParallelRequests() { job_->BuildParallelRequests(); } | 123 void BuildParallelRequests() { job_->BuildParallelRequests(); } |
| 85 | 124 |
| 125 void VerifyWorker(int64_t offset, int64_t length) const { | |
| 126 EXPECT_TRUE(job_->workers_.find(offset) != job_->workers_.end()); | |
| 127 EXPECT_EQ(offset, job_->workers_[offset]->offset()); | |
| 128 EXPECT_EQ(length, job_->workers_[offset]->length()); | |
| 129 } | |
| 130 | |
| 86 content::TestBrowserThreadBundle browser_threads_; | 131 content::TestBrowserThreadBundle browser_threads_; |
| 87 std::unique_ptr<DownloadItemImplDelegate> item_delegate_; | 132 std::unique_ptr<DownloadItemImplDelegate> item_delegate_; |
| 88 std::unique_ptr<MockDownloadItemImpl> download_item_; | 133 std::unique_ptr<MockDownloadItemImpl> download_item_; |
| 89 std::unique_ptr<ParallelDownloadJobForTest> job_; | 134 std::unique_ptr<ParallelDownloadJobForTest> job_; |
| 135 // Request handle for the original request. | |
| 136 MockDownloadRequestHandle* mock_request_handle_; | |
| 90 }; | 137 }; |
| 91 | 138 |
| 92 // Test if parallel requests can be built correctly for a new download. | 139 // Test if parallel requests can be built correctly for a new download. |
| 93 TEST_F(ParallelDownloadJobTest, CreateNewDownloadRequests) { | 140 TEST_F(ParallelDownloadJobTest, CreateNewDownloadRequests) { |
| 94 // Totally 2 requests for 100 bytes. | 141 // Totally 2 requests for 100 bytes. |
| 95 // Original request: Range:0-49, for 50 bytes. | 142 // Original request: Range:0-49, for 50 bytes. |
| 96 // Task 1: Range:50-, for 50 bytes. | 143 // Task 1: Range:50-, for 50 bytes. |
| 97 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); | 144 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); |
| 98 BuildParallelRequests(); | 145 BuildParallelRequests(); |
| 99 EXPECT_EQ(1, static_cast<int>(job_->fake_tasks_.size())); | 146 EXPECT_EQ(1, static_cast<int>(job_->mock_workers().size())); |
| 100 EXPECT_EQ(50, job_->fake_tasks_[0].first); | 147 VerifyWorker(50, 0); |
| 101 EXPECT_EQ(0, job_->fake_tasks_[0].second); | |
| 102 job_->fake_tasks_.clear(); | |
| 103 DestroyParallelJob(); | 148 DestroyParallelJob(); |
| 104 | 149 |
| 105 // Totally 3 requests for 100 bytes. | 150 // Totally 3 requests for 100 bytes. |
| 106 // Original request: Range:0-32, for 33 bytes. | 151 // Original request: Range:0-32, for 33 bytes. |
| 107 // Task 1: Range:33-65, for 33 bytes. | 152 // Task 1: Range:33-65, for 33 bytes. |
| 108 // Task 2: Range:66-, for 34 bytes. | 153 // Task 2: Range:66-, for 34 bytes. |
| 109 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 3); | 154 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 3); |
| 110 BuildParallelRequests(); | 155 BuildParallelRequests(); |
| 111 EXPECT_EQ(2, static_cast<int>(job_->fake_tasks_.size())); | 156 EXPECT_EQ(2, static_cast<int>(job_->mock_workers().size())); |
| 112 EXPECT_EQ(33, job_->fake_tasks_[0].first); | 157 VerifyWorker(33, 33); |
| 113 EXPECT_EQ(33, job_->fake_tasks_[0].second); | 158 VerifyWorker(66, 0); |
| 114 EXPECT_EQ(66, job_->fake_tasks_[1].first); | |
| 115 EXPECT_EQ(0, job_->fake_tasks_[1].second); | |
| 116 job_->fake_tasks_.clear(); | |
| 117 DestroyParallelJob(); | 159 DestroyParallelJob(); |
| 118 | 160 |
| 119 // Totally 3 requests for 100 bytes. Start from the 17th byte. | 161 // Totally 3 requests for 100 bytes. Start from the 17th byte. |
| 120 // Original request: Range:17-43, for 27 bytes. | 162 // Original request: Range:17-43, for 27 bytes. |
| 121 // Task 1: Range:44-70, for 27 bytes. | 163 // Task 1: Range:44-70, for 27 bytes. |
| 122 // Task 2: Range:71-99, for 29 bytes. | 164 // Task 2: Range:71-99, for 29 bytes. |
| 123 CreateParallelJob(17, 83, DownloadItem::ReceivedSlices(), 3); | 165 CreateParallelJob(17, 83, DownloadItem::ReceivedSlices(), 3); |
| 124 BuildParallelRequests(); | 166 BuildParallelRequests(); |
| 125 EXPECT_EQ(2, static_cast<int>(job_->fake_tasks_.size())); | 167 EXPECT_EQ(2, static_cast<int>(job_->mock_workers().size())); |
| 126 EXPECT_EQ(44, job_->fake_tasks_[0].first); | 168 VerifyWorker(44, 27); |
| 127 EXPECT_EQ(27, job_->fake_tasks_[0].second); | 169 VerifyWorker(71, 0); |
| 128 EXPECT_EQ(71, job_->fake_tasks_[1].first); | |
| 129 EXPECT_EQ(0, job_->fake_tasks_[1].second); | |
| 130 job_->fake_tasks_.clear(); | |
| 131 DestroyParallelJob(); | 170 DestroyParallelJob(); |
| 132 | 171 |
| 133 // Less than 2 requests, do nothing. | 172 // Less than 2 requests, do nothing. |
| 134 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 1); | 173 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 1); |
| 135 BuildParallelRequests(); | 174 BuildParallelRequests(); |
| 136 EXPECT_TRUE(job_->fake_tasks_.empty()); | 175 EXPECT_TRUE(job_->mock_workers().empty()); |
| 137 DestroyParallelJob(); | 176 DestroyParallelJob(); |
| 138 | 177 |
| 139 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 0); | 178 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 0); |
| 140 BuildParallelRequests(); | 179 BuildParallelRequests(); |
| 141 EXPECT_TRUE(job_->fake_tasks_.empty()); | 180 EXPECT_TRUE(job_->mock_workers().empty()); |
| 142 DestroyParallelJob(); | 181 DestroyParallelJob(); |
| 143 | 182 |
| 144 // Content-length is 0, do nothing. | 183 // Content-length is 0, do nothing. |
| 145 CreateParallelJob(100, 0, DownloadItem::ReceivedSlices(), 3); | 184 CreateParallelJob(100, 0, DownloadItem::ReceivedSlices(), 3); |
| 146 BuildParallelRequests(); | 185 BuildParallelRequests(); |
| 147 EXPECT_TRUE(job_->fake_tasks_.empty()); | 186 EXPECT_TRUE(job_->mock_workers().empty()); |
| 148 DestroyParallelJob(); | 187 DestroyParallelJob(); |
| 149 | 188 |
| 150 CreateParallelJob(0, 0, DownloadItem::ReceivedSlices(), 3); | 189 CreateParallelJob(0, 0, DownloadItem::ReceivedSlices(), 3); |
| 151 BuildParallelRequests(); | 190 BuildParallelRequests(); |
| 152 EXPECT_TRUE(job_->fake_tasks_.empty()); | 191 EXPECT_TRUE(job_->mock_workers().empty()); |
| 153 DestroyParallelJob(); | 192 DestroyParallelJob(); |
| 154 | 193 |
| 155 // 2 bytes left for 3 additional requests. Only 1 are built. | 194 // 2 bytes left for 3 additional requests. Only 1 are built. |
| 156 // Original request: Range:98-98, for 1 byte. | 195 // Original request: Range:98-98, for 1 byte. |
| 157 // Task 1: Range:99-, for 1 byte. | 196 // Task 1: Range:99-, for 1 byte. |
| 158 CreateParallelJob(98, 2, DownloadItem::ReceivedSlices(), 4); | 197 CreateParallelJob(98, 2, DownloadItem::ReceivedSlices(), 4); |
| 159 BuildParallelRequests(); | 198 BuildParallelRequests(); |
| 160 EXPECT_EQ(1, static_cast<int>(job_->fake_tasks_.size())); | 199 EXPECT_EQ(1, static_cast<int>(job_->mock_workers().size())); |
| 161 EXPECT_EQ(99, job_->fake_tasks_[0].first); | 200 VerifyWorker(99, 0); |
| 162 EXPECT_EQ(0, job_->fake_tasks_[0].second); | |
| 163 job_->fake_tasks_.clear(); | |
| 164 DestroyParallelJob(); | 201 DestroyParallelJob(); |
| 165 } | 202 } |
| 166 | 203 |
| 204 // Pause, cancel, resume can be called before or after the worker establish | |
| 205 // the byte stream. | |
| 206 // These tests ensure the states consistency between the job and workers. | |
| 207 | |
| 208 // Ensure cancel before building the requests will result in workers being | |
| 209 // canceled. | |
| 210 TEST_F(ParallelDownloadJobTest, EarlyCancelBeforeBuildRequests) { | |
| 211 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); | |
| 212 EXPECT_CALL(*mock_request_handle_, CancelRequest()); | |
| 213 | |
| 214 // Job is canceled before building parallel requests. | |
| 215 job_->Cancel(true); | |
| 216 EXPECT_TRUE(job_->is_canceled()); | |
| 217 | |
| 218 BuildParallelRequests(); | |
| 219 VerifyWorker(50, 0); | |
| 220 | |
| 221 for (auto* worker : job_->mock_workers()) { | |
| 222 std::unique_ptr<MockDownloadRequestHandle> mock_handle = | |
| 223 base::MakeUnique<MockDownloadRequestHandle>(); | |
| 224 EXPECT_CALL(*mock_handle.get(), CancelRequest()); | |
| 225 worker->MakeResponseReady(std::move(mock_handle)); | |
| 226 } | |
| 227 | |
| 228 DestroyParallelJob(); | |
| 229 } | |
| 230 | |
| 231 // Ensure cancel before adding the byte stream will result in workers being | |
| 232 // canceled. | |
| 233 TEST_F(ParallelDownloadJobTest, EarlyCancelBeforeByteStreamReady) { | |
| 234 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); | |
| 235 EXPECT_CALL(*mock_request_handle_, CancelRequest()); | |
| 236 | |
| 237 BuildParallelRequests(); | |
| 238 VerifyWorker(50, 0); | |
| 239 | |
| 240 // Job is canceled after building parallel requests and before byte streams | |
| 241 // are added to the file sink. | |
| 242 job_->Cancel(true); | |
| 243 EXPECT_TRUE(job_->is_canceled()); | |
| 244 | |
| 245 for (auto* worker : job_->mock_workers()) { | |
| 246 std::unique_ptr<MockDownloadRequestHandle> mock_handle = | |
| 247 base::MakeUnique<MockDownloadRequestHandle>(); | |
| 248 EXPECT_CALL(*mock_handle.get(), CancelRequest()); | |
| 249 worker->MakeResponseReady(std::move(mock_handle)); | |
| 250 } | |
| 251 | |
| 252 DestroyParallelJob(); | |
| 253 } | |
| 254 | |
| 255 // Ensure pause before building the requests will result in workers being | |
| 256 // paused. | |
| 257 TEST_F(ParallelDownloadJobTest, EarlyPauseBeforeBuildRequests) { | |
| 258 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); | |
| 259 EXPECT_CALL(*mock_request_handle_, PauseRequest()); | |
| 260 | |
| 261 // Job is paused before building parallel requests. | |
| 262 job_->Pause(); | |
| 263 EXPECT_TRUE(job_->is_paused()); | |
| 264 | |
| 265 BuildParallelRequests(); | |
| 266 VerifyWorker(50, 0); | |
| 267 | |
| 268 for (auto* worker : job_->mock_workers()) { | |
| 269 EXPECT_CALL(*job_.get(), CountOnByteStreamReady()); | |
| 270 std::unique_ptr<MockDownloadRequestHandle> mock_handle = | |
| 271 base::MakeUnique<MockDownloadRequestHandle>(); | |
| 272 EXPECT_CALL(*mock_handle.get(), PauseRequest()); | |
| 273 worker->MakeResponseReady(std::move(mock_handle)); | |
| 274 } | |
| 275 | |
| 276 DestroyParallelJob(); | |
| 277 } | |
| 278 | |
| 279 // Ensure pause before adding the byte stream will result in workers being | |
| 280 // paused. | |
| 281 TEST_F(ParallelDownloadJobTest, EarlyPauseBeforeByteStreamReady) { | |
| 282 CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2); | |
| 283 EXPECT_CALL(*mock_request_handle_, PauseRequest()); | |
| 284 | |
| 285 BuildParallelRequests(); | |
| 286 VerifyWorker(50, 0); | |
| 287 | |
| 288 // Job is paused after building parallel requests and before adding the byte | |
| 289 // stream to the file sink. | |
| 290 job_->Pause(); | |
| 291 EXPECT_TRUE(job_->is_paused()); | |
| 292 | |
| 293 for (auto* worker : job_->mock_workers()) { | |
| 294 EXPECT_CALL(*job_.get(), CountOnByteStreamReady()); | |
| 295 std::unique_ptr<MockDownloadRequestHandle> mock_handle = | |
| 296 base::MakeUnique<MockDownloadRequestHandle>(); | |
| 297 EXPECT_CALL(*mock_handle.get(), PauseRequest()); | |
| 298 worker->MakeResponseReady(std::move(mock_handle)); | |
| 299 } | |
| 300 | |
| 301 DestroyParallelJob(); | |
| 302 } | |
| 303 | |
| 167 } // namespace content | 304 } // namespace content |
| OLD | NEW |