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