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