Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/file_util.h" | 5 #include "base/file_util.h" |
| 6 #include "base/message_loop.h" | 6 #include "base/message_loop.h" |
| 7 #include "base/scoped_temp_dir.h" | 7 #include "base/scoped_temp_dir.h" |
| 8 #include "base/string_number_conversions.h" | 8 #include "base/string_number_conversions.h" |
| 9 #include "chrome/browser/download/download_util.h" | |
| 9 #include "content/browser/browser_thread.h" | 10 #include "content/browser/browser_thread.h" |
| 10 #include "content/browser/download/base_file.h" | 11 #include "content/browser/download/base_file.h" |
| 11 #include "net/base/file_stream.h" | 12 #include "net/base/file_stream.h" |
| 13 #include "net/base/net_errors.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 15 |
| 14 namespace { | 16 namespace { |
| 15 | 17 |
| 18 class MockFileStream : public net::FileStream { | |
| 19 public: | |
| 20 MockFileStream() : forced_error_(0) {} | |
| 21 MockFileStream(base::PlatformFile file, int flags) | |
| 22 : net::FileStream(file, flags), forced_error_(0) {} | |
| 23 | |
| 24 void set_forced_error(int error) { forced_error_ = error; } | |
| 25 void clear_forced_error() { forced_error_ = 0; } | |
|
wtc
2011/08/23 00:18:35
Nit: it may be better to use net::OK instead of 0
cbentzel
2011/08/23 01:34:01
+1
ahendrickson
2011/08/25 21:55:15
Done.
| |
| 26 | |
| 27 int Open(const FilePath& path, int open_flags) { | |
| 28 path_ = path; | |
| 29 return get_error(net::FileStream::Open(path, open_flags)); | |
| 30 } | |
| 31 | |
| 32 int64 Seek(net::Whence whence, int64 offset) { | |
| 33 return get_error64(net::FileStream::Seek(whence, offset)); | |
| 34 } | |
| 35 | |
| 36 int64 Available() { | |
| 37 return get_error64(net::FileStream::Available()); | |
| 38 } | |
| 39 | |
| 40 int Read(char* buf, int buf_len, net::CompletionCallback* callback) { | |
| 41 return get_error(net::FileStream::Read(buf, buf_len, callback)); | |
| 42 } | |
| 43 | |
| 44 int ReadUntilComplete(char *buf, int buf_len) { | |
| 45 return get_error(net::FileStream::ReadUntilComplete(buf, buf_len)); | |
| 46 } | |
| 47 | |
| 48 int Write(const char* buf, int buf_len, net::CompletionCallback* callback) { | |
| 49 return get_error(net::FileStream::Write(buf, buf_len, callback)); | |
| 50 } | |
|
wtc
2011/08/23 00:18:35
Nit: add a blank line after this line.
ahendrickson
2011/08/25 21:55:15
Done.
| |
| 51 int64 Truncate(int64 bytes) { | |
| 52 return get_error64(net::FileStream::Truncate(bytes)); | |
| 53 } | |
| 54 | |
| 55 int Flush() { | |
| 56 return get_error(net::FileStream::Flush()); | |
| 57 } | |
|
wtc
2011/08/23 00:18:35
All the net::FileStream virtual methods that you o
ahendrickson
2011/08/25 21:55:15
Done.
| |
| 58 | |
| 59 const FilePath& get_path() const { return path_; } | |
| 60 | |
| 61 private: | |
| 62 int get_error(int function_error) { | |
|
cbentzel
2011/08/23 01:34:01
Perhaps GetError or even ReturnError() since this
ahendrickson
2011/08/25 21:55:15
Done.
| |
| 63 if (forced_error_ != 0) { | |
| 64 int ret = forced_error_; | |
| 65 clear_forced_error(); | |
| 66 return ret; | |
| 67 } | |
| 68 | |
| 69 return function_error; | |
| 70 } | |
| 71 | |
| 72 int64 get_error64(int64 function_error) { | |
| 73 if (forced_error_ != 0) { | |
| 74 int64 ret = forced_error_; | |
| 75 clear_forced_error(); | |
| 76 return ret; | |
| 77 } | |
| 78 | |
| 79 return function_error; | |
| 80 } | |
| 81 | |
| 82 int forced_error_; | |
| 83 FilePath path_; | |
| 84 }; | |
| 85 | |
| 16 const char kTestData1[] = "Let's write some data to the file!\n"; | 86 const char kTestData1[] = "Let's write some data to the file!\n"; |
| 17 const char kTestData2[] = "Writing more data.\n"; | 87 const char kTestData2[] = "Writing more data.\n"; |
| 18 const char kTestData3[] = "Final line."; | 88 const char kTestData3[] = "Final line."; |
| 19 | 89 |
| 90 } // namespace | |
| 91 | |
| 20 class BaseFileTest : public testing::Test { | 92 class BaseFileTest : public testing::Test { |
| 21 public: | 93 public: |
| 22 BaseFileTest() | 94 BaseFileTest() |
| 23 : expect_file_survives_(false), | 95 : expect_file_survives_(false), |
| 24 file_thread_(BrowserThread::FILE, &message_loop_) { | 96 file_thread_(BrowserThread::FILE, &message_loop_) { |
| 25 } | 97 } |
| 26 | 98 |
| 27 virtual void SetUp() { | 99 virtual void SetUp() { |
| 28 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 100 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 29 base_file_.reset( | 101 base_file_.reset( |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 44 EXPECT_EQ(expected_data_, disk_data); | 116 EXPECT_EQ(expected_data_, disk_data); |
| 45 } | 117 } |
| 46 | 118 |
| 47 // Make sure the mock BrowserThread outlives the BaseFile to satisfy | 119 // Make sure the mock BrowserThread outlives the BaseFile to satisfy |
| 48 // thread checks inside it. | 120 // thread checks inside it. |
| 49 base_file_.reset(); | 121 base_file_.reset(); |
| 50 | 122 |
| 51 EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); | 123 EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); |
| 52 } | 124 } |
| 53 | 125 |
| 54 void AppendDataToFile(const std::string& data) { | 126 bool OpenMockFileStream() { |
| 55 ASSERT_TRUE(base_file_->in_progress()); | 127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 56 base_file_->AppendDataToFile(data.data(), data.size()); | 128 |
| 129 FilePath path; | |
| 130 if (!download_util::CreateTemporaryFileForDownload(&path)) | |
| 131 return false; | |
| 132 | |
| 133 // Create a new file stream if it is not provided. | |
|
cbentzel
2011/08/23 01:34:01
What does the "if it is not provided" mean? When
ahendrickson
2011/08/25 21:55:15
Removed.
| |
| 134 mock_file_stream_.reset(new MockFileStream); | |
| 135 if (mock_file_stream_->Open( | |
| 136 path, | |
| 137 base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE) != 0) { | |
| 138 mock_file_stream_.reset(); | |
| 139 return false; | |
| 140 } | |
| 141 | |
| 142 // We may be re-opening the file after rename. Always make sure we're | |
| 143 // writing at the end of the file. | |
| 144 if (mock_file_stream_->Seek(net::FROM_END, 0) < 0) { | |
| 145 mock_file_stream_.reset(); | |
| 146 return false; | |
| 147 } | |
| 148 | |
| 149 return true; | |
| 150 } | |
| 151 | |
| 152 void ForceError(net::Error error) { | |
| 153 mock_file_stream_->set_forced_error(error); | |
| 154 } | |
| 155 | |
| 156 bool AppendDataToFile(const std::string& data) { | |
| 157 EXPECT_TRUE(base_file_->in_progress()); | |
| 158 bool appended = base_file_->AppendDataToFile(data.data(), data.size()); | |
| 57 expected_data_ += data; | 159 expected_data_ += data; |
| 58 EXPECT_EQ(static_cast<int64>(expected_data_.size()), | 160 EXPECT_EQ(static_cast<int64>(expected_data_.size()), |
| 59 base_file_->bytes_so_far()); | 161 base_file_->bytes_so_far()); |
| 162 return appended; | |
| 60 } | 163 } |
| 61 | 164 |
| 62 protected: | 165 protected: |
| 63 linked_ptr<net::FileStream> file_stream_; | 166 linked_ptr<net::FileStream> file_stream_; |
| 167 linked_ptr<MockFileStream> mock_file_stream_; | |
| 64 | 168 |
| 65 // BaseClass instance we are testing. | 169 // BaseClass instance we are testing. |
| 66 scoped_ptr<BaseFile> base_file_; | 170 scoped_ptr<BaseFile> base_file_; |
| 67 | 171 |
| 68 // Temporary directory for renamed downloads. | 172 // Temporary directory for renamed downloads. |
| 69 ScopedTempDir temp_dir_; | 173 ScopedTempDir temp_dir_; |
| 70 | 174 |
| 71 // Expect the file to survive deletion of the BaseFile instance. | 175 // Expect the file to survive deletion of the BaseFile instance. |
| 72 bool expect_file_survives_; | 176 bool expect_file_survives_; |
| 73 | 177 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 93 EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); | 197 EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); |
| 94 base_file_->Cancel(); | 198 base_file_->Cancel(); |
| 95 EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); | 199 EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); |
| 96 EXPECT_NE(FilePath().value(), base_file_->full_path().value()); | 200 EXPECT_NE(FilePath().value(), base_file_->full_path().value()); |
| 97 } | 201 } |
| 98 | 202 |
| 99 // Write data to the file and detach it, so it doesn't get deleted | 203 // Write data to the file and detach it, so it doesn't get deleted |
| 100 // automatically when base_file_ is destructed. | 204 // automatically when base_file_ is destructed. |
| 101 TEST_F(BaseFileTest, WriteAndDetach) { | 205 TEST_F(BaseFileTest, WriteAndDetach) { |
| 102 ASSERT_TRUE(base_file_->Initialize(false)); | 206 ASSERT_TRUE(base_file_->Initialize(false)); |
| 103 AppendDataToFile(kTestData1); | 207 AppendDataToFile(kTestData1); |
|
cbentzel
2011/08/23 01:34:01
All calls to AppendDataToFile should be wrapped in
ahendrickson
2011/08/25 21:55:15
Done.
| |
| 104 base_file_->Finish(); | 208 base_file_->Finish(); |
| 105 base_file_->Detach(); | 209 base_file_->Detach(); |
| 106 expect_file_survives_ = true; | 210 expect_file_survives_ = true; |
| 107 } | 211 } |
| 108 | 212 |
| 109 // Write data to the file and detach it, and calculate its sha256 hash. | 213 // Write data to the file and detach it, and calculate its sha256 hash. |
| 110 TEST_F(BaseFileTest, WriteWithHashAndDetach) { | 214 TEST_F(BaseFileTest, WriteWithHashAndDetach) { |
| 111 ASSERT_TRUE(base_file_->Initialize(true)); | 215 ASSERT_TRUE(base_file_->Initialize(true)); |
| 112 AppendDataToFile(kTestData1); | 216 AppendDataToFile(kTestData1); |
| 113 base_file_->Finish(); | 217 base_file_->Finish(); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 EXPECT_TRUE(base_file_->in_progress()); | 324 EXPECT_TRUE(base_file_->in_progress()); |
| 221 EXPECT_TRUE(base_file_->Rename(new_path)); | 325 EXPECT_TRUE(base_file_->Rename(new_path)); |
| 222 EXPECT_FALSE(file_util::PathExists(initial_path)); | 326 EXPECT_FALSE(file_util::PathExists(initial_path)); |
| 223 EXPECT_TRUE(file_util::PathExists(new_path)); | 327 EXPECT_TRUE(file_util::PathExists(new_path)); |
| 224 | 328 |
| 225 AppendDataToFile(kTestData2); | 329 AppendDataToFile(kTestData2); |
| 226 | 330 |
| 227 base_file_->Finish(); | 331 base_file_->Finish(); |
| 228 } | 332 } |
| 229 | 333 |
| 230 } // namespace | 334 // Write data to the file multiple times. |
| 335 TEST_F(BaseFileTest, MultipleWritesWithError) { | |
| 336 ASSERT_TRUE(OpenMockFileStream()); | |
| 337 base_file_.reset(new BaseFile(mock_file_stream_->get_path(), | |
| 338 GURL(), GURL(), 0, mock_file_stream_)); | |
| 339 ASSERT_TRUE(base_file_->Initialize(false)); | |
| 340 ASSERT_TRUE(AppendDataToFile(kTestData1)); | |
| 341 ASSERT_TRUE(AppendDataToFile(kTestData2)); | |
| 342 ForceError(net::ERR_FAILED); | |
|
cbentzel
2011/08/23 01:34:01
Should you use one of the more likely ERR's here?
ahendrickson
2011/08/25 21:55:15
Yes, they will.
| |
| 343 ASSERT_FALSE(AppendDataToFile(kTestData3)); | |
| 344 std::string hash; | |
| 345 EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); | |
| 346 base_file_->Finish(); | |
| 347 } | |
| OLD | NEW |