OLD | NEW |
---|---|
(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 | |
OLD | NEW |