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/base_file.h" 10 #include "content/browser/browser_thread.h" 11 #include "net/base/file_stream.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 namespace { 15 16 const char kTestData1[] = "Let's write some data to the file!\n"; 17 const char kTestData2[] = "Writing more data.\n"; 18 const char kTestData3[] = "Final line."; 19 20 class BaseFileTest : public testing::Test { 21 public: 22 BaseFileTest() 23 : expect_file_survives_(false), 24 file_thread_(BrowserThread::FILE, &message_loop_) { 25 } 26 27 virtual void SetUp() { 28 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 29 base_file_.reset( 30 new BaseFile(FilePath(), GURL(), GURL(), 0, file_stream_)); 31 } 32 33 virtual void TearDown() { 34 EXPECT_FALSE(base_file_->in_progress()); 35 EXPECT_EQ(static_cast<int64>(expected_data_.size()), 36 base_file_->bytes_so_far()); 37 38 FilePath full_path = base_file_->full_path(); 39 40 if (!expected_data_.empty()) { 41 // Make sure the data has been properly written to disk. 42 std::string disk_data; 43 EXPECT_TRUE(file_util::ReadFileToString(full_path, &disk_data)); 44 EXPECT_EQ(expected_data_, disk_data); 45 } 46 47 // Make sure the mock BrowserThread outlives the BaseFile to satisfy 48 // thread checks inside it. 49 base_file_.reset(); 50 51 EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); 52 } 53 54 void AppendDataToFile(const std::string& data) { 55 ASSERT_TRUE(base_file_->in_progress()); 56 base_file_->AppendDataToFile(data.data(), data.size()); 57 expected_data_ += data; 58 EXPECT_EQ(static_cast<int64>(expected_data_.size()), 59 base_file_->bytes_so_far()); 60 } 61 62 protected: 63 linked_ptr<net::FileStream> file_stream_; 64 65 // BaseClass instance we are testing. 66 scoped_ptr<BaseFile> base_file_; 67 68 // Temporary directory for renamed downloads. 69 ScopedTempDir temp_dir_; 70 71 // Expect the file to survive deletion of the BaseFile instance. 72 bool expect_file_survives_; 73 74 private: 75 // Keep track of what data should be saved to the disk file. 76 std::string expected_data_; 77 78 // Mock file thread to satisfy debug checks in BaseFile. 79 MessageLoop message_loop_; 80 BrowserThread file_thread_; 81 }; 82 83 // Test the most basic scenario: just create the object and do a sanity check 84 // on all its accessors. This is actually a case that rarely happens 85 // in production, where we would at least Initialize it. 86 TEST_F(BaseFileTest, CreateDestroy) { 87 EXPECT_EQ(FilePath().value(), base_file_->full_path().value()); 88 } 89 90 // Cancel the download explicitly. 91 TEST_F(BaseFileTest, Cancel) { 92 ASSERT_TRUE(base_file_->Initialize(false)); 93 EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); 94 base_file_->Cancel(); 95 EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); 96 EXPECT_NE(FilePath().value(), base_file_->full_path().value()); 97 } 98 99 // Write data to the file and detach it, so it doesn't get deleted 100 // automatically when base_file_ is destructed. 101 TEST_F(BaseFileTest, WriteAndDetach) { 102 ASSERT_TRUE(base_file_->Initialize(false)); 103 AppendDataToFile(kTestData1); 104 base_file_->Finish(); 105 base_file_->Detach(); 106 expect_file_survives_ = true; 107 } 108 109 // Write data to the file and detach it, and calculate its sha256 hash. 110 TEST_F(BaseFileTest, WriteWithHashAndDetach) { 111 ASSERT_TRUE(base_file_->Initialize(true)); 112 AppendDataToFile(kTestData1); 113 base_file_->Finish(); 114 115 std::string hash; 116 base_file_->GetSha256Hash(&hash); 117 EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", 118 base::HexEncode(hash.data(), hash.size())); 119 120 base_file_->Detach(); 121 expect_file_survives_ = true; 122 } 123 124 // Rename the file after writing to it, then detach. 125 TEST_F(BaseFileTest, WriteThenRenameAndDetach) { 126 ASSERT_TRUE(base_file_->Initialize(false)); 127 128 FilePath initial_path(base_file_->full_path()); 129 EXPECT_TRUE(file_util::PathExists(initial_path)); 130 FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); 131 EXPECT_FALSE(file_util::PathExists(new_path)); 132 133 AppendDataToFile(kTestData1); 134 135 EXPECT_TRUE(base_file_->Rename(new_path)); 136 EXPECT_FALSE(file_util::PathExists(initial_path)); 137 EXPECT_TRUE(file_util::PathExists(new_path)); 138 139 base_file_->Finish(); 140 base_file_->Detach(); 141 expect_file_survives_ = true; 142 } 143 144 // Write data to the file once. 145 TEST_F(BaseFileTest, SingleWrite) { 146 ASSERT_TRUE(base_file_->Initialize(false)); 147 AppendDataToFile(kTestData1); 148 base_file_->Finish(); 149 } 150 151 // Write data to the file multiple times. 152 TEST_F(BaseFileTest, MultipleWrites) { 153 ASSERT_TRUE(base_file_->Initialize(false)); 154 AppendDataToFile(kTestData1); 155 AppendDataToFile(kTestData2); 156 AppendDataToFile(kTestData3); 157 std::string hash; 158 EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); 159 base_file_->Finish(); 160 } 161 162 // Write data to the file once and calculate its sha256 hash. 163 TEST_F(BaseFileTest, SingleWriteWithHash) { 164 ASSERT_TRUE(base_file_->Initialize(true)); 165 AppendDataToFile(kTestData1); 166 base_file_->Finish(); 167 168 std::string hash; 169 base_file_->GetSha256Hash(&hash); 170 EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", 171 base::HexEncode(hash.data(), hash.size())); 172 } 173 174 // Write data to the file multiple times and calculate its sha256 hash. 175 TEST_F(BaseFileTest, MultipleWritesWithHash) { 176 std::string hash; 177 178 ASSERT_TRUE(base_file_->Initialize(true)); 179 AppendDataToFile(kTestData1); 180 AppendDataToFile(kTestData2); 181 AppendDataToFile(kTestData3); 182 // no hash before Finish() is called either. 183 EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); 184 base_file_->Finish(); 185 186 EXPECT_TRUE(base_file_->GetSha256Hash(&hash)); 187 EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8", 188 base::HexEncode(hash.data(), hash.size())); 189 } 190 191 // Rename the file after all writes to it. 192 TEST_F(BaseFileTest, WriteThenRename) { 193 ASSERT_TRUE(base_file_->Initialize(false)); 194 195 FilePath initial_path(base_file_->full_path()); 196 EXPECT_TRUE(file_util::PathExists(initial_path)); 197 FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); 198 EXPECT_FALSE(file_util::PathExists(new_path)); 199 200 AppendDataToFile(kTestData1); 201 202 EXPECT_TRUE(base_file_->Rename(new_path)); 203 EXPECT_FALSE(file_util::PathExists(initial_path)); 204 EXPECT_TRUE(file_util::PathExists(new_path)); 205 206 base_file_->Finish(); 207 } 208 209 // Rename the file while the download is still in progress. 210 TEST_F(BaseFileTest, RenameWhileInProgress) { 211 ASSERT_TRUE(base_file_->Initialize(false)); 212 213 FilePath initial_path(base_file_->full_path()); 214 EXPECT_TRUE(file_util::PathExists(initial_path)); 215 FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); 216 EXPECT_FALSE(file_util::PathExists(new_path)); 217 218 AppendDataToFile(kTestData1); 219 220 EXPECT_TRUE(base_file_->in_progress()); 221 EXPECT_TRUE(base_file_->Rename(new_path)); 222 EXPECT_FALSE(file_util::PathExists(initial_path)); 223 EXPECT_TRUE(file_util::PathExists(new_path)); 224 225 AppendDataToFile(kTestData2); 226 227 base_file_->Finish(); 228 } 229 230 } // namespace 231