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/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" 18 19namespace chromeos { 20namespace file_system_provider { 21namespace { 22 23// Size of the fake file in bytes. 24const int kFileSize = 1024; 25 26// Size of the preloading buffer in bytes. 27const int kPreloadingBufferLength = 8; 28 29// Number of bytes requested per BufferingFileStreamReader::Read(). 30const int kChunkSize = 3; 31 32// Pushes a value to the passed log vector. 33template <typename T> 34void LogValue(std::vector<T>* log, T value) { 35 log->push_back(value); 36} 37 38// Fake internal file stream reader. 39class FakeFileStreamReader : public storage::FileStreamReader { 40 public: 41 FakeFileStreamReader(std::vector<int>* log, net::Error return_error) 42 : log_(log), return_error_(return_error) {} 43 virtual ~FakeFileStreamReader() {} 44 45 // storage::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_ != net::OK) { 53 base::MessageLoopProxy::current()->PostTask( 54 FROM_HERE, base::Bind(callback, return_error_)); 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 DCHECK_EQ(net::OK, return_error_); 69 base::MessageLoopProxy::current()->PostTask( 70 FROM_HERE, base::Bind(callback, kFileSize)); 71 return net::ERR_IO_PENDING; 72 } 73 74 private: 75 std::vector<int>* log_; // Not owned. 76 net::Error return_error_; 77 DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader); 78}; 79 80} // namespace 81 82class FileSystemProviderBufferingFileStreamReaderTest : public testing::Test { 83 protected: 84 FileSystemProviderBufferingFileStreamReaderTest() {} 85 virtual ~FileSystemProviderBufferingFileStreamReaderTest() {} 86 87 content::TestBrowserThreadBundle thread_bundle_; 88}; 89 90TEST_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, 96 kFileSize); 97 98 // For the first read, the internal file stream reader is fired, as there is 99 // no data in the preloading buffer. 100 { 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(); 106 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]); 112 } 113 114 // Second read should return data from the preloading buffer, without calling 115 // the internal file stream reader. 116 { 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(); 123 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()); 128 } 129 130 // Third read should return partial result from the preloading buffer. It is 131 // valid to return less bytes than requested. 132 { 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(); 139 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()); 144 } 145 146 // The preloading buffer is now empty, so reading should invoke the internal 147 // file stream reader. 148 { 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(); 155 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]); 161 } 162} 163 164TEST_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, 170 kFileSize); 171 172 // First read couple of bytes, so the internal buffer is filled out. 173 { 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(); 179 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]); 185 } 186 187 const int read_bytes = kPreloadingBufferLength * 2; 188 ASSERT_GT(kFileSize, read_bytes); 189 190 // Reading more than the internal buffer size would cause fetching only 191 // as much as available in the internal buffer. 192 { 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(); 199 200 EXPECT_EQ(kPreloadingBufferLength - kChunkSize, result); 201 EXPECT_EQ(0u, inner_read_log.size()); 202 EXPECT_EQ(0u, read_log.size()); 203 } 204 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. 208 { 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(); 215 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]); 221 } 222} 223 224TEST_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, 231 kFileSize); 232 // First read couple of bytes, so the internal buffer is filled out. 233 { 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(); 239 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]); 245 } 246 247 // Returning less than requested number of bytes is valid, and should not 248 // fail. 249 { 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(); 258 259 EXPECT_EQ(5, result); 260 EXPECT_EQ(0u, inner_read_log.size()); 261 EXPECT_EQ(0u, read_log.size()); 262 } 263} 264 265TEST_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); 275 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); 281 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(); 287 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]); 293} 294 295TEST_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); 303 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); 308 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(); 314 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]); 320} 321 322TEST_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, 328 kFileSize); 329 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(); 335 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]); 341} 342 343TEST_F(FileSystemProviderBufferingFileStreamReaderTest, GetLength) { 344 BufferingFileStreamReader reader(scoped_ptr<storage::FileStreamReader>( 345 new FakeFileStreamReader(NULL, net::OK)), 346 kPreloadingBufferLength, 347 kFileSize); 348 349 std::vector<int64> get_length_log; 350 const int64 result = 351 reader.GetLength(base::Bind(&LogValue<int64>, &get_length_log)); 352 base::RunLoop().RunUntilIdle(); 353 354 EXPECT_EQ(net::ERR_IO_PENDING, result); 355 ASSERT_EQ(1u, get_length_log.size()); 356 EXPECT_EQ(kFileSize, get_length_log[0]); 357} 358 359} // namespace file_system_provider 360} // namespace chromeos 361