- add sources.
[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/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"
24
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;
32
33 namespace content {
34 namespace {
35
36 class MockByteStreamReader : public ByteStreamReader {
37  public:
38   MockByteStreamReader() {}
39   ~MockByteStreamReader() {}
40
41   // ByteStream functions
42   MOCK_METHOD2(Read, ByteStreamReader::StreamState(
43       scoped_refptr<net::IOBuffer>*, size_t*));
44   MOCK_CONST_METHOD0(GetStatus, int());
45   MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
46 };
47
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&));
53
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&));
59 };
60
61 MATCHER(IsNullCallback, "") { return (arg.is_null()); }
62
63 }  // namespace
64
65 class DownloadFileTest : public testing::Test {
66  public:
67
68   static const char* kTestData1;
69   static const char* kTestData2;
70   static const char* kTestData3;
71   static const char* kDataHash;
72   static const uint32 kDummyDownloadId;
73   static const int kDummyChildId;
74   static const int kDummyRequestId;
75
76   DownloadFileTest() :
77       observer_(new StrictMock<MockDownloadDestinationObserver>),
78       observer_factory_(observer_.get()),
79       input_stream_(NULL),
80       bytes_(-1),
81       bytes_per_sec_(-1),
82       hash_state_("xyzzy"),
83       ui_thread_(BrowserThread::UI, &loop_),
84       file_thread_(BrowserThread::FILE, &loop_) {
85   }
86
87   virtual ~DownloadFileTest() {
88   }
89
90   void SetUpdateDownloadInfo(int64 bytes, int64 bytes_per_sec,
91                              const std::string& hash_state) {
92     bytes_ = bytes;
93     bytes_per_sec_ = bytes_per_sec;
94     hash_state_ = hash_state;
95   }
96
97   void ConfirmUpdateDownloadInfo() {
98     observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
99   }
100
101   virtual void SetUp() {
102     EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
103         .Times(AnyNumber())
104         .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
105   }
106
107   // Mock calls to this function are forwarded here.
108   void RegisterCallback(base::Closure sink_callback) {
109     sink_callback_ = sink_callback;
110   }
111
112   void SetInterruptReasonCallback(bool* was_called,
113                                   DownloadInterruptReason* reason_p,
114                                   DownloadInterruptReason reason) {
115     *was_called = true;
116     *reason_p = reason;
117   }
118
119   virtual bool CreateDownloadFile(int offset, bool calculate_hash) {
120     // There can be only one.
121     DCHECK(!download_file_.get());
122
123     input_stream_ = new StrictMock<MockByteStreamReader>();
124
125     // TODO: Need to actually create a function that'll set the variables
126     // based on the inputs from the callback.
127     EXPECT_CALL(*input_stream_, RegisterCallback(_))
128         .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
129         .RetiresOnSaturation();
130
131     scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
132     download_file_.reset(
133         new DownloadFileImpl(save_info.Pass(),
134                              base::FilePath(),
135                              GURL(),  // Source
136                              GURL(),  // Referrer
137                              calculate_hash,
138                              scoped_ptr<ByteStreamReader>(input_stream_),
139                              net::BoundNetLog(),
140                              scoped_ptr<PowerSaveBlocker>().Pass(),
141                              observer_factory_.GetWeakPtr()));
142     download_file_->SetClientGuid(
143         "12345678-ABCD-1234-DCBA-123456789ABC");
144
145     EXPECT_CALL(*input_stream_, Read(_, _))
146         .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
147         .RetiresOnSaturation();
148
149     base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
150     bool called = false;
151     DownloadInterruptReason result;
152     download_file_->Initialize(base::Bind(
153         &DownloadFileTest::SetInterruptReasonCallback,
154         weak_ptr_factory.GetWeakPtr(), &called, &result));
155     loop_.RunUntilIdle();
156     EXPECT_TRUE(called);
157
158     ::testing::Mock::VerifyAndClearExpectations(input_stream_);
159     return result == DOWNLOAD_INTERRUPT_REASON_NONE;
160   }
161
162   virtual void DestroyDownloadFile(int offset) {
163     EXPECT_FALSE(download_file_->InProgress());
164
165     // Make sure the data has been properly written to disk.
166     std::string disk_data;
167     EXPECT_TRUE(base::ReadFileToString(download_file_->FullPath(), &disk_data));
168     EXPECT_EQ(expected_data_, disk_data);
169
170     // Make sure the Browser and File threads outlive the DownloadFile
171     // to satisfy thread checks inside it.
172     download_file_.reset();
173   }
174
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;
192     }
193   }
194
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));
200   }
201
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();
212   }
213
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();
226   }
227
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));
242     }
243   }
244
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;
252
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();
259
260     EXPECT_TRUE(callback_was_called);
261     return result_reason;
262   }
263
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;
271
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();
278
279     EXPECT_TRUE(callback_was_called);
280     return result_reason;
281   }
282
283  protected:
284   scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
285   base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
286
287   // DownloadFile instance we are testing.
288   scoped_ptr<DownloadFile> download_file_;
289
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_;
293
294   // Sink callback data for stream.
295   base::Closure sink_callback_;
296
297   // Latest update sent to the observer.
298   int64 bytes_;
299   int64 bytes_per_sec_;
300   std::string hash_state_;
301
302   base::MessageLoop loop_;
303
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;
316   }
317
318   // UI thread.
319   BrowserThreadImpl ui_thread_;
320   // File thread to satisfy debug checks in DownloadFile.
321   BrowserThreadImpl file_thread_;
322
323   // Keep track of what data should be saved to the disk file.
324   std::string expected_data_;
325 };
326
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";
333
334 const uint32 DownloadFileTest::kDummyDownloadId = 23;
335 const int DownloadFileTest::kDummyChildId = 3;
336 const int DownloadFileTest::kDummyRequestId = 67;
337
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(base::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;
350
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);
357
358   // Check the files.
359   EXPECT_FALSE(base::PathExists(initial_path));
360   EXPECT_TRUE(base::PathExists(path_1));
361
362   // Download the data.
363   const char* chunks1[] = { kTestData1, kTestData2 };
364   AppendDataToFile(chunks1, 2);
365
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);
372
373   // Check the files.
374   EXPECT_FALSE(base::PathExists(path_1));
375   EXPECT_TRUE(base::PathExists(path_2));
376
377   const char* chunks2[] = { kTestData3 };
378   AppendDataToFile(chunks2, 1);
379
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);
386
387   // Check the files.
388   EXPECT_FALSE(base::PathExists(path_2));
389   EXPECT_TRUE(base::PathExists(path_3));
390
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();
396
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);
403
404   // Check the files.
405   EXPECT_FALSE(base::PathExists(path_3));
406   EXPECT_TRUE(base::PathExists(path_4));
407
408   // Check the hash.
409   EXPECT_TRUE(download_file_->GetHash(&hash));
410   EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
411
412   // Check that a rename with overwrite to an existing file succeeds.
413   std::string file_contents;
414   ASSERT_FALSE(base::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(base::PathExists(path_5));
419   EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
420   EXPECT_EQ(std::string(file_data), file_contents);
421
422   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
423             RenameAndAnnotate(path_5, &output_path));
424   EXPECT_EQ(path_5, output_path);
425
426   file_contents = "";
427   EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
428   EXPECT_NE(std::string(file_data), file_contents);
429
430   DestroyDownloadFile(0);
431 }
432
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(base::PathExists(initial_path));
439   base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
440   base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)"));
441
442   ASSERT_FALSE(base::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(base::PathExists(path_1));
447
448   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
449   EXPECT_TRUE(base::PathExists(path_1_suffixed));
450
451   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
452   loop_.RunUntilIdle();
453   DestroyDownloadFile(0);
454 }
455
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());
460
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()));
466
467   // Targets
468   base::FilePath target_path_suffixed(
469       target_path.InsertBeforeExtensionASCII(" (1)"));
470   ASSERT_FALSE(base::PathExists(target_path));
471   ASSERT_FALSE(base::PathExists(target_path_suffixed));
472
473   // Make the directory unwritable and try to rename within it.
474   {
475     file_util::PermissionRestorer restorer(tempdir);
476     ASSERT_TRUE(file_util::MakeFileUnwritable(tempdir));
477
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(base::PathExists(target_path_suffixed));
483   }
484
485   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
486   loop_.RunUntilIdle();
487   DestroyDownloadFile(0);
488 }
489
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(base::PathExists(initial_path));
495
496   // Test that calling the sink_callback_ on an empty stream shouldn't
497   // do anything.
498   AppendDataToFile(NULL, 0);
499
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();
505
506   DestroyDownloadFile(0);
507 }
508
509 TEST_F(DownloadFileTest, StreamEmptyError) {
510   ASSERT_TRUE(CreateDownloadFile(0, true));
511   base::FilePath initial_path(download_file_->FullPath());
512   EXPECT_TRUE(base::PathExists(initial_path));
513
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));
521
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, _, _));
528
529   FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
530
531   loop_.RunUntilIdle();
532
533   DestroyDownloadFile(0);
534 }
535
536 TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
537   ASSERT_TRUE(CreateDownloadFile(0, true));
538   base::FilePath initial_path(download_file_->FullPath());
539   EXPECT_TRUE(base::PathExists(initial_path));
540
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);
550 }
551
552 TEST_F(DownloadFileTest, StreamNonEmptyError) {
553   ASSERT_TRUE(CreateDownloadFile(0, true));
554   base::FilePath initial_path(download_file_->FullPath());
555   EXPECT_TRUE(base::PathExists(initial_path));
556
557   const char* chunks1[] = { kTestData1, kTestData2 };
558   ::testing::Sequence s1;
559   SetupDataAppend(chunks1, 2, s1);
560   SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
561
562   EXPECT_CALL(*(observer_.get()),
563               DestinationError(
564                   DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
565       .WillOnce(InvokeWithoutArgs(
566           this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
567
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                                   _, _));
576
577   sink_callback_.Run();
578   loop_.RunUntilIdle();
579   VerifyStreamAndSize();
580   DestroyDownloadFile(0);
581 }
582
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);
587
588   const char* chunks1[] = { kTestData1, kTestData2 };
589   AppendDataToFile(chunks1, 2);
590
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();
596
597   EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
598             bytes_);
599   EXPECT_EQ(download_file_->GetHashState(), hash_state_);
600
601   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
602   DestroyDownloadFile(0);
603 }
604
605 }  // namespace content