1// Copyright 2014 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_proxy.h" 6 7#include "base/bind.h" 8#include "base/files/file.h" 9#include "base/files/file_util.h" 10#include "base/files/scoped_temp_dir.h" 11#include "base/memory/weak_ptr.h" 12#include "base/message_loop/message_loop.h" 13#include "base/threading/thread.h" 14#include "base/threading/thread_restrictions.h" 15#include "testing/gtest/include/gtest/gtest.h" 16 17namespace base { 18 19class FileProxyTest : public testing::Test { 20 public: 21 FileProxyTest() 22 : file_thread_("FileProxyTestFileThread"), 23 error_(File::FILE_OK), 24 bytes_written_(-1), 25 weak_factory_(this) {} 26 27 virtual void SetUp() OVERRIDE { 28 ASSERT_TRUE(dir_.CreateUniqueTempDir()); 29 ASSERT_TRUE(file_thread_.Start()); 30 } 31 32 void DidFinish(File::Error error) { 33 error_ = error; 34 MessageLoop::current()->QuitWhenIdle(); 35 } 36 37 void DidCreateOrOpen(File::Error error) { 38 error_ = error; 39 MessageLoop::current()->QuitWhenIdle(); 40 } 41 42 void DidCreateTemporary(File::Error error, 43 const FilePath& path) { 44 error_ = error; 45 path_ = path; 46 MessageLoop::current()->QuitWhenIdle(); 47 } 48 49 void DidGetFileInfo(File::Error error, 50 const File::Info& file_info) { 51 error_ = error; 52 file_info_ = file_info; 53 MessageLoop::current()->QuitWhenIdle(); 54 } 55 56 void DidRead(File::Error error, 57 const char* data, 58 int bytes_read) { 59 error_ = error; 60 buffer_.resize(bytes_read); 61 memcpy(&buffer_[0], data, bytes_read); 62 MessageLoop::current()->QuitWhenIdle(); 63 } 64 65 void DidWrite(File::Error error, 66 int bytes_written) { 67 error_ = error; 68 bytes_written_ = bytes_written; 69 MessageLoop::current()->QuitWhenIdle(); 70 } 71 72 protected: 73 void CreateProxy(uint32 flags, FileProxy* proxy) { 74 proxy->CreateOrOpen( 75 test_path(), flags, 76 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); 77 MessageLoop::current()->Run(); 78 EXPECT_TRUE(proxy->IsValid()); 79 } 80 81 TaskRunner* file_task_runner() const { 82 return file_thread_.message_loop_proxy().get(); 83 } 84 const FilePath& test_dir_path() const { return dir_.path(); } 85 const FilePath test_path() const { return dir_.path().AppendASCII("test"); } 86 87 MessageLoopForIO message_loop_; 88 Thread file_thread_; 89 90 ScopedTempDir dir_; 91 File::Error error_; 92 FilePath path_; 93 File::Info file_info_; 94 std::vector<char> buffer_; 95 int bytes_written_; 96 WeakPtrFactory<FileProxyTest> weak_factory_; 97}; 98 99TEST_F(FileProxyTest, CreateOrOpen_Create) { 100 FileProxy proxy(file_task_runner()); 101 proxy.CreateOrOpen( 102 test_path(), 103 File::FLAG_CREATE | File::FLAG_READ, 104 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); 105 MessageLoop::current()->Run(); 106 107 EXPECT_EQ(File::FILE_OK, error_); 108 EXPECT_TRUE(proxy.IsValid()); 109 EXPECT_TRUE(proxy.created()); 110 EXPECT_TRUE(PathExists(test_path())); 111} 112 113TEST_F(FileProxyTest, CreateOrOpen_Open) { 114 // Creates a file. 115 base::WriteFile(test_path(), NULL, 0); 116 ASSERT_TRUE(PathExists(test_path())); 117 118 // Opens the created file. 119 FileProxy proxy(file_task_runner()); 120 proxy.CreateOrOpen( 121 test_path(), 122 File::FLAG_OPEN | File::FLAG_READ, 123 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); 124 MessageLoop::current()->Run(); 125 126 EXPECT_EQ(File::FILE_OK, error_); 127 EXPECT_TRUE(proxy.IsValid()); 128 EXPECT_FALSE(proxy.created()); 129} 130 131TEST_F(FileProxyTest, CreateOrOpen_OpenNonExistent) { 132 FileProxy proxy(file_task_runner()); 133 proxy.CreateOrOpen( 134 test_path(), 135 File::FLAG_OPEN | File::FLAG_READ, 136 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); 137 MessageLoop::current()->Run(); 138 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, error_); 139 EXPECT_FALSE(proxy.IsValid()); 140 EXPECT_FALSE(proxy.created()); 141 EXPECT_FALSE(PathExists(test_path())); 142} 143 144TEST_F(FileProxyTest, CreateOrOpen_AbandonedCreate) { 145 bool prev = ThreadRestrictions::SetIOAllowed(false); 146 { 147 FileProxy proxy(file_task_runner()); 148 proxy.CreateOrOpen( 149 test_path(), 150 File::FLAG_CREATE | File::FLAG_READ, 151 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); 152 } 153 MessageLoop::current()->Run(); 154 ThreadRestrictions::SetIOAllowed(prev); 155 156 EXPECT_TRUE(PathExists(test_path())); 157} 158 159TEST_F(FileProxyTest, Close) { 160 // Creates a file. 161 FileProxy proxy(file_task_runner()); 162 CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy); 163 164#if defined(OS_WIN) 165 // This fails on Windows if the file is not closed. 166 EXPECT_FALSE(base::Move(test_path(), test_dir_path().AppendASCII("new"))); 167#endif 168 169 proxy.Close(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); 170 MessageLoop::current()->Run(); 171 EXPECT_EQ(File::FILE_OK, error_); 172 EXPECT_FALSE(proxy.IsValid()); 173 174 // Now it should pass on all platforms. 175 EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new"))); 176} 177 178TEST_F(FileProxyTest, CreateTemporary) { 179 { 180 FileProxy proxy(file_task_runner()); 181 proxy.CreateTemporary( 182 0 /* additional_file_flags */, 183 Bind(&FileProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr())); 184 MessageLoop::current()->Run(); 185 186 EXPECT_TRUE(proxy.IsValid()); 187 EXPECT_EQ(File::FILE_OK, error_); 188 EXPECT_TRUE(PathExists(path_)); 189 190 // The file should be writable. 191 proxy.Write(0, "test", 4, 192 Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr())); 193 MessageLoop::current()->Run(); 194 EXPECT_EQ(File::FILE_OK, error_); 195 EXPECT_EQ(4, bytes_written_); 196 } 197 198 // Make sure the written data can be read from the returned path. 199 std::string data; 200 EXPECT_TRUE(ReadFileToString(path_, &data)); 201 EXPECT_EQ("test", data); 202 203 // Make sure we can & do delete the created file to prevent leaks on the bots. 204 EXPECT_TRUE(base::DeleteFile(path_, false)); 205} 206 207TEST_F(FileProxyTest, SetAndTake) { 208 File file(test_path(), File::FLAG_CREATE | File::FLAG_READ); 209 ASSERT_TRUE(file.IsValid()); 210 FileProxy proxy(file_task_runner()); 211 EXPECT_FALSE(proxy.IsValid()); 212 proxy.SetFile(file.Pass()); 213 EXPECT_TRUE(proxy.IsValid()); 214 EXPECT_FALSE(file.IsValid()); 215 216 file = proxy.TakeFile(); 217 EXPECT_FALSE(proxy.IsValid()); 218 EXPECT_TRUE(file.IsValid()); 219} 220 221TEST_F(FileProxyTest, GetInfo) { 222 // Setup. 223 ASSERT_EQ(4, base::WriteFile(test_path(), "test", 4)); 224 File::Info expected_info; 225 GetFileInfo(test_path(), &expected_info); 226 227 // Run. 228 FileProxy proxy(file_task_runner()); 229 CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy); 230 proxy.GetInfo( 231 Bind(&FileProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr())); 232 MessageLoop::current()->Run(); 233 234 // Verify. 235 EXPECT_EQ(File::FILE_OK, error_); 236 EXPECT_EQ(expected_info.size, file_info_.size); 237 EXPECT_EQ(expected_info.is_directory, file_info_.is_directory); 238 EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link); 239 EXPECT_EQ(expected_info.last_modified, file_info_.last_modified); 240 EXPECT_EQ(expected_info.creation_time, file_info_.creation_time); 241} 242 243TEST_F(FileProxyTest, Read) { 244 // Setup. 245 const char expected_data[] = "bleh"; 246 int expected_bytes = arraysize(expected_data); 247 ASSERT_EQ(expected_bytes, 248 base::WriteFile(test_path(), expected_data, expected_bytes)); 249 250 // Run. 251 FileProxy proxy(file_task_runner()); 252 CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy); 253 254 proxy.Read(0, 128, Bind(&FileProxyTest::DidRead, weak_factory_.GetWeakPtr())); 255 MessageLoop::current()->Run(); 256 257 // Verify. 258 EXPECT_EQ(File::FILE_OK, error_); 259 EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size())); 260 for (size_t i = 0; i < buffer_.size(); ++i) { 261 EXPECT_EQ(expected_data[i], buffer_[i]); 262 } 263} 264 265TEST_F(FileProxyTest, WriteAndFlush) { 266 FileProxy proxy(file_task_runner()); 267 CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy); 268 269 const char data[] = "foo!"; 270 int data_bytes = ARRAYSIZE_UNSAFE(data); 271 proxy.Write(0, data, data_bytes, 272 Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr())); 273 MessageLoop::current()->Run(); 274 EXPECT_EQ(File::FILE_OK, error_); 275 EXPECT_EQ(data_bytes, bytes_written_); 276 277 // Flush the written data. (So that the following read should always 278 // succeed. On some platforms it may work with or without this flush.) 279 proxy.Flush(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); 280 MessageLoop::current()->Run(); 281 EXPECT_EQ(File::FILE_OK, error_); 282 283 // Verify the written data. 284 char buffer[10]; 285 EXPECT_EQ(data_bytes, base::ReadFile(test_path(), buffer, data_bytes)); 286 for (int i = 0; i < data_bytes; ++i) { 287 EXPECT_EQ(data[i], buffer[i]); 288 } 289} 290 291TEST_F(FileProxyTest, SetTimes) { 292 FileProxy proxy(file_task_runner()); 293 CreateProxy( 294 File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES, 295 &proxy); 296 297 Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345); 298 Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765); 299 300 proxy.SetTimes(last_accessed_time, last_modified_time, 301 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); 302 MessageLoop::current()->Run(); 303 EXPECT_EQ(File::FILE_OK, error_); 304 305 File::Info info; 306 GetFileInfo(test_path(), &info); 307 308 // The returned values may only have the seconds precision, so we cast 309 // the double values to int here. 310 EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()), 311 static_cast<int>(info.last_modified.ToDoubleT())); 312 EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()), 313 static_cast<int>(info.last_accessed.ToDoubleT())); 314} 315 316TEST_F(FileProxyTest, SetLength_Shrink) { 317 // Setup. 318 const char kTestData[] = "0123456789"; 319 ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10)); 320 File::Info info; 321 GetFileInfo(test_path(), &info); 322 ASSERT_EQ(10, info.size); 323 324 // Run. 325 FileProxy proxy(file_task_runner()); 326 CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy); 327 proxy.SetLength(7, 328 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); 329 MessageLoop::current()->Run(); 330 331 // Verify. 332 GetFileInfo(test_path(), &info); 333 ASSERT_EQ(7, info.size); 334 335 char buffer[7]; 336 EXPECT_EQ(7, base::ReadFile(test_path(), buffer, 7)); 337 int i = 0; 338 for (; i < 7; ++i) 339 EXPECT_EQ(kTestData[i], buffer[i]); 340} 341 342TEST_F(FileProxyTest, SetLength_Expand) { 343 // Setup. 344 const char kTestData[] = "9876543210"; 345 ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10)); 346 File::Info info; 347 GetFileInfo(test_path(), &info); 348 ASSERT_EQ(10, info.size); 349 350 // Run. 351 FileProxy proxy(file_task_runner()); 352 CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy); 353 proxy.SetLength(53, 354 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); 355 MessageLoop::current()->Run(); 356 357 // Verify. 358 GetFileInfo(test_path(), &info); 359 ASSERT_EQ(53, info.size); 360 361 char buffer[53]; 362 EXPECT_EQ(53, base::ReadFile(test_path(), buffer, 53)); 363 int i = 0; 364 for (; i < 10; ++i) 365 EXPECT_EQ(kTestData[i], buffer[i]); 366 for (; i < 53; ++i) 367 EXPECT_EQ(0, buffer[i]); 368} 369 370} // namespace base 371