OLD | NEW |
| (Empty) |
1 // Copyright 2015 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 "storage/browser/blob/blob_reader.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/callback.h" | |
10 #include "base/files/file_path.h" | |
11 #include "base/location.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "base/run_loop.h" | |
15 #include "base/strings/stringprintf.h" | |
16 #include "base/task_runner.h" | |
17 #include "base/time/time.h" | |
18 #include "content/public/test/async_file_test_helper.h" | |
19 #include "content/public/test/test_file_system_context.h" | |
20 #include "net/base/completion_callback.h" | |
21 #include "net/base/io_buffer.h" | |
22 #include "net/base/net_errors.h" | |
23 #include "net/base/test_completion_callback.h" | |
24 #include "net/disk_cache/disk_cache.h" | |
25 #include "storage/browser/blob/blob_data_builder.h" | |
26 #include "storage/browser/blob/blob_data_handle.h" | |
27 #include "storage/browser/blob/blob_storage_context.h" | |
28 #include "storage/browser/fileapi/file_stream_reader.h" | |
29 #include "storage/browser/fileapi/file_system_context.h" | |
30 #include "storage/browser/fileapi/file_system_file_util.h" | |
31 #include "testing/gmock/include/gmock/gmock.h" | |
32 #include "testing/gtest/include/gtest/gtest.h" | |
33 #include "url/gurl.h" | |
34 | |
35 using base::FilePath; | |
36 using content::AsyncFileTestHelper; | |
37 using net::DrainableIOBuffer; | |
38 using net::IOBuffer; | |
39 | |
40 namespace storage { | |
41 namespace { | |
42 | |
43 const int kTestDiskCacheStreamIndex = 0; | |
44 | |
45 // Our disk cache tests don't need a real data handle since the tests themselves | |
46 // scope the disk cache and entries. | |
47 class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle { | |
48 private: | |
49 ~EmptyDataHandle() override {} | |
50 }; | |
51 | |
52 // A disk_cache::Entry that arbitrarily delays the completion of a read | |
53 // operation to allow testing some races without flake. This is particularly | |
54 // relevant in this unit test, which uses the always-synchronous MEMORY_CACHE. | |
55 class DelayedReadEntry : public disk_cache::Entry { | |
56 public: | |
57 explicit DelayedReadEntry(disk_cache::ScopedEntryPtr entry) | |
58 : entry_(entry.Pass()) {} | |
59 ~DelayedReadEntry() override { EXPECT_FALSE(HasPendingReadCallbacks()); } | |
60 | |
61 bool HasPendingReadCallbacks() { return !pending_read_callbacks_.empty(); } | |
62 | |
63 void RunPendingReadCallbacks() { | |
64 std::vector<base::Callback<void(void)>> callbacks; | |
65 pending_read_callbacks_.swap(callbacks); | |
66 for (const auto& callback : callbacks) | |
67 callback.Run(); | |
68 } | |
69 | |
70 // From disk_cache::Entry: | |
71 void Doom() override { entry_->Doom(); } | |
72 | |
73 void Close() override { delete this; } // Note this is required by the API. | |
74 | |
75 std::string GetKey() const override { return entry_->GetKey(); } | |
76 | |
77 base::Time GetLastUsed() const override { return entry_->GetLastUsed(); } | |
78 | |
79 base::Time GetLastModified() const override { | |
80 return entry_->GetLastModified(); | |
81 } | |
82 | |
83 int32 GetDataSize(int index) const override { | |
84 return entry_->GetDataSize(index); | |
85 } | |
86 | |
87 int ReadData(int index, | |
88 int offset, | |
89 IOBuffer* buf, | |
90 int buf_len, | |
91 const CompletionCallback& original_callback) override { | |
92 net::TestCompletionCallback callback; | |
93 int rv = entry_->ReadData(index, offset, buf, buf_len, callback.callback()); | |
94 DCHECK_NE(rv, net::ERR_IO_PENDING) | |
95 << "Test expects to use a MEMORY_CACHE instance, which is synchronous."; | |
96 pending_read_callbacks_.push_back(base::Bind(original_callback, rv)); | |
97 return net::ERR_IO_PENDING; | |
98 } | |
99 | |
100 int WriteData(int index, | |
101 int offset, | |
102 IOBuffer* buf, | |
103 int buf_len, | |
104 const CompletionCallback& callback, | |
105 bool truncate) override { | |
106 return entry_->WriteData(index, offset, buf, buf_len, callback, truncate); | |
107 } | |
108 | |
109 int ReadSparseData(int64 offset, | |
110 IOBuffer* buf, | |
111 int buf_len, | |
112 const CompletionCallback& callback) override { | |
113 return entry_->ReadSparseData(offset, buf, buf_len, callback); | |
114 } | |
115 | |
116 int WriteSparseData(int64 offset, | |
117 IOBuffer* buf, | |
118 int buf_len, | |
119 const CompletionCallback& callback) override { | |
120 return entry_->WriteSparseData(offset, buf, buf_len, callback); | |
121 } | |
122 | |
123 int GetAvailableRange(int64 offset, | |
124 int len, | |
125 int64* start, | |
126 const CompletionCallback& callback) override { | |
127 return entry_->GetAvailableRange(offset, len, start, callback); | |
128 } | |
129 | |
130 bool CouldBeSparse() const override { return entry_->CouldBeSparse(); } | |
131 | |
132 void CancelSparseIO() override { entry_->CancelSparseIO(); } | |
133 | |
134 int ReadyForSparseIO(const CompletionCallback& callback) override { | |
135 return entry_->ReadyForSparseIO(callback); | |
136 } | |
137 | |
138 private: | |
139 disk_cache::ScopedEntryPtr entry_; | |
140 std::vector<base::Callback<void(void)>> pending_read_callbacks_; | |
141 }; | |
142 | |
143 scoped_ptr<disk_cache::Backend> CreateInMemoryDiskCache( | |
144 const scoped_refptr<base::SingleThreadTaskRunner>& thread) { | |
145 scoped_ptr<disk_cache::Backend> cache; | |
146 net::TestCompletionCallback callback; | |
147 int rv = disk_cache::CreateCacheBackend( | |
148 net::MEMORY_CACHE, net::CACHE_BACKEND_DEFAULT, FilePath(), 0, false, | |
149 thread, nullptr, &cache, callback.callback()); | |
150 EXPECT_EQ(net::OK, callback.GetResult(rv)); | |
151 | |
152 return cache.Pass(); | |
153 } | |
154 | |
155 disk_cache::ScopedEntryPtr CreateDiskCacheEntry(disk_cache::Backend* cache, | |
156 const char* key, | |
157 const std::string& data) { | |
158 disk_cache::Entry* temp_entry = nullptr; | |
159 net::TestCompletionCallback callback; | |
160 int rv = cache->CreateEntry(key, &temp_entry, callback.callback()); | |
161 if (callback.GetResult(rv) != net::OK) | |
162 return nullptr; | |
163 disk_cache::ScopedEntryPtr entry(temp_entry); | |
164 | |
165 scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data); | |
166 rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(), | |
167 iobuffer->size(), callback.callback(), false); | |
168 EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv)); | |
169 return entry.Pass(); | |
170 } | |
171 | |
172 template <typename T> | |
173 void SetValue(T* address, T value) { | |
174 *address = value; | |
175 } | |
176 | |
177 class FakeFileStreamReader : public FileStreamReader { | |
178 public: | |
179 explicit FakeFileStreamReader(const std::string& contents) | |
180 : buffer_(new DrainableIOBuffer( | |
181 new net::StringIOBuffer( | |
182 scoped_ptr<std::string>(new std::string(contents))), | |
183 contents.size())), | |
184 net_error_(net::OK), | |
185 size_(contents.size()) {} | |
186 FakeFileStreamReader(const std::string& contents, uint64_t size) | |
187 : buffer_(new DrainableIOBuffer( | |
188 new net::StringIOBuffer( | |
189 scoped_ptr<std::string>(new std::string(contents))), | |
190 contents.size())), | |
191 net_error_(net::OK), | |
192 size_(size) {} | |
193 | |
194 ~FakeFileStreamReader() override {} | |
195 | |
196 void SetReturnError(int net_error) { net_error_ = net_error; } | |
197 | |
198 void SetAsyncRunner(base::SingleThreadTaskRunner* runner) { | |
199 async_task_runner_ = runner; | |
200 } | |
201 | |
202 int Read(net::IOBuffer* buf, | |
203 int buf_length, | |
204 const net::CompletionCallback& done) override { | |
205 DCHECK(buf); | |
206 // When async_task_runner_ is not set, return synchronously. | |
207 if (!async_task_runner_.get()) { | |
208 if (net_error_ == net::OK) { | |
209 return ReadImpl(buf, buf_length, net::CompletionCallback()); | |
210 } else { | |
211 return net_error_; | |
212 } | |
213 } | |
214 | |
215 // Otherwise always return asynchronously. | |
216 if (net_error_ == net::OK) { | |
217 async_task_runner_->PostTask( | |
218 FROM_HERE, | |
219 base::Bind(base::IgnoreResult(&FakeFileStreamReader::ReadImpl), | |
220 base::Unretained(this), make_scoped_refptr(buf), | |
221 buf_length, done)); | |
222 } else { | |
223 async_task_runner_->PostTask(FROM_HERE, base::Bind(done, net_error_)); | |
224 } | |
225 return net::ERR_IO_PENDING; | |
226 } | |
227 | |
228 int64 GetLength(const net::Int64CompletionCallback& size_callback) override { | |
229 // When async_task_runner_ is not set, return synchronously. | |
230 if (!async_task_runner_.get()) { | |
231 if (net_error_ == net::OK) { | |
232 return size_; | |
233 } else { | |
234 return net_error_; | |
235 } | |
236 } | |
237 if (net_error_ == net::OK) { | |
238 async_task_runner_->PostTask(FROM_HERE, base::Bind(size_callback, size_)); | |
239 } else { | |
240 async_task_runner_->PostTask( | |
241 FROM_HERE, | |
242 base::Bind(size_callback, static_cast<int64_t>(net_error_))); | |
243 } | |
244 return net::ERR_IO_PENDING; | |
245 } | |
246 | |
247 private: | |
248 int ReadImpl(scoped_refptr<net::IOBuffer> buf, int buf_length, | |
249 const net::CompletionCallback& done) { | |
250 CHECK_GE(buf_length, 0); | |
251 int length = std::min(buf_length, buffer_->BytesRemaining()); | |
252 memcpy(buf->data(), buffer_->data(), length); | |
253 buffer_->DidConsume(length); | |
254 if (done.is_null()) { | |
255 return length; | |
256 } | |
257 done.Run(length); | |
258 return net::ERR_IO_PENDING; | |
259 } | |
260 | |
261 scoped_refptr<net::DrainableIOBuffer> buffer_; | |
262 scoped_refptr<base::SingleThreadTaskRunner> async_task_runner_; | |
263 int net_error_; | |
264 uint64_t size_; | |
265 | |
266 DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader); | |
267 }; | |
268 | |
269 class MockFileStreamReaderProvider | |
270 : public BlobReader::FileStreamReaderProvider { | |
271 public: | |
272 ~MockFileStreamReaderProvider() override {} | |
273 | |
274 MOCK_METHOD4(CreateForLocalFileMock, | |
275 FileStreamReader*(base::TaskRunner* task_runner, | |
276 const FilePath& file_path, | |
277 int64_t initial_offset, | |
278 const base::Time& expected_modification_time)); | |
279 MOCK_METHOD4(CreateFileStreamReaderMock, | |
280 FileStreamReader*(const GURL& filesystem_url, | |
281 int64_t offset, | |
282 int64_t max_bytes_to_read, | |
283 const base::Time& expected_modification_time)); | |
284 // Since we're returning a move-only type, we have to do some delegation for | |
285 // gmock. | |
286 scoped_ptr<FileStreamReader> CreateForLocalFile( | |
287 base::TaskRunner* task_runner, | |
288 const base::FilePath& file_path, | |
289 int64_t initial_offset, | |
290 const base::Time& expected_modification_time) override { | |
291 return make_scoped_ptr(CreateForLocalFileMock( | |
292 task_runner, file_path, initial_offset, expected_modification_time)); | |
293 } | |
294 | |
295 scoped_ptr<FileStreamReader> CreateFileStreamReader( | |
296 const GURL& filesystem_url, | |
297 int64_t offset, | |
298 int64_t max_bytes_to_read, | |
299 const base::Time& expected_modification_time) override { | |
300 return make_scoped_ptr(CreateFileStreamReaderMock( | |
301 filesystem_url, offset, max_bytes_to_read, expected_modification_time)); | |
302 } | |
303 }; | |
304 | |
305 } // namespace | |
306 | |
307 class BlobReaderTest : public ::testing::Test { | |
308 public: | |
309 BlobReaderTest() {} | |
310 ~BlobReaderTest() override {} | |
311 | |
312 void TearDown() override { | |
313 reader_.reset(); | |
314 blob_handle_.reset(); | |
315 message_loop_.RunUntilIdle(); | |
316 base::RunLoop().RunUntilIdle(); | |
317 } | |
318 | |
319 protected: | |
320 void InitializeReader(BlobDataBuilder* builder) { | |
321 blob_handle_ = builder ? context_.AddFinishedBlob(builder).Pass() : nullptr; | |
322 provider_ = new MockFileStreamReaderProvider(); | |
323 scoped_ptr<BlobReader::FileStreamReaderProvider> temp_ptr(provider_); | |
324 reader_.reset(new BlobReader(blob_handle_.get(), temp_ptr.Pass(), | |
325 message_loop_.task_runner().get())); | |
326 } | |
327 | |
328 // Takes ownership of the file reader (the blob reader takes ownership). | |
329 void ExpectLocalFileCall(const FilePath& file_path, | |
330 base::Time modification_time, | |
331 uint64_t initial_offset, | |
332 FakeFileStreamReader* reader) { | |
333 EXPECT_CALL(*provider_, CreateForLocalFileMock( | |
334 message_loop_.task_runner().get(), file_path, | |
335 initial_offset, modification_time)) | |
336 .WillOnce(testing::Return(reader)); | |
337 } | |
338 | |
339 // Takes ownership of the file reader (the blob reader takes ownership). | |
340 void ExpectFileSystemCall(const GURL& filesystem_url, | |
341 int64_t offset, | |
342 int64_t max_bytes_to_read, | |
343 base::Time expected_modification_time, | |
344 FakeFileStreamReader* reader) { | |
345 EXPECT_CALL(*provider_, CreateFileStreamReaderMock( | |
346 filesystem_url, offset, max_bytes_to_read, | |
347 expected_modification_time)) | |
348 .WillOnce(testing::Return(reader)); | |
349 } | |
350 | |
351 void CheckSizeCalculatedSynchronously(size_t expected_size, int async_size) { | |
352 EXPECT_EQ(-1, async_size); | |
353 EXPECT_EQ(net::OK, reader_->net_error()); | |
354 EXPECT_EQ(expected_size, reader_->total_size()); | |
355 EXPECT_TRUE(reader_->total_size_calculated()); | |
356 } | |
357 | |
358 void CheckSizeNotCalculatedYet(int async_size) { | |
359 EXPECT_EQ(-1, async_size); | |
360 EXPECT_EQ(net::OK, reader_->net_error()); | |
361 EXPECT_FALSE(reader_->total_size_calculated()); | |
362 } | |
363 | |
364 void CheckSizeCalculatedAsynchronously(size_t expected_size, | |
365 int async_result) { | |
366 EXPECT_EQ(net::OK, async_result); | |
367 EXPECT_EQ(net::OK, reader_->net_error()); | |
368 EXPECT_EQ(expected_size, reader_->total_size()); | |
369 EXPECT_TRUE(reader_->total_size_calculated()); | |
370 } | |
371 | |
372 scoped_refptr<net::IOBuffer> CreateBuffer(uint64_t size) { | |
373 return scoped_refptr<net::IOBuffer>( | |
374 new net::IOBuffer(static_cast<size_t>(size))); | |
375 } | |
376 | |
377 bool IsReaderTotalSizeCalculated() { | |
378 return reader_->total_size_calculated(); | |
379 } | |
380 | |
381 BlobStorageContext context_; | |
382 scoped_ptr<BlobDataHandle> blob_handle_; | |
383 MockFileStreamReaderProvider* provider_ = nullptr; | |
384 base::MessageLoop message_loop_; | |
385 scoped_ptr<BlobReader> reader_; | |
386 | |
387 private: | |
388 DISALLOW_COPY_AND_ASSIGN(BlobReaderTest); | |
389 }; | |
390 | |
391 namespace { | |
392 | |
393 TEST_F(BlobReaderTest, BasicMemory) { | |
394 BlobDataBuilder b("uuid"); | |
395 const std::string kData("Hello!!!"); | |
396 const size_t kDataSize = 8ul; | |
397 b.AppendData(kData); | |
398 this->InitializeReader(&b); | |
399 | |
400 int size_result = -1; | |
401 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
402 EXPECT_EQ(BlobReader::Status::DONE, | |
403 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
404 CheckSizeCalculatedSynchronously(kDataSize, size_result); | |
405 | |
406 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kDataSize)); | |
407 | |
408 int bytes_read = 0; | |
409 int async_bytes_read = 0; | |
410 EXPECT_EQ(BlobReader::Status::DONE, | |
411 reader_->Read(buffer.get(), kDataSize, &bytes_read, | |
412 base::Bind(&SetValue<int>, &async_bytes_read))); | |
413 EXPECT_EQ(net::OK, reader_->net_error()); | |
414 EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read)); | |
415 EXPECT_EQ(0, async_bytes_read); | |
416 EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize)); | |
417 } | |
418 | |
419 TEST_F(BlobReaderTest, BasicFile) { | |
420 BlobDataBuilder b("uuid"); | |
421 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
422 const std::string kData = "FileData!!!"; | |
423 const base::Time kTime = base::Time::Now(); | |
424 b.AppendFile(kPath, 0, kData.size(), kTime); | |
425 this->InitializeReader(&b); | |
426 | |
427 // Non-async reader. | |
428 ExpectLocalFileCall(kPath, kTime, 0, new FakeFileStreamReader(kData)); | |
429 | |
430 int size_result = -1; | |
431 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
432 EXPECT_EQ(BlobReader::Status::DONE, | |
433 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
434 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
435 | |
436 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
437 | |
438 int bytes_read = 0; | |
439 int async_bytes_read = 0; | |
440 EXPECT_EQ(BlobReader::Status::DONE, | |
441 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
442 base::Bind(&SetValue<int>, &async_bytes_read))); | |
443 EXPECT_EQ(net::OK, reader_->net_error()); | |
444 EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read)); | |
445 EXPECT_EQ(0, async_bytes_read); | |
446 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
447 } | |
448 | |
449 TEST_F(BlobReaderTest, BasicFileSystem) { | |
450 BlobDataBuilder b("uuid"); | |
451 const GURL kURL("file://test_file/here.txt"); | |
452 const std::string kData = "FileData!!!"; | |
453 const base::Time kTime = base::Time::Now(); | |
454 b.AppendFileSystemFile(kURL, 0, kData.size(), kTime); | |
455 this->InitializeReader(&b); | |
456 | |
457 // Non-async reader. | |
458 ExpectFileSystemCall(kURL, 0, kData.size(), kTime, | |
459 new FakeFileStreamReader(kData)); | |
460 | |
461 int size_result = -1; | |
462 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
463 EXPECT_EQ(BlobReader::Status::DONE, | |
464 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
465 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
466 | |
467 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
468 | |
469 int bytes_read = 0; | |
470 int async_bytes_read = 0; | |
471 EXPECT_EQ(BlobReader::Status::DONE, | |
472 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
473 base::Bind(&SetValue<int>, &async_bytes_read))); | |
474 EXPECT_EQ(net::OK, reader_->net_error()); | |
475 EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read)); | |
476 EXPECT_EQ(0, async_bytes_read); | |
477 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
478 } | |
479 | |
480 TEST_F(BlobReaderTest, BasicDiskCache) { | |
481 scoped_ptr<disk_cache::Backend> cache = | |
482 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
483 ASSERT_TRUE(cache); | |
484 | |
485 BlobDataBuilder b("uuid"); | |
486 const std::string kData = "Test Blob Data"; | |
487 scoped_refptr<BlobDataBuilder::DataHandle> data_handle = | |
488 new EmptyDataHandle(); | |
489 disk_cache::ScopedEntryPtr entry = | |
490 CreateDiskCacheEntry(cache.get(), "test entry", kData); | |
491 b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex); | |
492 this->InitializeReader(&b); | |
493 | |
494 int size_result = -1; | |
495 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
496 EXPECT_EQ(BlobReader::Status::DONE, | |
497 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
498 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
499 | |
500 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
501 | |
502 int bytes_read = 0; | |
503 int async_bytes_read = 0; | |
504 EXPECT_EQ(BlobReader::Status::DONE, | |
505 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
506 base::Bind(&SetValue<int>, &async_bytes_read))); | |
507 EXPECT_EQ(net::OK, reader_->net_error()); | |
508 EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read)); | |
509 EXPECT_EQ(0, async_bytes_read); | |
510 EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size())); | |
511 } | |
512 | |
513 TEST_F(BlobReaderTest, BufferLargerThanMemory) { | |
514 BlobDataBuilder b("uuid"); | |
515 const std::string kData("Hello!!!"); | |
516 const size_t kDataSize = 8ul; | |
517 const size_t kBufferSize = 10ul; | |
518 b.AppendData(kData); | |
519 this->InitializeReader(&b); | |
520 | |
521 int size_result = -1; | |
522 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
523 EXPECT_EQ(BlobReader::Status::DONE, | |
524 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
525 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
526 | |
527 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
528 | |
529 int bytes_read = 0; | |
530 int async_bytes_read = 0; | |
531 EXPECT_EQ(BlobReader::Status::DONE, | |
532 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
533 base::Bind(&SetValue<int>, &async_bytes_read))); | |
534 EXPECT_EQ(net::OK, reader_->net_error()); | |
535 EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read)); | |
536 EXPECT_EQ(0, async_bytes_read); | |
537 EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize)); | |
538 } | |
539 | |
540 TEST_F(BlobReaderTest, MemoryRange) { | |
541 BlobDataBuilder b("uuid"); | |
542 const std::string kData("Hello!!!"); | |
543 const size_t kDataSize = 8ul; | |
544 const size_t kSeekOffset = 2ul; | |
545 const uint64_t kReadLength = 4ull; | |
546 b.AppendData(kData); | |
547 this->InitializeReader(&b); | |
548 | |
549 int size_result = -1; | |
550 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
551 EXPECT_EQ(BlobReader::Status::DONE, | |
552 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
553 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
554 | |
555 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength); | |
556 | |
557 reader_->SetReadRange(kSeekOffset, kReadLength); | |
558 int bytes_read = 0; | |
559 int async_bytes_read = 0; | |
560 EXPECT_EQ(BlobReader::Status::DONE, | |
561 reader_->Read(buffer.get(), kDataSize - kSeekOffset, &bytes_read, | |
562 base::Bind(&SetValue<int>, &async_bytes_read))); | |
563 EXPECT_EQ(net::OK, reader_->net_error()); | |
564 EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read)); | |
565 EXPECT_EQ(0, async_bytes_read); | |
566 EXPECT_EQ(0, memcmp(buffer->data(), "llo!", kReadLength)); | |
567 } | |
568 | |
569 TEST_F(BlobReaderTest, BufferSmallerThanMemory) { | |
570 BlobDataBuilder b("uuid"); | |
571 const std::string kData("Hello!!!"); | |
572 const size_t kBufferSize = 4ul; | |
573 b.AppendData(kData); | |
574 this->InitializeReader(&b); | |
575 | |
576 int size_result = -1; | |
577 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
578 EXPECT_EQ(BlobReader::Status::DONE, | |
579 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
580 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
581 | |
582 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
583 | |
584 int bytes_read = 0; | |
585 int async_bytes_read = 0; | |
586 EXPECT_EQ(BlobReader::Status::DONE, | |
587 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
588 base::Bind(&SetValue<int>, &async_bytes_read))); | |
589 EXPECT_EQ(net::OK, reader_->net_error()); | |
590 EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read)); | |
591 EXPECT_EQ(0, async_bytes_read); | |
592 EXPECT_EQ(0, memcmp(buffer->data(), "Hell", kBufferSize)); | |
593 | |
594 bytes_read = 0; | |
595 EXPECT_EQ(BlobReader::Status::DONE, | |
596 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
597 base::Bind(&SetValue<int>, &async_bytes_read))); | |
598 EXPECT_EQ(net::OK, reader_->net_error()); | |
599 EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read)); | |
600 EXPECT_EQ(0, async_bytes_read); | |
601 EXPECT_EQ(0, memcmp(buffer->data(), "o!!!", kBufferSize)); | |
602 } | |
603 | |
604 TEST_F(BlobReaderTest, SegmentedBufferAndMemory) { | |
605 BlobDataBuilder b("uuid"); | |
606 const size_t kNumItems = 10; | |
607 const size_t kItemSize = 6; | |
608 const size_t kBufferSize = 10; | |
609 const size_t kTotalSize = kNumItems * kItemSize; | |
610 char current_value = 0; | |
611 for (size_t i = 0; i < kNumItems; i++) { | |
612 char buf[kItemSize]; | |
613 for (size_t j = 0; j < kItemSize; j++) { | |
614 buf[j] = current_value++; | |
615 } | |
616 b.AppendData(buf, kItemSize); | |
617 } | |
618 this->InitializeReader(&b); | |
619 | |
620 int size_result = -1; | |
621 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
622 EXPECT_EQ(BlobReader::Status::DONE, | |
623 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
624 CheckSizeCalculatedSynchronously(kTotalSize, size_result); | |
625 | |
626 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
627 | |
628 current_value = 0; | |
629 for (size_t i = 0; i < kTotalSize / kBufferSize; i++) { | |
630 int bytes_read = 0; | |
631 int async_bytes_read = 0; | |
632 EXPECT_EQ(BlobReader::Status::DONE, | |
633 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
634 base::Bind(&SetValue<int>, &async_bytes_read))); | |
635 EXPECT_EQ(net::OK, reader_->net_error()); | |
636 EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read)); | |
637 EXPECT_EQ(0, async_bytes_read); | |
638 for (size_t j = 0; j < kBufferSize; j++) { | |
639 EXPECT_EQ(current_value, buffer->data()[j]); | |
640 current_value++; | |
641 } | |
642 } | |
643 } | |
644 | |
645 TEST_F(BlobReaderTest, FileAsync) { | |
646 BlobDataBuilder b("uuid"); | |
647 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
648 const std::string kData = "FileData!!!"; | |
649 const base::Time kTime = base::Time::Now(); | |
650 b.AppendFile(kPath, 0, kData.size(), kTime); | |
651 this->InitializeReader(&b); | |
652 | |
653 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData)); | |
654 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
655 | |
656 ExpectLocalFileCall(kPath, kTime, 0, reader.release()); | |
657 | |
658 int size_result = -1; | |
659 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
660 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
661 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
662 CheckSizeNotCalculatedYet(size_result); | |
663 message_loop_.RunUntilIdle(); | |
664 CheckSizeCalculatedAsynchronously(kData.size(), size_result); | |
665 | |
666 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
667 | |
668 int bytes_read = 0; | |
669 int async_bytes_read = 0; | |
670 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
671 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
672 base::Bind(&SetValue<int>, &async_bytes_read))); | |
673 message_loop_.RunUntilIdle(); | |
674 EXPECT_EQ(net::OK, reader_->net_error()); | |
675 EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read)); | |
676 EXPECT_EQ(0, bytes_read); | |
677 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
678 } | |
679 | |
680 TEST_F(BlobReaderTest, FileSystemAsync) { | |
681 BlobDataBuilder b("uuid"); | |
682 const GURL kURL("file://test_file/here.txt"); | |
683 const std::string kData = "FileData!!!"; | |
684 const base::Time kTime = base::Time::Now(); | |
685 b.AppendFileSystemFile(kURL, 0, kData.size(), kTime); | |
686 this->InitializeReader(&b); | |
687 | |
688 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData)); | |
689 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
690 | |
691 ExpectFileSystemCall(kURL, 0, kData.size(), kTime, reader.release()); | |
692 | |
693 int size_result = -1; | |
694 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
695 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
696 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
697 CheckSizeNotCalculatedYet(size_result); | |
698 message_loop_.RunUntilIdle(); | |
699 CheckSizeCalculatedAsynchronously(kData.size(), size_result); | |
700 | |
701 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
702 | |
703 int bytes_read = 0; | |
704 int async_bytes_read = 0; | |
705 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
706 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
707 base::Bind(&SetValue<int>, &async_bytes_read))); | |
708 message_loop_.RunUntilIdle(); | |
709 EXPECT_EQ(net::OK, reader_->net_error()); | |
710 EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read)); | |
711 EXPECT_EQ(0, bytes_read); | |
712 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
713 } | |
714 | |
715 TEST_F(BlobReaderTest, DiskCacheAsync) { | |
716 scoped_ptr<disk_cache::Backend> cache = | |
717 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
718 ASSERT_TRUE(cache); | |
719 | |
720 BlobDataBuilder b("uuid"); | |
721 const std::string kData = "Test Blob Data"; | |
722 scoped_refptr<BlobDataBuilder::DataHandle> data_handle = | |
723 new EmptyDataHandle(); | |
724 scoped_ptr<DelayedReadEntry> delayed_read_entry(new DelayedReadEntry( | |
725 CreateDiskCacheEntry(cache.get(), "test entry", kData).Pass())); | |
726 b.AppendDiskCacheEntry(data_handle, delayed_read_entry.get(), | |
727 kTestDiskCacheStreamIndex); | |
728 this->InitializeReader(&b); | |
729 | |
730 int size_result = -1; | |
731 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
732 EXPECT_EQ(BlobReader::Status::DONE, | |
733 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
734 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
735 | |
736 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
737 | |
738 int bytes_read = 0; | |
739 int async_bytes_read = 0; | |
740 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
741 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
742 base::Bind(&SetValue<int>, &async_bytes_read))); | |
743 EXPECT_TRUE(delayed_read_entry->HasPendingReadCallbacks()); | |
744 delayed_read_entry->RunPendingReadCallbacks(); | |
745 EXPECT_EQ(net::OK, reader_->net_error()); | |
746 EXPECT_EQ(0, bytes_read); | |
747 EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read)); | |
748 EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size())); | |
749 } | |
750 | |
751 TEST_F(BlobReaderTest, FileRange) { | |
752 BlobDataBuilder b("uuid"); | |
753 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
754 // We check the offset in the ExpectLocalFileCall mock. | |
755 const std::string kRangeData = "leD"; | |
756 const std::string kData = "FileData!!!"; | |
757 const uint64_t kOffset = 2; | |
758 const uint64_t kReadLength = 3; | |
759 const base::Time kTime = base::Time::Now(); | |
760 b.AppendFile(kPath, 0, kData.size(), kTime); | |
761 this->InitializeReader(&b); | |
762 | |
763 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData)); | |
764 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
765 ExpectLocalFileCall(kPath, kTime, 0, reader.release()); | |
766 | |
767 // We create the reader again with the offset after the seek. | |
768 reader.reset(new FakeFileStreamReader(kRangeData)); | |
769 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
770 ExpectLocalFileCall(kPath, kTime, kOffset, reader.release()); | |
771 | |
772 int size_result = -1; | |
773 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
774 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
775 message_loop_.RunUntilIdle(); | |
776 | |
777 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength); | |
778 EXPECT_EQ(BlobReader::Status::DONE, | |
779 reader_->SetReadRange(kOffset, kReadLength)); | |
780 | |
781 int bytes_read = 0; | |
782 int async_bytes_read = 0; | |
783 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
784 reader_->Read(buffer.get(), kReadLength, &bytes_read, | |
785 base::Bind(&SetValue<int>, &async_bytes_read))); | |
786 message_loop_.RunUntilIdle(); | |
787 EXPECT_EQ(net::OK, reader_->net_error()); | |
788 EXPECT_EQ(kReadLength, static_cast<size_t>(async_bytes_read)); | |
789 EXPECT_EQ(0, bytes_read); | |
790 EXPECT_EQ(0, memcmp(buffer->data(), "leD", kReadLength)); | |
791 } | |
792 | |
793 TEST_F(BlobReaderTest, DiskCacheRange) { | |
794 scoped_ptr<disk_cache::Backend> cache = | |
795 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
796 ASSERT_TRUE(cache); | |
797 | |
798 BlobDataBuilder b("uuid"); | |
799 const std::string kData = "Test Blob Data"; | |
800 const uint64_t kOffset = 2; | |
801 const uint64_t kReadLength = 3; | |
802 scoped_refptr<BlobDataBuilder::DataHandle> data_handle = | |
803 new EmptyDataHandle(); | |
804 disk_cache::ScopedEntryPtr entry = | |
805 CreateDiskCacheEntry(cache.get(), "test entry", kData); | |
806 b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex); | |
807 this->InitializeReader(&b); | |
808 | |
809 int size_result = -1; | |
810 EXPECT_EQ(BlobReader::Status::DONE, | |
811 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
812 | |
813 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength); | |
814 EXPECT_EQ(BlobReader::Status::DONE, | |
815 reader_->SetReadRange(kOffset, kReadLength)); | |
816 | |
817 int bytes_read = 0; | |
818 int async_bytes_read = 0; | |
819 EXPECT_EQ(BlobReader::Status::DONE, | |
820 reader_->Read(buffer.get(), kReadLength, &bytes_read, | |
821 base::Bind(&SetValue<int>, &async_bytes_read))); | |
822 EXPECT_EQ(net::OK, reader_->net_error()); | |
823 EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read)); | |
824 EXPECT_EQ(0, async_bytes_read); | |
825 EXPECT_EQ(0, memcmp(buffer->data(), "st ", kReadLength)); | |
826 } | |
827 | |
828 TEST_F(BlobReaderTest, FileSomeAsyncSegmentedOffsetsUnknownSizes) { | |
829 // This tests includes: | |
830 // * Unknown file sizes (item length of uint64::max) for every other item. | |
831 // * Offsets for every 3rd file item. | |
832 // * Non-async reader for every 4th file item. | |
833 BlobDataBuilder b("uuid"); | |
834 const FilePath kPathBase = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
835 const base::Time kTime = base::Time::Now(); | |
836 const size_t kNumItems = 10; | |
837 const size_t kItemSize = 6; | |
838 const size_t kBufferSize = 10; | |
839 const size_t kTotalSize = kNumItems * kItemSize; | |
840 char current_value = 0; | |
841 // Create blob and reader. | |
842 for (size_t i = 0; i < kNumItems; i++) { | |
843 current_value += kItemSize; | |
844 FilePath path = kPathBase.Append( | |
845 FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value))); | |
846 uint64_t offset = i % 3 == 0 ? 1 : 0; | |
847 uint64_t size = | |
848 i % 2 == 0 ? kItemSize : std::numeric_limits<uint64_t>::max(); | |
849 b.AppendFile(path, offset, size, kTime); | |
850 } | |
851 this->InitializeReader(&b); | |
852 | |
853 // Set expectations. | |
854 current_value = 0; | |
855 for (size_t i = 0; i < kNumItems; i++) { | |
856 uint64_t offset = i % 3 == 0 ? 1 : 0; | |
857 scoped_ptr<char[]> buf(new char[kItemSize + offset]); | |
858 if (offset > 0) { | |
859 memset(buf.get(), 7, offset); | |
860 } | |
861 for (size_t j = 0; j < kItemSize; j++) { | |
862 buf.get()[j + offset] = current_value++; | |
863 } | |
864 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader( | |
865 std::string(buf.get() + offset, kItemSize), kItemSize + offset)); | |
866 if (i % 4 != 0) { | |
867 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
868 } | |
869 FilePath path = kPathBase.Append( | |
870 FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value))); | |
871 ExpectLocalFileCall(path, kTime, offset, reader.release()); | |
872 } | |
873 | |
874 int size_result = -1; | |
875 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
876 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
877 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
878 CheckSizeNotCalculatedYet(size_result); | |
879 message_loop_.RunUntilIdle(); | |
880 CheckSizeCalculatedAsynchronously(kTotalSize, size_result); | |
881 | |
882 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
883 | |
884 current_value = 0; | |
885 for (size_t i = 0; i < kTotalSize / kBufferSize; i++) { | |
886 int bytes_read = 0; | |
887 int async_bytes_read = 0; | |
888 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
889 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
890 base::Bind(&SetValue<int>, &async_bytes_read))); | |
891 message_loop_.RunUntilIdle(); | |
892 EXPECT_EQ(net::OK, reader_->net_error()); | |
893 EXPECT_EQ(0, bytes_read); | |
894 EXPECT_EQ(kBufferSize, static_cast<size_t>(async_bytes_read)); | |
895 for (size_t j = 0; j < kBufferSize; j++) { | |
896 EXPECT_EQ(current_value, buffer->data()[j]); | |
897 current_value++; | |
898 } | |
899 } | |
900 } | |
901 | |
902 TEST_F(BlobReaderTest, MixedContent) { | |
903 // Includes data, a file, and a disk cache entry. | |
904 scoped_ptr<disk_cache::Backend> cache = | |
905 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
906 ASSERT_TRUE(cache); | |
907 | |
908 BlobDataBuilder b("uuid"); | |
909 const std::string kData1("Hello "); | |
910 const std::string kData2("there. "); | |
911 const std::string kData3("This "); | |
912 const std::string kData4("is multi-content."); | |
913 const uint64_t kDataSize = 35; | |
914 | |
915 const base::Time kTime = base::Time::Now(); | |
916 const FilePath kData1Path = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
917 | |
918 disk_cache::ScopedEntryPtr entry3 = | |
919 CreateDiskCacheEntry(cache.get(), "test entry", kData3); | |
920 | |
921 b.AppendFile(kData1Path, 0, kData1.size(), kTime); | |
922 b.AppendData(kData2); | |
923 b.AppendDiskCacheEntry( | |
924 scoped_refptr<BlobDataBuilder::DataHandle>(new EmptyDataHandle()), | |
925 entry3.get(), kTestDiskCacheStreamIndex); | |
926 b.AppendData(kData4); | |
927 | |
928 this->InitializeReader(&b); | |
929 | |
930 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData1)); | |
931 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
932 ExpectLocalFileCall(kData1Path, kTime, 0, reader.release()); | |
933 | |
934 int size_result = -1; | |
935 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
936 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
937 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
938 CheckSizeNotCalculatedYet(size_result); | |
939 message_loop_.RunUntilIdle(); | |
940 CheckSizeCalculatedAsynchronously(kDataSize, size_result); | |
941 | |
942 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize); | |
943 | |
944 int bytes_read = 0; | |
945 int async_bytes_read = 0; | |
946 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
947 reader_->Read(buffer.get(), kDataSize, &bytes_read, | |
948 base::Bind(&SetValue<int>, &async_bytes_read))); | |
949 EXPECT_EQ(0, async_bytes_read); | |
950 message_loop_.RunUntilIdle(); | |
951 EXPECT_EQ(net::OK, reader_->net_error()); | |
952 EXPECT_EQ(0, bytes_read); | |
953 EXPECT_EQ(kDataSize, static_cast<size_t>(async_bytes_read)); | |
954 EXPECT_EQ(0, memcmp(buffer->data(), "Hello there. This is multi-content.", | |
955 kDataSize)); | |
956 } | |
957 | |
958 TEST_F(BlobReaderTest, StateErrors) { | |
959 // Test common variables | |
960 int bytes_read = -1; | |
961 int async_bytes_read = -1; | |
962 int size_result = -1; | |
963 const std::string kData("Hello!!!"); | |
964 | |
965 // Case: Blob handle is a nullptr. | |
966 InitializeReader(nullptr); | |
967 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
968 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
969 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
970 EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10)); | |
971 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
972 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(10); | |
973 EXPECT_DEATH(reader_->Read(buffer.get(), 10, &bytes_read, | |
974 base::Bind(&SetValue<int>, &async_bytes_read)), | |
975 ".*total_size_calculated_.*"); | |
976 | |
977 // Case: Not calling CalculateSize before SetReadRange. | |
978 BlobDataBuilder builder1("uuid1"); | |
979 builder1.AppendData(kData); | |
980 InitializeReader(&builder1); | |
981 EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10)); | |
982 EXPECT_EQ(net::ERR_FAILED, reader_->net_error()); | |
983 EXPECT_DEATH(reader_->Read(buffer.get(), 10, &bytes_read, | |
984 base::Bind(&SetValue<int>, &async_bytes_read)), | |
985 ".*total_size_calculated_.*"); | |
986 | |
987 // Case: Not calling CalculateSize before Read. | |
988 BlobDataBuilder builder2("uuid2"); | |
989 builder2.AppendData(kData); | |
990 InitializeReader(&builder2); | |
991 EXPECT_DEATH(reader_->Read(buffer.get(), 10, &bytes_read, | |
992 base::Bind(&SetValue<int>, &async_bytes_read)), | |
993 ".*total_size_calculated_.*"); | |
994 } | |
995 | |
996 TEST_F(BlobReaderTest, FileErrorsSync) { | |
997 int size_result = -1; | |
998 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
999 const std::string kData = "FileData!!!"; | |
1000 const base::Time kTime = base::Time::Now(); | |
1001 | |
1002 // Case: Error on length query. | |
1003 BlobDataBuilder builder1("uuid1"); | |
1004 builder1.AppendFile(kPath, 0, kData.size(), kTime); | |
1005 this->InitializeReader(&builder1); | |
1006 FakeFileStreamReader* reader = new FakeFileStreamReader(kData); | |
1007 reader->SetReturnError(net::ERR_FILE_NOT_FOUND); | |
1008 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1009 | |
1010 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1011 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1012 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1013 | |
1014 // Case: Error on read. | |
1015 BlobDataBuilder builder2("uuid2"); | |
1016 builder2.AppendFile(kPath, 0, kData.size(), kTime); | |
1017 this->InitializeReader(&builder2); | |
1018 reader = new FakeFileStreamReader(kData); | |
1019 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1020 EXPECT_EQ(BlobReader::Status::DONE, | |
1021 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1022 reader->SetReturnError(net::ERR_FILE_NOT_FOUND); | |
1023 | |
1024 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
1025 int bytes_read = 0; | |
1026 int async_bytes_read = 0; | |
1027 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1028 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
1029 base::Bind(&SetValue<int>, &async_bytes_read))); | |
1030 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1031 } | |
1032 | |
1033 TEST_F(BlobReaderTest, FileErrorsAsync) { | |
1034 int size_result = -1; | |
1035 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
1036 const std::string kData = "FileData!!!"; | |
1037 const base::Time kTime = base::Time::Now(); | |
1038 | |
1039 // Case: Error on length query. | |
1040 BlobDataBuilder builder1("uuid1"); | |
1041 builder1.AppendFile(kPath, 0, kData.size(), kTime); | |
1042 this->InitializeReader(&builder1); | |
1043 FakeFileStreamReader* reader = new FakeFileStreamReader(kData); | |
1044 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
1045 reader->SetReturnError(net::ERR_FILE_NOT_FOUND); | |
1046 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1047 | |
1048 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
1049 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1050 EXPECT_EQ(net::OK, reader_->net_error()); | |
1051 message_loop_.RunUntilIdle(); | |
1052 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, size_result); | |
1053 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1054 | |
1055 // Case: Error on read. | |
1056 BlobDataBuilder builder2("uuid2"); | |
1057 builder2.AppendFile(kPath, 0, kData.size(), kTime); | |
1058 this->InitializeReader(&builder2); | |
1059 reader = new FakeFileStreamReader(kData); | |
1060 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1061 EXPECT_EQ(BlobReader::Status::DONE, | |
1062 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1063 reader->SetReturnError(net::ERR_FILE_NOT_FOUND); | |
1064 reader->SetAsyncRunner(message_loop_.task_runner().get()); | |
1065 | |
1066 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
1067 int bytes_read = 0; | |
1068 int async_bytes_read = 0; | |
1069 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
1070 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
1071 base::Bind(&SetValue<int>, &async_bytes_read))); | |
1072 EXPECT_EQ(net::OK, reader_->net_error()); | |
1073 message_loop_.RunUntilIdle(); | |
1074 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, async_bytes_read); | |
1075 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1076 } | |
1077 | |
1078 TEST_F(BlobReaderTest, RangeError) { | |
1079 const std::string kData("Hello!!!"); | |
1080 const size_t kDataSize = 8ul; | |
1081 const uint64_t kReadLength = 4ull; | |
1082 | |
1083 // Case: offset too high. | |
1084 BlobDataBuilder b("uuid1"); | |
1085 b.AppendData(kData); | |
1086 this->InitializeReader(&b); | |
1087 int size_result = -1; | |
1088 EXPECT_EQ(BlobReader::Status::DONE, | |
1089 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1090 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize); | |
1091 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1092 reader_->SetReadRange(kDataSize + 1, kReadLength)); | |
1093 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1094 | |
1095 // Case: length too long. | |
1096 BlobDataBuilder b2("uuid2"); | |
1097 b2.AppendData(kData); | |
1098 this->InitializeReader(&b2); | |
1099 size_result = -1; | |
1100 EXPECT_EQ(BlobReader::Status::DONE, | |
1101 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1102 buffer = CreateBuffer(kDataSize + 1); | |
1103 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1104 reader_->SetReadRange(0, kDataSize + 1)); | |
1105 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1106 } | |
1107 | |
1108 } // namespace | |
1109 } // namespace storage | |
OLD | NEW |