Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / download / download_file_unittest.cc
blob604baa4ea090ce7cadd1c8d43b5cfacaaa942a73
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.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/browser/power_save_blocker.h"
18 #include "content/public/test/mock_download_manager.h"
19 #include "net/base/file_stream.h"
20 #include "net/base/mock_file_stream.h"
21 #include "net/base/net_errors.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using ::testing::_;
26 using ::testing::AnyNumber;
27 using ::testing::DoAll;
28 using ::testing::InSequence;
29 using ::testing::Return;
30 using ::testing::SetArgPointee;
31 using ::testing::StrictMock;
33 namespace content {
34 namespace {
36 class MockByteStreamReader : public ByteStreamReader {
37 public:
38 MockByteStreamReader() {}
39 ~MockByteStreamReader() {}
41 // ByteStream functions
42 MOCK_METHOD2(Read, ByteStreamReader::StreamState(
43 scoped_refptr<net::IOBuffer>*, size_t*));
44 MOCK_CONST_METHOD0(GetStatus, DownloadInterruptReason());
45 MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
48 class MockDownloadDestinationObserver : public DownloadDestinationObserver {
49 public:
50 MOCK_METHOD3(DestinationUpdate, void(int64, int64, const std::string&));
51 MOCK_METHOD1(DestinationError, void(DownloadInterruptReason));
52 MOCK_METHOD1(DestinationCompleted, void(const std::string&));
54 // Doesn't override any methods in the base class. Used to make sure
55 // that the last DestinationUpdate before a Destination{Completed,Error}
56 // had the right values.
57 MOCK_METHOD3(CurrentUpdateStatus,
58 void(int64, int64, const std::string&));
61 MATCHER(IsNullCallback, "") { return (arg.is_null()); }
63 } // namespace
65 DownloadId::Domain kValidIdDomain = "valid DownloadId::Domain";
67 class DownloadFileTest : public testing::Test {
68 public:
70 static const char* kTestData1;
71 static const char* kTestData2;
72 static const char* kTestData3;
73 static const char* kDataHash;
74 static const int32 kDummyDownloadId;
75 static const int kDummyChildId;
76 static const int kDummyRequestId;
78 DownloadFileTest() :
79 observer_(new StrictMock<MockDownloadDestinationObserver>),
80 observer_factory_(observer_.get()),
81 bytes_(-1),
82 bytes_per_sec_(-1),
83 hash_state_("xyzzy"),
84 ui_thread_(BrowserThread::UI, &loop_),
85 file_thread_(BrowserThread::FILE, &loop_) {
88 virtual ~DownloadFileTest() {
91 void SetUpdateDownloadInfo(int64 bytes, int64 bytes_per_sec,
92 const std::string& hash_state) {
93 bytes_ = bytes;
94 bytes_per_sec_ = bytes_per_sec;
95 hash_state_ = hash_state;
98 void ConfirmUpdateDownloadInfo() {
99 observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
102 virtual void SetUp() {
103 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
104 .Times(AnyNumber())
105 .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
108 // Mock calls to this function are forwarded here.
109 void RegisterCallback(base::Closure sink_callback) {
110 sink_callback_ = sink_callback;
113 void SetInterruptReasonCallback(bool* was_called,
114 DownloadInterruptReason* reason_p,
115 DownloadInterruptReason reason) {
116 *was_called = true;
117 *reason_p = reason;
120 virtual bool CreateDownloadFile(int offset, bool calculate_hash) {
121 // There can be only one.
122 DCHECK(!download_file_.get());
124 input_stream_ = new StrictMock<MockByteStreamReader>();
126 // TODO: Need to actually create a function that'll set the variables
127 // based on the inputs from the callback.
128 EXPECT_CALL(*input_stream_, RegisterCallback(_))
129 .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
130 .RetiresOnSaturation();
132 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
133 download_file_.reset(
134 new DownloadFileImpl(save_info.Pass(),
135 base::FilePath(),
136 GURL(), // Source
137 GURL(), // Referrer
138 calculate_hash,
139 scoped_ptr<ByteStreamReader>(input_stream_),
140 net::BoundNetLog(),
141 scoped_ptr<PowerSaveBlocker>().Pass(),
142 observer_factory_.GetWeakPtr()));
144 EXPECT_CALL(*input_stream_, Read(_, _))
145 .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
146 .RetiresOnSaturation();
148 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
149 bool called = false;
150 DownloadInterruptReason result;
151 download_file_->Initialize(base::Bind(
152 &DownloadFileTest::SetInterruptReasonCallback,
153 weak_ptr_factory.GetWeakPtr(), &called, &result));
154 loop_.RunUntilIdle();
155 EXPECT_TRUE(called);
157 ::testing::Mock::VerifyAndClearExpectations(input_stream_);
158 return result == DOWNLOAD_INTERRUPT_REASON_NONE;
161 virtual void DestroyDownloadFile(int offset) {
162 EXPECT_FALSE(download_file_->InProgress());
164 // Make sure the data has been properly written to disk.
165 std::string disk_data;
166 EXPECT_TRUE(file_util::ReadFileToString(download_file_->FullPath(),
167 &disk_data));
168 EXPECT_EQ(expected_data_, disk_data);
170 // Make sure the Browser and File threads outlive the DownloadFile
171 // to satisfy thread checks inside it.
172 download_file_.reset();
175 // Setup the stream to do be a data append; don't actually trigger
176 // the callback or do verifications.
177 void SetupDataAppend(const char **data_chunks, size_t num_chunks,
178 ::testing::Sequence s) {
179 DCHECK(input_stream_);
180 for (size_t i = 0; i < num_chunks; i++) {
181 const char *source_data = data_chunks[i];
182 size_t length = strlen(source_data);
183 scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length);
184 memcpy(data->data(), source_data, length);
185 EXPECT_CALL(*input_stream_, Read(_, _))
186 .InSequence(s)
187 .WillOnce(DoAll(SetArgPointee<0>(data),
188 SetArgPointee<1>(length),
189 Return(ByteStreamReader::STREAM_HAS_DATA)))
190 .RetiresOnSaturation();
191 expected_data_ += source_data;
195 void VerifyStreamAndSize() {
196 ::testing::Mock::VerifyAndClearExpectations(input_stream_);
197 int64 size;
198 EXPECT_TRUE(file_util::GetFileSize(download_file_->FullPath(), &size));
199 EXPECT_EQ(expected_data_.size(), static_cast<size_t>(size));
202 // TODO(rdsmith): Manage full percentage issues properly.
203 void AppendDataToFile(const char **data_chunks, size_t num_chunks) {
204 ::testing::Sequence s1;
205 SetupDataAppend(data_chunks, num_chunks, s1);
206 EXPECT_CALL(*input_stream_, Read(_, _))
207 .InSequence(s1)
208 .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
209 .RetiresOnSaturation();
210 sink_callback_.Run();
211 VerifyStreamAndSize();
214 void SetupFinishStream(DownloadInterruptReason interrupt_reason,
215 ::testing::Sequence s) {
216 EXPECT_CALL(*input_stream_, Read(_, _))
217 .InSequence(s)
218 .WillOnce(Return(ByteStreamReader::STREAM_COMPLETE))
219 .RetiresOnSaturation();
220 EXPECT_CALL(*input_stream_, GetStatus())
221 .InSequence(s)
222 .WillOnce(Return(interrupt_reason))
223 .RetiresOnSaturation();
224 EXPECT_CALL(*input_stream_, RegisterCallback(_))
225 .RetiresOnSaturation();
228 void FinishStream(DownloadInterruptReason interrupt_reason,
229 bool check_observer) {
230 ::testing::Sequence s1;
231 SetupFinishStream(interrupt_reason, s1);
232 sink_callback_.Run();
233 VerifyStreamAndSize();
234 if (check_observer) {
235 EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
236 loop_.RunUntilIdle();
237 ::testing::Mock::VerifyAndClearExpectations(observer_.get());
238 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
239 .Times(AnyNumber())
240 .WillRepeatedly(Invoke(this,
241 &DownloadFileTest::SetUpdateDownloadInfo));
245 DownloadInterruptReason RenameAndUniquify(
246 const base::FilePath& full_path,
247 base::FilePath* result_path_p) {
248 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
249 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
250 bool callback_was_called(false);
251 base::FilePath result_path;
253 download_file_->RenameAndUniquify(
254 full_path, base::Bind(&DownloadFileTest::SetRenameResult,
255 weak_ptr_factory.GetWeakPtr(),
256 &callback_was_called,
257 &result_reason, result_path_p));
258 loop_.RunUntilIdle();
260 EXPECT_TRUE(callback_was_called);
261 return result_reason;
264 DownloadInterruptReason RenameAndAnnotate(
265 const base::FilePath& full_path,
266 base::FilePath* result_path_p) {
267 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
268 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
269 bool callback_was_called(false);
270 base::FilePath result_path;
272 download_file_->RenameAndAnnotate(
273 full_path, base::Bind(&DownloadFileTest::SetRenameResult,
274 weak_ptr_factory.GetWeakPtr(),
275 &callback_was_called,
276 &result_reason, result_path_p));
277 loop_.RunUntilIdle();
279 EXPECT_TRUE(callback_was_called);
280 return result_reason;
283 protected:
284 scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
285 base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
287 // DownloadFile instance we are testing.
288 scoped_ptr<DownloadFile> download_file_;
290 // Stream for sending data into the download file.
291 // Owned by download_file_; will be alive for lifetime of download_file_.
292 StrictMock<MockByteStreamReader>* input_stream_;
294 // Sink callback data for stream.
295 base::Closure sink_callback_;
297 // Latest update sent to the observer.
298 int64 bytes_;
299 int64 bytes_per_sec_;
300 std::string hash_state_;
302 base::MessageLoop loop_;
304 private:
305 void SetRenameResult(bool* called_p,
306 DownloadInterruptReason* reason_p,
307 base::FilePath* result_path_p,
308 DownloadInterruptReason reason,
309 const base::FilePath& result_path) {
310 if (called_p)
311 *called_p = true;
312 if (reason_p)
313 *reason_p = reason;
314 if (result_path_p)
315 *result_path_p = result_path;
318 // UI thread.
319 BrowserThreadImpl ui_thread_;
320 // File thread to satisfy debug checks in DownloadFile.
321 BrowserThreadImpl file_thread_;
323 // Keep track of what data should be saved to the disk file.
324 std::string expected_data_;
327 const char* DownloadFileTest::kTestData1 =
328 "Let's write some data to the file!\n";
329 const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
330 const char* DownloadFileTest::kTestData3 = "Final line.";
331 const char* DownloadFileTest::kDataHash =
332 "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
334 const int32 DownloadFileTest::kDummyDownloadId = 23;
335 const int DownloadFileTest::kDummyChildId = 3;
336 const int DownloadFileTest::kDummyRequestId = 67;
338 // Rename the file before any data is downloaded, after some has, after it all
339 // has, and after it's closed.
340 TEST_F(DownloadFileTest, RenameFileFinal) {
341 ASSERT_TRUE(CreateDownloadFile(0, true));
342 base::FilePath initial_path(download_file_->FullPath());
343 EXPECT_TRUE(file_util::PathExists(initial_path));
344 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
345 base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
346 base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
347 base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
348 base::FilePath path_5(initial_path.InsertBeforeExtensionASCII("_5"));
349 base::FilePath output_path;
351 // Rename the file before downloading any data.
352 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
353 RenameAndUniquify(path_1, &output_path));
354 base::FilePath renamed_path = download_file_->FullPath();
355 EXPECT_EQ(path_1, renamed_path);
356 EXPECT_EQ(path_1, output_path);
358 // Check the files.
359 EXPECT_FALSE(file_util::PathExists(initial_path));
360 EXPECT_TRUE(file_util::PathExists(path_1));
362 // Download the data.
363 const char* chunks1[] = { kTestData1, kTestData2 };
364 AppendDataToFile(chunks1, 2);
366 // Rename the file after downloading some data.
367 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
368 RenameAndUniquify(path_2, &output_path));
369 renamed_path = download_file_->FullPath();
370 EXPECT_EQ(path_2, renamed_path);
371 EXPECT_EQ(path_2, output_path);
373 // Check the files.
374 EXPECT_FALSE(file_util::PathExists(path_1));
375 EXPECT_TRUE(file_util::PathExists(path_2));
377 const char* chunks2[] = { kTestData3 };
378 AppendDataToFile(chunks2, 1);
380 // Rename the file after downloading all the data.
381 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
382 RenameAndUniquify(path_3, &output_path));
383 renamed_path = download_file_->FullPath();
384 EXPECT_EQ(path_3, renamed_path);
385 EXPECT_EQ(path_3, output_path);
387 // Check the files.
388 EXPECT_FALSE(file_util::PathExists(path_2));
389 EXPECT_TRUE(file_util::PathExists(path_3));
391 // Should not be able to get the hash until the file is closed.
392 std::string hash;
393 EXPECT_FALSE(download_file_->GetHash(&hash));
394 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
395 loop_.RunUntilIdle();
397 // Rename the file after downloading all the data and closing the file.
398 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
399 RenameAndUniquify(path_4, &output_path));
400 renamed_path = download_file_->FullPath();
401 EXPECT_EQ(path_4, renamed_path);
402 EXPECT_EQ(path_4, output_path);
404 // Check the files.
405 EXPECT_FALSE(file_util::PathExists(path_3));
406 EXPECT_TRUE(file_util::PathExists(path_4));
408 // Check the hash.
409 EXPECT_TRUE(download_file_->GetHash(&hash));
410 EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
412 // Check that a rename with overwrite to an existing file succeeds.
413 std::string file_contents;
414 ASSERT_FALSE(file_util::PathExists(path_5));
415 static const char file_data[] = "xyzzy";
416 ASSERT_EQ(static_cast<int>(sizeof(file_data) - 1),
417 file_util::WriteFile(path_5, file_data, sizeof(file_data) - 1));
418 ASSERT_TRUE(file_util::PathExists(path_5));
419 EXPECT_TRUE(file_util::ReadFileToString(path_5, &file_contents));
420 EXPECT_EQ(std::string(file_data), file_contents);
422 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
423 RenameAndAnnotate(path_5, &output_path));
424 EXPECT_EQ(path_5, output_path);
426 file_contents = "";
427 EXPECT_TRUE(file_util::ReadFileToString(path_5, &file_contents));
428 EXPECT_NE(std::string(file_data), file_contents);
430 DestroyDownloadFile(0);
433 // Test to make sure the rename uniquifies if we aren't overwriting
434 // and there's a file where we're aiming.
435 TEST_F(DownloadFileTest, RenameUniquifies) {
436 ASSERT_TRUE(CreateDownloadFile(0, true));
437 base::FilePath initial_path(download_file_->FullPath());
438 EXPECT_TRUE(file_util::PathExists(initial_path));
439 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
440 base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)"));
442 ASSERT_FALSE(file_util::PathExists(path_1));
443 static const char file_data[] = "xyzzy";
444 ASSERT_EQ(static_cast<int>(sizeof(file_data)),
445 file_util::WriteFile(path_1, file_data, sizeof(file_data)));
446 ASSERT_TRUE(file_util::PathExists(path_1));
448 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
449 EXPECT_TRUE(file_util::PathExists(path_1_suffixed));
451 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
452 loop_.RunUntilIdle();
453 DestroyDownloadFile(0);
456 // Test to make sure we get the proper error on failure.
457 TEST_F(DownloadFileTest, RenameError) {
458 ASSERT_TRUE(CreateDownloadFile(0, true));
459 base::FilePath initial_path(download_file_->FullPath());
461 // Create a subdirectory.
462 base::FilePath tempdir(
463 initial_path.DirName().Append(FILE_PATH_LITERAL("tempdir")));
464 ASSERT_TRUE(file_util::CreateDirectory(tempdir));
465 base::FilePath target_path(tempdir.Append(initial_path.BaseName()));
467 // Targets
468 base::FilePath target_path_suffixed(
469 target_path.InsertBeforeExtensionASCII(" (1)"));
470 ASSERT_FALSE(file_util::PathExists(target_path));
471 ASSERT_FALSE(file_util::PathExists(target_path_suffixed));
473 // Make the directory unwritable and try to rename within it.
475 file_util::PermissionRestorer restorer(tempdir);
476 ASSERT_TRUE(file_util::MakeFileUnwritable(tempdir));
478 // Expect nulling out of further processing.
479 EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback()));
480 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
481 RenameAndAnnotate(target_path, NULL));
482 EXPECT_FALSE(file_util::PathExists(target_path_suffixed));
485 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
486 loop_.RunUntilIdle();
487 DestroyDownloadFile(0);
490 // Various tests of the StreamActive method.
491 TEST_F(DownloadFileTest, StreamEmptySuccess) {
492 ASSERT_TRUE(CreateDownloadFile(0, true));
493 base::FilePath initial_path(download_file_->FullPath());
494 EXPECT_TRUE(file_util::PathExists(initial_path));
496 // Test that calling the sink_callback_ on an empty stream shouldn't
497 // do anything.
498 AppendDataToFile(NULL, 0);
500 // Finish the download this way and make sure we see it on the
501 // observer.
502 EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
503 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, false);
504 loop_.RunUntilIdle();
506 DestroyDownloadFile(0);
509 TEST_F(DownloadFileTest, StreamEmptyError) {
510 ASSERT_TRUE(CreateDownloadFile(0, true));
511 base::FilePath initial_path(download_file_->FullPath());
512 EXPECT_TRUE(file_util::PathExists(initial_path));
514 // Finish the download in error and make sure we see it on the
515 // observer.
516 EXPECT_CALL(*(observer_.get()),
517 DestinationError(
518 DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
519 .WillOnce(InvokeWithoutArgs(
520 this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
522 // If this next EXPECT_CALL fails flakily, it's probably a real failure.
523 // We'll be getting a stream of UpdateDownload calls from the timer, and
524 // the last one may have the correct information even if the failure
525 // doesn't produce an update, as the timer update may have triggered at the
526 // same time.
527 EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(0, _, _));
529 FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
531 loop_.RunUntilIdle();
533 DestroyDownloadFile(0);
536 TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
537 ASSERT_TRUE(CreateDownloadFile(0, true));
538 base::FilePath initial_path(download_file_->FullPath());
539 EXPECT_TRUE(file_util::PathExists(initial_path));
541 const char* chunks1[] = { kTestData1, kTestData2 };
542 ::testing::Sequence s1;
543 SetupDataAppend(chunks1, 2, s1);
544 SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, s1);
545 EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
546 sink_callback_.Run();
547 VerifyStreamAndSize();
548 loop_.RunUntilIdle();
549 DestroyDownloadFile(0);
552 TEST_F(DownloadFileTest, StreamNonEmptyError) {
553 ASSERT_TRUE(CreateDownloadFile(0, true));
554 base::FilePath initial_path(download_file_->FullPath());
555 EXPECT_TRUE(file_util::PathExists(initial_path));
557 const char* chunks1[] = { kTestData1, kTestData2 };
558 ::testing::Sequence s1;
559 SetupDataAppend(chunks1, 2, s1);
560 SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
562 EXPECT_CALL(*(observer_.get()),
563 DestinationError(
564 DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
565 .WillOnce(InvokeWithoutArgs(
566 this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
568 // If this next EXPECT_CALL fails flakily, it's probably a real failure.
569 // We'll be getting a stream of UpdateDownload calls from the timer, and
570 // the last one may have the correct information even if the failure
571 // doesn't produce an update, as the timer update may have triggered at the
572 // same time.
573 EXPECT_CALL(*(observer_.get()),
574 CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2),
575 _, _));
577 sink_callback_.Run();
578 loop_.RunUntilIdle();
579 VerifyStreamAndSize();
580 DestroyDownloadFile(0);
583 // Send some data, wait 3/4s of a second, run the message loop, and
584 // confirm the values the observer received are correct.
585 TEST_F(DownloadFileTest, ConfirmUpdate) {
586 CreateDownloadFile(0, true);
588 const char* chunks1[] = { kTestData1, kTestData2 };
589 AppendDataToFile(chunks1, 2);
591 // Run the message loops for 750ms and check for results.
592 loop_.PostDelayedTask(FROM_HERE,
593 base::MessageLoop::QuitClosure(),
594 base::TimeDelta::FromMilliseconds(750));
595 loop_.Run();
597 EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
598 bytes_);
599 EXPECT_EQ(download_file_->GetHashState(), hash_state_);
601 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
602 DestroyDownloadFile(0);
605 } // namespace content