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/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(base::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(base::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
    606