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
19namespace chromeos {
20namespace file_system_provider {
21namespace {
22
23// Size of the fake file in bytes.
24const int kFileSize = 1024;
25
26// Size of the preloading buffer in bytes.
27const int kPreloadingBufferLength = 8;
28
29// Number of bytes requested per BufferingFileStreamReader::Read().
30const int kChunkSize = 3;
31
32// Pushes a value to the passed log vector.
33template <typename T>
34void LogValue(std::vector<T>* log, T value) {
35  log->push_back(value);
36}
37
38// Fake internal file stream reader.
39class 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
82class FileSystemProviderBufferingFileStreamReaderTest : public testing::Test {
83 protected:
84  FileSystemProviderBufferingFileStreamReaderTest() {}
85  virtual ~FileSystemProviderBufferingFileStreamReaderTest() {}
86
87  content::TestBrowserThreadBundle thread_bundle_;
88};
89
90TEST_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
164TEST_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
224TEST_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
265TEST_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
295TEST_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
322TEST_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
343TEST_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