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.
5 #include "net/base/upload_disk_cache_entry_element_reader.h"
13 #include "base/basictypes.h"
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/logging.h"
17 #include "base/macros.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/time/time.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/test_completion_callback.h"
24 #include "net/disk_cache/disk_cache.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/platform_test.h"
31 const int kTestDiskCacheStreamIndex
= 0;
33 const char kDataKey
[] = "a key";
35 const char kData
[] = "this is data in a disk cache entry";
36 const size_t kDataSize
= arraysize(kData
) - 1;
38 // A disk_cache::Entry that arbitrarily delays the completion of a read
39 // operation to allow testing some races without flake. This is particularly
40 // relevant in this unit test, which uses the always-synchronous MEMORY_CACHE.
41 class DelayedReadEntry
: public disk_cache::Entry
{
43 explicit DelayedReadEntry(disk_cache::ScopedEntryPtr entry
)
44 : entry_(entry
.Pass()) {}
45 ~DelayedReadEntry() override
{ EXPECT_FALSE(HasPendingReadCallbacks()); }
47 bool HasPendingReadCallbacks() { return !pending_read_callbacks_
.empty(); }
49 void RunPendingReadCallbacks() {
50 std::vector
<base::Callback
<void(void)>> callbacks
;
51 pending_read_callbacks_
.swap(callbacks
);
52 for (const auto& callback
: callbacks
)
56 // From disk_cache::Entry:
57 void Doom() override
{ entry_
->Doom(); }
59 void Close() override
{ delete this; } // Note this is required by the API.
61 std::string
GetKey() const override
{ return entry_
->GetKey(); }
63 base::Time
GetLastUsed() const override
{ return entry_
->GetLastUsed(); }
65 base::Time
GetLastModified() const override
{
66 return entry_
->GetLastModified();
69 int32
GetDataSize(int index
) const override
{
70 return entry_
->GetDataSize(index
);
73 int ReadData(int index
,
77 const CompletionCallback
& original_callback
) override
{
78 TestCompletionCallback callback
;
79 int rv
= entry_
->ReadData(index
, offset
, buf
, buf_len
, callback
.callback());
80 DCHECK_NE(rv
, ERR_IO_PENDING
)
81 << "Test expects to use a MEMORY_CACHE instance, which is synchronous.";
82 pending_read_callbacks_
.push_back(base::Bind(original_callback
, rv
));
83 return ERR_IO_PENDING
;
86 int WriteData(int index
,
90 const CompletionCallback
& callback
,
91 bool truncate
) override
{
92 return entry_
->WriteData(index
, offset
, buf
, buf_len
, callback
, truncate
);
95 int ReadSparseData(int64 offset
,
98 const CompletionCallback
& callback
) override
{
99 return entry_
->ReadSparseData(offset
, buf
, buf_len
, callback
);
102 int WriteSparseData(int64 offset
,
105 const CompletionCallback
& callback
) override
{
106 return entry_
->WriteSparseData(offset
, buf
, buf_len
, callback
);
109 int GetAvailableRange(int64 offset
,
112 const CompletionCallback
& callback
) override
{
113 return entry_
->GetAvailableRange(offset
, len
, start
, callback
);
116 bool CouldBeSparse() const override
{ return entry_
->CouldBeSparse(); }
118 void CancelSparseIO() override
{ entry_
->CancelSparseIO(); }
120 int ReadyForSparseIO(const CompletionCallback
& callback
) override
{
121 return entry_
->ReadyForSparseIO(callback
);
125 disk_cache::ScopedEntryPtr entry_
;
126 std::vector
<base::Callback
<void(void)>> pending_read_callbacks_
;
129 class UploadDiskCacheEntryElementReaderTest
: public PlatformTest
{
131 UploadDiskCacheEntryElementReaderTest() {}
133 ~UploadDiskCacheEntryElementReaderTest() override
{}
135 void SetUp() override
{
136 TestCompletionCallback callback
;
137 int rv
= disk_cache::CreateCacheBackend(
138 MEMORY_CACHE
, CACHE_BACKEND_DEFAULT
, base::FilePath(), 0, false,
139 nullptr, nullptr, &cache_
, callback
.callback());
140 ASSERT_EQ(OK
, callback
.GetResult(rv
));
142 disk_cache::Entry
* tmp_entry
= nullptr;
143 rv
= cache_
->CreateEntry(kDataKey
, &tmp_entry
, callback
.callback());
144 ASSERT_EQ(OK
, callback
.GetResult(rv
));
145 entry_
.reset(tmp_entry
);
147 scoped_refptr
<IOBuffer
> io_buffer
= new WrappedIOBuffer(kData
);
148 rv
= entry_
->WriteData(kTestDiskCacheStreamIndex
, 0, io_buffer
.get(),
149 kDataSize
, callback
.callback(), false);
150 EXPECT_EQ(static_cast<int>(kDataSize
), callback
.GetResult(rv
));
153 void set_entry(disk_cache::ScopedEntryPtr entry
) { entry_
.swap(entry
); }
154 disk_cache::Entry
* entry() { return entry_
.get(); }
155 disk_cache::ScopedEntryPtr
release_entry() { return entry_
.Pass(); }
158 scoped_ptr
<disk_cache::Backend
> cache_
;
159 disk_cache::ScopedEntryPtr entry_
;
162 TEST_F(UploadDiskCacheEntryElementReaderTest
, ReadAll
) {
163 UploadDiskCacheEntryElementReader
reader(entry(), kTestDiskCacheStreamIndex
,
165 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
167 char read_buffer
[kDataSize
];
168 std::fill(read_buffer
, read_buffer
+ arraysize(read_buffer
), '\0');
170 scoped_refptr
<IOBuffer
> io_buffer
= new WrappedIOBuffer(read_buffer
);
171 TestCompletionCallback callback
;
172 int rv
= reader
.Read(io_buffer
.get(), kDataSize
, callback
.callback());
173 EXPECT_EQ(static_cast<int>(kDataSize
), callback
.GetResult(rv
));
174 EXPECT_EQ(0U, reader
.BytesRemaining())
175 << "Expected a single read of |kDataSize| to retrieve entire entry.";
176 EXPECT_EQ(std::string(kData
, kDataSize
), std::string(read_buffer
, kDataSize
));
179 TEST_F(UploadDiskCacheEntryElementReaderTest
, ReadPartially
) {
180 UploadDiskCacheEntryElementReader
reader(entry(), kTestDiskCacheStreamIndex
,
182 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
184 const size_t kReadBuffer1Size
= kDataSize
/ 3;
185 char read_buffer1
[kReadBuffer1Size
];
186 std::fill(read_buffer1
, read_buffer1
+ arraysize(read_buffer1
), '\0');
188 scoped_refptr
<IOBuffer
> io_buffer1
= new WrappedIOBuffer(read_buffer1
);
190 const size_t kReadBuffer2Size
= kDataSize
- kReadBuffer1Size
;
191 char read_buffer2
[kReadBuffer2Size
];
192 scoped_refptr
<IOBuffer
> io_buffer2
= new WrappedIOBuffer(read_buffer2
);
194 TestCompletionCallback callback
;
195 int rv
= reader
.Read(io_buffer1
.get(), kReadBuffer1Size
, callback
.callback());
196 EXPECT_EQ(static_cast<int>(kReadBuffer1Size
), callback
.GetResult(rv
));
197 EXPECT_EQ(static_cast<uint64_t>(kReadBuffer2Size
), reader
.BytesRemaining());
199 rv
= reader
.Read(io_buffer2
.get(), kReadBuffer2Size
, callback
.callback());
200 EXPECT_EQ(static_cast<int>(kReadBuffer2Size
), callback
.GetResult(rv
));
201 EXPECT_EQ(0U, reader
.BytesRemaining());
203 EXPECT_EQ(std::string(kData
, kDataSize
),
204 std::string(read_buffer1
, kReadBuffer1Size
) +
205 std::string(read_buffer2
, kReadBuffer2Size
));
208 TEST_F(UploadDiskCacheEntryElementReaderTest
, ReadTooMuch
) {
209 UploadDiskCacheEntryElementReader
reader(entry(), kTestDiskCacheStreamIndex
,
211 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
213 const size_t kTooLargeSize
= kDataSize
+ kDataSize
/ 2;
215 char read_buffer
[kTooLargeSize
];
216 std::fill(read_buffer
, read_buffer
+ arraysize(read_buffer
), '\0');
218 scoped_refptr
<IOBuffer
> io_buffer
= new WrappedIOBuffer(read_buffer
);
219 TestCompletionCallback callback
;
220 int rv
= reader
.Read(io_buffer
.get(), kTooLargeSize
, callback
.callback());
221 EXPECT_EQ(static_cast<int>(kDataSize
), callback
.GetResult(rv
));
222 EXPECT_EQ(0U, reader
.BytesRemaining());
223 EXPECT_EQ(std::string(kData
, kDataSize
), std::string(read_buffer
, kDataSize
));
226 TEST_F(UploadDiskCacheEntryElementReaderTest
, ReadAsync
) {
227 DelayedReadEntry
* delayed_read_entry
= new DelayedReadEntry(release_entry());
228 set_entry(disk_cache::ScopedEntryPtr(delayed_read_entry
));
230 UploadDiskCacheEntryElementReader
reader(entry(), kTestDiskCacheStreamIndex
,
233 char read_buffer
[kDataSize
];
234 std::fill(read_buffer
, read_buffer
+ arraysize(read_buffer
), '\0');
236 scoped_refptr
<IOBuffer
> io_buffer
= new WrappedIOBuffer(read_buffer
);
237 TestCompletionCallback callback
;
238 int rv
= reader
.Read(io_buffer
.get(), kDataSize
, callback
.callback());
239 EXPECT_EQ(ERR_IO_PENDING
, rv
);
240 EXPECT_TRUE(delayed_read_entry
->HasPendingReadCallbacks());
241 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
243 delayed_read_entry
->RunPendingReadCallbacks();
244 EXPECT_EQ(static_cast<int>(kDataSize
), callback
.GetResult(rv
));
245 EXPECT_EQ(0U, reader
.BytesRemaining())
246 << "Expected a single read of |kDataSize| to retrieve entire entry.";
247 EXPECT_EQ(std::string(kData
, kDataSize
), std::string(read_buffer
, kDataSize
));
250 TEST_F(UploadDiskCacheEntryElementReaderTest
, MultipleInit
) {
251 UploadDiskCacheEntryElementReader
reader(entry(), kTestDiskCacheStreamIndex
,
253 char read_buffer
[kDataSize
];
254 std::fill(read_buffer
, read_buffer
+ arraysize(read_buffer
), '\0');
256 scoped_refptr
<IOBuffer
> io_buffer
= new WrappedIOBuffer(read_buffer
);
257 TestCompletionCallback callback
;
258 int rv
= reader
.Read(io_buffer
.get(), kDataSize
, callback
.callback());
259 EXPECT_EQ(static_cast<int>(kDataSize
), callback
.GetResult(rv
));
260 EXPECT_EQ(std::string(kData
, kDataSize
), std::string(read_buffer
, kDataSize
));
262 rv
= reader
.Init(callback
.callback());
263 EXPECT_EQ(OK
, callback
.GetResult(rv
));
264 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
265 rv
= reader
.Read(io_buffer
.get(), kDataSize
, callback
.callback());
266 EXPECT_EQ(static_cast<int>(kDataSize
), callback
.GetResult(rv
));
267 EXPECT_EQ(std::string(kData
, kDataSize
), std::string(read_buffer
, kDataSize
));
270 TEST_F(UploadDiskCacheEntryElementReaderTest
, InitDuringAsyncOperation
) {
271 DelayedReadEntry
* delayed_read_entry
= new DelayedReadEntry(release_entry());
272 set_entry(disk_cache::ScopedEntryPtr(delayed_read_entry
));
274 UploadDiskCacheEntryElementReader
reader(entry(), kTestDiskCacheStreamIndex
,
276 char read_buffer
[kDataSize
];
277 std::fill(read_buffer
, read_buffer
+ arraysize(read_buffer
), '\0');
279 scoped_refptr
<IOBuffer
> io_buffer
= new WrappedIOBuffer(read_buffer
);
280 TestCompletionCallback read_callback
;
281 int rv
= reader
.Read(io_buffer
.get(), kDataSize
, read_callback
.callback());
282 EXPECT_EQ(ERR_IO_PENDING
, rv
);
283 EXPECT_TRUE(delayed_read_entry
->HasPendingReadCallbacks());
284 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
286 TestCompletionCallback init_callback
;
287 rv
= reader
.Init(init_callback
.callback());
288 EXPECT_EQ(OK
, init_callback
.GetResult(rv
));
290 delayed_read_entry
->RunPendingReadCallbacks();
291 EXPECT_FALSE(delayed_read_entry
->HasPendingReadCallbacks());
292 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
294 char read_buffer2
[kDataSize
];
295 std::fill(read_buffer2
, read_buffer2
+ arraysize(read_buffer2
), '\0');
296 scoped_refptr
<IOBuffer
> io_buffer2
= new WrappedIOBuffer(read_buffer2
);
297 TestCompletionCallback read_callback2
;
298 rv
= reader
.Read(io_buffer2
.get(), kDataSize
, read_callback2
.callback());
299 EXPECT_EQ(ERR_IO_PENDING
, rv
);
300 EXPECT_TRUE(delayed_read_entry
->HasPendingReadCallbacks());
301 EXPECT_EQ(static_cast<uint64_t>(kDataSize
), reader
.BytesRemaining());
303 delayed_read_entry
->RunPendingReadCallbacks();
304 EXPECT_FALSE(delayed_read_entry
->HasPendingReadCallbacks());
305 read_callback2
.WaitForResult(); // Succeeds if this does not deadlock.
306 EXPECT_EQ(std::string(kData
, kDataSize
),
307 std::string(read_buffer2
, kDataSize
));
310 TEST_F(UploadDiskCacheEntryElementReaderTest
, Range
) {
311 const size_t kOffset
= kDataSize
/ 4;
312 const size_t kLength
= kDataSize
/ 3;
314 UploadDiskCacheEntryElementReader
reader(entry(), kTestDiskCacheStreamIndex
,
316 EXPECT_EQ(static_cast<uint64_t>(kLength
), reader
.BytesRemaining());
318 char read_buffer
[kLength
];
319 std::fill(read_buffer
, read_buffer
+ arraysize(read_buffer
), '\0');
321 scoped_refptr
<IOBuffer
> io_buffer
= new WrappedIOBuffer(read_buffer
);
322 TestCompletionCallback callback
;
323 int rv
= reader
.Read(io_buffer
.get(), kLength
, callback
.callback());
324 EXPECT_EQ(static_cast<int>(kLength
), callback
.GetResult(rv
));
325 EXPECT_EQ(0U, reader
.BytesRemaining());
326 EXPECT_EQ(std::string(kData
+ kOffset
, kLength
),
327 std::string(read_buffer
, kLength
));