Home | History | Annotate | Download | only in fileapi
      1 // Copyright 2013 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 <string>
      6 
      7 #include "base/files/file.h"
      8 #include "base/files/file_path.h"
      9 #include "base/files/file_util.h"
     10 #include "base/files/scoped_temp_dir.h"
     11 #include "base/message_loop/message_loop_proxy.h"
     12 #include "base/run_loop.h"
     13 #include "base/strings/sys_string_conversions.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "content/public/test/async_file_test_helper.h"
     16 #include "content/public/test/test_file_system_context.h"
     17 #include "storage/browser/fileapi/async_file_util_adapter.h"
     18 #include "storage/browser/fileapi/file_system_context.h"
     19 #include "storage/browser/fileapi/file_system_file_util.h"
     20 #include "storage/browser/fileapi/file_system_operation_context.h"
     21 #include "storage/browser/fileapi/local_file_util.h"
     22 #include "storage/browser/fileapi/native_file_util.h"
     23 #include "storage/common/fileapi/file_system_types.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 using content::AsyncFileTestHelper;
     27 using storage::AsyncFileUtilAdapter;
     28 using storage::FileSystemContext;
     29 using storage::FileSystemOperationContext;
     30 using storage::FileSystemURL;
     31 using storage::LocalFileUtil;
     32 
     33 namespace content {
     34 
     35 namespace {
     36 
     37 const GURL kOrigin("http://foo/");
     38 const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
     39 
     40 }  // namespace
     41 
     42 class LocalFileUtilTest : public testing::Test {
     43  public:
     44   LocalFileUtilTest() {}
     45 
     46   virtual void SetUp() {
     47     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     48     file_system_context_ = CreateFileSystemContextForTesting(
     49         NULL, data_dir_.path());
     50   }
     51 
     52   virtual void TearDown() {
     53     file_system_context_ = NULL;
     54     base::RunLoop().RunUntilIdle();
     55   }
     56 
     57  protected:
     58   FileSystemOperationContext* NewContext() {
     59     FileSystemOperationContext* context =
     60         new FileSystemOperationContext(file_system_context_.get());
     61     context->set_update_observers(
     62         *file_system_context_->GetUpdateObservers(kFileSystemType));
     63     return context;
     64   }
     65 
     66   LocalFileUtil* file_util() {
     67     AsyncFileUtilAdapter* adapter = static_cast<AsyncFileUtilAdapter*>(
     68         file_system_context_->GetAsyncFileUtil(kFileSystemType));
     69     return static_cast<LocalFileUtil*>(adapter->sync_file_util());
     70   }
     71 
     72   FileSystemURL CreateURL(const std::string& file_name) {
     73     return file_system_context_->CreateCrackedFileSystemURL(
     74         kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name));
     75   }
     76 
     77   base::FilePath LocalPath(const char *file_name) {
     78     base::FilePath path;
     79     scoped_ptr<FileSystemOperationContext> context(NewContext());
     80     file_util()->GetLocalFilePath(context.get(), CreateURL(file_name), &path);
     81     return path;
     82   }
     83 
     84   bool FileExists(const char *file_name) {
     85     return base::PathExists(LocalPath(file_name)) &&
     86         !base::DirectoryExists(LocalPath(file_name));
     87   }
     88 
     89   bool DirectoryExists(const char *file_name) {
     90     return base::DirectoryExists(LocalPath(file_name));
     91   }
     92 
     93   int64 GetSize(const char *file_name) {
     94     base::File::Info info;
     95     base::GetFileInfo(LocalPath(file_name), &info);
     96     return info.size;
     97   }
     98 
     99   base::File CreateFile(const char* file_name) {
    100     int file_flags = base::File::FLAG_CREATE |
    101                      base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
    102 
    103     scoped_ptr<FileSystemOperationContext> context(NewContext());
    104     return file_util()->CreateOrOpen(context.get(), CreateURL(file_name),
    105                                      file_flags);
    106   }
    107 
    108   base::File::Error EnsureFileExists(const char* file_name,
    109                                      bool* created) {
    110     scoped_ptr<FileSystemOperationContext> context(NewContext());
    111     return file_util()->EnsureFileExists(context.get(),
    112                                          CreateURL(file_name), created);
    113   }
    114 
    115   FileSystemContext* file_system_context() {
    116     return file_system_context_.get();
    117   }
    118 
    119  private:
    120   base::MessageLoop message_loop_;
    121   scoped_refptr<FileSystemContext> file_system_context_;
    122   base::ScopedTempDir data_dir_;
    123 
    124   DISALLOW_COPY_AND_ASSIGN(LocalFileUtilTest);
    125 };
    126 
    127 TEST_F(LocalFileUtilTest, CreateAndClose) {
    128   const char *file_name = "test_file";
    129   base::File file = CreateFile(file_name);
    130   ASSERT_TRUE(file.IsValid());
    131   ASSERT_TRUE(file.created());
    132 
    133   EXPECT_TRUE(FileExists(file_name));
    134   EXPECT_EQ(0, GetSize(file_name));
    135 
    136   scoped_ptr<FileSystemOperationContext> context(NewContext());
    137 }
    138 
    139 // base::CreateSymbolicLink is only supported on POSIX.
    140 #if defined(OS_POSIX)
    141 TEST_F(LocalFileUtilTest, CreateFailForSymlink) {
    142   // Create symlink target file.
    143   const char *target_name = "symlink_target";
    144   base::File target_file = CreateFile(target_name);
    145   ASSERT_TRUE(target_file.IsValid());
    146   ASSERT_TRUE(target_file.created());
    147   base::FilePath target_path = LocalPath(target_name);
    148 
    149   // Create symlink where target must be real file.
    150   const char *symlink_name = "symlink_file";
    151   base::FilePath symlink_path = LocalPath(symlink_name);
    152   ASSERT_TRUE(base::CreateSymbolicLink(target_path, symlink_path));
    153   ASSERT_TRUE(FileExists(symlink_name));
    154 
    155   // Try to open the symlink file which should fail.
    156   scoped_ptr<FileSystemOperationContext> context(NewContext());
    157   FileSystemURL url = CreateURL(symlink_name);
    158   int file_flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
    159   base::File file = file_util()->CreateOrOpen(context.get(), url, file_flags);
    160   ASSERT_FALSE(file.IsValid());
    161   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
    162 }
    163 #endif
    164 
    165 TEST_F(LocalFileUtilTest, EnsureFileExists) {
    166   const char *file_name = "foobar";
    167   bool created;
    168   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(file_name, &created));
    169   ASSERT_TRUE(created);
    170 
    171   EXPECT_TRUE(FileExists(file_name));
    172   EXPECT_EQ(0, GetSize(file_name));
    173 
    174   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(file_name, &created));
    175   EXPECT_FALSE(created);
    176 }
    177 
    178 TEST_F(LocalFileUtilTest, TouchFile) {
    179   const char *file_name = "test_file";
    180   base::File file = CreateFile(file_name);
    181   ASSERT_TRUE(file.IsValid());
    182   ASSERT_TRUE(file.created());
    183 
    184   scoped_ptr<FileSystemOperationContext> context(NewContext());
    185 
    186   base::File::Info info;
    187   ASSERT_TRUE(base::GetFileInfo(LocalPath(file_name), &info));
    188   const base::Time new_accessed =
    189       info.last_accessed + base::TimeDelta::FromHours(10);
    190   const base::Time new_modified =
    191       info.last_modified + base::TimeDelta::FromHours(5);
    192 
    193   EXPECT_EQ(base::File::FILE_OK,
    194             file_util()->Touch(context.get(), CreateURL(file_name),
    195                               new_accessed, new_modified));
    196 
    197   ASSERT_TRUE(base::GetFileInfo(LocalPath(file_name), &info));
    198   EXPECT_EQ(new_accessed, info.last_accessed);
    199   EXPECT_EQ(new_modified, info.last_modified);
    200 }
    201 
    202 TEST_F(LocalFileUtilTest, TouchDirectory) {
    203   const char *dir_name = "test_dir";
    204   scoped_ptr<FileSystemOperationContext> context(NewContext());
    205   ASSERT_EQ(base::File::FILE_OK,
    206             file_util()->CreateDirectory(context.get(),
    207                                         CreateURL(dir_name),
    208                                         false /* exclusive */,
    209                                         false /* recursive */));
    210 
    211   base::File::Info info;
    212   ASSERT_TRUE(base::GetFileInfo(LocalPath(dir_name), &info));
    213   const base::Time new_accessed =
    214       info.last_accessed + base::TimeDelta::FromHours(10);
    215   const base::Time new_modified =
    216       info.last_modified + base::TimeDelta::FromHours(5);
    217 
    218   EXPECT_EQ(base::File::FILE_OK,
    219             file_util()->Touch(context.get(), CreateURL(dir_name),
    220                               new_accessed, new_modified));
    221 
    222   ASSERT_TRUE(base::GetFileInfo(LocalPath(dir_name), &info));
    223   EXPECT_EQ(new_accessed, info.last_accessed);
    224   EXPECT_EQ(new_modified, info.last_modified);
    225 }
    226 
    227 TEST_F(LocalFileUtilTest, Truncate) {
    228   const char *file_name = "truncated";
    229   bool created;
    230   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(file_name, &created));
    231   ASSERT_TRUE(created);
    232 
    233   scoped_ptr<FileSystemOperationContext> context;
    234 
    235   context.reset(NewContext());
    236   ASSERT_EQ(base::File::FILE_OK,
    237             file_util()->Truncate(context.get(), CreateURL(file_name), 1020));
    238 
    239   EXPECT_TRUE(FileExists(file_name));
    240   EXPECT_EQ(1020, GetSize(file_name));
    241 }
    242 
    243 TEST_F(LocalFileUtilTest, CopyFile) {
    244   const char *from_file = "fromfile";
    245   const char *to_file1 = "tofile1";
    246   const char *to_file2 = "tofile2";
    247   bool created;
    248   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
    249   ASSERT_TRUE(created);
    250 
    251   scoped_ptr<FileSystemOperationContext> context;
    252   context.reset(NewContext());
    253   ASSERT_EQ(base::File::FILE_OK,
    254             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
    255 
    256   EXPECT_TRUE(FileExists(from_file));
    257   EXPECT_EQ(1020, GetSize(from_file));
    258 
    259   ASSERT_EQ(base::File::FILE_OK,
    260             AsyncFileTestHelper::Copy(file_system_context(),
    261                                       CreateURL(from_file),
    262                                       CreateURL(to_file1)));
    263 
    264   context.reset(NewContext());
    265   ASSERT_EQ(base::File::FILE_OK,
    266             AsyncFileTestHelper::Copy(file_system_context(),
    267                                       CreateURL(from_file),
    268                                       CreateURL(to_file2)));
    269 
    270   EXPECT_TRUE(FileExists(from_file));
    271   EXPECT_EQ(1020, GetSize(from_file));
    272   EXPECT_TRUE(FileExists(to_file1));
    273   EXPECT_EQ(1020, GetSize(to_file1));
    274   EXPECT_TRUE(FileExists(to_file2));
    275   EXPECT_EQ(1020, GetSize(to_file2));
    276 }
    277 
    278 TEST_F(LocalFileUtilTest, CopyDirectory) {
    279   const char *from_dir = "fromdir";
    280   const char *from_file = "fromdir/fromfile";
    281   const char *to_dir = "todir";
    282   const char *to_file = "todir/fromfile";
    283   bool created;
    284   scoped_ptr<FileSystemOperationContext> context;
    285 
    286   context.reset(NewContext());
    287   ASSERT_EQ(base::File::FILE_OK,
    288             file_util()->CreateDirectory(context.get(), CreateURL(from_dir),
    289                                          false, false));
    290   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
    291   ASSERT_TRUE(created);
    292 
    293   context.reset(NewContext());
    294   ASSERT_EQ(base::File::FILE_OK,
    295             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
    296 
    297   EXPECT_TRUE(DirectoryExists(from_dir));
    298   EXPECT_TRUE(FileExists(from_file));
    299   EXPECT_EQ(1020, GetSize(from_file));
    300   EXPECT_FALSE(DirectoryExists(to_dir));
    301 
    302   context.reset(NewContext());
    303   ASSERT_EQ(base::File::FILE_OK,
    304             AsyncFileTestHelper::Copy(file_system_context(),
    305                                       CreateURL(from_dir), CreateURL(to_dir)));
    306 
    307   EXPECT_TRUE(DirectoryExists(from_dir));
    308   EXPECT_TRUE(FileExists(from_file));
    309   EXPECT_EQ(1020, GetSize(from_file));
    310   EXPECT_TRUE(DirectoryExists(to_dir));
    311   EXPECT_TRUE(FileExists(to_file));
    312   EXPECT_EQ(1020, GetSize(to_file));
    313 }
    314 
    315 TEST_F(LocalFileUtilTest, MoveFile) {
    316   const char *from_file = "fromfile";
    317   const char *to_file = "tofile";
    318   bool created;
    319   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
    320   ASSERT_TRUE(created);
    321   scoped_ptr<FileSystemOperationContext> context;
    322 
    323   context.reset(NewContext());
    324   ASSERT_EQ(base::File::FILE_OK,
    325             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
    326 
    327   EXPECT_TRUE(FileExists(from_file));
    328   EXPECT_EQ(1020, GetSize(from_file));
    329 
    330   context.reset(NewContext());
    331   ASSERT_EQ(base::File::FILE_OK,
    332             AsyncFileTestHelper::Move(file_system_context(),
    333                                       CreateURL(from_file),
    334                                       CreateURL(to_file)));
    335 
    336   EXPECT_FALSE(FileExists(from_file));
    337   EXPECT_TRUE(FileExists(to_file));
    338   EXPECT_EQ(1020, GetSize(to_file));
    339 }
    340 
    341 TEST_F(LocalFileUtilTest, MoveDirectory) {
    342   const char *from_dir = "fromdir";
    343   const char *from_file = "fromdir/fromfile";
    344   const char *to_dir = "todir";
    345   const char *to_file = "todir/fromfile";
    346   bool created;
    347   scoped_ptr<FileSystemOperationContext> context;
    348 
    349   context.reset(NewContext());
    350   ASSERT_EQ(base::File::FILE_OK,
    351             file_util()->CreateDirectory(context.get(), CreateURL(from_dir),
    352                                          false, false));
    353   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
    354   ASSERT_TRUE(created);
    355 
    356   context.reset(NewContext());
    357   ASSERT_EQ(base::File::FILE_OK,
    358             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
    359 
    360   EXPECT_TRUE(DirectoryExists(from_dir));
    361   EXPECT_TRUE(FileExists(from_file));
    362   EXPECT_EQ(1020, GetSize(from_file));
    363   EXPECT_FALSE(DirectoryExists(to_dir));
    364 
    365   context.reset(NewContext());
    366   ASSERT_EQ(base::File::FILE_OK,
    367             AsyncFileTestHelper::Move(file_system_context(),
    368                                       CreateURL(from_dir),
    369                                       CreateURL(to_dir)));
    370 
    371   EXPECT_FALSE(DirectoryExists(from_dir));
    372   EXPECT_TRUE(DirectoryExists(to_dir));
    373   EXPECT_TRUE(FileExists(to_file));
    374   EXPECT_EQ(1020, GetSize(to_file));
    375 }
    376 
    377 }  // namespace content
    378