Home | History | Annotate | Download | only in files
      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/file_util.h"
      9 #include "base/files/file.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 
     17 namespace base {
     18 
     19 class 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 
     99 TEST_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 
    113 TEST_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 
    131 TEST_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 
    144 TEST_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 
    159 TEST_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 
    178 TEST_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 
    207 TEST_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 
    221 TEST_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 
    243 TEST_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 
    265 TEST_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 
    291 TEST_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 
    316 TEST_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 
    342 TEST_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