Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / download / download_file_unittest.cc
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.
4
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"
23
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;
31
32 namespace content {
33 namespace {
34
35 class MockByteStreamReader : public ByteStreamReader {
36  public:
37   MockByteStreamReader() {}
38   ~MockByteStreamReader() {}
39
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&));
45 };
46
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&));
52
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&));
58 };
59
60 MATCHER(IsNullCallback, "") { return (arg.is_null()); }
61
62 }  // namespace
63
64 class DownloadFileTest : public testing::Test {
65  public:
66
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;
74
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_) {
84   }
85
86   virtual ~DownloadFileTest() {
87   }
88
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;
94   }
95
96   void ConfirmUpdateDownloadInfo() {
97     observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
98   }
99
100   virtual void SetUp() {
101     EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
102         .Times(AnyNumber())
103         .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
104   }
105
106   // Mock calls to this function are forwarded here.
107   void RegisterCallback(base::Closure sink_callback) {
108     sink_callback_ = sink_callback;
109   }
110
111   void SetInterruptReasonCallback(bool* was_called,
112                                   DownloadInterruptReason* reason_p,
113                                   DownloadInterruptReason reason) {
114     *was_called = true;
115     *reason_p = reason;
116   }
117
118   bool CreateDownloadFile(int offset, bool calculate_hash) {
119     // There can be only one.
120     DCHECK(!download_file_.get());
121
122     input_stream_ = new StrictMock<MockByteStreamReader>();
123
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();
129
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");
142
143     EXPECT_CALL(*input_stream_, Read(_, _))
144         .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
145         .RetiresOnSaturation();
146
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);
155
156     ::testing::Mock::VerifyAndClearExpectations(input_stream_);
157     return result == DOWNLOAD_INTERRUPT_REASON_NONE;
158   }
159
160   void DestroyDownloadFile(int offset) {
161     EXPECT_FALSE(download_file_->InProgress());
162
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);
167
168     // Make sure the Browser and File threads outlive the DownloadFile
169     // to satisfy thread checks inside it.
170     download_file_.reset();
171   }
172
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;
190     }
191   }
192
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));
198   }
199
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();
210   }
211
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();
224   }
225
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));
240     }
241   }
242
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;
250
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();
257
258     EXPECT_TRUE(callback_was_called);
259     return result_reason;
260   }
261
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;
269
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();
276
277     EXPECT_TRUE(callback_was_called);
278     return result_reason;
279   }
280
281  protected:
282   scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
283   base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
284
285   // DownloadFile instance we are testing.
286   scoped_ptr<DownloadFile> download_file_;
287
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_;
291
292   // Sink callback data for stream.
293   base::Closure sink_callback_;
294
295   // Latest update sent to the observer.
296   int64 bytes_;
297   int64 bytes_per_sec_;
298   std::string hash_state_;
299
300   base::MessageLoop loop_;
301
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;
314   }
315
316   // UI thread.
317   BrowserThreadImpl ui_thread_;
318   // File thread to satisfy debug checks in DownloadFile.
319   BrowserThreadImpl file_thread_;
320
321   // Keep track of what data should be saved to the disk file.
322   std::string expected_data_;
323 };
324
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";
331
332 const uint32 DownloadFileTest::kDummyDownloadId = 23;
333 const int DownloadFileTest::kDummyChildId = 3;
334 const int DownloadFileTest::kDummyRequestId = 67;
335
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;
348
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);
355
356   // Check the files.
357   EXPECT_FALSE(base::PathExists(initial_path));
358   EXPECT_TRUE(base::PathExists(path_1));
359
360   // Download the data.
361   const char* chunks1[] = { kTestData1, kTestData2 };
362   AppendDataToFile(chunks1, 2);
363
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);
370
371   // Check the files.
372   EXPECT_FALSE(base::PathExists(path_1));
373   EXPECT_TRUE(base::PathExists(path_2));
374
375   const char* chunks2[] = { kTestData3 };
376   AppendDataToFile(chunks2, 1);
377
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);
384
385   // Check the files.
386   EXPECT_FALSE(base::PathExists(path_2));
387   EXPECT_TRUE(base::PathExists(path_3));
388
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();
394
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);
401
402   // Check the files.
403   EXPECT_FALSE(base::PathExists(path_3));
404   EXPECT_TRUE(base::PathExists(path_4));
405
406   // Check the hash.
407   EXPECT_TRUE(download_file_->GetHash(&hash));
408   EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
409
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);
419
420   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
421             RenameAndAnnotate(path_5, &output_path));
422   EXPECT_EQ(path_5, output_path);
423
424   file_contents = "";
425   EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
426   EXPECT_NE(std::string(file_data), file_contents);
427
428   DestroyDownloadFile(0);
429 }
430
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)"));
439
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));
445
446   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
447   EXPECT_TRUE(base::PathExists(path_1_suffixed));
448
449   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
450   loop_.RunUntilIdle();
451   DestroyDownloadFile(0);
452 }
453
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());
458
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()));
464
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));
470
471   // Make the directory unwritable and try to rename within it.
472   {
473     base::FilePermissionRestorer restorer(tempdir);
474     ASSERT_TRUE(base::MakeFileUnwritable(tempdir));
475
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));
481   }
482
483   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
484   loop_.RunUntilIdle();
485   DestroyDownloadFile(0);
486 }
487
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));
493
494   // Test that calling the sink_callback_ on an empty stream shouldn't
495   // do anything.
496   AppendDataToFile(NULL, 0);
497
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();
503
504   DestroyDownloadFile(0);
505 }
506
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));
511
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));
519
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, _, _));
526
527   FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
528
529   loop_.RunUntilIdle();
530
531   DestroyDownloadFile(0);
532 }
533
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));
538
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);
548 }
549
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));
554
555   const char* chunks1[] = { kTestData1, kTestData2 };
556   ::testing::Sequence s1;
557   SetupDataAppend(chunks1, 2, s1);
558   SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
559
560   EXPECT_CALL(*(observer_.get()),
561               DestinationError(
562                   DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
563       .WillOnce(InvokeWithoutArgs(
564           this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
565
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                                   _, _));
574
575   sink_callback_.Run();
576   loop_.RunUntilIdle();
577   VerifyStreamAndSize();
578   DestroyDownloadFile(0);
579 }
580
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);
585
586   const char* chunks1[] = { kTestData1, kTestData2 };
587   AppendDataToFile(chunks1, 2);
588
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();
594
595   EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
596             bytes_);
597   EXPECT_EQ(download_file_->GetHashState(), hash_state_);
598
599   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
600   DestroyDownloadFile(0);
601 }
602
603 }  // namespace content