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