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