Home | History | Annotate | Download | only in fileapi
      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 <string>
      6 #include <vector>
      7 
      8 #include "base/memory/ref_counted.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/run_loop.h"
     12 #include "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_reader.h"
     13 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
     14 #include "content/public/test/test_browser_thread_bundle.h"
     15 #include "net/base/io_buffer.h"
     16 #include "net/base/net_errors.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 namespace chromeos {
     20 namespace file_system_provider {
     21 namespace {
     22 
     23 // Size of the fake file in bytes.
     24 const int kFileSize = 1024;
     25 
     26 // Size of the preloading buffer in bytes.
     27 const int kPreloadingBufferLength = 8;
     28 
     29 // Number of bytes requested per BufferingFileStreamReader::Read().
     30 const int kChunkSize = 3;
     31 
     32 // Pushes a value to the passed log vector.
     33 template <typename T>
     34 void LogValue(std::vector<T>* log, T value) {
     35   log->push_back(value);
     36 }
     37 
     38 // Fake internal file stream reader.
     39 class FakeFileStreamReader : public storage::FileStreamReader {
     40  public:
     41   FakeFileStreamReader(std::vector<int>* log, net::Error return_error)
     42       : log_(log), return_error_(return_error) {}
     43   virtual ~FakeFileStreamReader() {}
     44 
     45   // storage::FileStreamReader overrides.
     46   virtual int Read(net::IOBuffer* buf,
     47                    int buf_len,
     48                    const net::CompletionCallback& callback) OVERRIDE {
     49     DCHECK(log_);
     50     log_->push_back(buf_len);
     51 
     52     if (return_error_ != net::OK) {
     53       base::MessageLoopProxy::current()->PostTask(
     54           FROM_HERE, base::Bind(callback, return_error_));
     55       return net::ERR_IO_PENDING;
     56     }
     57 
     58     const std::string fake_data('X', buf_len);
     59     memcpy(buf->data(), fake_data.c_str(), buf_len);
     60 
     61     base::MessageLoopProxy::current()->PostTask(FROM_HERE,
     62                                                 base::Bind(callback, buf_len));
     63     return net::ERR_IO_PENDING;
     64   }
     65 
     66   virtual int64 GetLength(
     67       const net::Int64CompletionCallback& callback) OVERRIDE {
     68     DCHECK_EQ(net::OK, return_error_);
     69     base::MessageLoopProxy::current()->PostTask(
     70         FROM_HERE, base::Bind(callback, kFileSize));
     71     return net::ERR_IO_PENDING;
     72   }
     73 
     74  private:
     75   std::vector<int>* log_;  // Not owned.
     76   net::Error return_error_;
     77   DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader);
     78 };
     79 
     80 }  // namespace
     81 
     82 class FileSystemProviderBufferingFileStreamReaderTest : public testing::Test {
     83  protected:
     84   FileSystemProviderBufferingFileStreamReaderTest() {}
     85   virtual ~FileSystemProviderBufferingFileStreamReaderTest() {}
     86 
     87   content::TestBrowserThreadBundle thread_bundle_;
     88 };
     89 
     90 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read) {
     91   std::vector<int> inner_read_log;
     92   BufferingFileStreamReader reader(
     93       scoped_ptr<storage::FileStreamReader>(
     94           new FakeFileStreamReader(&inner_read_log, net::OK)),
     95       kPreloadingBufferLength,
     96       kFileSize);
     97 
     98   // For the first read, the internal file stream reader is fired, as there is
     99   // no data in the preloading buffer.
    100   {
    101     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
    102     std::vector<int> read_log;
    103     const int result = reader.Read(
    104         buffer.get(), kChunkSize, base::Bind(&LogValue<int>, &read_log));
    105     base::RunLoop().RunUntilIdle();
    106 
    107     EXPECT_EQ(net::ERR_IO_PENDING, result);
    108     ASSERT_EQ(1u, inner_read_log.size());
    109     EXPECT_EQ(kPreloadingBufferLength, inner_read_log[0]);
    110     ASSERT_EQ(1u, read_log.size());
    111     EXPECT_EQ(kChunkSize, read_log[0]);
    112   }
    113 
    114   // Second read should return data from the preloading buffer, without calling
    115   // the internal file stream reader.
    116   {
    117     inner_read_log.clear();
    118     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
    119     std::vector<int> read_log;
    120     const int result = reader.Read(
    121         buffer.get(), kChunkSize, base::Bind(&LogValue<int>, &read_log));
    122     base::RunLoop().RunUntilIdle();
    123 
    124     EXPECT_EQ(kChunkSize, result);
    125     EXPECT_EQ(0u, inner_read_log.size());
    126     // Results returned synchronously, so no new read result events.
    127     EXPECT_EQ(0u, read_log.size());
    128   }
    129 
    130   // Third read should return partial result from the preloading buffer. It is
    131   // valid to return less bytes than requested.
    132   {
    133     inner_read_log.clear();
    134     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
    135     std::vector<int> read_log;
    136     const int result = reader.Read(
    137         buffer.get(), kChunkSize, base::Bind(&LogValue<int>, &read_log));
    138     base::RunLoop().RunUntilIdle();
    139 
    140     EXPECT_EQ(kPreloadingBufferLength - 2 * kChunkSize, result);
    141     EXPECT_EQ(0u, inner_read_log.size());
    142     // Results returned synchronously, so no new read result events.
    143     EXPECT_EQ(0u, read_log.size());
    144   }
    145 
    146   // The preloading buffer is now empty, so reading should invoke the internal
    147   // file stream reader.
    148   {
    149     inner_read_log.clear();
    150     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
    151     std::vector<int> read_log;
    152     const int result = reader.Read(
    153         buffer.get(), kChunkSize, base::Bind(&LogValue<int>, &read_log));
    154     base::RunLoop().RunUntilIdle();
    155 
    156     EXPECT_EQ(net::ERR_IO_PENDING, result);
    157     ASSERT_EQ(1u, inner_read_log.size());
    158     EXPECT_EQ(kPreloadingBufferLength, inner_read_log[0]);
    159     ASSERT_EQ(1u, read_log.size());
    160     EXPECT_EQ(kChunkSize, read_log[0]);
    161   }
    162 }
    163 
    164 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read_Directly) {
    165   std::vector<int> inner_read_log;
    166   BufferingFileStreamReader reader(
    167       scoped_ptr<storage::FileStreamReader>(
    168           new FakeFileStreamReader(&inner_read_log, net::OK)),
    169       kPreloadingBufferLength,
    170       kFileSize);
    171 
    172   // First read couple of bytes, so the internal buffer is filled out.
    173   {
    174     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
    175     std::vector<int> read_log;
    176     const int result = reader.Read(
    177         buffer.get(), kChunkSize, base::Bind(&LogValue<int>, &read_log));
    178     base::RunLoop().RunUntilIdle();
    179 
    180     EXPECT_EQ(net::ERR_IO_PENDING, result);
    181     ASSERT_EQ(1u, inner_read_log.size());
    182     EXPECT_EQ(kPreloadingBufferLength, inner_read_log[0]);
    183     ASSERT_EQ(1u, read_log.size());
    184     EXPECT_EQ(kChunkSize, read_log[0]);
    185   }
    186 
    187   const int read_bytes = kPreloadingBufferLength * 2;
    188   ASSERT_GT(kFileSize, read_bytes);
    189 
    190   // Reading more than the internal buffer size would cause fetching only
    191   // as much as available in the internal buffer.
    192   {
    193     inner_read_log.clear();
    194     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(read_bytes));
    195     std::vector<int> read_log;
    196     const int result = reader.Read(
    197         buffer.get(), read_bytes, base::Bind(&LogValue<int>, &read_log));
    198     base::RunLoop().RunUntilIdle();
    199 
    200     EXPECT_EQ(kPreloadingBufferLength - kChunkSize, result);
    201     EXPECT_EQ(0u, inner_read_log.size());
    202     EXPECT_EQ(0u, read_log.size());
    203   }
    204 
    205   // The internal buffer is clean. Fetching more than the internal buffer size
    206   // would cause fetching data directly from the inner reader, with skipping
    207   // the internal buffer.
    208   {
    209     inner_read_log.clear();
    210     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(read_bytes));
    211     std::vector<int> read_log;
    212     const int result = reader.Read(
    213         buffer.get(), read_bytes, base::Bind(&LogValue<int>, &read_log));
    214     base::RunLoop().RunUntilIdle();
    215 
    216     EXPECT_EQ(net::ERR_IO_PENDING, result);
    217     ASSERT_EQ(1u, inner_read_log.size());
    218     EXPECT_EQ(read_bytes, inner_read_log[0]);
    219     ASSERT_EQ(1u, read_log.size());
    220     EXPECT_EQ(read_bytes, read_log[0]);
    221   }
    222 }
    223 
    224 TEST_F(FileSystemProviderBufferingFileStreamReaderTest,
    225        Read_MoreThanBufferSize) {
    226   std::vector<int> inner_read_log;
    227   BufferingFileStreamReader reader(
    228       scoped_ptr<storage::FileStreamReader>(
    229           new FakeFileStreamReader(&inner_read_log, net::OK)),
    230       kPreloadingBufferLength,
    231       kFileSize);
    232   // First read couple of bytes, so the internal buffer is filled out.
    233   {
    234     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
    235     std::vector<int> read_log;
    236     const int result = reader.Read(
    237         buffer.get(), kChunkSize, base::Bind(&LogValue<int>, &read_log));
    238     base::RunLoop().RunUntilIdle();
    239 
    240     EXPECT_EQ(net::ERR_IO_PENDING, result);
    241     ASSERT_EQ(1u, inner_read_log.size());
    242     EXPECT_EQ(kPreloadingBufferLength, inner_read_log[0]);
    243     ASSERT_EQ(1u, read_log.size());
    244     EXPECT_EQ(kChunkSize, read_log[0]);
    245   }
    246 
    247   // Returning less than requested number of bytes is valid, and should not
    248   // fail.
    249   {
    250     inner_read_log.clear();
    251     const int chunk_size = 20;
    252     ASSERT_LT(kPreloadingBufferLength, chunk_size);
    253     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(chunk_size));
    254     std::vector<int> read_log;
    255     const int result = reader.Read(
    256         buffer.get(), chunk_size, base::Bind(&LogValue<int>, &read_log));
    257     base::RunLoop().RunUntilIdle();
    258 
    259     EXPECT_EQ(5, result);
    260     EXPECT_EQ(0u, inner_read_log.size());
    261     EXPECT_EQ(0u, read_log.size());
    262   }
    263 }
    264 
    265 TEST_F(FileSystemProviderBufferingFileStreamReaderTest,
    266        Read_LessThanBufferSize) {
    267   std::vector<int> inner_read_log;
    268   const int total_bytes_to_read = 3;
    269   ASSERT_LT(total_bytes_to_read, kPreloadingBufferLength);
    270   BufferingFileStreamReader reader(
    271       scoped_ptr<storage::FileStreamReader>(
    272           new FakeFileStreamReader(&inner_read_log, net::OK)),
    273       kPreloadingBufferLength,
    274       total_bytes_to_read);
    275 
    276   // For the first read, the internal file stream reader is fired, as there is
    277   // no data in the preloading buffer.
    278   const int read_bytes = 2;
    279   ASSERT_LT(read_bytes, kPreloadingBufferLength);
    280   ASSERT_LE(read_bytes, total_bytes_to_read);
    281 
    282   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(read_bytes));
    283   std::vector<int> read_log;
    284   const int result = reader.Read(
    285       buffer.get(), read_bytes, base::Bind(&LogValue<int>, &read_log));
    286   base::RunLoop().RunUntilIdle();
    287 
    288   EXPECT_EQ(net::ERR_IO_PENDING, result);
    289   ASSERT_EQ(1u, inner_read_log.size());
    290   EXPECT_EQ(total_bytes_to_read, inner_read_log[0]);
    291   ASSERT_EQ(1u, read_log.size());
    292   EXPECT_EQ(read_bytes, read_log[0]);
    293 }
    294 
    295 TEST_F(FileSystemProviderBufferingFileStreamReaderTest,
    296        Read_LessThanBufferSize_WithoutSpecifiedLength) {
    297   std::vector<int> inner_read_log;
    298   BufferingFileStreamReader reader(
    299       scoped_ptr<storage::FileStreamReader>(
    300           new FakeFileStreamReader(&inner_read_log, net::OK)),
    301       kPreloadingBufferLength,
    302       storage::kMaximumLength);
    303 
    304   // For the first read, the internal file stream reader is fired, as there is
    305   // no data in the preloading buffer.
    306   const int read_bytes = 2;
    307   ASSERT_LT(read_bytes, kPreloadingBufferLength);
    308 
    309   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(read_bytes));
    310   std::vector<int> read_log;
    311   const int result = reader.Read(
    312       buffer.get(), read_bytes, base::Bind(&LogValue<int>, &read_log));
    313   base::RunLoop().RunUntilIdle();
    314 
    315   EXPECT_EQ(net::ERR_IO_PENDING, result);
    316   ASSERT_EQ(1u, inner_read_log.size());
    317   EXPECT_EQ(kPreloadingBufferLength, inner_read_log[0]);
    318   ASSERT_EQ(1u, read_log.size());
    319   EXPECT_EQ(read_bytes, read_log[0]);
    320 }
    321 
    322 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read_WithError) {
    323   std::vector<int> inner_read_log;
    324   BufferingFileStreamReader reader(
    325       scoped_ptr<storage::FileStreamReader>(
    326           new FakeFileStreamReader(&inner_read_log, net::ERR_ACCESS_DENIED)),
    327       kPreloadingBufferLength,
    328       kFileSize);
    329 
    330   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
    331   std::vector<int> read_log;
    332   const int result = reader.Read(
    333       buffer.get(), kChunkSize, base::Bind(&LogValue<int>, &read_log));
    334   base::RunLoop().RunUntilIdle();
    335 
    336   EXPECT_EQ(net::ERR_IO_PENDING, result);
    337   ASSERT_EQ(1u, inner_read_log.size());
    338   EXPECT_EQ(kPreloadingBufferLength, inner_read_log[0]);
    339   ASSERT_EQ(1u, read_log.size());
    340   EXPECT_EQ(net::ERR_ACCESS_DENIED, read_log[0]);
    341 }
    342 
    343 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, GetLength) {
    344   BufferingFileStreamReader reader(scoped_ptr<storage::FileStreamReader>(
    345                                        new FakeFileStreamReader(NULL, net::OK)),
    346                                    kPreloadingBufferLength,
    347                                    kFileSize);
    348 
    349   std::vector<int64> get_length_log;
    350   const int64 result =
    351       reader.GetLength(base::Bind(&LogValue<int64>, &get_length_log));
    352   base::RunLoop().RunUntilIdle();
    353 
    354   EXPECT_EQ(net::ERR_IO_PENDING, result);
    355   ASSERT_EQ(1u, get_length_log.size());
    356   EXPECT_EQ(kFileSize, get_length_log[0]);
    357 }
    358 
    359 }  // namespace file_system_provider
    360 }  // namespace chromeos
    361