• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • 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.
DownloadFileTest()34   DownloadFileTest() :
35       ui_thread_(BrowserThread::UI, &loop_),
36       file_thread_(BrowserThread::FILE, &loop_) {
37   }
38 
~DownloadFileTest()39   ~DownloadFileTest() {
40   }
41 
SetUp()42   virtual void SetUp() {
43     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
44     download_manager_ = new MockDownloadManager(&download_status_updater_);
45   }
46 
TearDown()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 
CreateDownloadFile(scoped_ptr<DownloadFile> * file,int offset)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 
DestroyDownloadFile(scoped_ptr<DownloadFile> * file,int offset)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 
AppendDataToFile(scoped_ptr<DownloadFile> * file,const std::string & data)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.
TEST_F(DownloadFileTest,RenameFileFinal)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