Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / download / download_file_unittest.cc
blobe283fa439f617fa49377225d580c2688186c2901
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/file_util.h"
6 #include "base/message_loop/message_loop.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/test/test_file_util.h"
9 #include "content/browser/browser_thread_impl.h"
10 #include "content/browser/byte_stream.h"
11 #include "content/browser/download/download_create_info.h"
12 #include "content/browser/download/download_file_impl.h"
13 #include "content/browser/download/download_request_handle.h"
14 #include "content/public/browser/download_destination_observer.h"
15 #include "content/public/browser/download_interrupt_reasons.h"
16 #include "content/public/browser/download_manager.h"
17 #include "content/public/test/mock_download_manager.h"
18 #include "net/base/file_stream.h"
19 #include "net/base/mock_file_stream.h"
20 #include "net/base/net_errors.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using ::testing::_;
25 using ::testing::AnyNumber;
26 using ::testing::DoAll;
27 using ::testing::InSequence;
28 using ::testing::Return;
29 using ::testing::SetArgPointee;
30 using ::testing::StrictMock;
32 namespace content {
33 namespace {
35 class MockByteStreamReader : public ByteStreamReader {
36 public:
37 MockByteStreamReader() {}
38 ~MockByteStreamReader() {}
40 // ByteStream functions
41 MOCK_METHOD2(Read, ByteStreamReader::StreamState(
42 scoped_refptr<net::IOBuffer>*, size_t*));
43 MOCK_CONST_METHOD0(GetStatus, int());
44 MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
47 class MockDownloadDestinationObserver : public DownloadDestinationObserver {
48 public:
49 MOCK_METHOD3(DestinationUpdate, void(int64, int64, const std::string&));
50 MOCK_METHOD1(DestinationError, void(DownloadInterruptReason));
51 MOCK_METHOD1(DestinationCompleted, void(const std::string&));
53 // Doesn't override any methods in the base class. Used to make sure
54 // that the last DestinationUpdate before a Destination{Completed,Error}
55 // had the right values.
56 MOCK_METHOD3(CurrentUpdateStatus,
57 void(int64, int64, const std::string&));
60 MATCHER(IsNullCallback, "") { return (arg.is_null()); }
62 } // namespace
64 class DownloadFileTest : public testing::Test {
65 public:
67 static const char* kTestData1;
68 static const char* kTestData2;
69 static const char* kTestData3;
70 static const char* kDataHash;
71 static const uint32 kDummyDownloadId;
72 static const int kDummyChildId;
73 static const int kDummyRequestId;
75 DownloadFileTest() :
76 observer_(new StrictMock<MockDownloadDestinationObserver>),
77 observer_factory_(observer_.get()),
78 input_stream_(NULL),
79 bytes_(-1),
80 bytes_per_sec_(-1),
81 hash_state_("xyzzy"),
82 ui_thread_(BrowserThread::UI, &loop_),
83 file_thread_(BrowserThread::FILE, &loop_) {
86 virtual ~DownloadFileTest() {
89 void SetUpdateDownloadInfo(int64 bytes, int64 bytes_per_sec,
90 const std::string& hash_state) {
91 bytes_ = bytes;
92 bytes_per_sec_ = bytes_per_sec;
93 hash_state_ = hash_state;
96 void ConfirmUpdateDownloadInfo() {
97 observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
100 virtual void SetUp() {
101 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
102 .Times(AnyNumber())
103 .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
106 // Mock calls to this function are forwarded here.
107 void RegisterCallback(base::Closure sink_callback) {
108 sink_callback_ = sink_callback;
111 void SetInterruptReasonCallback(bool* was_called,
112 DownloadInterruptReason* reason_p,
113 DownloadInterruptReason reason) {
114 *was_called = true;
115 *reason_p = reason;
118 bool CreateDownloadFile(int offset, bool calculate_hash) {
119 // There can be only one.
120 DCHECK(!download_file_.get());
122 input_stream_ = new StrictMock<MockByteStreamReader>();
124 // TODO: Need to actually create a function that'll set the variables
125 // based on the inputs from the callback.
126 EXPECT_CALL(*input_stream_, RegisterCallback(_))
127 .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
128 .RetiresOnSaturation();
130 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
131 download_file_.reset(
132 new DownloadFileImpl(save_info.Pass(),
133 base::FilePath(),
134 GURL(), // Source
135 GURL(), // Referrer
136 calculate_hash,
137 scoped_ptr<ByteStreamReader>(input_stream_),
138 net::BoundNetLog(),
139 observer_factory_.GetWeakPtr()));
140 download_file_->SetClientGuid(
141 "12345678-ABCD-1234-DCBA-123456789ABC");
143 EXPECT_CALL(*input_stream_, Read(_, _))
144 .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
145 .RetiresOnSaturation();
147 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
148 bool called = false;
149 DownloadInterruptReason result;
150 download_file_->Initialize(base::Bind(
151 &DownloadFileTest::SetInterruptReasonCallback,
152 weak_ptr_factory.GetWeakPtr(), &called, &result));
153 loop_.RunUntilIdle();
154 EXPECT_TRUE(called);
156 ::testing::Mock::VerifyAndClearExpectations(input_stream_);
157 return result == DOWNLOAD_INTERRUPT_REASON_NONE;
160 void DestroyDownloadFile(int offset) {
161 EXPECT_FALSE(download_file_->InProgress());
163 // Make sure the data has been properly written to disk.
164 std::string disk_data;
165 EXPECT_TRUE(base::ReadFileToString(download_file_->FullPath(), &disk_data));
166 EXPECT_EQ(expected_data_, disk_data);
168 // Make sure the Browser and File threads outlive the DownloadFile
169 // to satisfy thread checks inside it.
170 download_file_.reset();
173 // Setup the stream to do be a data append; don't actually trigger
174 // the callback or do verifications.
175 void SetupDataAppend(const char **data_chunks, size_t num_chunks,
176 ::testing::Sequence s) {
177 DCHECK(input_stream_);
178 for (size_t i = 0; i < num_chunks; i++) {
179 const char *source_data = data_chunks[i];
180 size_t length = strlen(source_data);
181 scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length);
182 memcpy(data->data(), source_data, length);
183 EXPECT_CALL(*input_stream_, Read(_, _))
184 .InSequence(s)
185 .WillOnce(DoAll(SetArgPointee<0>(data),
186 SetArgPointee<1>(length),
187 Return(ByteStreamReader::STREAM_HAS_DATA)))
188 .RetiresOnSaturation();
189 expected_data_ += source_data;
193 void VerifyStreamAndSize() {
194 ::testing::Mock::VerifyAndClearExpectations(input_stream_);
195 int64 size;
196 EXPECT_TRUE(base::GetFileSize(download_file_->FullPath(), &size));
197 EXPECT_EQ(expected_data_.size(), static_cast<size_t>(size));
200 // TODO(rdsmith): Manage full percentage issues properly.
201 void AppendDataToFile(const char **data_chunks, size_t num_chunks) {
202 ::testing::Sequence s1;
203 SetupDataAppend(data_chunks, num_chunks, s1);
204 EXPECT_CALL(*input_stream_, Read(_, _))
205 .InSequence(s1)
206 .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
207 .RetiresOnSaturation();
208 sink_callback_.Run();
209 VerifyStreamAndSize();
212 void SetupFinishStream(DownloadInterruptReason interrupt_reason,
213 ::testing::Sequence s) {
214 EXPECT_CALL(*input_stream_, Read(_, _))
215 .InSequence(s)
216 .WillOnce(Return(ByteStreamReader::STREAM_COMPLETE))
217 .RetiresOnSaturation();
218 EXPECT_CALL(*input_stream_, GetStatus())
219 .InSequence(s)
220 .WillOnce(Return(interrupt_reason))
221 .RetiresOnSaturation();
222 EXPECT_CALL(*input_stream_, RegisterCallback(_))
223 .RetiresOnSaturation();
226 void FinishStream(DownloadInterruptReason interrupt_reason,
227 bool check_observer) {
228 ::testing::Sequence s1;
229 SetupFinishStream(interrupt_reason, s1);
230 sink_callback_.Run();
231 VerifyStreamAndSize();
232 if (check_observer) {
233 EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
234 loop_.RunUntilIdle();
235 ::testing::Mock::VerifyAndClearExpectations(observer_.get());
236 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
237 .Times(AnyNumber())
238 .WillRepeatedly(Invoke(this,
239 &DownloadFileTest::SetUpdateDownloadInfo));
243 DownloadInterruptReason RenameAndUniquify(
244 const base::FilePath& full_path,
245 base::FilePath* result_path_p) {
246 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
247 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
248 bool callback_was_called(false);
249 base::FilePath result_path;
251 download_file_->RenameAndUniquify(
252 full_path, base::Bind(&DownloadFileTest::SetRenameResult,
253 weak_ptr_factory.GetWeakPtr(),
254 &callback_was_called,
255 &result_reason, result_path_p));
256 loop_.RunUntilIdle();
258 EXPECT_TRUE(callback_was_called);
259 return result_reason;
262 DownloadInterruptReason RenameAndAnnotate(
263 const base::FilePath& full_path,
264 base::FilePath* result_path_p) {
265 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
266 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
267 bool callback_was_called(false);
268 base::FilePath result_path;
270 download_file_->RenameAndAnnotate(
271 full_path, base::Bind(&DownloadFileTest::SetRenameResult,
272 weak_ptr_factory.GetWeakPtr(),
273 &callback_was_called,
274 &result_reason, result_path_p));
275 loop_.RunUntilIdle();
277 EXPECT_TRUE(callback_was_called);
278 return result_reason;
281 protected:
282 scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
283 base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
285 // DownloadFile instance we are testing.
286 scoped_ptr<DownloadFile> download_file_;
288 // Stream for sending data into the download file.
289 // Owned by download_file_; will be alive for lifetime of download_file_.
290 StrictMock<MockByteStreamReader>* input_stream_;
292 // Sink callback data for stream.
293 base::Closure sink_callback_;
295 // Latest update sent to the observer.
296 int64 bytes_;
297 int64 bytes_per_sec_;
298 std::string hash_state_;
300 base::MessageLoop loop_;
302 private:
303 void SetRenameResult(bool* called_p,
304 DownloadInterruptReason* reason_p,
305 base::FilePath* result_path_p,
306 DownloadInterruptReason reason,
307 const base::FilePath& result_path) {
308 if (called_p)
309 *called_p = true;
310 if (reason_p)
311 *reason_p = reason;
312 if (result_path_p)
313 *result_path_p = result_path;
316 // UI thread.
317 BrowserThreadImpl ui_thread_;
318 // File thread to satisfy debug checks in DownloadFile.
319 BrowserThreadImpl file_thread_;
321 // Keep track of what data should be saved to the disk file.
322 std::string expected_data_;
325 const char* DownloadFileTest::kTestData1 =
326 "Let's write some data to the file!\n";
327 const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
328 const char* DownloadFileTest::kTestData3 = "Final line.";
329 const char* DownloadFileTest::kDataHash =
330 "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
332 const uint32 DownloadFileTest::kDummyDownloadId = 23;
333 const int DownloadFileTest::kDummyChildId = 3;
334 const int DownloadFileTest::kDummyRequestId = 67;
336 // Rename the file before any data is downloaded, after some has, after it all
337 // has, and after it's closed.
338 TEST_F(DownloadFileTest, RenameFileFinal) {
339 ASSERT_TRUE(CreateDownloadFile(0, true));
340 base::FilePath initial_path(download_file_->FullPath());
341 EXPECT_TRUE(base::PathExists(initial_path));
342 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
343 base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
344 base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
345 base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
346 base::FilePath path_5(initial_path.InsertBeforeExtensionASCII("_5"));
347 base::FilePath output_path;
349 // Rename the file before downloading any data.
350 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
351 RenameAndUniquify(path_1, &output_path));
352 base::FilePath renamed_path = download_file_->FullPath();
353 EXPECT_EQ(path_1, renamed_path);
354 EXPECT_EQ(path_1, output_path);
356 // Check the files.
357 EXPECT_FALSE(base::PathExists(initial_path));
358 EXPECT_TRUE(base::PathExists(path_1));
360 // Download the data.
361 const char* chunks1[] = { kTestData1, kTestData2 };
362 AppendDataToFile(chunks1, 2);
364 // Rename the file after downloading some data.
365 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
366 RenameAndUniquify(path_2, &output_path));
367 renamed_path = download_file_->FullPath();
368 EXPECT_EQ(path_2, renamed_path);
369 EXPECT_EQ(path_2, output_path);
371 // Check the files.
372 EXPECT_FALSE(base::PathExists(path_1));
373 EXPECT_TRUE(base::PathExists(path_2));
375 const char* chunks2[] = { kTestData3 };
376 AppendDataToFile(chunks2, 1);
378 // Rename the file after downloading all the data.
379 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
380 RenameAndUniquify(path_3, &output_path));
381 renamed_path = download_file_->FullPath();
382 EXPECT_EQ(path_3, renamed_path);
383 EXPECT_EQ(path_3, output_path);
385 // Check the files.
386 EXPECT_FALSE(base::PathExists(path_2));
387 EXPECT_TRUE(base::PathExists(path_3));
389 // Should not be able to get the hash until the file is closed.
390 std::string hash;
391 EXPECT_FALSE(download_file_->GetHash(&hash));
392 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
393 loop_.RunUntilIdle();
395 // Rename the file after downloading all the data and closing the file.
396 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
397 RenameAndUniquify(path_4, &output_path));
398 renamed_path = download_file_->FullPath();
399 EXPECT_EQ(path_4, renamed_path);
400 EXPECT_EQ(path_4, output_path);
402 // Check the files.
403 EXPECT_FALSE(base::PathExists(path_3));
404 EXPECT_TRUE(base::PathExists(path_4));
406 // Check the hash.
407 EXPECT_TRUE(download_file_->GetHash(&hash));
408 EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
410 // Check that a rename with overwrite to an existing file succeeds.
411 std::string file_contents;
412 ASSERT_FALSE(base::PathExists(path_5));
413 static const char file_data[] = "xyzzy";
414 ASSERT_EQ(static_cast<int>(sizeof(file_data) - 1),
415 base::WriteFile(path_5, file_data, sizeof(file_data) - 1));
416 ASSERT_TRUE(base::PathExists(path_5));
417 EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
418 EXPECT_EQ(std::string(file_data), file_contents);
420 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
421 RenameAndAnnotate(path_5, &output_path));
422 EXPECT_EQ(path_5, output_path);
424 file_contents = "";
425 EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
426 EXPECT_NE(std::string(file_data), file_contents);
428 DestroyDownloadFile(0);
431 // Test to make sure the rename uniquifies if we aren't overwriting
432 // and there's a file where we're aiming.
433 TEST_F(DownloadFileTest, RenameUniquifies) {
434 ASSERT_TRUE(CreateDownloadFile(0, true));
435 base::FilePath initial_path(download_file_->FullPath());
436 EXPECT_TRUE(base::PathExists(initial_path));
437 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
438 base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)"));
440 ASSERT_FALSE(base::PathExists(path_1));
441 static const char file_data[] = "xyzzy";
442 ASSERT_EQ(static_cast<int>(sizeof(file_data)),
443 base::WriteFile(path_1, file_data, sizeof(file_data)));
444 ASSERT_TRUE(base::PathExists(path_1));
446 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
447 EXPECT_TRUE(base::PathExists(path_1_suffixed));
449 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
450 loop_.RunUntilIdle();
451 DestroyDownloadFile(0);
454 // Test to make sure we get the proper error on failure.
455 TEST_F(DownloadFileTest, RenameError) {
456 ASSERT_TRUE(CreateDownloadFile(0, true));
457 base::FilePath initial_path(download_file_->FullPath());
459 // Create a subdirectory.
460 base::FilePath tempdir(
461 initial_path.DirName().Append(FILE_PATH_LITERAL("tempdir")));
462 ASSERT_TRUE(base::CreateDirectory(tempdir));
463 base::FilePath target_path(tempdir.Append(initial_path.BaseName()));
465 // Targets
466 base::FilePath target_path_suffixed(
467 target_path.InsertBeforeExtensionASCII(" (1)"));
468 ASSERT_FALSE(base::PathExists(target_path));
469 ASSERT_FALSE(base::PathExists(target_path_suffixed));
471 // Make the directory unwritable and try to rename within it.
473 base::FilePermissionRestorer restorer(tempdir);
474 ASSERT_TRUE(base::MakeFileUnwritable(tempdir));
476 // Expect nulling out of further processing.
477 EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback()));
478 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
479 RenameAndAnnotate(target_path, NULL));
480 EXPECT_FALSE(base::PathExists(target_path_suffixed));
483 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
484 loop_.RunUntilIdle();
485 DestroyDownloadFile(0);
488 // Various tests of the StreamActive method.
489 TEST_F(DownloadFileTest, StreamEmptySuccess) {
490 ASSERT_TRUE(CreateDownloadFile(0, true));
491 base::FilePath initial_path(download_file_->FullPath());
492 EXPECT_TRUE(base::PathExists(initial_path));
494 // Test that calling the sink_callback_ on an empty stream shouldn't
495 // do anything.
496 AppendDataToFile(NULL, 0);
498 // Finish the download this way and make sure we see it on the
499 // observer.
500 EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
501 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, false);
502 loop_.RunUntilIdle();
504 DestroyDownloadFile(0);
507 TEST_F(DownloadFileTest, StreamEmptyError) {
508 ASSERT_TRUE(CreateDownloadFile(0, true));
509 base::FilePath initial_path(download_file_->FullPath());
510 EXPECT_TRUE(base::PathExists(initial_path));
512 // Finish the download in error and make sure we see it on the
513 // observer.
514 EXPECT_CALL(*(observer_.get()),
515 DestinationError(
516 DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
517 .WillOnce(InvokeWithoutArgs(
518 this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
520 // If this next EXPECT_CALL fails flakily, it's probably a real failure.
521 // We'll be getting a stream of UpdateDownload calls from the timer, and
522 // the last one may have the correct information even if the failure
523 // doesn't produce an update, as the timer update may have triggered at the
524 // same time.
525 EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(0, _, _));
527 FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
529 loop_.RunUntilIdle();
531 DestroyDownloadFile(0);
534 TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
535 ASSERT_TRUE(CreateDownloadFile(0, true));
536 base::FilePath initial_path(download_file_->FullPath());
537 EXPECT_TRUE(base::PathExists(initial_path));
539 const char* chunks1[] = { kTestData1, kTestData2 };
540 ::testing::Sequence s1;
541 SetupDataAppend(chunks1, 2, s1);
542 SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, s1);
543 EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
544 sink_callback_.Run();
545 VerifyStreamAndSize();
546 loop_.RunUntilIdle();
547 DestroyDownloadFile(0);
550 TEST_F(DownloadFileTest, StreamNonEmptyError) {
551 ASSERT_TRUE(CreateDownloadFile(0, true));
552 base::FilePath initial_path(download_file_->FullPath());
553 EXPECT_TRUE(base::PathExists(initial_path));
555 const char* chunks1[] = { kTestData1, kTestData2 };
556 ::testing::Sequence s1;
557 SetupDataAppend(chunks1, 2, s1);
558 SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
560 EXPECT_CALL(*(observer_.get()),
561 DestinationError(
562 DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
563 .WillOnce(InvokeWithoutArgs(
564 this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
566 // If this next EXPECT_CALL fails flakily, it's probably a real failure.
567 // We'll be getting a stream of UpdateDownload calls from the timer, and
568 // the last one may have the correct information even if the failure
569 // doesn't produce an update, as the timer update may have triggered at the
570 // same time.
571 EXPECT_CALL(*(observer_.get()),
572 CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2),
573 _, _));
575 sink_callback_.Run();
576 loop_.RunUntilIdle();
577 VerifyStreamAndSize();
578 DestroyDownloadFile(0);
581 // Send some data, wait 3/4s of a second, run the message loop, and
582 // confirm the values the observer received are correct.
583 TEST_F(DownloadFileTest, ConfirmUpdate) {
584 CreateDownloadFile(0, true);
586 const char* chunks1[] = { kTestData1, kTestData2 };
587 AppendDataToFile(chunks1, 2);
589 // Run the message loops for 750ms and check for results.
590 loop_.PostDelayedTask(FROM_HERE,
591 base::MessageLoop::QuitClosure(),
592 base::TimeDelta::FromMilliseconds(750));
593 loop_.Run();
595 EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
596 bytes_);
597 EXPECT_EQ(download_file_->GetHashState(), hash_state_);
599 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
600 DestroyDownloadFile(0);
603 } // namespace content