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.
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"
20 namespace file_system_provider {
23 // Size of the fake file in bytes.
24 const int kFileSize = 1024;
26 // Size of the preloading buffer in bytes.
27 const int kPreloadingBufferLength = 8;
29 // Number of bytes requested per BufferingFileStreamReader::Read().
30 const int kChunkSize = 3;
32 // Pushes a value to the passed log vector.
34 void LogValue(std::vector<T>* log, T value) {
35 log->push_back(value);
38 // Fake internal file stream reader.
39 class FakeFileStreamReader : public storage::FileStreamReader {
41 FakeFileStreamReader(std::vector<int>* log, net::Error return_error)
42 : log_(log), return_error_(return_error) {}
43 virtual ~FakeFileStreamReader() {}
45 // storage::FileStreamReader overrides.
46 virtual int Read(net::IOBuffer* buf,
48 const net::CompletionCallback& callback) override {
50 log_->push_back(buf_len);
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;
58 const std::string fake_data('X', buf_len);
59 memcpy(buf->data(), fake_data.c_str(), buf_len);
61 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
62 base::Bind(callback, buf_len));
63 return net::ERR_IO_PENDING;
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;
75 std::vector<int>* log_; // Not owned.
76 net::Error return_error_;
77 DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader);
82 class FileSystemProviderBufferingFileStreamReaderTest : public testing::Test {
84 FileSystemProviderBufferingFileStreamReaderTest() {}
85 virtual ~FileSystemProviderBufferingFileStreamReaderTest() {}
87 content::TestBrowserThreadBundle thread_bundle_;
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,
98 // For the first read, the internal file stream reader is fired, as there is
99 // no data in the preloading buffer.
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();
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]);
114 // Second read should return data from the preloading buffer, without calling
115 // the internal file stream reader.
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();
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());
130 // Third read should return partial result from the preloading buffer. It is
131 // valid to return less bytes than requested.
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();
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());
146 // The preloading buffer is now empty, so reading should invoke the internal
147 // file stream reader.
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();
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]);
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,
172 // First read couple of bytes, so the internal buffer is filled out.
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();
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]);
187 const int read_bytes = kPreloadingBufferLength * 2;
188 ASSERT_GT(kFileSize, read_bytes);
190 // Reading more than the internal buffer size would cause fetching only
191 // as much as available in the internal buffer.
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();
200 EXPECT_EQ(kPreloadingBufferLength - kChunkSize, result);
201 EXPECT_EQ(0u, inner_read_log.size());
202 EXPECT_EQ(0u, read_log.size());
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.
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();
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]);
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,
232 // First read couple of bytes, so the internal buffer is filled out.
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();
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]);
247 // Returning less than requested number of bytes is valid, and should not
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();
259 EXPECT_EQ(5, result);
260 EXPECT_EQ(0u, inner_read_log.size());
261 EXPECT_EQ(0u, read_log.size());
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);
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);
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();
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]);
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);
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);
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();
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]);
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,
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();
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]);
343 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, GetLength) {
344 BufferingFileStreamReader reader(scoped_ptr<storage::FileStreamReader>(
345 new FakeFileStreamReader(NULL, net::OK)),
346 kPreloadingBufferLength,
349 std::vector<int64> get_length_log;
351 reader.GetLength(base::Bind(&LogValue<int64>, &get_length_log));
352 base::RunLoop().RunUntilIdle();
354 EXPECT_EQ(net::ERR_IO_PENDING, result);
355 ASSERT_EQ(1u, get_length_log.size());
356 EXPECT_EQ(kFileSize, get_length_log[0]);
359 } // namespace file_system_provider
360 } // namespace chromeos