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/files/file.h"
      6 #include "base/files/file_util.h"
      7 #include "base/message_loop/message_loop.h"
      8 #include "base/run_loop.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/test/test_file_util.h"
     11 #include "content/browser/browser_thread_impl.h"
     12 #include "content/browser/byte_stream.h"
     13 #include "content/browser/download/download_create_info.h"
     14 #include "content/browser/download/download_file_impl.h"
     15 #include "content/browser/download/download_request_handle.h"
     16 #include "content/public/browser/download_destination_observer.h"
     17 #include "content/public/browser/download_interrupt_reasons.h"
     18 #include "content/public/browser/download_manager.h"
     19 #include "content/public/test/mock_download_manager.h"
     20 #include "net/base/file_stream.h"
     21 #include "net/base/mock_file_stream.h"
     22 #include "net/base/net_errors.h"
     23 #include "testing/gmock/include/gmock/gmock.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 using ::testing::_;
     27 using ::testing::AnyNumber;
     28 using ::testing::DoAll;
     29 using ::testing::InSequence;
     30 using ::testing::Return;
     31 using ::testing::SetArgPointee;
     32 using ::testing::StrictMock;
     33 
     34 namespace content {
     35 namespace {
     36 
     37 class MockByteStreamReader : public ByteStreamReader {
     38  public:
     39   MockByteStreamReader() {}
     40   ~MockByteStreamReader() {}
     41 
     42   // ByteStream functions
     43   MOCK_METHOD2(Read, ByteStreamReader::StreamState(
     44       scoped_refptr<net::IOBuffer>*, size_t*));
     45   MOCK_CONST_METHOD0(GetStatus, int());
     46   MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
     47 };
     48 
     49 class MockDownloadDestinationObserver : public DownloadDestinationObserver {
     50  public:
     51   MOCK_METHOD3(DestinationUpdate, void(int64, int64, const std::string&));
     52   MOCK_METHOD1(DestinationError, void(DownloadInterruptReason));
     53   MOCK_METHOD1(DestinationCompleted, void(const std::string&));
     54 
     55   // Doesn't override any methods in the base class.  Used to make sure
     56   // that the last DestinationUpdate before a Destination{Completed,Error}
     57   // had the right values.
     58   MOCK_METHOD3(CurrentUpdateStatus,
     59                void(int64, int64, const std::string&));
     60 };
     61 
     62 MATCHER(IsNullCallback, "") { return (arg.is_null()); }
     63 
     64 typedef void (DownloadFile::*DownloadFileRenameMethodType)(
     65     const base::FilePath&,
     66     const DownloadFile::RenameCompletionCallback&);
     67 
     68 // This is a test DownloadFileImpl that has no retry delay and, on Posix,
     69 // retries renames failed due to ACCESS_DENIED.
     70 class TestDownloadFileImpl : public DownloadFileImpl {
     71  public:
     72   TestDownloadFileImpl(scoped_ptr<DownloadSaveInfo> save_info,
     73                        const base::FilePath& default_downloads_directory,
     74                        const GURL& url,
     75                        const GURL& referrer_url,
     76                        bool calculate_hash,
     77                        scoped_ptr<ByteStreamReader> stream,
     78                        const net::BoundNetLog& bound_net_log,
     79                        base::WeakPtr<DownloadDestinationObserver> observer)
     80       : DownloadFileImpl(save_info.Pass(),
     81                          default_downloads_directory,
     82                          url,
     83                          referrer_url,
     84                          calculate_hash,
     85                          stream.Pass(),
     86                          bound_net_log,
     87                          observer) {}
     88 
     89  protected:
     90   virtual base::TimeDelta GetRetryDelayForFailedRename(
     91       int attempt_count) OVERRIDE {
     92     return base::TimeDelta::FromMilliseconds(0);
     93   }
     94 
     95 #if !defined(OS_WIN)
     96   // On Posix, we don't encounter transient errors during renames, except
     97   // possibly EAGAIN, which is difficult to replicate reliably. So we resort to
     98   // simulating a transient error using ACCESS_DENIED instead.
     99   virtual bool ShouldRetryFailedRename(
    100       DownloadInterruptReason reason) OVERRIDE {
    101     return reason == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED;
    102   }
    103 #endif
    104 };
    105 
    106 }  // namespace
    107 
    108 class DownloadFileTest : public testing::Test {
    109  public:
    110 
    111   static const char* kTestData1;
    112   static const char* kTestData2;
    113   static const char* kTestData3;
    114   static const char* kDataHash;
    115   static const uint32 kDummyDownloadId;
    116   static const int kDummyChildId;
    117   static const int kDummyRequestId;
    118 
    119   DownloadFileTest() :
    120       observer_(new StrictMock<MockDownloadDestinationObserver>),
    121       observer_factory_(observer_.get()),
    122       input_stream_(NULL),
    123       bytes_(-1),
    124       bytes_per_sec_(-1),
    125       hash_state_("xyzzy"),
    126       ui_thread_(BrowserThread::UI, &loop_),
    127       file_thread_(BrowserThread::FILE, &loop_) {
    128   }
    129 
    130   virtual ~DownloadFileTest() {
    131   }
    132 
    133   void SetUpdateDownloadInfo(int64 bytes, int64 bytes_per_sec,
    134                              const std::string& hash_state) {
    135     bytes_ = bytes;
    136     bytes_per_sec_ = bytes_per_sec;
    137     hash_state_ = hash_state;
    138   }
    139 
    140   void ConfirmUpdateDownloadInfo() {
    141     observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
    142   }
    143 
    144   virtual void SetUp() {
    145     EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
    146         .Times(AnyNumber())
    147         .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
    148   }
    149 
    150   // Mock calls to this function are forwarded here.
    151   void RegisterCallback(const base::Closure& sink_callback) {
    152     sink_callback_ = sink_callback;
    153   }
    154 
    155   void SetInterruptReasonCallback(const base::Closure& closure,
    156                                   DownloadInterruptReason* reason_p,
    157                                   DownloadInterruptReason reason) {
    158     *reason_p = reason;
    159     closure.Run();
    160   }
    161 
    162   bool CreateDownloadFile(int offset, bool calculate_hash) {
    163     // There can be only one.
    164     DCHECK(!download_file_.get());
    165 
    166     input_stream_ = new StrictMock<MockByteStreamReader>();
    167 
    168     // TODO: Need to actually create a function that'll set the variables
    169     // based on the inputs from the callback.
    170     EXPECT_CALL(*input_stream_, RegisterCallback(_))
    171         .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
    172         .RetiresOnSaturation();
    173 
    174     scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
    175     scoped_ptr<TestDownloadFileImpl> download_file_impl(
    176         new TestDownloadFileImpl(save_info.Pass(),
    177                                  base::FilePath(),
    178                                  GURL(),  // Source
    179                                  GURL(),  // Referrer
    180                                  calculate_hash,
    181                                  scoped_ptr<ByteStreamReader>(input_stream_),
    182                                  net::BoundNetLog(),
    183                                  observer_factory_.GetWeakPtr()));
    184     download_file_impl->SetClientGuid("12345678-ABCD-1234-DCBA-123456789ABC");
    185     download_file_ = download_file_impl.PassAs<DownloadFile>();
    186 
    187     EXPECT_CALL(*input_stream_, Read(_, _))
    188         .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
    189         .RetiresOnSaturation();
    190 
    191     base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
    192     DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE;
    193     base::RunLoop loop_runner;
    194     download_file_->Initialize(base::Bind(
    195         &DownloadFileTest::SetInterruptReasonCallback,
    196         weak_ptr_factory.GetWeakPtr(), loop_runner.QuitClosure(), &result));
    197     loop_runner.Run();
    198 
    199     ::testing::Mock::VerifyAndClearExpectations(input_stream_);
    200     return result == DOWNLOAD_INTERRUPT_REASON_NONE;
    201   }
    202 
    203   void DestroyDownloadFile(int offset) {
    204     EXPECT_FALSE(download_file_->InProgress());
    205 
    206     // Make sure the data has been properly written to disk.
    207     std::string disk_data;
    208     EXPECT_TRUE(base::ReadFileToString(download_file_->FullPath(), &disk_data));
    209     EXPECT_EQ(expected_data_, disk_data);
    210 
    211     // Make sure the Browser and File threads outlive the DownloadFile
    212     // to satisfy thread checks inside it.
    213     download_file_.reset();
    214   }
    215 
    216   // Setup the stream to do be a data append; don't actually trigger
    217   // the callback or do verifications.
    218   void SetupDataAppend(const char **data_chunks, size_t num_chunks,
    219                        ::testing::Sequence s) {
    220     DCHECK(input_stream_);
    221     for (size_t i = 0; i < num_chunks; i++) {
    222       const char *source_data = data_chunks[i];
    223       size_t length = strlen(source_data);
    224       scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length);
    225       memcpy(data->data(), source_data, length);
    226       EXPECT_CALL(*input_stream_, Read(_, _))
    227           .InSequence(s)
    228           .WillOnce(DoAll(SetArgPointee<0>(data),
    229                           SetArgPointee<1>(length),
    230                           Return(ByteStreamReader::STREAM_HAS_DATA)))
    231           .RetiresOnSaturation();
    232       expected_data_ += source_data;
    233     }
    234   }
    235 
    236   void VerifyStreamAndSize() {
    237     ::testing::Mock::VerifyAndClearExpectations(input_stream_);
    238     int64 size;
    239     EXPECT_TRUE(base::GetFileSize(download_file_->FullPath(), &size));
    240     EXPECT_EQ(expected_data_.size(), static_cast<size_t>(size));
    241   }
    242 
    243   // TODO(rdsmith): Manage full percentage issues properly.
    244   void AppendDataToFile(const char **data_chunks, size_t num_chunks) {
    245     ::testing::Sequence s1;
    246     SetupDataAppend(data_chunks, num_chunks, s1);
    247     EXPECT_CALL(*input_stream_, Read(_, _))
    248         .InSequence(s1)
    249         .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
    250         .RetiresOnSaturation();
    251     sink_callback_.Run();
    252     VerifyStreamAndSize();
    253   }
    254 
    255   void SetupFinishStream(DownloadInterruptReason interrupt_reason,
    256                        ::testing::Sequence s) {
    257     EXPECT_CALL(*input_stream_, Read(_, _))
    258         .InSequence(s)
    259         .WillOnce(Return(ByteStreamReader::STREAM_COMPLETE))
    260         .RetiresOnSaturation();
    261     EXPECT_CALL(*input_stream_, GetStatus())
    262         .InSequence(s)
    263         .WillOnce(Return(interrupt_reason))
    264         .RetiresOnSaturation();
    265     EXPECT_CALL(*input_stream_, RegisterCallback(_))
    266         .RetiresOnSaturation();
    267   }
    268 
    269   void FinishStream(DownloadInterruptReason interrupt_reason,
    270                     bool check_observer) {
    271     ::testing::Sequence s1;
    272     SetupFinishStream(interrupt_reason, s1);
    273     sink_callback_.Run();
    274     VerifyStreamAndSize();
    275     if (check_observer) {
    276       EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
    277       loop_.RunUntilIdle();
    278       ::testing::Mock::VerifyAndClearExpectations(observer_.get());
    279       EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
    280           .Times(AnyNumber())
    281           .WillRepeatedly(Invoke(this,
    282                                  &DownloadFileTest::SetUpdateDownloadInfo));
    283     }
    284   }
    285 
    286   DownloadInterruptReason RenameAndUniquify(
    287       const base::FilePath& full_path,
    288       base::FilePath* result_path_p) {
    289     return InvokeRenameMethodAndWaitForCallback(
    290         &DownloadFile::RenameAndUniquify, full_path, result_path_p);
    291   }
    292 
    293   DownloadInterruptReason RenameAndAnnotate(
    294       const base::FilePath& full_path,
    295       base::FilePath* result_path_p) {
    296     return InvokeRenameMethodAndWaitForCallback(
    297         &DownloadFile::RenameAndAnnotate, full_path, result_path_p);
    298   }
    299 
    300   void ExpectPermissionError(DownloadInterruptReason err) {
    301     EXPECT_TRUE(err == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR ||
    302                 err == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED)
    303         << "Interrupt reason = " << err;
    304   }
    305 
    306  protected:
    307   DownloadInterruptReason InvokeRenameMethodAndWaitForCallback(
    308       DownloadFileRenameMethodType method,
    309       const base::FilePath& full_path,
    310       base::FilePath* result_path_p) {
    311     DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
    312     base::FilePath result_path;
    313 
    314     base::RunLoop loop_runner;
    315     ((*download_file_).*method)(full_path,
    316                                 base::Bind(&DownloadFileTest::SetRenameResult,
    317                                            base::Unretained(this),
    318                                            loop_runner.QuitClosure(),
    319                                            &result_reason,
    320                                            result_path_p));
    321     loop_runner.Run();
    322     return result_reason;
    323   }
    324 
    325   scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
    326   base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
    327 
    328   // DownloadFile instance we are testing.
    329   scoped_ptr<DownloadFile> download_file_;
    330 
    331   // Stream for sending data into the download file.
    332   // Owned by download_file_; will be alive for lifetime of download_file_.
    333   StrictMock<MockByteStreamReader>* input_stream_;
    334 
    335   // Sink callback data for stream.
    336   base::Closure sink_callback_;
    337 
    338   // Latest update sent to the observer.
    339   int64 bytes_;
    340   int64 bytes_per_sec_;
    341   std::string hash_state_;
    342 
    343   base::MessageLoop loop_;
    344 
    345  private:
    346   void SetRenameResult(const base::Closure& closure,
    347                        DownloadInterruptReason* reason_p,
    348                        base::FilePath* result_path_p,
    349                        DownloadInterruptReason reason,
    350                        const base::FilePath& result_path) {
    351     if (reason_p)
    352       *reason_p = reason;
    353     if (result_path_p)
    354       *result_path_p = result_path;
    355     closure.Run();
    356   }
    357 
    358   // UI thread.
    359   BrowserThreadImpl ui_thread_;
    360   // File thread to satisfy debug checks in DownloadFile.
    361   BrowserThreadImpl file_thread_;
    362 
    363   // Keep track of what data should be saved to the disk file.
    364   std::string expected_data_;
    365 };
    366 
    367 // DownloadFile::RenameAndAnnotate and DownloadFile::RenameAndUniquify have a
    368 // considerable amount of functional overlap. In order to re-use test logic, we
    369 // are going to introduce this value parameterized test fixture. It will take a
    370 // DownloadFileRenameMethodType value which can be either of the two rename
    371 // methods.
    372 class DownloadFileTestWithRename
    373     : public DownloadFileTest,
    374       public ::testing::WithParamInterface<DownloadFileRenameMethodType> {
    375  protected:
    376   DownloadInterruptReason InvokeSelectedRenameMethod(
    377       const base::FilePath& full_path,
    378       base::FilePath* result_path_p) {
    379     return InvokeRenameMethodAndWaitForCallback(
    380         GetParam(), full_path, result_path_p);
    381   }
    382 };
    383 
    384 // And now instantiate all DownloadFileTestWithRename tests using both
    385 // DownloadFile rename methods. Each test of the form
    386 // DownloadFileTestWithRename.<FooTest> will be instantiated once with
    387 // RenameAndAnnotate as the value parameter and once with RenameAndUniquify as
    388 // the value parameter.
    389 INSTANTIATE_TEST_CASE_P(DownloadFile,
    390                         DownloadFileTestWithRename,
    391                         ::testing::Values(&DownloadFile::RenameAndAnnotate,
    392                                           &DownloadFile::RenameAndUniquify));
    393 
    394 const char* DownloadFileTest::kTestData1 =
    395     "Let's write some data to the file!\n";
    396 const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
    397 const char* DownloadFileTest::kTestData3 = "Final line.";
    398 const char* DownloadFileTest::kDataHash =
    399     "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
    400 
    401 const uint32 DownloadFileTest::kDummyDownloadId = 23;
    402 const int DownloadFileTest::kDummyChildId = 3;
    403 const int DownloadFileTest::kDummyRequestId = 67;
    404 
    405 // Rename the file before any data is downloaded, after some has, after it all
    406 // has, and after it's closed.
    407 TEST_P(DownloadFileTestWithRename, RenameFileFinal) {
    408   ASSERT_TRUE(CreateDownloadFile(0, true));
    409   base::FilePath initial_path(download_file_->FullPath());
    410   EXPECT_TRUE(base::PathExists(initial_path));
    411   base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
    412   base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
    413   base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
    414   base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
    415   base::FilePath output_path;
    416 
    417   // Rename the file before downloading any data.
    418   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    419             InvokeSelectedRenameMethod(path_1, &output_path));
    420   base::FilePath renamed_path = download_file_->FullPath();
    421   EXPECT_EQ(path_1, renamed_path);
    422   EXPECT_EQ(path_1, output_path);
    423 
    424   // Check the files.
    425   EXPECT_FALSE(base::PathExists(initial_path));
    426   EXPECT_TRUE(base::PathExists(path_1));
    427 
    428   // Download the data.
    429   const char* chunks1[] = { kTestData1, kTestData2 };
    430   AppendDataToFile(chunks1, 2);
    431 
    432   // Rename the file after downloading some data.
    433   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    434             InvokeSelectedRenameMethod(path_2, &output_path));
    435   renamed_path = download_file_->FullPath();
    436   EXPECT_EQ(path_2, renamed_path);
    437   EXPECT_EQ(path_2, output_path);
    438 
    439   // Check the files.
    440   EXPECT_FALSE(base::PathExists(path_1));
    441   EXPECT_TRUE(base::PathExists(path_2));
    442 
    443   const char* chunks2[] = { kTestData3 };
    444   AppendDataToFile(chunks2, 1);
    445 
    446   // Rename the file after downloading all the data.
    447   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    448             InvokeSelectedRenameMethod(path_3, &output_path));
    449   renamed_path = download_file_->FullPath();
    450   EXPECT_EQ(path_3, renamed_path);
    451   EXPECT_EQ(path_3, output_path);
    452 
    453   // Check the files.
    454   EXPECT_FALSE(base::PathExists(path_2));
    455   EXPECT_TRUE(base::PathExists(path_3));
    456 
    457   // Should not be able to get the hash until the file is closed.
    458   std::string hash;
    459   EXPECT_FALSE(download_file_->GetHash(&hash));
    460   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
    461   loop_.RunUntilIdle();
    462 
    463   // Rename the file after downloading all the data and closing the file.
    464   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    465             InvokeSelectedRenameMethod(path_4, &output_path));
    466   renamed_path = download_file_->FullPath();
    467   EXPECT_EQ(path_4, renamed_path);
    468   EXPECT_EQ(path_4, output_path);
    469 
    470   // Check the files.
    471   EXPECT_FALSE(base::PathExists(path_3));
    472   EXPECT_TRUE(base::PathExists(path_4));
    473 
    474   // Check the hash.
    475   EXPECT_TRUE(download_file_->GetHash(&hash));
    476   EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
    477 
    478   DestroyDownloadFile(0);
    479 }
    480 
    481 // Test to make sure the rename overwrites when requested. This is separate from
    482 // the above test because it only applies to RenameAndAnnotate().
    483 // RenameAndUniquify() doesn't overwrite by design.
    484 TEST_F(DownloadFileTest, RenameOverwrites) {
    485   ASSERT_TRUE(CreateDownloadFile(0, true));
    486   base::FilePath initial_path(download_file_->FullPath());
    487   EXPECT_TRUE(base::PathExists(initial_path));
    488   base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
    489 
    490   ASSERT_FALSE(base::PathExists(path_1));
    491   static const char file_data[] = "xyzzy";
    492   ASSERT_EQ(static_cast<int>(sizeof(file_data)),
    493             base::WriteFile(path_1, file_data, sizeof(file_data)));
    494   ASSERT_TRUE(base::PathExists(path_1));
    495 
    496   base::FilePath new_path;
    497   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    498             RenameAndAnnotate(path_1, &new_path));
    499   EXPECT_EQ(path_1.value(), new_path.value());
    500 
    501   std::string file_contents;
    502   ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents));
    503   EXPECT_NE(std::string(file_data), file_contents);
    504 
    505   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
    506   loop_.RunUntilIdle();
    507   DestroyDownloadFile(0);
    508 }
    509 
    510 // Test to make sure the rename uniquifies if we aren't overwriting
    511 // and there's a file where we're aiming. As above, not a
    512 // DownloadFileTestWithRename test because this only applies to
    513 // RenameAndUniquify().
    514 TEST_F(DownloadFileTest, RenameUniquifies) {
    515   ASSERT_TRUE(CreateDownloadFile(0, true));
    516   base::FilePath initial_path(download_file_->FullPath());
    517   EXPECT_TRUE(base::PathExists(initial_path));
    518   base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
    519   base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)"));
    520 
    521   ASSERT_FALSE(base::PathExists(path_1));
    522   static const char file_data[] = "xyzzy";
    523   ASSERT_EQ(static_cast<int>(sizeof(file_data)),
    524             base::WriteFile(path_1, file_data, sizeof(file_data)));
    525   ASSERT_TRUE(base::PathExists(path_1));
    526 
    527   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
    528   EXPECT_TRUE(base::PathExists(path_1_suffixed));
    529 
    530   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
    531   loop_.RunUntilIdle();
    532   DestroyDownloadFile(0);
    533 }
    534 
    535 // Test that RenameAndUniquify doesn't try to uniquify in the case where the
    536 // target filename is the same as the current filename.
    537 TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) {
    538   ASSERT_TRUE(CreateDownloadFile(0, true));
    539   base::FilePath initial_path(download_file_->FullPath());
    540   EXPECT_TRUE(base::PathExists(initial_path));
    541 
    542   base::FilePath new_path;
    543   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    544             RenameAndUniquify(initial_path, &new_path));
    545   EXPECT_TRUE(base::PathExists(initial_path));
    546 
    547   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
    548   loop_.RunUntilIdle();
    549   DestroyDownloadFile(0);
    550   EXPECT_EQ(initial_path.value(), new_path.value());
    551 }
    552 
    553 // Test to make sure we get the proper error on failure.
    554 TEST_P(DownloadFileTestWithRename, RenameError) {
    555   ASSERT_TRUE(CreateDownloadFile(0, true));
    556   base::FilePath initial_path(download_file_->FullPath());
    557 
    558   // Create a subdirectory.
    559   base::FilePath target_dir(
    560       initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir")));
    561   ASSERT_FALSE(base::DirectoryExists(target_dir));
    562   ASSERT_TRUE(base::CreateDirectory(target_dir));
    563   base::FilePath target_path(target_dir.Append(initial_path.BaseName()));
    564 
    565   // Targets
    566   base::FilePath target_path_suffixed(
    567       target_path.InsertBeforeExtensionASCII(" (1)"));
    568   ASSERT_FALSE(base::PathExists(target_path));
    569   ASSERT_FALSE(base::PathExists(target_path_suffixed));
    570 
    571   // Make the directory unwritable and try to rename within it.
    572   {
    573     base::FilePermissionRestorer restorer(target_dir);
    574     ASSERT_TRUE(base::MakeFileUnwritable(target_dir));
    575 
    576     // Expect nulling out of further processing.
    577     EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback()));
    578     ExpectPermissionError(InvokeSelectedRenameMethod(target_path, NULL));
    579     EXPECT_FALSE(base::PathExists(target_path_suffixed));
    580   }
    581 
    582   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
    583   loop_.RunUntilIdle();
    584   DestroyDownloadFile(0);
    585 }
    586 
    587 namespace {
    588 
    589 void TestRenameCompletionCallback(const base::Closure& closure,
    590                                   bool* did_run_callback,
    591                                   DownloadInterruptReason interrupt_reason,
    592                                   const base::FilePath& new_path) {
    593   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
    594   *did_run_callback = true;
    595   closure.Run();
    596 }
    597 
    598 }  // namespace
    599 
    600 // Test that the retry logic works. This test assumes that DownloadFileImpl will
    601 // post tasks to the current message loop (acting as the FILE thread)
    602 // asynchronously to retry the renames. We will stuff RunLoop::QuitClosures()
    603 // in between the retry tasks to stagger them and then allow the rename to
    604 // succeed.
    605 //
    606 // Note that there is only one queue of tasks to run, and that is in the tests'
    607 // base::MessageLoop::current(). Each RunLoop processes that queue until it sees
    608 // a QuitClosure() targeted at itself, at which point it stops processing.
    609 TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) {
    610   ASSERT_TRUE(CreateDownloadFile(0, true));
    611   base::FilePath initial_path(download_file_->FullPath());
    612 
    613   // Create a subdirectory.
    614   base::FilePath target_dir(
    615       initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir")));
    616   ASSERT_FALSE(base::DirectoryExists(target_dir));
    617   ASSERT_TRUE(base::CreateDirectory(target_dir));
    618   base::FilePath target_path(target_dir.Append(initial_path.BaseName()));
    619 
    620   bool did_run_callback = false;
    621 
    622   // Each RunLoop can be used the run the MessageLoop until the corresponding
    623   // QuitClosure() is run. This one is used to produce the QuitClosure() that
    624   // will be run when the entire rename operation is complete.
    625   base::RunLoop succeeding_run;
    626   {
    627     // (Scope for the base::File or base::FilePermissionRestorer below.)
    628 #if defined(OS_WIN)
    629     // On Windows we test with an actual transient error, a sharing violation.
    630     // The rename will fail because we are holding the file open for READ. On
    631     // Posix this doesn't cause a failure.
    632     base::File locked_file(initial_path,
    633                            base::File::FLAG_OPEN | base::File::FLAG_READ);
    634     ASSERT_TRUE(locked_file.IsValid());
    635 #else
    636     // Simulate a transient failure by revoking write permission for target_dir.
    637     // The TestDownloadFileImpl class treats this error as transient even though
    638     // DownloadFileImpl itself doesn't.
    639     base::FilePermissionRestorer restore_permissions_for(target_dir);
    640     ASSERT_TRUE(base::MakeFileUnwritable(target_dir));
    641 #endif
    642 
    643     // The Rename() should fail here and enqueue a retry task without invoking
    644     // the completion callback.
    645     ((*download_file_).*GetParam())(target_path,
    646                                     base::Bind(&TestRenameCompletionCallback,
    647                                                succeeding_run.QuitClosure(),
    648                                                &did_run_callback));
    649     EXPECT_FALSE(did_run_callback);
    650 
    651     base::RunLoop first_failing_run;
    652     // Queue the QuitClosure() on the MessageLoop now. Any tasks queued by the
    653     // Rename() will be in front of the QuitClosure(). Running the message loop
    654     // now causes the just the first retry task to be run. The rename still
    655     // fails, so another retry task would get queued behind the QuitClosure().
    656     base::MessageLoop::current()->PostTask(FROM_HERE,
    657                                            first_failing_run.QuitClosure());
    658     first_failing_run.Run();
    659     EXPECT_FALSE(did_run_callback);
    660 
    661     // Running another loop should have the same effect as the above as long as
    662     // kMaxRenameRetries is greater than 2.
    663     base::RunLoop second_failing_run;
    664     base::MessageLoop::current()->PostTask(FROM_HERE,
    665                                            second_failing_run.QuitClosure());
    666     second_failing_run.Run();
    667     EXPECT_FALSE(did_run_callback);
    668   }
    669 
    670   // This time the QuitClosure from succeeding_run should get executed.
    671   succeeding_run.Run();
    672   EXPECT_TRUE(did_run_callback);
    673 
    674   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
    675   loop_.RunUntilIdle();
    676   DestroyDownloadFile(0);
    677 }
    678 
    679 // Various tests of the StreamActive method.
    680 TEST_F(DownloadFileTest, StreamEmptySuccess) {
    681   ASSERT_TRUE(CreateDownloadFile(0, true));
    682   base::FilePath initial_path(download_file_->FullPath());
    683   EXPECT_TRUE(base::PathExists(initial_path));
    684 
    685   // Test that calling the sink_callback_ on an empty stream shouldn't
    686   // do anything.
    687   AppendDataToFile(NULL, 0);
    688 
    689   // Finish the download this way and make sure we see it on the
    690   // observer.
    691   EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
    692   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, false);
    693   loop_.RunUntilIdle();
    694 
    695   DestroyDownloadFile(0);
    696 }
    697 
    698 TEST_F(DownloadFileTest, StreamEmptyError) {
    699   ASSERT_TRUE(CreateDownloadFile(0, true));
    700   base::FilePath initial_path(download_file_->FullPath());
    701   EXPECT_TRUE(base::PathExists(initial_path));
    702 
    703   // Finish the download in error and make sure we see it on the
    704   // observer.
    705   EXPECT_CALL(*(observer_.get()),
    706               DestinationError(
    707                   DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
    708       .WillOnce(InvokeWithoutArgs(
    709           this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
    710 
    711   // If this next EXPECT_CALL fails flakily, it's probably a real failure.
    712   // We'll be getting a stream of UpdateDownload calls from the timer, and
    713   // the last one may have the correct information even if the failure
    714   // doesn't produce an update, as the timer update may have triggered at the
    715   // same time.
    716   EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(0, _, _));
    717 
    718   FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
    719 
    720   loop_.RunUntilIdle();
    721 
    722   DestroyDownloadFile(0);
    723 }
    724 
    725 TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
    726   ASSERT_TRUE(CreateDownloadFile(0, true));
    727   base::FilePath initial_path(download_file_->FullPath());
    728   EXPECT_TRUE(base::PathExists(initial_path));
    729 
    730   const char* chunks1[] = { kTestData1, kTestData2 };
    731   ::testing::Sequence s1;
    732   SetupDataAppend(chunks1, 2, s1);
    733   SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, s1);
    734   EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
    735   sink_callback_.Run();
    736   VerifyStreamAndSize();
    737   loop_.RunUntilIdle();
    738   DestroyDownloadFile(0);
    739 }
    740 
    741 TEST_F(DownloadFileTest, StreamNonEmptyError) {
    742   ASSERT_TRUE(CreateDownloadFile(0, true));
    743   base::FilePath initial_path(download_file_->FullPath());
    744   EXPECT_TRUE(base::PathExists(initial_path));
    745 
    746   const char* chunks1[] = { kTestData1, kTestData2 };
    747   ::testing::Sequence s1;
    748   SetupDataAppend(chunks1, 2, s1);
    749   SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
    750 
    751   EXPECT_CALL(*(observer_.get()),
    752               DestinationError(
    753                   DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
    754       .WillOnce(InvokeWithoutArgs(
    755           this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
    756 
    757   // If this next EXPECT_CALL fails flakily, it's probably a real failure.
    758   // We'll be getting a stream of UpdateDownload calls from the timer, and
    759   // the last one may have the correct information even if the failure
    760   // doesn't produce an update, as the timer update may have triggered at the
    761   // same time.
    762   EXPECT_CALL(*(observer_.get()),
    763               CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2),
    764                                   _, _));
    765 
    766   sink_callback_.Run();
    767   loop_.RunUntilIdle();
    768   VerifyStreamAndSize();
    769   DestroyDownloadFile(0);
    770 }
    771 
    772 // Send some data, wait 3/4s of a second, run the message loop, and
    773 // confirm the values the observer received are correct.
    774 TEST_F(DownloadFileTest, ConfirmUpdate) {
    775   CreateDownloadFile(0, true);
    776 
    777   const char* chunks1[] = { kTestData1, kTestData2 };
    778   AppendDataToFile(chunks1, 2);
    779 
    780   // Run the message loops for 750ms and check for results.
    781   loop_.PostDelayedTask(FROM_HERE,
    782                         base::MessageLoop::QuitClosure(),
    783                         base::TimeDelta::FromMilliseconds(750));
    784   loop_.Run();
    785 
    786   EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
    787             bytes_);
    788   EXPECT_EQ(download_file_->GetHashState(), hash_state_);
    789 
    790   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
    791   DestroyDownloadFile(0);
    792 }
    793 
    794 }  // namespace content
    795