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

Side by Side Diff: content/browser/download/parallel_download_job_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698