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 "storage/browser/fileapi/file_system_file_stream_reader.h"
      6 
      7 #include <limits>
      8 #include <string>
      9 
     10 #include "base/files/scoped_temp_dir.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/run_loop.h"
     13 #include "content/public/test/async_file_test_helper.h"
     14 #include "content/public/test/test_file_system_context.h"
     15 #include "net/base/io_buffer.h"
     16 #include "net/base/net_errors.h"
     17 #include "net/base/test_completion_callback.h"
     18 #include "storage/browser/fileapi/external_mount_points.h"
     19 #include "storage/browser/fileapi/file_system_context.h"
     20 #include "storage/browser/fileapi/file_system_file_util.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 using content::AsyncFileTestHelper;
     24 using storage::FileSystemContext;
     25 using storage::FileSystemFileStreamReader;
     26 using storage::FileSystemType;
     27 using storage::FileSystemURL;
     28 
     29 namespace content {
     30 
     31 namespace {
     32 
     33 const char kURLOrigin[] = "http://remote/";
     34 const char kTestFileName[] = "test.dat";
     35 const char kTestData[] = "0123456789";
     36 const int kTestDataSize = arraysize(kTestData) - 1;
     37 
     38 void ReadFromReader(storage::FileSystemFileStreamReader* reader,
     39                     std::string* data,
     40                     size_t size,
     41                     int* result) {
     42   ASSERT_TRUE(reader != NULL);
     43   ASSERT_TRUE(result != NULL);
     44   *result = net::OK;
     45   net::TestCompletionCallback callback;
     46   size_t total_bytes_read = 0;
     47   while (total_bytes_read < size) {
     48     scoped_refptr<net::IOBufferWithSize> buf(
     49         new net::IOBufferWithSize(size - total_bytes_read));
     50     int rv = reader->Read(buf.get(), buf->size(), callback.callback());
     51     if (rv == net::ERR_IO_PENDING)
     52       rv = callback.WaitForResult();
     53     if (rv < 0)
     54       *result = rv;
     55     if (rv <= 0)
     56       break;
     57     total_bytes_read += rv;
     58     data->append(buf->data(), rv);
     59   }
     60 }
     61 
     62 void NeverCalled(int unused) { ADD_FAILURE(); }
     63 
     64 }  // namespace
     65 
     66 class FileSystemFileStreamReaderTest : public testing::Test {
     67  public:
     68   FileSystemFileStreamReaderTest() {}
     69 
     70   virtual void SetUp() OVERRIDE {
     71     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     72 
     73     file_system_context_ = CreateFileSystemContextForTesting(
     74         NULL, temp_dir_.path());
     75 
     76     file_system_context_->OpenFileSystem(
     77         GURL(kURLOrigin),
     78         storage::kFileSystemTypeTemporary,
     79         storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
     80         base::Bind(&OnOpenFileSystem));
     81     base::RunLoop().RunUntilIdle();
     82 
     83     WriteFile(kTestFileName, kTestData, kTestDataSize,
     84               &test_file_modification_time_);
     85   }
     86 
     87   virtual void TearDown() OVERRIDE {
     88     base::RunLoop().RunUntilIdle();
     89   }
     90 
     91  protected:
     92   storage::FileSystemFileStreamReader* CreateFileReader(
     93       const std::string& file_name,
     94       int64 initial_offset,
     95       const base::Time& expected_modification_time) {
     96     return new FileSystemFileStreamReader(file_system_context_.get(),
     97                                           GetFileSystemURL(file_name),
     98                                           initial_offset,
     99                                           expected_modification_time);
    100   }
    101 
    102   base::Time test_file_modification_time() const {
    103     return test_file_modification_time_;
    104   }
    105 
    106   void WriteFile(const std::string& file_name,
    107                  const char* buf,
    108                  int buf_size,
    109                  base::Time* modification_time) {
    110     FileSystemURL url = GetFileSystemURL(file_name);
    111 
    112     ASSERT_EQ(base::File::FILE_OK,
    113               content::AsyncFileTestHelper::CreateFileWithData(
    114                   file_system_context_.get(), url, buf, buf_size));
    115 
    116     base::File::Info file_info;
    117     ASSERT_EQ(base::File::FILE_OK,
    118               AsyncFileTestHelper::GetMetadata(
    119                   file_system_context_.get(), url, &file_info));
    120     if (modification_time)
    121       *modification_time = file_info.last_modified;
    122   }
    123 
    124  private:
    125   static void OnOpenFileSystem(const GURL& root_url,
    126                                const std::string& name,
    127                                base::File::Error result) {
    128     ASSERT_EQ(base::File::FILE_OK, result);
    129   }
    130 
    131   FileSystemURL GetFileSystemURL(const std::string& file_name) {
    132     return file_system_context_->CreateCrackedFileSystemURL(
    133         GURL(kURLOrigin),
    134         storage::kFileSystemTypeTemporary,
    135         base::FilePath().AppendASCII(file_name));
    136   }
    137 
    138   base::MessageLoopForIO message_loop_;
    139   base::ScopedTempDir temp_dir_;
    140   scoped_refptr<FileSystemContext> file_system_context_;
    141   base::Time test_file_modification_time_;
    142 };
    143 
    144 TEST_F(FileSystemFileStreamReaderTest, NonExistent) {
    145   const char kFileName[] = "nonexistent";
    146   scoped_ptr<FileSystemFileStreamReader> reader(
    147       CreateFileReader(kFileName, 0, base::Time()));
    148   int result = 0;
    149   std::string data;
    150   ReadFromReader(reader.get(), &data, 10, &result);
    151   ASSERT_EQ(net::ERR_FILE_NOT_FOUND, result);
    152   ASSERT_EQ(0U, data.size());
    153 }
    154 
    155 TEST_F(FileSystemFileStreamReaderTest, Empty) {
    156   const char kFileName[] = "empty";
    157   WriteFile(kFileName, NULL, 0, NULL);
    158 
    159   scoped_ptr<FileSystemFileStreamReader> reader(
    160       CreateFileReader(kFileName, 0, base::Time()));
    161   int result = 0;
    162   std::string data;
    163   ReadFromReader(reader.get(), &data, 10, &result);
    164   ASSERT_EQ(net::OK, result);
    165   ASSERT_EQ(0U, data.size());
    166 
    167   net::TestInt64CompletionCallback callback;
    168   int64 length_result = reader->GetLength(callback.callback());
    169   if (length_result == net::ERR_IO_PENDING)
    170     length_result = callback.WaitForResult();
    171   ASSERT_EQ(0, length_result);
    172 }
    173 
    174 TEST_F(FileSystemFileStreamReaderTest, GetLengthNormal) {
    175   scoped_ptr<FileSystemFileStreamReader> reader(
    176       CreateFileReader(kTestFileName, 0, test_file_modification_time()));
    177   net::TestInt64CompletionCallback callback;
    178   int64 result = reader->GetLength(callback.callback());
    179   if (result == net::ERR_IO_PENDING)
    180     result = callback.WaitForResult();
    181   ASSERT_EQ(kTestDataSize, result);
    182 }
    183 
    184 TEST_F(FileSystemFileStreamReaderTest, GetLengthAfterModified) {
    185   // Pass a fake expected modifictaion time so that the expectation fails.
    186   base::Time fake_expected_modification_time =
    187       test_file_modification_time() - base::TimeDelta::FromSeconds(10);
    188 
    189   scoped_ptr<FileSystemFileStreamReader> reader(
    190       CreateFileReader(kTestFileName, 0, fake_expected_modification_time));
    191   net::TestInt64CompletionCallback callback;
    192   int64 result = reader->GetLength(callback.callback());
    193   if (result == net::ERR_IO_PENDING)
    194     result = callback.WaitForResult();
    195   ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
    196 
    197   // With NULL expected modification time this should work.
    198   reader.reset(CreateFileReader(kTestFileName, 0, base::Time()));
    199   result = reader->GetLength(callback.callback());
    200   if (result == net::ERR_IO_PENDING)
    201     result = callback.WaitForResult();
    202   ASSERT_EQ(kTestDataSize, result);
    203 }
    204 
    205 TEST_F(FileSystemFileStreamReaderTest, GetLengthWithOffset) {
    206   scoped_ptr<FileSystemFileStreamReader> reader(
    207       CreateFileReader(kTestFileName, 3, base::Time()));
    208   net::TestInt64CompletionCallback callback;
    209   int64 result = reader->GetLength(callback.callback());
    210   if (result == net::ERR_IO_PENDING)
    211     result = callback.WaitForResult();
    212   // Initial offset does not affect the result of GetLength.
    213   ASSERT_EQ(kTestDataSize, result);
    214 }
    215 
    216 TEST_F(FileSystemFileStreamReaderTest, ReadNormal) {
    217   scoped_ptr<FileSystemFileStreamReader> reader(
    218       CreateFileReader(kTestFileName, 0, test_file_modification_time()));
    219   int result = 0;
    220   std::string data;
    221   ReadFromReader(reader.get(), &data, kTestDataSize, &result);
    222   ASSERT_EQ(net::OK, result);
    223   ASSERT_EQ(kTestData, data);
    224 }
    225 
    226 TEST_F(FileSystemFileStreamReaderTest, ReadAfterModified) {
    227   // Pass a fake expected modifictaion time so that the expectation fails.
    228   base::Time fake_expected_modification_time =
    229       test_file_modification_time() - base::TimeDelta::FromSeconds(10);
    230 
    231   scoped_ptr<FileSystemFileStreamReader> reader(
    232       CreateFileReader(kTestFileName, 0, fake_expected_modification_time));
    233   int result = 0;
    234   std::string data;
    235   ReadFromReader(reader.get(), &data, kTestDataSize, &result);
    236   ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
    237   ASSERT_EQ(0U, data.size());
    238 
    239   // With NULL expected modification time this should work.
    240   data.clear();
    241   reader.reset(CreateFileReader(kTestFileName, 0, base::Time()));
    242   ReadFromReader(reader.get(), &data, kTestDataSize, &result);
    243   ASSERT_EQ(net::OK, result);
    244   ASSERT_EQ(kTestData, data);
    245 }
    246 
    247 TEST_F(FileSystemFileStreamReaderTest, ReadWithOffset) {
    248   scoped_ptr<FileSystemFileStreamReader> reader(
    249       CreateFileReader(kTestFileName, 3, base::Time()));
    250   int result = 0;
    251   std::string data;
    252   ReadFromReader(reader.get(), &data, kTestDataSize, &result);
    253   ASSERT_EQ(net::OK, result);
    254   ASSERT_EQ(&kTestData[3], data);
    255 }
    256 
    257 TEST_F(FileSystemFileStreamReaderTest, DeleteWithUnfinishedRead) {
    258   scoped_ptr<FileSystemFileStreamReader> reader(
    259       CreateFileReader(kTestFileName, 0, base::Time()));
    260 
    261   net::TestCompletionCallback callback;
    262   scoped_refptr<net::IOBufferWithSize> buf(
    263       new net::IOBufferWithSize(kTestDataSize));
    264   int rv = reader->Read(buf.get(), buf->size(), base::Bind(&NeverCalled));
    265   ASSERT_TRUE(rv == net::ERR_IO_PENDING || rv >= 0);
    266 
    267   // Delete immediately.
    268   // Should not crash; nor should NeverCalled be callback.
    269   reader.reset();
    270 }
    271 
    272 }  // namespace content
    273