Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Side by Side Diff: chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_reader_unittest.cc

Issue 318563002: [fsp] Introduce BufferingFileStreamReader to read files in bigger chunks. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed a test. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/memory/weak_ptr.h"
11 #include "base/run_loop.h"
12 #include "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_st ream_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"
17
18 namespace chromeos {
19 namespace file_system_provider {
20 namespace {
21
22 // Size of the fake file in bytes.
23 const int kFileSize = 1024;
24
25 // Size of the preloading buffer in bytes.
26 const int kBufferSize = 8;
27
28 // Number of bytes requested per BufferingFileStreamReader::Read().
29 const int kChunkSize = 3;
30
31 // Behaviour tested by a test case.
32 enum TestMode { SYNCHRONOUS, ASYNCHRONOUS };
33
34 // Logs invocations on the fake file stream reader.
35 class Logger {
36 public:
37 Logger() : weak_ptr_factory_(this) {}
38 virtual ~Logger() {}
39
40 // Registers calls to the internal file stream reader, for the Read() method.
41 void OnInnerReadRequested(int buf_len) {
42 inner_read_requested_events_.push_back(buf_len);
43 }
44
45 // Registers results returned asynchronously by the buffering stream reader,
46 // for the Read() method.
47 void OnReadResult(int result) { read_result_events_.push_back(result); }
48
49 // Registers eresults returned asynchronously by the buffering strem reader,
hashimoto 2014/06/05 03:18:36 nit: s/eresults/results/?
mtomasz 2014/06/05 09:22:27 Done.
50 // for the GetLength() method.
51 void OnGetLengthResult(int64 result) {
52 get_length_result_events_.push_back(result);
53 }
54
55 // Gets a weak pointer for asynchronous callback invocations on the logger.
56 base::WeakPtr<Logger> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
hashimoto 2014/06/05 03:18:36 No need to have this method? I don't see any dange
mtomasz 2014/06/05 09:22:27 We are passing it to the BufferingFileStreamReader
hashimoto 2014/06/05 10:07:10 I think it's OK to take advantage of the single th
mtomasz 2014/06/06 01:31:03 Even if all threads are backed by the same message
hashimoto 2014/06/06 03:36:52 (1) Here we know that doesn't happen with the test
mtomasz 2014/06/06 04:22:56 Your suggestion also uses vectors and base::Bind,
hashimoto 2014/06/09 11:12:04 I still don't understand why you need this class:
mtomasz 2014/06/09 13:51:15 I think we are talking about two different things.
hashimoto 2014/06/10 10:43:24 Sorry, I forgot to note that inner_read_requested_
mtomasz 2014/06/10 12:23:55 1. inner_read_requested_events_ can't be replaced.
hashimoto 2014/06/11 06:01:03 You can do it because you are passing a new callba
mtomasz 2014/06/12 04:10:09 I made the change as you suggested for comparison.
57
58 const std::vector<int>& inner_read_requested_events() const {
59 return inner_read_requested_events_;
60 }
61
62 const std::vector<int>& read_result_events() const {
63 return read_result_events_;
64 }
65
66 const std::vector<int64>& get_length_result_events() const {
67 return get_length_result_events_;
68 }
69
70 private:
71 std::vector<int> inner_read_requested_events_;
72 std::vector<int> read_result_events_;
73 std::vector<int64> get_length_result_events_;
74
75 base::WeakPtrFactory<Logger> weak_ptr_factory_;
76 DISALLOW_COPY_AND_ASSIGN(Logger);
77 };
78
79 // Fake internal file stream reader.
80 class FakeFileStreamReader : public webkit_blob::FileStreamReader {
81 public:
82 FakeFileStreamReader(Logger* logger, TestMode mode, bool return_error)
83 : logger_(logger), mode_(mode), return_error_(return_error) {}
84 virtual ~FakeFileStreamReader() {}
85
86 // webkit_blob::FileStreamReader overrides.
87 virtual int Read(net::IOBuffer* buf,
88 int buf_len,
89 const net::CompletionCallback& callback) OVERRIDE {
90 logger_->OnInnerReadRequested(buf_len);
91
92 if (return_error_) {
93 if (mode_ == SYNCHRONOUS)
94 return net::ERR_ACCESS_DENIED;
95
96 base::MessageLoopProxy::current()->PostTask(
97 FROM_HERE, base::Bind(callback, net::ERR_ACCESS_DENIED));
98 return net::ERR_IO_PENDING;
99 }
100
101 const std::string fake_data('X', buf_len);
102 memcpy(buf->data(), fake_data.c_str(), buf_len);
103
104 if (mode_ == SYNCHRONOUS)
105 return buf_len;
106
107 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
108 base::Bind(callback, buf_len));
109 return net::ERR_IO_PENDING;
110 }
111
112 virtual int64 GetLength(
113 const net::Int64CompletionCallback& callback) OVERRIDE {
114 if (mode_ == SYNCHRONOUS)
115 return kFileSize;
116
117 base::MessageLoopProxy::current()->PostTask(
118 FROM_HERE, base::Bind(callback, kFileSize));
119 return net::ERR_IO_PENDING;
120 }
121
122 private:
123 Logger* logger_; // Not owned.
124 TestMode mode_;
125 bool return_error_;
126 DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader);
127 };
128
129 } // namespace
130
131 class FileSystemProviderBufferingFileStreamReaderTest
132 : public testing::Test,
133 public ::testing::WithParamInterface<TestMode> {
134 protected:
135 FileSystemProviderBufferingFileStreamReaderTest() {}
136 virtual ~FileSystemProviderBufferingFileStreamReaderTest() {}
137
138 content::TestBrowserThreadBundle thread_bundle_;
139 };
140
141 TEST_P(FileSystemProviderBufferingFileStreamReaderTest, Read) {
142 Logger logger;
143 BufferingFileStreamReader reader(
144 scoped_ptr<webkit_blob::FileStreamReader>(new FakeFileStreamReader(
145 &logger, GetParam(), false /* return_error */)),
146 kBufferSize);
147
148 // For the first read, the internal file stream reader is fired, as there is
149 // no data in the preloading buffer.
150 {
151 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
152 const int result =
153 reader.Read(buffer,
154 kChunkSize,
155 base::Bind(&Logger::OnReadResult, logger.GetWeakPtr()));
hashimoto 2014/06/05 03:18:36 How about using TestCompletionCallback? The same g
mtomasz 2014/06/05 09:22:27 With TestCompletionCallback we can't control how m
hashimoto 2014/06/06 03:36:52 What do you mean? TestCompletionCallback::WaitForR
mtomasz 2014/06/06 04:22:56 If the tested class by accident calls the callback
hashimoto 2014/06/09 11:12:04 At least, we can catch it because it crashes as yo
mtomasz 2014/06/09 13:51:15 It would crash. But I don't think crashing is bett
hashimoto 2014/06/10 10:43:24 You cannot prepare for every possible failure whic
mtomasz 2014/06/10 12:23:55 I cannot test everything, but I'm not sure if it i
hashimoto 2014/06/11 06:01:03 This doesn't affect the test coverage (i.e. how mu
mtomasz 2014/06/16 04:12:17 It affects how detailed the tests are. IMHO tests
hashimoto 2014/06/19 07:27:45 TestCompletionCallback is widely used and it makes
mtomasz 2014/06/20 04:20:23 TestCompletionCallback makes the code nice and sho
156 base::RunLoop().RunUntilIdle();
157
158 EXPECT_EQ(net::ERR_IO_PENDING, result);
159 ASSERT_EQ(1u, logger.inner_read_requested_events().size());
160 EXPECT_EQ(kBufferSize, logger.inner_read_requested_events()[0]);
161 ASSERT_EQ(1u, logger.read_result_events().size());
162 EXPECT_EQ(kChunkSize, logger.read_result_events()[0]);
163 }
164
165 // Second read should return data from the preloading buffer, without calling
166 // the internal file stream reader.
167 {
168 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
169 const int result =
170 reader.Read(buffer,
171 kChunkSize,
172 base::Bind(&Logger::OnReadResult, logger.GetWeakPtr()));
173 base::RunLoop().RunUntilIdle();
174
175 EXPECT_EQ(kChunkSize, result);
176 EXPECT_EQ(1u, logger.inner_read_requested_events().size());
177 // Results returned synchronously, so no new read result events.
178 EXPECT_EQ(1u, logger.read_result_events().size());
179 }
180
181 // Third read should return partial result from the preloading buffer. It is
182 // valid to return less bytes than requested.
183 {
184 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
185 const int result =
186 reader.Read(buffer,
187 kChunkSize,
188 base::Bind(&Logger::OnReadResult, logger.GetWeakPtr()));
189 base::RunLoop().RunUntilIdle();
190
191 EXPECT_EQ(kBufferSize - 2 * kChunkSize, result);
192 EXPECT_EQ(1u, logger.inner_read_requested_events().size());
193 // Results returned synchronously, so no new read result events.
194 EXPECT_EQ(1u, logger.read_result_events().size());
195 }
196
197 // The preloading buffer is now empty, so reading should invoke the internal
198 // file stream reader.
199 {
200 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
201 const int result =
202 reader.Read(buffer,
203 kChunkSize,
204 base::Bind(&Logger::OnReadResult, logger.GetWeakPtr()));
205 base::RunLoop().RunUntilIdle();
206
207 EXPECT_EQ(net::ERR_IO_PENDING, result);
208 ASSERT_EQ(2u, logger.inner_read_requested_events().size());
209 EXPECT_EQ(kBufferSize, logger.inner_read_requested_events()[0]);
210 ASSERT_EQ(2u, logger.read_result_events().size());
211 EXPECT_EQ(kChunkSize, logger.read_result_events()[1]);
212 }
213 }
214
215 TEST_P(FileSystemProviderBufferingFileStreamReaderTest,
216 Read_MoreThanBufferSize) {
217 Logger logger;
218 BufferingFileStreamReader reader(
219 scoped_ptr<webkit_blob::FileStreamReader>(new FakeFileStreamReader(
220 &logger, GetParam(), false /* return_error */)),
221 kBufferSize);
222
223 // Returning less than requested number of bytes is valid, and should not
224 // fail.
225 const int chunk_size = 20;
226 ASSERT_LT(kBufferSize, chunk_size);
227 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(chunk_size));
228 const int result =
229 reader.Read(buffer,
230 chunk_size,
231 base::Bind(&Logger::OnReadResult, logger.GetWeakPtr()));
232 base::RunLoop().RunUntilIdle();
233
234 EXPECT_EQ(net::ERR_IO_PENDING, result);
235 ASSERT_EQ(1u, logger.inner_read_requested_events().size());
236 EXPECT_EQ(kBufferSize, logger.inner_read_requested_events()[0]);
237 ASSERT_EQ(1u, logger.read_result_events().size());
238 EXPECT_EQ(kBufferSize, logger.read_result_events()[0]);
239 }
240
241 TEST_P(FileSystemProviderBufferingFileStreamReaderTest, Read_WithError) {
242 Logger logger;
243 BufferingFileStreamReader reader(
244 scoped_ptr<webkit_blob::FileStreamReader>(new FakeFileStreamReader(
245 &logger, GetParam(), true /* return_error */)),
246 kBufferSize);
247
248 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize));
249 const int result =
250 reader.Read(buffer,
251 kChunkSize,
252 base::Bind(&Logger::OnReadResult, logger.GetWeakPtr()));
253 base::RunLoop().RunUntilIdle();
254
255 EXPECT_EQ(net::ERR_IO_PENDING, result);
256 ASSERT_EQ(1u, logger.inner_read_requested_events().size());
257 EXPECT_EQ(kBufferSize, logger.inner_read_requested_events()[0]);
258 ASSERT_EQ(1u, logger.read_result_events().size());
259 EXPECT_EQ(net::ERR_ACCESS_DENIED, logger.read_result_events()[0]);
260 }
261
262 TEST_P(FileSystemProviderBufferingFileStreamReaderTest, GetLength) {
263 Logger logger;
264 BufferingFileStreamReader reader(
265 scoped_ptr<webkit_blob::FileStreamReader>(new FakeFileStreamReader(
266 &logger, GetParam(), false /* return_error */)),
267 kBufferSize);
268
269 const int64 result = reader.GetLength(
270 base::Bind(&Logger::OnGetLengthResult, logger.GetWeakPtr()));
271 base::RunLoop().RunUntilIdle();
272
273 if (GetParam() == SYNCHRONOUS) {
274 EXPECT_EQ(kFileSize, result);
275 EXPECT_EQ(0u, logger.get_length_result_events().size());
276 } else {
277 EXPECT_EQ(net::ERR_IO_PENDING, result);
278 ASSERT_EQ(1u, logger.get_length_result_events().size());
279 EXPECT_EQ(kFileSize, logger.get_length_result_events()[0]);
280 }
281 }
282
283 INSTANTIATE_TEST_CASE_P(Synchronous,
284 FileSystemProviderBufferingFileStreamReaderTest,
285 testing::Values(SYNCHRONOUS));
286
287 INSTANTIATE_TEST_CASE_P(Asynchronous,
288 FileSystemProviderBufferingFileStreamReaderTest,
289 testing::Values(ASYNCHRONOUS));
290
291 } // namespace file_system_provider
292 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698