Home | History | Annotate | Download | only in download
      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     file_util::PermissionRestorer restorer(tempdir);
    474     ASSERT_TRUE(file_util::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
    604