Home | History | Annotate | Download | only in download
      1 // Copyright (c) 2011 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/memory/scoped_temp_dir.h"
      7 #include "base/message_loop.h"
      8 #include "base/string_number_conversions.h"
      9 #include "chrome/browser/download/download_file.h"
     10 #include "chrome/browser/download/download_manager.h"
     11 #include "chrome/browser/download/download_status_updater.h"
     12 #include "chrome/browser/download/download_util.h"
     13 #include "chrome/browser/download/mock_download_manager.h"
     14 #include "chrome/browser/history/download_create_info.h"
     15 #include "content/browser/browser_thread.h"
     16 #include "net/base/file_stream.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 class DownloadFileTest : public testing::Test {
     20  public:
     21 
     22   static const char* kTestData1;
     23   static const char* kTestData2;
     24   static const char* kTestData3;
     25   static const char* kDataHash;
     26   static const int32 kDummyDownloadId;
     27   static const int kDummyChildId;
     28   static const int kDummyRequestId;
     29 
     30   // We need a UI |BrowserThread| in order to destruct |download_manager_|,
     31   // which has trait |BrowserThread::DeleteOnUIThread|.  Without this,
     32   // calling Release() on |download_manager_| won't ever result in its
     33   // destructor being called and we get a leak.
     34   DownloadFileTest() :
     35       ui_thread_(BrowserThread::UI, &loop_),
     36       file_thread_(BrowserThread::FILE, &loop_) {
     37   }
     38 
     39   ~DownloadFileTest() {
     40   }
     41 
     42   virtual void SetUp() {
     43     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     44     download_manager_ = new MockDownloadManager(&download_status_updater_);
     45   }
     46 
     47   virtual void TearDown() {
     48     // When a DownloadManager's reference count drops to 0, it is not
     49     // deleted immediately. Instead, a task is posted to the UI thread's
     50     // message loop to delete it.
     51     // So, drop the reference count to 0 and run the message loop once
     52     // to ensure that all resources are cleaned up before the test exits.
     53     download_manager_ = NULL;
     54     ui_thread_.message_loop()->RunAllPending();
     55   }
     56 
     57   virtual void CreateDownloadFile(scoped_ptr<DownloadFile>* file, int offset) {
     58     DownloadCreateInfo info;
     59     info.download_id = kDummyDownloadId + offset;
     60     info.child_id = kDummyChildId;
     61     info.request_id = kDummyRequestId - offset;
     62     info.save_info.file_stream = file_stream_;
     63     file->reset(new DownloadFile(&info, download_manager_));
     64   }
     65 
     66   virtual void DestroyDownloadFile(scoped_ptr<DownloadFile>* file, int offset) {
     67     EXPECT_EQ(kDummyDownloadId + offset, (*file)->id());
     68     EXPECT_EQ(download_manager_, (*file)->GetDownloadManager());
     69     EXPECT_FALSE((*file)->in_progress());
     70     EXPECT_EQ(static_cast<int64>(expected_data_.size()),
     71               (*file)->bytes_so_far());
     72 
     73     // Make sure the data has been properly written to disk.
     74     std::string disk_data;
     75     EXPECT_TRUE(file_util::ReadFileToString((*file)->full_path(),
     76                                             &disk_data));
     77     EXPECT_EQ(expected_data_, disk_data);
     78 
     79     // Make sure the mock BrowserThread outlives the DownloadFile to satisfy
     80     // thread checks inside it.
     81     file->reset();
     82   }
     83 
     84   void AppendDataToFile(scoped_ptr<DownloadFile>* file,
     85                         const std::string& data) {
     86     EXPECT_TRUE((*file)->in_progress());
     87     (*file)->AppendDataToFile(data.data(), data.size());
     88     expected_data_ += data;
     89     EXPECT_EQ(static_cast<int64>(expected_data_.size()),
     90               (*file)->bytes_so_far());
     91   }
     92 
     93  protected:
     94   // Temporary directory for renamed downloads.
     95   ScopedTempDir temp_dir_;
     96 
     97   DownloadStatusUpdater download_status_updater_;
     98   scoped_refptr<DownloadManager> download_manager_;
     99 
    100   linked_ptr<net::FileStream> file_stream_;
    101 
    102   // DownloadFile instance we are testing.
    103   scoped_ptr<DownloadFile> download_file_;
    104 
    105  private:
    106   MessageLoop loop_;
    107   // UI thread.
    108   BrowserThread ui_thread_;
    109   // File thread to satisfy debug checks in DownloadFile.
    110   BrowserThread file_thread_;
    111 
    112   // Keep track of what data should be saved to the disk file.
    113   std::string expected_data_;
    114 };
    115 
    116 const char* DownloadFileTest::kTestData1 =
    117     "Let's write some data to the file!\n";
    118 const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
    119 const char* DownloadFileTest::kTestData3 = "Final line.";
    120 const char* DownloadFileTest::kDataHash =
    121     "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
    122 
    123 const int32 DownloadFileTest::kDummyDownloadId = 23;
    124 const int DownloadFileTest::kDummyChildId = 3;
    125 const int DownloadFileTest::kDummyRequestId = 67;
    126 
    127 // Rename the file before any data is downloaded, after some has, after it all
    128 // has, and after it's closed.
    129 TEST_F(DownloadFileTest, RenameFileFinal) {
    130   CreateDownloadFile(&download_file_, 0);
    131   ASSERT_TRUE(download_file_->Initialize(true));
    132   FilePath initial_path(download_file_->full_path());
    133   EXPECT_TRUE(file_util::PathExists(initial_path));
    134   FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
    135   FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
    136   FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
    137   FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
    138 
    139   // Rename the file before downloading any data.
    140   EXPECT_TRUE(download_file_->Rename(path_1));
    141   FilePath renamed_path = download_file_->full_path();
    142   EXPECT_EQ(path_1, renamed_path);
    143 
    144   // Check the files.
    145   EXPECT_FALSE(file_util::PathExists(initial_path));
    146   EXPECT_TRUE(file_util::PathExists(path_1));
    147 
    148   // Download the data.
    149   AppendDataToFile(&download_file_, kTestData1);
    150   AppendDataToFile(&download_file_, kTestData2);
    151 
    152   // Rename the file after downloading some data.
    153   EXPECT_TRUE(download_file_->Rename(path_2));
    154   renamed_path = download_file_->full_path();
    155   EXPECT_EQ(path_2, renamed_path);
    156 
    157   // Check the files.
    158   EXPECT_FALSE(file_util::PathExists(path_1));
    159   EXPECT_TRUE(file_util::PathExists(path_2));
    160 
    161   AppendDataToFile(&download_file_, kTestData3);
    162 
    163   // Rename the file after downloading all the data.
    164   EXPECT_TRUE(download_file_->Rename(path_3));
    165   renamed_path = download_file_->full_path();
    166   EXPECT_EQ(path_3, renamed_path);
    167 
    168   // Check the files.
    169   EXPECT_FALSE(file_util::PathExists(path_2));
    170   EXPECT_TRUE(file_util::PathExists(path_3));
    171 
    172   // Should not be able to get the hash until the file is closed.
    173   std::string hash;
    174   EXPECT_FALSE(download_file_->GetSha256Hash(&hash));
    175 
    176   download_file_->Finish();
    177 
    178   // Rename the file after downloading all the data and closing the file.
    179   EXPECT_TRUE(download_file_->Rename(path_4));
    180   renamed_path = download_file_->full_path();
    181   EXPECT_EQ(path_4, renamed_path);
    182 
    183   // Check the files.
    184   EXPECT_FALSE(file_util::PathExists(path_3));
    185   EXPECT_TRUE(file_util::PathExists(path_4));
    186 
    187   // Check the hash.
    188   EXPECT_TRUE(download_file_->GetSha256Hash(&hash));
    189   EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
    190 
    191   DestroyDownloadFile(&download_file_, 0);
    192 }
    193