Chromium Code Reviews| 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" | |
|
hashimoto
2014/07/08 11:12:55
nit: No need to include this.
mtomasz
2014/07/09 02:05:22
Done.
| |
| 11 #include "base/message_loop/message_loop.h" | |
|
hashimoto
2014/07/08 11:12:55
nit: This should be message_loop_proxy
mtomasz
2014/07/09 02:05:22
Done.
| |
| 12 #include "base/run_loop.h" | |
| 13 #include "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_st ream_reader.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 | |
| 19 namespace chromeos { | |
| 20 namespace file_system_provider { | |
| 21 namespace { | |
| 22 | |
| 23 // Size of the fake file in bytes. | |
| 24 const int kFileSize = 1024; | |
| 25 | |
| 26 // Size of the preloading buffer in bytes. | |
| 27 const int kBufferSize = 8; | |
| 28 | |
| 29 // Number of bytes requested per BufferingFileStreamReader::Read(). | |
| 30 const int kChunkSize = 3; | |
| 31 | |
| 32 // Pushes a value to the passed log vector. | |
| 33 template <typename T> | |
| 34 void LogValue(std::vector<T>* log, T value) { | |
| 35 log->push_back(value); | |
| 36 } | |
| 37 | |
| 38 // Fake internal file stream reader. | |
| 39 class FakeFileStreamReader : public webkit_blob::FileStreamReader { | |
| 40 public: | |
| 41 FakeFileStreamReader(std::vector<int>* log, bool return_error) | |
|
hashimoto
2014/07/08 11:12:55
How about replacing |return_error| with net::Error
mtomasz
2014/07/09 02:05:22
Done.
| |
| 42 : log_(log), return_error_(return_error) {} | |
| 43 virtual ~FakeFileStreamReader() {} | |
| 44 | |
| 45 // webkit_blob::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_) { | |
| 53 base::MessageLoopProxy::current()->PostTask( | |
| 54 FROM_HERE, base::Bind(callback, net::ERR_ACCESS_DENIED)); | |
| 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 base::MessageLoopProxy::current()->PostTask( | |
| 69 FROM_HERE, base::Bind(callback, kFileSize)); | |
| 70 return net::ERR_IO_PENDING; | |
| 71 } | |
| 72 | |
| 73 private: | |
| 74 std::vector<int>* log_; // Not owned. | |
| 75 bool return_error_; | |
| 76 DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader); | |
| 77 }; | |
| 78 | |
| 79 } // namespace | |
| 80 | |
| 81 class FileSystemProviderBufferingFileStreamReaderTest : public testing::Test { | |
| 82 protected: | |
| 83 FileSystemProviderBufferingFileStreamReaderTest() {} | |
| 84 virtual ~FileSystemProviderBufferingFileStreamReaderTest() {} | |
| 85 | |
| 86 content::TestBrowserThreadBundle thread_bundle_; | |
| 87 }; | |
| 88 | |
| 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, false /* return_error */)), | |
| 94 kBufferSize); | |
| 95 | |
| 96 // For the first read, the internal file stream reader is fired, as there is | |
| 97 // no data in the preloading buffer. | |
| 98 { | |
| 99 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 100 std::vector<int> read_log; | |
| 101 const int result = | |
| 102 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log)); | |
| 103 base::RunLoop().RunUntilIdle(); | |
| 104 | |
| 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]); | |
| 110 } | |
| 111 | |
| 112 // Second read should return data from the preloading buffer, without calling | |
| 113 // the internal file stream reader. | |
| 114 { | |
| 115 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 116 std::vector<int> read_log; | |
| 117 const int result = | |
| 118 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log)); | |
| 119 base::RunLoop().RunUntilIdle(); | |
| 120 | |
| 121 EXPECT_EQ(kChunkSize, result); | |
| 122 EXPECT_EQ(1u, inner_read_log.size()); | |
| 123 // Results returned synchronously, so no new read result events. | |
| 124 EXPECT_EQ(0u, read_log.size()); | |
| 125 } | |
| 126 | |
| 127 // Third read should return partial result from the preloading buffer. It is | |
| 128 // valid to return less bytes than requested. | |
| 129 { | |
| 130 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 131 std::vector<int> read_log; | |
| 132 const int result = | |
| 133 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log)); | |
| 134 base::RunLoop().RunUntilIdle(); | |
| 135 | |
| 136 EXPECT_EQ(kBufferSize - 2 * kChunkSize, result); | |
| 137 EXPECT_EQ(1u, inner_read_log.size()); | |
| 138 // Results returned synchronously, so no new read result events. | |
| 139 EXPECT_EQ(0u, read_log.size()); | |
| 140 } | |
| 141 | |
| 142 // The preloading buffer is now empty, so reading should invoke the internal | |
| 143 // file stream reader. | |
| 144 { | |
| 145 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 146 std::vector<int> read_log; | |
| 147 const int result = | |
| 148 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log)); | |
| 149 base::RunLoop().RunUntilIdle(); | |
| 150 | |
| 151 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
| 152 ASSERT_EQ(2u, inner_read_log.size()); | |
| 153 EXPECT_EQ(kBufferSize, inner_read_log[0]); | |
|
hashimoto
2014/07/08 11:12:55
Shouldn't this be inner_read_log[1]?
BTW, how abo
mtomasz
2014/07/09 02:05:22
Good idea. Done.
| |
| 154 ASSERT_EQ(1u, read_log.size()); | |
| 155 EXPECT_EQ(kChunkSize, read_log[0]); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read_Directly) { | |
| 160 std::vector<int> inner_read_log; | |
| 161 BufferingFileStreamReader reader( | |
| 162 scoped_ptr<webkit_blob::FileStreamReader>( | |
| 163 new FakeFileStreamReader(&inner_read_log, false /* return_error */)), | |
| 164 kBufferSize); | |
| 165 | |
| 166 // First read couple of bytes, so the internal buffer is filled out. | |
| 167 { | |
| 168 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 169 std::vector<int> read_log; | |
| 170 const int result = | |
| 171 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log)); | |
| 172 base::RunLoop().RunUntilIdle(); | |
| 173 | |
| 174 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
| 175 ASSERT_EQ(1u, inner_read_log.size()); | |
| 176 EXPECT_EQ(kBufferSize, inner_read_log[0]); | |
| 177 ASSERT_EQ(1u, read_log.size()); | |
| 178 EXPECT_EQ(kChunkSize, read_log[0]); | |
| 179 } | |
| 180 | |
| 181 const int read_bytes = kBufferSize * 2; | |
| 182 ASSERT_GT(kFileSize, read_bytes); | |
| 183 | |
| 184 // Reading more than the internal buffer size would cause fetching only | |
| 185 // as much as available in the internal buffer. | |
| 186 { | |
| 187 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 188 std::vector<int> read_log; | |
| 189 const int result = | |
| 190 reader.Read(buffer, read_bytes, base::Bind(&LogValue<int>, &read_log)); | |
| 191 base::RunLoop().RunUntilIdle(); | |
| 192 | |
| 193 EXPECT_EQ(kBufferSize - kChunkSize, result); | |
| 194 ASSERT_EQ(1u, inner_read_log.size()); | |
| 195 EXPECT_EQ(kBufferSize, inner_read_log[0]); | |
| 196 EXPECT_EQ(0u, read_log.size()); | |
| 197 } | |
| 198 | |
| 199 // The internal buffer is clean. Fetching more than the internal buffer size | |
| 200 // would cause fetching data directly from the inner reader, with skipping | |
| 201 // the internal buffer. | |
| 202 { | |
| 203 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 204 std::vector<int> read_log; | |
| 205 const int result = | |
| 206 reader.Read(buffer, read_bytes, base::Bind(&LogValue<int>, &read_log)); | |
| 207 base::RunLoop().RunUntilIdle(); | |
| 208 | |
| 209 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
| 210 ASSERT_EQ(2u, inner_read_log.size()); | |
| 211 EXPECT_EQ(read_bytes, inner_read_log[1]); | |
| 212 ASSERT_EQ(1u, read_log.size()); | |
| 213 EXPECT_EQ(read_bytes, read_log[0]); | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, | |
| 218 Read_MoreThanBufferSize) { | |
| 219 std::vector<int> inner_read_log; | |
| 220 BufferingFileStreamReader reader( | |
| 221 scoped_ptr<webkit_blob::FileStreamReader>( | |
| 222 new FakeFileStreamReader(&inner_read_log, false /* return_error */)), | |
| 223 kBufferSize); | |
| 224 // First read couple of bytes, so the internal buffer is filled out. | |
| 225 { | |
| 226 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 227 std::vector<int> read_log; | |
| 228 const int result = | |
| 229 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log)); | |
| 230 base::RunLoop().RunUntilIdle(); | |
| 231 | |
| 232 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
| 233 ASSERT_EQ(1u, inner_read_log.size()); | |
| 234 EXPECT_EQ(kBufferSize, inner_read_log[0]); | |
| 235 ASSERT_EQ(1u, read_log.size()); | |
| 236 EXPECT_EQ(kChunkSize, read_log[0]); | |
| 237 } | |
| 238 | |
| 239 // Returning less than requested number of bytes is valid, and should not | |
| 240 // fail. | |
| 241 { | |
| 242 const int chunk_size = 20; | |
| 243 ASSERT_LT(kBufferSize, chunk_size); | |
| 244 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(chunk_size)); | |
| 245 std::vector<int> read_log; | |
| 246 const int result = | |
| 247 reader.Read(buffer, chunk_size, base::Bind(&LogValue<int>, &read_log)); | |
| 248 base::RunLoop().RunUntilIdle(); | |
| 249 | |
| 250 EXPECT_EQ(5, result); | |
| 251 EXPECT_EQ(1u, inner_read_log.size()); | |
| 252 EXPECT_EQ(0u, read_log.size()); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, Read_WithError) { | |
| 257 std::vector<int> inner_read_log; | |
| 258 BufferingFileStreamReader reader( | |
| 259 scoped_ptr<webkit_blob::FileStreamReader>( | |
| 260 new FakeFileStreamReader(&inner_read_log, true /* return_error */)), | |
| 261 kBufferSize); | |
| 262 | |
| 263 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kChunkSize)); | |
| 264 std::vector<int> read_log; | |
| 265 const int result = | |
| 266 reader.Read(buffer, kChunkSize, base::Bind(&LogValue<int>, &read_log)); | |
| 267 base::RunLoop().RunUntilIdle(); | |
| 268 | |
| 269 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
| 270 ASSERT_EQ(1u, inner_read_log.size()); | |
| 271 EXPECT_EQ(kBufferSize, inner_read_log[0]); | |
| 272 ASSERT_EQ(1u, read_log.size()); | |
| 273 EXPECT_EQ(net::ERR_ACCESS_DENIED, read_log[0]); | |
| 274 } | |
| 275 | |
| 276 TEST_F(FileSystemProviderBufferingFileStreamReaderTest, GetLength) { | |
| 277 BufferingFileStreamReader reader( | |
| 278 scoped_ptr<webkit_blob::FileStreamReader>( | |
| 279 new FakeFileStreamReader(NULL, false /* return_error */)), | |
| 280 kBufferSize); | |
| 281 | |
| 282 std::vector<int64> get_length_log; | |
| 283 const int64 result = | |
| 284 reader.GetLength(base::Bind(&LogValue<int64>, &get_length_log)); | |
| 285 base::RunLoop().RunUntilIdle(); | |
| 286 | |
| 287 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
| 288 ASSERT_EQ(1u, get_length_log.size()); | |
| 289 EXPECT_EQ(kFileSize, get_length_log[0]); | |
| 290 } | |
| 291 | |
| 292 } // namespace file_system_provider | |
| 293 } // namespace chromeos | |
| OLD | NEW |