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 "content/public/test/test_browser_thread_bundle.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "testing/gtest/include/gtest/gtest.h"
19 namespace file_system_provider {
22 // Size of the fake file in bytes.
23 const int kFileSize = 1024;
25 // Size of the preloading buffer in bytes.
26 const int kBufferSize = 8;
28 // Number of bytes requested per BufferingFileStreamReader::Read().
29 const int kChunkSize = 3;
31 // Pushes a value to the passed log vector.
33 void LogValue(std::vector<T>* log, T value) {
34 log->push_back(value);
37 // Fake internal file stream reader.
38 class FakeFileStreamReader : public webkit_blob::FileStreamReader {
40 FakeFileStreamReader(std::vector<int>* log, net::Error return_error)
41 : log_(log), return_error_(return_error) {}
42 virtual ~FakeFileStreamReader() {}
44 // webkit_blob::FileStreamReader overrides.
45 virtual int Read(net::IOBuffer* buf,
47 const net::CompletionCallback& callback) OVERRIDE {
49 log_->push_back(buf_len);
51 if (return_error_ != net::OK) {
52 base::MessageLoopProxy::current()->PostTask(
53 FROM_HERE, base::Bind(callback, return_error_));
54 return net::ERR_IO_PENDING;
57 const std::string fake_data('X', buf_len);
58 memcpy(buf->data(), fake_data.c_str(), buf_len);
60 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
61 base::Bind(callback, buf_len));
62 return net::ERR_IO_PENDING;
65 virtual int64 GetLength(
66 const net::Int64CompletionCallback& callback) OVERRIDE {
67 DCHECK_EQ(net::OK, return_error_);
68 base::MessageLoopProxy::current()->PostTask(
69 FROM_HERE, base::Bind(callback, kFileSize));
70 return net::ERR_IO_PENDING;
74 std::vector<int>* log_; // Not owned.
75 net::Error return_error_;
76 DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader);
81 class FileSystemProviderBufferingFileStreamReaderTest : public testing::Test {
83 FileSystemProviderBufferingFileStreamReaderTest() {}
84 virtual ~FileSystemProviderBufferingFileStreamReaderTest() {}
86 content::TestBrowserThreadBundle thread_bundle_;
89 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read) {
90 std::vector<int> inner_read_log;
91 BufferingFileStreamReader reader(
92 scoped_ptr<webkit_blob::FileStreamReader>(
93 new FakeFileStreamReader(&inner_read_log, net::OK)),
96 // For the first read, the internal file stream reader is fired, as there is
97 // no data in the preloading buffer.
99 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
100 std::vector<int> read_log;
102 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log));
103 base::RunLoop().RunUntilIdle();
105 EXPECT_EQ(net::ERR_IO_PENDING, result);
106 ASSERT_EQ(1u, inner_read_log.size());
107 EXPECT_EQ(kBufferSize, inner_read_log[0]);
108 ASSERT_EQ(1u, read_log.size());
109 EXPECT_EQ(kChunkSize, read_log[0]);
112 // Second read should return data from the preloading buffer, without calling
113 // the internal file stream reader.
115 inner_read_log.clear();
116 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
117 std::vector<int> read_log;
119 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log));
120 base::RunLoop().RunUntilIdle();
122 EXPECT_EQ(kChunkSize, result);
123 EXPECT_EQ(0u, inner_read_log.size());
124 // Results returned synchronously, so no new read result events.
125 EXPECT_EQ(0u, read_log.size());
128 // Third read should return partial result from the preloading buffer. It is
129 // valid to return less bytes than requested.
131 inner_read_log.clear();
132 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
133 std::vector<int> read_log;
135 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log));
136 base::RunLoop().RunUntilIdle();
138 EXPECT_EQ(kBufferSize - 2 * kChunkSize, result);
139 EXPECT_EQ(0u, inner_read_log.size());
140 // Results returned synchronously, so no new read result events.
141 EXPECT_EQ(0u, read_log.size());
144 // The preloading buffer is now empty, so reading should invoke the internal
145 // file stream reader.
147 inner_read_log.clear();
148 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
149 std::vector<int> read_log;
151 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log));
152 base::RunLoop().RunUntilIdle();
154 EXPECT_EQ(net::ERR_IO_PENDING, result);
155 ASSERT_EQ(1u, inner_read_log.size());
156 EXPECT_EQ(kBufferSize, inner_read_log[0]);
157 ASSERT_EQ(1u, read_log.size());
158 EXPECT_EQ(kChunkSize, read_log[0]);
162 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read_Directly) {
163 std::vector<int> inner_read_log;
164 BufferingFileStreamReader reader(
165 scoped_ptr<webkit_blob::FileStreamReader>(
166 new FakeFileStreamReader(&inner_read_log, net::OK)),
169 // First read couple of bytes, so the internal buffer is filled out.
171 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
172 std::vector<int> read_log;
174 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log));
175 base::RunLoop().RunUntilIdle();
177 EXPECT_EQ(net::ERR_IO_PENDING, result);
178 ASSERT_EQ(1u, inner_read_log.size());
179 EXPECT_EQ(kBufferSize, inner_read_log[0]);
180 ASSERT_EQ(1u, read_log.size());
181 EXPECT_EQ(kChunkSize, read_log[0]);
184 const int read_bytes = kBufferSize * 2;
185 ASSERT_GT(kFileSize, read_bytes);
187 // Reading more than the internal buffer size would cause fetching only
188 // as much as available in the internal buffer.
190 inner_read_log.clear();
191 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(read_bytes));
192 std::vector<int> read_log;
194 reader.Read(buffer, read_bytes, base::Bind(&LogValue<int>, &read_log));
195 base::RunLoop().RunUntilIdle();
197 EXPECT_EQ(kBufferSize - kChunkSize, result);
198 EXPECT_EQ(0u, inner_read_log.size());
199 EXPECT_EQ(0u, read_log.size());
202 // The internal buffer is clean. Fetching more than the internal buffer size
203 // would cause fetching data directly from the inner reader, with skipping
204 // the internal buffer.
206 inner_read_log.clear();
207 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(read_bytes));
208 std::vector<int> read_log;
210 reader.Read(buffer, read_bytes, base::Bind(&LogValue<int>, &read_log));
211 base::RunLoop().RunUntilIdle();
213 EXPECT_EQ(net::ERR_IO_PENDING, result);
214 ASSERT_EQ(1u, inner_read_log.size());
215 EXPECT_EQ(read_bytes, inner_read_log[0]);
216 ASSERT_EQ(1u, read_log.size());
217 EXPECT_EQ(read_bytes, read_log[0]);
221 TEST_F(FileSystemProviderBufferingFileStreamReaderTest,
222 Read_MoreThanBufferSize) {
223 std::vector<int> inner_read_log;
224 BufferingFileStreamReader reader(
225 scoped_ptr<webkit_blob::FileStreamReader>(
226 new FakeFileStreamReader(&inner_read_log, net::OK)),
228 // First read couple of bytes, so the internal buffer is filled out.
230 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
231 std::vector<int> read_log;
233 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log));
234 base::RunLoop().RunUntilIdle();
236 EXPECT_EQ(net::ERR_IO_PENDING, result);
237 ASSERT_EQ(1u, inner_read_log.size());
238 EXPECT_EQ(kBufferSize, inner_read_log[0]);
239 ASSERT_EQ(1u, read_log.size());
240 EXPECT_EQ(kChunkSize, read_log[0]);
243 // Returning less than requested number of bytes is valid, and should not
246 inner_read_log.clear();
247 const int chunk_size = 20;
248 ASSERT_LT(kBufferSize, chunk_size);
249 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(chunk_size));
250 std::vector<int> read_log;
252 reader.Read(buffer, chunk_size, base::Bind(&LogValue<int>, &read_log));
253 base::RunLoop().RunUntilIdle();
255 EXPECT_EQ(5, result);
256 EXPECT_EQ(0u, inner_read_log.size());
257 EXPECT_EQ(0u, read_log.size());
261 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read_WithError) {
262 std::vector<int> inner_read_log;
263 BufferingFileStreamReader reader(
264 scoped_ptr<webkit_blob::FileStreamReader>(
265 new FakeFileStreamReader(&inner_read_log, net::ERR_ACCESS_DENIED)),
268 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
269 std::vector<int> read_log;
271 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log));
272 base::RunLoop().RunUntilIdle();
274 EXPECT_EQ(net::ERR_IO_PENDING, result);
275 ASSERT_EQ(1u, inner_read_log.size());
276 EXPECT_EQ(kBufferSize, inner_read_log[0]);
277 ASSERT_EQ(1u, read_log.size());
278 EXPECT_EQ(net::ERR_ACCESS_DENIED, read_log[0]);
281 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, GetLength) {
282 BufferingFileStreamReader reader(scoped_ptr<webkit_blob::FileStreamReader>(
283 new FakeFileStreamReader(NULL, net::OK)),
286 std::vector<int64> get_length_log;
288 reader.GetLength(base::Bind(&LogValue<int64>, &get_length_log));
289 base::RunLoop().RunUntilIdle();
291 EXPECT_EQ(net::ERR_IO_PENDING, result);
292 ASSERT_EQ(1u, get_length_log.size());
293 EXPECT_EQ(kFileSize, get_length_log[0]);
296 } // namespace file_system_provider
297 } // namespace chromeos