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 void ReturnError(int net_error) { net_error_ = net_error; } | |
195 | |
196 void DoAsync(base::SingleThreadTaskRunner* runner) { | |
197 async_task_runner_ = runner; | |
198 } | |
199 | |
200 ~FakeFileStreamReader() override {} | |
201 | |
202 int Read(net::IOBuffer* buf, | |
203 int buf_length, | |
204 const net::CompletionCallback& done) override { | |
205 if (net_error_ == net::OK) { | |
206 if (async_task_runner_.get()) { | |
207 async_task_runner_->PostTask( | |
208 FROM_HERE, | |
209 base::Bind(base::IgnoreResult(&FakeFileStreamReader::ReadImpl), | |
210 base::Unretained(this), scoped_refptr<IOBuffer>(buf), | |
211 buf_length, done)); | |
212 return net::ERR_IO_PENDING; | |
213 } else { | |
214 return ReadImpl(buf, buf_length, net::CompletionCallback()); | |
215 } | |
216 } | |
217 if (async_task_runner_.get()) { | |
218 async_task_runner_->PostTask(FROM_HERE, base::Bind(done, net_error_)); | |
219 return net::ERR_IO_PENDING; | |
220 } | |
221 return net_error_; | |
222 } | |
223 | |
224 int64 GetLength(const net::Int64CompletionCallback& size_callback) override { | |
225 if (net_error_ == net::OK) { | |
226 if (async_task_runner_.get()) { | |
227 async_task_runner_->PostTask( | |
228 FROM_HERE, | |
229 base::Bind(base::IgnoreResult(&FakeFileStreamReader::GetLengthImpl), | |
230 base::Unretained(this), size_callback)); | |
231 return net::ERR_IO_PENDING; | |
232 } else { | |
233 return GetLengthImpl(net::Int64CompletionCallback()); | |
michaeln
2015/09/23 18:52:45
What is the purpose of the GetLenghtImpl helper? S
dmurph
2015/09/25 17:11:43
Yeah I'll just return size.
| |
234 } | |
235 } | |
236 if (async_task_runner_.get()) { | |
237 async_task_runner_->PostTask( | |
238 FROM_HERE, | |
239 base::Bind(size_callback, static_cast<int64_t>(net_error_))); | |
240 return net::ERR_IO_PENDING; | |
241 } | |
242 return net_error_; | |
243 } | |
244 | |
245 private: | |
246 int ReadImpl(scoped_refptr<net::IOBuffer> buf, | |
247 int buf_length, | |
248 const net::CompletionCallback& done) { | |
249 CHECK_GE(buf_length, 0); | |
250 int length = std::min(buf_length, buffer_->BytesRemaining()); | |
251 memcpy(buf->data(), buffer_->data(), length); | |
252 buffer_->DidConsume(length); | |
253 if (done.is_null()) { | |
254 return length; | |
255 } | |
256 done.Run(length); | |
257 return net::ERR_IO_PENDING; | |
258 } | |
259 | |
260 int64 GetLengthImpl(const net::Int64CompletionCallback& size_callback) { | |
261 if (size_callback.is_null()) { | |
262 return size_; | |
263 } | |
264 size_callback.Run(size_); | |
265 return net::ERR_IO_PENDING; | |
michaeln
2015/09/23 18:52:45
looks odd to be calling the callback and returning
dmurph
2015/09/25 17:11:43
Yeah, I'll only use this as a callback, and switch
| |
266 } | |
267 | |
268 scoped_refptr<net::DrainableIOBuffer> buffer_; | |
269 scoped_refptr<base::SingleThreadTaskRunner> async_task_runner_; | |
270 int net_error_; | |
271 uint64_t size_; | |
272 | |
273 DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader); | |
274 }; | |
275 | |
276 class MockFileStreamReaderProvider | |
277 : public BlobReader::FileStreamReaderProvider { | |
278 public: | |
279 ~MockFileStreamReaderProvider() override {} | |
280 | |
281 MOCK_METHOD4(CreateForLocalFileMock, | |
282 FileStreamReader*(base::TaskRunner* task_runner, | |
283 const FilePath& file_path, | |
284 int64_t initial_offset, | |
285 const base::Time& expected_modification_time)); | |
286 MOCK_METHOD4(CreateFileStreamReaderMock, | |
287 FileStreamReader*(const GURL& filesystem_url, | |
288 int64_t offset, | |
289 int64_t max_bytes_to_read, | |
290 const base::Time& expected_modification_time)); | |
291 // Since we're returning a move-only type, we have to do some delegation for | |
292 // gmock. | |
293 scoped_ptr<FileStreamReader> CreateForLocalFile( | |
294 base::TaskRunner* task_runner, | |
295 const base::FilePath& file_path, | |
296 int64_t initial_offset, | |
297 const base::Time& expected_modification_time) override { | |
298 return make_scoped_ptr(CreateForLocalFileMock( | |
299 task_runner, file_path, initial_offset, expected_modification_time)); | |
300 } | |
301 | |
302 scoped_ptr<FileStreamReader> CreateFileStreamReader( | |
303 const GURL& filesystem_url, | |
304 int64_t offset, | |
305 int64_t max_bytes_to_read, | |
306 const base::Time& expected_modification_time) override { | |
307 return make_scoped_ptr(CreateFileStreamReaderMock( | |
308 filesystem_url, offset, max_bytes_to_read, expected_modification_time)); | |
309 } | |
310 }; | |
311 | |
312 } // namespace | |
313 | |
314 class BlobReaderTest : public ::testing::Test { | |
315 public: | |
316 BlobReaderTest() {} | |
317 ~BlobReaderTest() override {} | |
318 | |
319 void TearDown() override { | |
320 reader_.reset(); | |
321 blob_handle_.reset(); | |
322 message_loop_.RunUntilIdle(); | |
323 base::RunLoop().RunUntilIdle(); | |
324 } | |
325 | |
326 protected: | |
327 void InitializeReader(BlobDataBuilder* builder) { | |
328 blob_handle_ = builder ? context_.AddFinishedBlob(builder).Pass() : nullptr; | |
329 provider_ = new MockFileStreamReaderProvider(); | |
330 scoped_ptr<BlobReader::FileStreamReaderProvider> temp_ptr(provider_); | |
331 reader_.reset(new BlobReader(blob_handle_.get(), temp_ptr.Pass(), | |
332 message_loop_.task_runner().get())); | |
333 } | |
334 | |
335 // Takes ownership of the file reader (the blob reader takes ownership). | |
336 void ExpectLocalFileCall(const FilePath& file_path, | |
337 base::Time modification_time, | |
338 uint64_t initial_offset, | |
339 FakeFileStreamReader* reader) { | |
340 EXPECT_CALL(*provider_, CreateForLocalFileMock( | |
341 message_loop_.task_runner().get(), file_path, | |
342 initial_offset, modification_time)) | |
343 .WillOnce(testing::Return(reader)); | |
344 } | |
345 | |
346 // Takes ownership of the file reader (the blob reader takes ownership). | |
347 void ExpectFileSystemCall(const GURL& filesystem_url, | |
348 int64_t offset, | |
349 int64_t max_bytes_to_read, | |
350 base::Time expected_modification_time, | |
351 FakeFileStreamReader* reader) { | |
352 EXPECT_CALL(*provider_, CreateFileStreamReaderMock( | |
353 filesystem_url, offset, max_bytes_to_read, | |
354 expected_modification_time)) | |
355 .WillOnce(testing::Return(reader)); | |
356 } | |
357 | |
358 void CheckSizeCalculatedSynchronously(size_t expected_size, int async_size) { | |
359 EXPECT_EQ(-1, async_size); | |
360 EXPECT_EQ(net::OK, reader_->net_error()); | |
361 EXPECT_EQ(expected_size, reader_->total_size()); | |
362 EXPECT_TRUE(reader_->total_size_calculated()); | |
363 } | |
364 | |
365 void CheckSizeNotCalculatedYet(int async_size) { | |
366 EXPECT_EQ(-1, async_size); | |
367 EXPECT_EQ(net::OK, reader_->net_error()); | |
368 EXPECT_FALSE(reader_->total_size_calculated()); | |
369 } | |
370 | |
371 void CheckSizeCalculatedAsynchronously(size_t expected_size, | |
372 int async_result) { | |
373 EXPECT_EQ(net::OK, async_result); | |
374 EXPECT_EQ(net::OK, reader_->net_error()); | |
375 EXPECT_EQ(expected_size, reader_->total_size()); | |
376 EXPECT_TRUE(reader_->total_size_calculated()); | |
377 } | |
378 | |
379 scoped_refptr<net::IOBuffer> CreateBuffer(uint64_t size) { | |
380 return scoped_refptr<net::IOBuffer>( | |
381 new net::IOBuffer(static_cast<size_t>(size))); | |
382 } | |
383 | |
384 bool IsReaderTotalSizeCalculated() { | |
385 return reader_->total_size_calculated(); | |
386 } | |
387 | |
388 BlobStorageContext context_; | |
389 scoped_ptr<BlobDataHandle> blob_handle_; | |
390 MockFileStreamReaderProvider* provider_ = nullptr; | |
391 base::MessageLoop message_loop_; | |
392 scoped_ptr<BlobReader> reader_; | |
393 | |
394 private: | |
395 DISALLOW_COPY_AND_ASSIGN(BlobReaderTest); | |
396 }; | |
397 | |
398 namespace { | |
399 | |
400 TEST_F(BlobReaderTest, BasicMemory) { | |
401 BlobDataBuilder b("uuid"); | |
402 const std::string kData("Hello!!!"); | |
403 const size_t kDataSize = 8ul; | |
404 b.AppendData(kData); | |
405 this->InitializeReader(&b); | |
406 | |
407 int size_result = -1; | |
408 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
409 EXPECT_EQ(BlobReader::Status::DONE, | |
410 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
411 CheckSizeCalculatedSynchronously(kDataSize, size_result); | |
412 | |
413 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kDataSize)); | |
414 | |
415 int bytes_read = 0; | |
416 int async_bytes_read = 0; | |
417 EXPECT_EQ(BlobReader::Status::DONE, | |
418 reader_->Read(buffer.get(), kDataSize, &bytes_read, | |
419 base::Bind(&SetValue<int>, &async_bytes_read))); | |
420 EXPECT_EQ(net::OK, reader_->net_error()); | |
421 EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read)); | |
422 EXPECT_EQ(0, async_bytes_read); | |
423 EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize)); | |
424 } | |
425 | |
426 TEST_F(BlobReaderTest, BasicFile) { | |
427 BlobDataBuilder b("uuid"); | |
428 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
429 const std::string kData = "FileData!!!"; | |
430 const base::Time kTime = base::Time::Now(); | |
431 b.AppendFile(kPath, 0, kData.size(), kTime); | |
432 this->InitializeReader(&b); | |
433 | |
434 // Non-async reader. | |
435 ExpectLocalFileCall(kPath, kTime, 0, new FakeFileStreamReader(kData)); | |
436 | |
437 int size_result = -1; | |
438 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
439 EXPECT_EQ(BlobReader::Status::DONE, | |
440 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
441 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
442 | |
443 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
444 | |
445 int bytes_read = 0; | |
446 int async_bytes_read = 0; | |
447 EXPECT_EQ(BlobReader::Status::DONE, | |
448 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
449 base::Bind(&SetValue<int>, &async_bytes_read))); | |
450 EXPECT_EQ(net::OK, reader_->net_error()); | |
451 EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read)); | |
452 EXPECT_EQ(0, async_bytes_read); | |
453 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
454 } | |
455 | |
456 TEST_F(BlobReaderTest, BasicFileSystem) { | |
457 BlobDataBuilder b("uuid"); | |
458 const GURL kURL("file://test_file/here.txt"); | |
459 const std::string kData = "FileData!!!"; | |
460 const base::Time kTime = base::Time::Now(); | |
461 b.AppendFileSystemFile(kURL, 0, kData.size(), kTime); | |
462 this->InitializeReader(&b); | |
463 | |
464 // Non-async reader. | |
465 ExpectFileSystemCall(kURL, 0, kData.size(), kTime, | |
466 new FakeFileStreamReader(kData)); | |
467 | |
468 int size_result = -1; | |
469 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
470 EXPECT_EQ(BlobReader::Status::DONE, | |
471 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
472 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
473 | |
474 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
475 | |
476 int bytes_read = 0; | |
477 int async_bytes_read = 0; | |
478 EXPECT_EQ(BlobReader::Status::DONE, | |
479 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
480 base::Bind(&SetValue<int>, &async_bytes_read))); | |
481 EXPECT_EQ(net::OK, reader_->net_error()); | |
482 EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read)); | |
483 EXPECT_EQ(0, async_bytes_read); | |
484 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
485 } | |
486 | |
487 TEST_F(BlobReaderTest, BasicDiskCache) { | |
488 scoped_ptr<disk_cache::Backend> cache = | |
489 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
490 ASSERT_TRUE(cache); | |
491 | |
492 BlobDataBuilder b("uuid"); | |
493 const std::string kData = "Test Blob Data"; | |
494 scoped_refptr<BlobDataBuilder::DataHandle> data_handle = | |
495 new EmptyDataHandle(); | |
496 disk_cache::ScopedEntryPtr entry = | |
497 CreateDiskCacheEntry(cache.get(), "test entry", kData); | |
498 b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex); | |
499 this->InitializeReader(&b); | |
500 | |
501 int size_result = -1; | |
502 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
503 EXPECT_EQ(BlobReader::Status::DONE, | |
504 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
505 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
506 | |
507 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
508 | |
509 int bytes_read = 0; | |
510 int async_bytes_read = 0; | |
511 EXPECT_EQ(BlobReader::Status::DONE, | |
512 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
513 base::Bind(&SetValue<int>, &async_bytes_read))); | |
514 EXPECT_EQ(net::OK, reader_->net_error()); | |
515 EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read)); | |
516 EXPECT_EQ(0, async_bytes_read); | |
517 EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size())); | |
518 } | |
519 | |
520 TEST_F(BlobReaderTest, BufferLargerThanMemory) { | |
521 BlobDataBuilder b("uuid"); | |
522 const std::string kData("Hello!!!"); | |
523 const size_t kDataSize = 8ul; | |
524 const size_t kBufferSize = 10ul; | |
525 b.AppendData(kData); | |
526 this->InitializeReader(&b); | |
527 | |
528 int size_result = -1; | |
529 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
530 EXPECT_EQ(BlobReader::Status::DONE, | |
531 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
532 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
533 | |
534 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
535 | |
536 int bytes_read = 0; | |
537 int async_bytes_read = 0; | |
538 EXPECT_EQ(BlobReader::Status::DONE, | |
539 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
540 base::Bind(&SetValue<int>, &async_bytes_read))); | |
541 EXPECT_EQ(net::OK, reader_->net_error()); | |
542 EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read)); | |
543 EXPECT_EQ(0, async_bytes_read); | |
544 EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize)); | |
545 } | |
546 | |
547 TEST_F(BlobReaderTest, MemoryRange) { | |
548 BlobDataBuilder b("uuid"); | |
549 const std::string kData("Hello!!!"); | |
550 const size_t kDataSize = 8ul; | |
551 const size_t kSeekOffset = 2ul; | |
552 const uint64_t kReadLength = 4ull; | |
553 b.AppendData(kData); | |
554 this->InitializeReader(&b); | |
555 | |
556 int size_result = -1; | |
557 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
558 EXPECT_EQ(BlobReader::Status::DONE, | |
559 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
560 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
561 | |
562 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength); | |
563 | |
564 reader_->SetReadRange(kSeekOffset, kReadLength); | |
565 int bytes_read = 0; | |
566 int async_bytes_read = 0; | |
567 EXPECT_EQ(BlobReader::Status::DONE, | |
568 reader_->Read(buffer.get(), kDataSize - kSeekOffset, &bytes_read, | |
569 base::Bind(&SetValue<int>, &async_bytes_read))); | |
570 EXPECT_EQ(net::OK, reader_->net_error()); | |
571 EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read)); | |
572 EXPECT_EQ(0, async_bytes_read); | |
573 EXPECT_EQ(0, memcmp(buffer->data(), "llo!", kReadLength)); | |
574 } | |
575 | |
576 TEST_F(BlobReaderTest, BufferSmallerThanMemory) { | |
577 BlobDataBuilder b("uuid"); | |
578 const std::string kData("Hello!!!"); | |
579 const size_t kBufferSize = 4ul; | |
580 b.AppendData(kData); | |
581 this->InitializeReader(&b); | |
582 | |
583 int size_result = -1; | |
584 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
585 EXPECT_EQ(BlobReader::Status::DONE, | |
586 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
587 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
588 | |
589 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
590 | |
591 int bytes_read = 0; | |
592 int async_bytes_read = 0; | |
593 EXPECT_EQ(BlobReader::Status::DONE, | |
594 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
595 base::Bind(&SetValue<int>, &async_bytes_read))); | |
596 EXPECT_EQ(net::OK, reader_->net_error()); | |
597 EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read)); | |
598 EXPECT_EQ(0, async_bytes_read); | |
599 EXPECT_EQ(0, memcmp(buffer->data(), "Hell", kBufferSize)); | |
600 | |
601 bytes_read = 0; | |
602 EXPECT_EQ(BlobReader::Status::DONE, | |
603 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
604 base::Bind(&SetValue<int>, &async_bytes_read))); | |
605 EXPECT_EQ(net::OK, reader_->net_error()); | |
606 EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read)); | |
607 EXPECT_EQ(0, async_bytes_read); | |
608 EXPECT_EQ(0, memcmp(buffer->data(), "o!!!", kBufferSize)); | |
609 } | |
610 | |
611 TEST_F(BlobReaderTest, SegmentedBufferAndMemory) { | |
612 BlobDataBuilder b("uuid"); | |
613 const size_t kNumItems = 10; | |
614 const size_t kItemSize = 6; | |
615 const size_t kBufferSize = 10; | |
616 const size_t kTotalSize = kNumItems * kItemSize; | |
617 char current_value = 0; | |
618 for (size_t i = 0; i < kNumItems; i++) { | |
619 char buf[kItemSize]; | |
620 for (size_t j = 0; j < kItemSize; j++) { | |
621 buf[j] = current_value++; | |
622 } | |
623 b.AppendData(buf, kItemSize); | |
624 } | |
625 this->InitializeReader(&b); | |
626 | |
627 int size_result = -1; | |
628 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
629 EXPECT_EQ(BlobReader::Status::DONE, | |
630 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
631 CheckSizeCalculatedSynchronously(kTotalSize, size_result); | |
632 | |
633 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
634 | |
635 current_value = 0; | |
636 for (size_t i = 0; i < kTotalSize / kBufferSize; i++) { | |
637 int bytes_read = 0; | |
638 int async_bytes_read = 0; | |
639 EXPECT_EQ(BlobReader::Status::DONE, | |
640 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
641 base::Bind(&SetValue<int>, &async_bytes_read))); | |
642 EXPECT_EQ(net::OK, reader_->net_error()); | |
643 EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read)); | |
644 EXPECT_EQ(0, async_bytes_read); | |
645 for (size_t j = 0; j < kBufferSize; j++) { | |
646 EXPECT_EQ(current_value, buffer->data()[j]); | |
647 current_value++; | |
648 } | |
649 } | |
650 } | |
651 | |
652 TEST_F(BlobReaderTest, FileAsync) { | |
653 BlobDataBuilder b("uuid"); | |
654 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
655 const std::string kData = "FileData!!!"; | |
656 const base::Time kTime = base::Time::Now(); | |
657 b.AppendFile(kPath, 0, kData.size(), kTime); | |
658 this->InitializeReader(&b); | |
659 | |
660 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData)); | |
661 reader->DoAsync(message_loop_.task_runner().get()); | |
662 | |
663 ExpectLocalFileCall(kPath, kTime, 0, reader.release()); | |
664 | |
665 int size_result = -1; | |
666 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
667 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
668 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
669 CheckSizeNotCalculatedYet(size_result); | |
670 message_loop_.RunUntilIdle(); | |
671 CheckSizeCalculatedAsynchronously(kData.size(), size_result); | |
672 | |
673 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
674 | |
675 int bytes_read = 0; | |
676 int async_bytes_read = 0; | |
677 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
678 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
679 base::Bind(&SetValue<int>, &async_bytes_read))); | |
680 message_loop_.RunUntilIdle(); | |
681 EXPECT_EQ(net::OK, reader_->net_error()); | |
682 EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read)); | |
683 EXPECT_EQ(0, bytes_read); | |
684 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
685 } | |
686 | |
687 TEST_F(BlobReaderTest, FileSystemAsync) { | |
688 BlobDataBuilder b("uuid"); | |
689 const GURL kURL("file://test_file/here.txt"); | |
690 const std::string kData = "FileData!!!"; | |
691 const base::Time kTime = base::Time::Now(); | |
692 b.AppendFileSystemFile(kURL, 0, kData.size(), kTime); | |
693 this->InitializeReader(&b); | |
694 | |
695 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData)); | |
696 reader->DoAsync(message_loop_.task_runner().get()); | |
697 | |
698 ExpectFileSystemCall(kURL, 0, kData.size(), kTime, reader.release()); | |
699 | |
700 int size_result = -1; | |
701 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
702 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
703 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
704 CheckSizeNotCalculatedYet(size_result); | |
705 message_loop_.RunUntilIdle(); | |
706 CheckSizeCalculatedAsynchronously(kData.size(), size_result); | |
707 | |
708 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
709 | |
710 int bytes_read = 0; | |
711 int async_bytes_read = 0; | |
712 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
713 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
714 base::Bind(&SetValue<int>, &async_bytes_read))); | |
715 message_loop_.RunUntilIdle(); | |
716 EXPECT_EQ(net::OK, reader_->net_error()); | |
717 EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read)); | |
718 EXPECT_EQ(0, bytes_read); | |
719 EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())); | |
720 } | |
721 | |
722 TEST_F(BlobReaderTest, DiskCacheAsync) { | |
723 scoped_ptr<disk_cache::Backend> cache = | |
724 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
725 ASSERT_TRUE(cache); | |
726 | |
727 BlobDataBuilder b("uuid"); | |
728 const std::string kData = "Test Blob Data"; | |
729 scoped_refptr<BlobDataBuilder::DataHandle> data_handle = | |
730 new EmptyDataHandle(); | |
731 scoped_ptr<DelayedReadEntry> delayed_read_entry(new DelayedReadEntry( | |
732 CreateDiskCacheEntry(cache.get(), "test entry", kData).Pass())); | |
733 b.AppendDiskCacheEntry(data_handle, delayed_read_entry.get(), | |
734 kTestDiskCacheStreamIndex); | |
735 this->InitializeReader(&b); | |
736 | |
737 int size_result = -1; | |
738 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
739 EXPECT_EQ(BlobReader::Status::DONE, | |
740 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
741 CheckSizeCalculatedSynchronously(kData.size(), size_result); | |
742 | |
743 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
744 | |
745 int bytes_read = 0; | |
746 int async_bytes_read = 0; | |
747 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
748 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
749 base::Bind(&SetValue<int>, &async_bytes_read))); | |
750 EXPECT_TRUE(delayed_read_entry->HasPendingReadCallbacks()); | |
751 delayed_read_entry->RunPendingReadCallbacks(); | |
752 EXPECT_EQ(net::OK, reader_->net_error()); | |
753 EXPECT_EQ(0, bytes_read); | |
754 EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read)); | |
755 EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size())); | |
756 } | |
757 | |
758 TEST_F(BlobReaderTest, FileRange) { | |
759 BlobDataBuilder b("uuid"); | |
760 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
761 // We check the offset in the ExpectLocalFileCall mock. | |
762 const std::string kRangeData = "leD"; | |
763 const std::string kData = "FileData!!!"; | |
764 const uint64_t kOffset = 2; | |
765 const uint64_t kReadLength = 3; | |
766 const base::Time kTime = base::Time::Now(); | |
767 b.AppendFile(kPath, 0, kData.size(), kTime); | |
768 this->InitializeReader(&b); | |
769 | |
770 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData)); | |
771 reader->DoAsync(message_loop_.task_runner().get()); | |
772 ExpectLocalFileCall(kPath, kTime, 0, reader.release()); | |
773 | |
774 // We create the reader again with the offset after the seek. | |
775 reader.reset(new FakeFileStreamReader(kRangeData)); | |
776 reader->DoAsync(message_loop_.task_runner().get()); | |
777 ExpectLocalFileCall(kPath, kTime, kOffset, reader.release()); | |
778 | |
779 int size_result = -1; | |
780 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
781 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
782 message_loop_.RunUntilIdle(); | |
783 | |
784 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength); | |
785 EXPECT_EQ(BlobReader::Status::DONE, | |
786 reader_->SetReadRange(kOffset, kReadLength)); | |
787 | |
788 int bytes_read = 0; | |
789 int async_bytes_read = 0; | |
790 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
791 reader_->Read(buffer.get(), kReadLength, &bytes_read, | |
792 base::Bind(&SetValue<int>, &async_bytes_read))); | |
793 message_loop_.RunUntilIdle(); | |
794 EXPECT_EQ(net::OK, reader_->net_error()); | |
795 EXPECT_EQ(kReadLength, static_cast<size_t>(async_bytes_read)); | |
796 EXPECT_EQ(0, bytes_read); | |
797 EXPECT_EQ(0, memcmp(buffer->data(), "leD", kReadLength)); | |
798 } | |
799 | |
800 TEST_F(BlobReaderTest, DiskCacheRange) { | |
801 scoped_ptr<disk_cache::Backend> cache = | |
802 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
803 ASSERT_TRUE(cache); | |
804 | |
805 BlobDataBuilder b("uuid"); | |
806 const std::string kData = "Test Blob Data"; | |
807 const uint64_t kOffset = 2; | |
808 const uint64_t kReadLength = 3; | |
809 scoped_refptr<BlobDataBuilder::DataHandle> data_handle = | |
810 new EmptyDataHandle(); | |
811 disk_cache::ScopedEntryPtr entry = | |
812 CreateDiskCacheEntry(cache.get(), "test entry", kData); | |
813 b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex); | |
814 this->InitializeReader(&b); | |
815 | |
816 int size_result = -1; | |
817 EXPECT_EQ(BlobReader::Status::DONE, | |
818 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
819 | |
820 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength); | |
821 EXPECT_EQ(BlobReader::Status::DONE, | |
822 reader_->SetReadRange(kOffset, kReadLength)); | |
823 | |
824 int bytes_read = 0; | |
825 int async_bytes_read = 0; | |
826 EXPECT_EQ(BlobReader::Status::DONE, | |
827 reader_->Read(buffer.get(), kReadLength, &bytes_read, | |
828 base::Bind(&SetValue<int>, &async_bytes_read))); | |
829 EXPECT_EQ(net::OK, reader_->net_error()); | |
830 EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read)); | |
831 EXPECT_EQ(0, async_bytes_read); | |
832 EXPECT_EQ(0, memcmp(buffer->data(), "st ", kReadLength)); | |
833 } | |
834 | |
835 TEST_F(BlobReaderTest, FileSomeAsyncSegmentedOffsetsUnknownSizes) { | |
836 // This tests includes: | |
837 // * Unknown file sizes (item length of uint64::max) for every other item. | |
838 // * Offsets for every 3rd file item. | |
839 // * Non-async reader for every 4th file item. | |
840 BlobDataBuilder b("uuid"); | |
841 const FilePath kPathBase = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
842 const base::Time kTime = base::Time::Now(); | |
843 const size_t kNumItems = 10; | |
844 const size_t kItemSize = 6; | |
845 const size_t kBufferSize = 10; | |
846 const size_t kTotalSize = kNumItems * kItemSize; | |
847 char current_value = 0; | |
848 // Create blob and reader. | |
849 for (size_t i = 0; i < kNumItems; i++) { | |
850 current_value += kItemSize; | |
851 FilePath path = kPathBase.Append( | |
852 FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value))); | |
853 uint64_t offset = i % 3 == 0 ? 1 : 0; | |
854 uint64_t size = | |
855 i % 2 == 0 ? kItemSize : std::numeric_limits<uint64_t>::max(); | |
856 b.AppendFile(path, offset, size, kTime); | |
857 } | |
858 this->InitializeReader(&b); | |
859 | |
860 // Set expectations. | |
861 current_value = 0; | |
862 for (size_t i = 0; i < kNumItems; i++) { | |
863 uint64_t offset = i % 3 == 0 ? 1 : 0; | |
864 scoped_ptr<char[]> buf(new char[kItemSize + offset]); | |
865 if (offset > 0) { | |
866 memset(buf.get(), 7, offset); | |
867 } | |
868 for (size_t j = 0; j < kItemSize; j++) { | |
869 buf.get()[j + offset] = current_value++; | |
870 } | |
871 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader( | |
872 std::string(buf.get() + offset, kItemSize), kItemSize + offset)); | |
873 if (i % 4 != 0) { | |
874 reader->DoAsync(message_loop_.task_runner().get()); | |
875 } | |
876 FilePath path = kPathBase.Append( | |
877 FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value))); | |
878 ExpectLocalFileCall(path, kTime, offset, reader.release()); | |
879 } | |
880 | |
881 int size_result = -1; | |
882 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
883 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
884 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
885 CheckSizeNotCalculatedYet(size_result); | |
886 message_loop_.RunUntilIdle(); | |
887 CheckSizeCalculatedAsynchronously(kTotalSize, size_result); | |
888 | |
889 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); | |
890 | |
891 current_value = 0; | |
892 for (size_t i = 0; i < kTotalSize / kBufferSize; i++) { | |
893 int bytes_read = 0; | |
894 int async_bytes_read = 0; | |
895 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
896 reader_->Read(buffer.get(), kBufferSize, &bytes_read, | |
897 base::Bind(&SetValue<int>, &async_bytes_read))); | |
898 message_loop_.RunUntilIdle(); | |
899 EXPECT_EQ(net::OK, reader_->net_error()); | |
900 EXPECT_EQ(0, bytes_read); | |
901 EXPECT_EQ(kBufferSize, static_cast<size_t>(async_bytes_read)); | |
902 for (size_t j = 0; j < kBufferSize; j++) { | |
903 EXPECT_EQ(current_value, buffer->data()[j]); | |
904 current_value++; | |
905 } | |
906 } | |
907 } | |
908 | |
909 TEST_F(BlobReaderTest, MixedContent) { | |
910 // Includes data, a file, and a disk cache entry. | |
911 scoped_ptr<disk_cache::Backend> cache = | |
912 CreateInMemoryDiskCache(message_loop_.task_runner()); | |
913 ASSERT_TRUE(cache); | |
914 | |
915 BlobDataBuilder b("uuid"); | |
916 const std::string kData1("Hello "); | |
917 const std::string kData2("there. "); | |
918 const std::string kData3("This "); | |
919 const std::string kData4("is multi-content."); | |
920 const uint64_t kDataSize = 35; | |
921 | |
922 const base::Time kTime = base::Time::Now(); | |
923 const FilePath kData1Path = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
924 | |
925 disk_cache::ScopedEntryPtr entry3 = | |
926 CreateDiskCacheEntry(cache.get(), "test entry", kData3); | |
927 | |
928 b.AppendFile(kData1Path, 0, kData1.size(), kTime); | |
929 b.AppendData(kData2); | |
930 b.AppendDiskCacheEntry( | |
931 scoped_refptr<BlobDataBuilder::DataHandle>(new EmptyDataHandle()), | |
932 entry3.get(), kTestDiskCacheStreamIndex); | |
933 b.AppendData(kData4); | |
934 | |
935 this->InitializeReader(&b); | |
936 | |
937 scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData1)); | |
938 reader->DoAsync(message_loop_.task_runner().get()); | |
939 ExpectLocalFileCall(kData1Path, kTime, 0, reader.release()); | |
940 | |
941 int size_result = -1; | |
942 EXPECT_FALSE(IsReaderTotalSizeCalculated()); | |
943 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
944 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
945 CheckSizeNotCalculatedYet(size_result); | |
946 message_loop_.RunUntilIdle(); | |
947 CheckSizeCalculatedAsynchronously(kDataSize, size_result); | |
948 | |
949 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize); | |
950 | |
951 int bytes_read = 0; | |
952 int async_bytes_read = 0; | |
953 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
954 reader_->Read(buffer.get(), kDataSize, &bytes_read, | |
955 base::Bind(&SetValue<int>, &async_bytes_read))); | |
956 EXPECT_EQ(0, async_bytes_read); | |
957 message_loop_.RunUntilIdle(); | |
958 EXPECT_EQ(net::OK, reader_->net_error()); | |
959 EXPECT_EQ(0, bytes_read); | |
960 EXPECT_EQ(kDataSize, static_cast<size_t>(async_bytes_read)); | |
961 EXPECT_EQ(0, memcmp(buffer->data(), "Hello there. This is multi-content.", | |
962 kDataSize)); | |
963 } | |
964 | |
965 TEST_F(BlobReaderTest, StateErrors) { | |
966 // Test common variables | |
967 int bytes_read = -1; | |
968 int async_bytes_read = -1; | |
969 int size_result = -1; | |
970 const std::string kData("Hello!!!"); | |
971 | |
972 // Case: Blob handle is a nullptr. | |
973 InitializeReader(nullptr); | |
974 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
975 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
976 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
977 EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10)); | |
978 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
979 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(10); | |
980 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
981 reader_->Read(buffer.get(), 10, &bytes_read, | |
982 base::Bind(&SetValue<int>, &async_bytes_read))); | |
983 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
984 | |
985 // Case: Not calling CalculateSize before SetReadRange. | |
986 BlobDataBuilder builder1("uuid1"); | |
987 builder1.AppendData(kData); | |
988 InitializeReader(&builder1); | |
989 EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10)); | |
990 EXPECT_EQ(net::ERR_FAILED, reader_->net_error()); | |
991 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
992 reader_->Read(buffer.get(), 10, &bytes_read, | |
993 base::Bind(&SetValue<int>, &async_bytes_read))); | |
994 EXPECT_EQ(net::ERR_FAILED, reader_->net_error()); | |
995 EXPECT_EQ(0, bytes_read); | |
996 | |
997 // Case: Not calling CalculateSize before Read. | |
998 BlobDataBuilder builder2("uuid2"); | |
999 builder2.AppendData(kData); | |
1000 InitializeReader(&builder2); | |
1001 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1002 reader_->Read(buffer.get(), 10, &bytes_read, | |
1003 base::Bind(&SetValue<int>, &async_bytes_read))); | |
1004 EXPECT_EQ(net::ERR_FAILED, reader_->net_error()); | |
1005 EXPECT_EQ(0, bytes_read); | |
1006 } | |
1007 | |
1008 TEST_F(BlobReaderTest, FileErrorsSync) { | |
1009 int size_result = -1; | |
1010 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
1011 const std::string kData = "FileData!!!"; | |
1012 const base::Time kTime = base::Time::Now(); | |
1013 | |
1014 // Case: Error on length query. | |
1015 BlobDataBuilder builder1("uuid1"); | |
1016 builder1.AppendFile(kPath, 0, kData.size(), kTime); | |
1017 this->InitializeReader(&builder1); | |
1018 FakeFileStreamReader* reader = new FakeFileStreamReader(kData); | |
1019 reader->ReturnError(net::ERR_FILE_NOT_FOUND); | |
1020 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1021 | |
1022 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1023 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1024 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1025 | |
1026 // Case: Error on read. | |
1027 BlobDataBuilder builder2("uuid2"); | |
1028 builder2.AppendFile(kPath, 0, kData.size(), kTime); | |
1029 this->InitializeReader(&builder2); | |
1030 reader = new FakeFileStreamReader(kData); | |
1031 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1032 EXPECT_EQ(BlobReader::Status::DONE, | |
1033 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1034 reader->ReturnError(net::ERR_FILE_NOT_FOUND); | |
1035 | |
1036 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
1037 int bytes_read = 0; | |
1038 int async_bytes_read = 0; | |
1039 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1040 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
1041 base::Bind(&SetValue<int>, &async_bytes_read))); | |
1042 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1043 } | |
1044 | |
1045 TEST_F(BlobReaderTest, FileErrorsAsync) { | |
1046 int size_result = -1; | |
1047 const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt"); | |
1048 const std::string kData = "FileData!!!"; | |
1049 const base::Time kTime = base::Time::Now(); | |
1050 | |
1051 // Case: Error on length query. | |
1052 BlobDataBuilder builder1("uuid1"); | |
1053 builder1.AppendFile(kPath, 0, kData.size(), kTime); | |
1054 this->InitializeReader(&builder1); | |
1055 FakeFileStreamReader* reader = new FakeFileStreamReader(kData); | |
1056 reader->DoAsync(message_loop_.task_runner().get()); | |
1057 reader->ReturnError(net::ERR_FILE_NOT_FOUND); | |
1058 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1059 | |
1060 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
1061 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1062 EXPECT_EQ(net::OK, reader_->net_error()); | |
1063 message_loop_.RunUntilIdle(); | |
1064 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, size_result); | |
1065 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1066 | |
1067 // Case: Error on read. | |
1068 BlobDataBuilder builder2("uuid2"); | |
1069 builder2.AppendFile(kPath, 0, kData.size(), kTime); | |
1070 this->InitializeReader(&builder2); | |
1071 reader = new FakeFileStreamReader(kData); | |
1072 ExpectLocalFileCall(kPath, kTime, 0, reader); | |
1073 EXPECT_EQ(BlobReader::Status::DONE, | |
1074 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1075 reader->ReturnError(net::ERR_FILE_NOT_FOUND); | |
1076 reader->DoAsync(message_loop_.task_runner().get()); | |
1077 | |
1078 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size())); | |
1079 int bytes_read = 0; | |
1080 int async_bytes_read = 0; | |
1081 EXPECT_EQ(BlobReader::Status::IO_PENDING, | |
1082 reader_->Read(buffer.get(), kData.size(), &bytes_read, | |
1083 base::Bind(&SetValue<int>, &async_bytes_read))); | |
1084 EXPECT_EQ(net::OK, reader_->net_error()); | |
1085 message_loop_.RunUntilIdle(); | |
1086 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, async_bytes_read); | |
1087 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1088 } | |
1089 | |
1090 TEST_F(BlobReaderTest, RangeError) { | |
1091 const std::string kData("Hello!!!"); | |
1092 const size_t kDataSize = 8ul; | |
1093 const uint64_t kReadLength = 4ull; | |
1094 | |
1095 // Case: offset too high. | |
1096 BlobDataBuilder b("uuid1"); | |
1097 b.AppendData(kData); | |
1098 this->InitializeReader(&b); | |
1099 int size_result = -1; | |
1100 EXPECT_EQ(BlobReader::Status::DONE, | |
1101 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1102 scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize); | |
1103 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1104 reader_->SetReadRange(kDataSize + 1, kReadLength)); | |
1105 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1106 | |
1107 // Case: length too long. | |
1108 BlobDataBuilder b2("uuid2"); | |
1109 b2.AppendData(kData); | |
1110 this->InitializeReader(&b2); | |
1111 size_result = -1; | |
1112 EXPECT_EQ(BlobReader::Status::DONE, | |
1113 reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result))); | |
1114 buffer = CreateBuffer(kDataSize + 1); | |
1115 EXPECT_EQ(BlobReader::Status::NET_ERROR, | |
1116 reader_->SetReadRange(0, kDataSize + 1)); | |
1117 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error()); | |
1118 } | |
1119 | |
1120 } // namespace | |
1121 } // namespace storage | |
OLD | NEW |