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"
26 using ::testing::AnyNumber
;
27 using ::testing::DoAll
;
28 using ::testing::InSequence
;
29 using ::testing::Return
;
30 using ::testing::SetArgPointee
;
31 using ::testing::StrictMock
;
36 class MockByteStreamReader
: public ByteStreamReader
{
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
{
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()); }
65 DownloadId::Domain kValidIdDomain
= "valid DownloadId::Domain";
67 class DownloadFileTest
: public testing::Test
{
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
;
79 observer_(new StrictMock
<MockDownloadDestinationObserver
>),
80 observer_factory_(observer_
.get()),
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
) {
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(_
, _
, _
))
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
) {
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(),
139 scoped_ptr
<ByteStreamReader
>(input_stream_
),
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);
150 DownloadInterruptReason result
;
151 download_file_
->Initialize(base::Bind(
152 &DownloadFileTest::SetInterruptReasonCallback
,
153 weak_ptr_factory
.GetWeakPtr(), &called
, &result
));
154 loop_
.RunUntilIdle();
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(),
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(_
, _
))
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_
);
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(_
, _
))
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(_
, _
))
218 .WillOnce(Return(ByteStreamReader::STREAM_COMPLETE
))
219 .RetiresOnSaturation();
220 EXPECT_CALL(*input_stream_
, GetStatus())
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(_
, _
, _
))
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
;
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.
299 int64 bytes_per_sec_
;
300 std::string hash_state_
;
302 base::MessageLoop loop_
;
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
) {
315 *result_path_p
= result_path
;
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
);
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
);
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
);
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.
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
);
405 EXPECT_FALSE(file_util::PathExists(path_3
));
406 EXPECT_TRUE(file_util::PathExists(path_4
));
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
);
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()));
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
498 AppendDataToFile(NULL
, 0);
500 // Finish the download this way and make sure we see it on the
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
516 EXPECT_CALL(*(observer_
.get()),
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
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()),
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
573 EXPECT_CALL(*(observer_
.get()),
574 CurrentUpdateStatus(strlen(kTestData1
) + strlen(kTestData2
),
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));
597 EXPECT_EQ(static_cast<int64
>(strlen(kTestData1
) + strlen(kTestData2
)),
599 EXPECT_EQ(download_file_
->GetHashState(), hash_state_
);
601 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE
, true);
602 DestroyDownloadFile(0);
605 } // namespace content