Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / loader / upload_data_stream_builder_unittest.cc
blobb3edd5d65843b69b80439896ecde6caf3feca5f3
1 // Copyright 2013 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 "content/browser/loader/upload_data_stream_builder.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/run_loop.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "content/common/resource_request_body.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/base/upload_bytes_element_reader.h"
20 #include "net/base/upload_data_stream.h"
21 #include "net/base/upload_disk_cache_entry_element_reader.h"
22 #include "net/base/upload_file_element_reader.h"
23 #include "net/disk_cache/disk_cache.h"
24 #include "storage/browser/blob/blob_data_builder.h"
25 #include "storage/browser/blob/blob_storage_context.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "url/gurl.h"
29 using storage::BlobDataBuilder;
30 using storage::BlobDataHandle;
31 using storage::BlobStorageContext;
33 namespace content {
34 namespace {
36 const int kTestDiskCacheStreamIndex = 0;
38 // Our disk cache tests don't need a real data handle since the tests themselves
39 // scope the disk cache and entries.
40 class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle {
41 private:
42 ~EmptyDataHandle() override {}
45 scoped_ptr<disk_cache::Backend> CreateInMemoryDiskCache() {
46 scoped_ptr<disk_cache::Backend> cache;
47 net::TestCompletionCallback callback;
48 int rv = disk_cache::CreateCacheBackend(net::MEMORY_CACHE,
49 net::CACHE_BACKEND_DEFAULT,
50 base::FilePath(), 0,
51 false, nullptr, nullptr, &cache,
52 callback.callback());
53 EXPECT_EQ(net::OK, callback.GetResult(rv));
55 return cache.Pass();
58 disk_cache::ScopedEntryPtr CreateDiskCacheEntry(disk_cache::Backend* cache,
59 const char* key,
60 const std::string& data) {
61 disk_cache::Entry* temp_entry = nullptr;
62 net::TestCompletionCallback callback;
63 int rv = cache->CreateEntry(key, &temp_entry, callback.callback());
64 if (callback.GetResult(rv) != net::OK)
65 return nullptr;
66 disk_cache::ScopedEntryPtr entry(temp_entry);
68 scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data);
69 rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(),
70 iobuffer->size(), callback.callback(), false);
71 EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv));
72 return entry.Pass();
75 bool AreElementsEqual(const net::UploadElementReader& reader,
76 const ResourceRequestBody::Element& element) {
77 switch(element.type()) {
78 case ResourceRequestBody::Element::TYPE_BYTES: {
79 const net::UploadBytesElementReader* bytes_reader =
80 reader.AsBytesReader();
81 return bytes_reader &&
82 element.length() == bytes_reader->length() &&
83 std::equal(element.bytes(), element.bytes() + element.length(),
84 bytes_reader->bytes());
86 case ResourceRequestBody::Element::TYPE_FILE: {
87 const net::UploadFileElementReader* file_reader = reader.AsFileReader();
88 return file_reader &&
89 file_reader->path() == element.path() &&
90 file_reader->range_offset() == element.offset() &&
91 file_reader->range_length() == element.length() &&
92 file_reader->expected_modification_time() ==
93 element.expected_modification_time();
94 break;
96 case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY: {
97 // TODO(gavinp): Should we be comparing a higher level structure
98 // such as the BlobDataItem so that we can do stronger equality
99 // comparisons?
100 const net::UploadDiskCacheEntryElementReader* disk_cache_entry_reader =
101 reader.AsDiskCacheEntryReaderForTests();
102 return disk_cache_entry_reader &&
103 disk_cache_entry_reader->range_offset_for_tests() ==
104 static_cast<int>(element.offset()) &&
105 disk_cache_entry_reader->range_length_for_tests() ==
106 static_cast<int>(element.length());
107 break;
109 default:
110 NOTREACHED();
112 return false;
115 } // namespace
117 TEST(UploadDataStreamBuilderTest, CreateUploadDataStreamWithoutBlob) {
118 base::MessageLoop message_loop;
119 scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
121 const char kData[] = "123";
122 const base::FilePath::StringType kFilePath = FILE_PATH_LITERAL("abc");
123 const uint64 kFileOffset = 10U;
124 const uint64 kFileLength = 100U;
125 const base::Time kFileTime = base::Time::FromDoubleT(999);
126 const int64 kIdentifier = 12345;
128 request_body->AppendBytes(kData, arraysize(kData) - 1);
129 request_body->AppendFileRange(base::FilePath(kFilePath),
130 kFileOffset, kFileLength, kFileTime);
131 request_body->set_identifier(kIdentifier);
133 scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
134 request_body.get(), NULL, NULL,
135 base::ThreadTaskRunnerHandle::Get().get()));
137 EXPECT_EQ(kIdentifier, upload->identifier());
138 ASSERT_TRUE(upload->GetElementReaders());
139 ASSERT_EQ(request_body->elements()->size(),
140 upload->GetElementReaders()->size());
142 const net::UploadBytesElementReader* r1 =
143 (*upload->GetElementReaders())[0]->AsBytesReader();
144 ASSERT_TRUE(r1);
145 EXPECT_EQ(kData, std::string(r1->bytes(), r1->length()));
147 const net::UploadFileElementReader* r2 =
148 (*upload->GetElementReaders())[1]->AsFileReader();
149 ASSERT_TRUE(r2);
150 EXPECT_EQ(kFilePath, r2->path().value());
151 EXPECT_EQ(kFileOffset, r2->range_offset());
152 EXPECT_EQ(kFileLength, r2->range_length());
153 EXPECT_EQ(kFileTime, r2->expected_modification_time());
156 TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
157 base::MessageLoop message_loop;
159 // Setup blob data for testing.
160 base::Time time1, time2;
161 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1);
162 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2);
164 BlobStorageContext blob_storage_context;
166 const std::string blob_id0("id-0");
167 scoped_ptr<BlobDataBuilder> blob_data_builder(
168 new BlobDataBuilder(blob_id0));
169 scoped_ptr<BlobDataHandle> handle1 =
170 blob_storage_context.AddFinishedBlob(blob_data_builder.get());
172 const std::string blob_id1("id-1");
173 const std::string kBlobData = "BlobData";
174 blob_data_builder.reset(new BlobDataBuilder(blob_id1));
175 blob_data_builder->AppendData(kBlobData);
176 blob_data_builder->AppendFile(
177 base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1);
178 scoped_ptr<BlobDataHandle> handle2 =
179 blob_storage_context.AddFinishedBlob(blob_data_builder.get());
181 const std::string blob_id2("id-2");
182 const std::string kDiskCacheData = "DiskCacheData";
183 scoped_ptr<disk_cache::Backend> disk_cache_backend =
184 CreateInMemoryDiskCache();
185 ASSERT_TRUE(disk_cache_backend);
186 disk_cache::ScopedEntryPtr disk_cache_entry =
187 CreateDiskCacheEntry(disk_cache_backend.get(), "a key", kDiskCacheData);
188 ASSERT_TRUE(disk_cache_entry);
189 blob_data_builder.reset(new BlobDataBuilder(blob_id2));
190 blob_data_builder->AppendDiskCacheEntry(
191 new EmptyDataHandle(), disk_cache_entry.get(),
192 kTestDiskCacheStreamIndex);
193 scoped_ptr<BlobDataHandle> handle3 =
194 blob_storage_context.AddFinishedBlob(blob_data_builder.get());
196 // Setup upload data elements for comparison.
197 ResourceRequestBody::Element blob_element1, blob_element2, blob_element3;
198 blob_element1.SetToBytes(kBlobData.c_str(), kBlobData.size());
199 blob_element2.SetToFilePathRange(
200 base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1);
201 blob_element3.SetToDiskCacheEntryRange(0, kDiskCacheData.size());
203 ResourceRequestBody::Element upload_element1, upload_element2;
204 upload_element1.SetToBytes("Hello", 5);
205 upload_element2.SetToFilePathRange(
206 base::FilePath(FILE_PATH_LITERAL("foo1.txt")), 0, 20, time2);
208 // Test no blob reference.
209 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
210 request_body->AppendBytes(
211 upload_element1.bytes(),
212 upload_element1.length());
213 request_body->AppendFileRange(
214 upload_element2.path(),
215 upload_element2.offset(),
216 upload_element2.length(),
217 upload_element2.expected_modification_time());
219 scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
220 request_body.get(), &blob_storage_context, NULL,
221 base::ThreadTaskRunnerHandle::Get().get()));
223 ASSERT_TRUE(upload->GetElementReaders());
224 ASSERT_EQ(2U, upload->GetElementReaders()->size());
225 EXPECT_TRUE(AreElementsEqual(
226 *(*upload->GetElementReaders())[0], upload_element1));
227 EXPECT_TRUE(AreElementsEqual(
228 *(*upload->GetElementReaders())[1], upload_element2));
230 // Test having only one blob reference that refers to empty blob data.
231 request_body = new ResourceRequestBody();
232 request_body->AppendBlob(blob_id0);
234 upload = UploadDataStreamBuilder::Build(
235 request_body.get(), &blob_storage_context, NULL,
236 base::ThreadTaskRunnerHandle::Get().get());
237 ASSERT_TRUE(upload->GetElementReaders());
238 ASSERT_EQ(0U, upload->GetElementReaders()->size());
240 // Test having only one blob reference.
241 request_body = new ResourceRequestBody();
242 request_body->AppendBlob(blob_id1);
244 upload = UploadDataStreamBuilder::Build(
245 request_body.get(), &blob_storage_context, NULL,
246 base::ThreadTaskRunnerHandle::Get().get());
247 ASSERT_TRUE(upload->GetElementReaders());
248 ASSERT_EQ(2U, upload->GetElementReaders()->size());
249 EXPECT_TRUE(AreElementsEqual(
250 *(*upload->GetElementReaders())[0], blob_element1));
251 EXPECT_TRUE(AreElementsEqual(
252 *(*upload->GetElementReaders())[1], blob_element2));
254 // Test having one blob reference which refers to a disk cache entry.
255 request_body = new ResourceRequestBody();
256 request_body->AppendBlob(blob_id2);
258 upload = UploadDataStreamBuilder::Build(
259 request_body.get(), &blob_storage_context, nullptr,
260 base::ThreadTaskRunnerHandle::Get().get());
261 ASSERT_TRUE(upload->GetElementReaders());
262 ASSERT_EQ(1U, upload->GetElementReaders()->size());
263 EXPECT_TRUE(AreElementsEqual(
264 *(*upload->GetElementReaders())[0], blob_element3));
266 // Test having one blob reference at the beginning.
267 request_body = new ResourceRequestBody();
268 request_body->AppendBlob(blob_id1);
269 request_body->AppendBytes(
270 upload_element1.bytes(),
271 upload_element1.length());
272 request_body->AppendFileRange(
273 upload_element2.path(),
274 upload_element2.offset(),
275 upload_element2.length(),
276 upload_element2.expected_modification_time());
278 upload = UploadDataStreamBuilder::Build(
279 request_body.get(), &blob_storage_context, NULL,
280 base::ThreadTaskRunnerHandle::Get().get());
281 ASSERT_TRUE(upload->GetElementReaders());
282 ASSERT_EQ(4U, upload->GetElementReaders()->size());
283 EXPECT_TRUE(AreElementsEqual(
284 *(*upload->GetElementReaders())[0], blob_element1));
285 EXPECT_TRUE(AreElementsEqual(
286 *(*upload->GetElementReaders())[1], blob_element2));
287 EXPECT_TRUE(AreElementsEqual(
288 *(*upload->GetElementReaders())[2], upload_element1));
289 EXPECT_TRUE(AreElementsEqual(
290 *(*upload->GetElementReaders())[3], upload_element2));
292 // Test having one blob reference at the end.
293 request_body = new ResourceRequestBody();
294 request_body->AppendBytes(
295 upload_element1.bytes(),
296 upload_element1.length());
297 request_body->AppendFileRange(
298 upload_element2.path(),
299 upload_element2.offset(),
300 upload_element2.length(),
301 upload_element2.expected_modification_time());
302 request_body->AppendBlob(blob_id1);
304 upload = UploadDataStreamBuilder::Build(
305 request_body.get(), &blob_storage_context, NULL,
306 base::ThreadTaskRunnerHandle::Get().get());
307 ASSERT_TRUE(upload->GetElementReaders());
308 ASSERT_EQ(4U, upload->GetElementReaders()->size());
309 EXPECT_TRUE(AreElementsEqual(
310 *(*upload->GetElementReaders())[0], upload_element1));
311 EXPECT_TRUE(AreElementsEqual(
312 *(*upload->GetElementReaders())[1], upload_element2));
313 EXPECT_TRUE(AreElementsEqual(
314 *(*upload->GetElementReaders())[2], blob_element1));
315 EXPECT_TRUE(AreElementsEqual(
316 *(*upload->GetElementReaders())[3], blob_element2));
318 // Test having one blob reference in the middle.
319 request_body = new ResourceRequestBody();
320 request_body->AppendBytes(
321 upload_element1.bytes(),
322 upload_element1.length());
323 request_body->AppendBlob(blob_id1);
324 request_body->AppendFileRange(
325 upload_element2.path(),
326 upload_element2.offset(),
327 upload_element2.length(),
328 upload_element2.expected_modification_time());
330 upload = UploadDataStreamBuilder::Build(
331 request_body.get(), &blob_storage_context, NULL,
332 base::ThreadTaskRunnerHandle::Get().get());
333 ASSERT_TRUE(upload->GetElementReaders());
334 ASSERT_EQ(4U, upload->GetElementReaders()->size());
335 EXPECT_TRUE(AreElementsEqual(
336 *(*upload->GetElementReaders())[0], upload_element1));
337 EXPECT_TRUE(AreElementsEqual(
338 *(*upload->GetElementReaders())[1], blob_element1));
339 EXPECT_TRUE(AreElementsEqual(
340 *(*upload->GetElementReaders())[2], blob_element2));
341 EXPECT_TRUE(AreElementsEqual(
342 *(*upload->GetElementReaders())[3], upload_element2));
344 // Test having multiple blob references.
345 request_body = new ResourceRequestBody();
346 request_body->AppendBlob(blob_id1);
347 request_body->AppendBytes(
348 upload_element1.bytes(),
349 upload_element1.length());
350 request_body->AppendBlob(blob_id1);
351 request_body->AppendBlob(blob_id1);
352 request_body->AppendFileRange(
353 upload_element2.path(),
354 upload_element2.offset(),
355 upload_element2.length(),
356 upload_element2.expected_modification_time());
358 upload = UploadDataStreamBuilder::Build(
359 request_body.get(), &blob_storage_context, NULL,
360 base::ThreadTaskRunnerHandle::Get().get());
361 ASSERT_TRUE(upload->GetElementReaders());
362 ASSERT_EQ(8U, upload->GetElementReaders()->size());
363 EXPECT_TRUE(AreElementsEqual(
364 *(*upload->GetElementReaders())[0], blob_element1));
365 EXPECT_TRUE(AreElementsEqual(
366 *(*upload->GetElementReaders())[1], blob_element2));
367 EXPECT_TRUE(AreElementsEqual(
368 *(*upload->GetElementReaders())[2], upload_element1));
369 EXPECT_TRUE(AreElementsEqual(
370 *(*upload->GetElementReaders())[3], blob_element1));
371 EXPECT_TRUE(AreElementsEqual(
372 *(*upload->GetElementReaders())[4], blob_element2));
373 EXPECT_TRUE(AreElementsEqual(
374 *(*upload->GetElementReaders())[5], blob_element1));
375 EXPECT_TRUE(AreElementsEqual(
376 *(*upload->GetElementReaders())[6], blob_element2));
377 EXPECT_TRUE(AreElementsEqual(
378 *(*upload->GetElementReaders())[7], upload_element2));
380 // Clean up for ASAN.
381 base::RunLoop().RunUntilIdle();
384 TEST(UploadDataStreamBuilderTest,
385 WriteUploadDataStreamWithEmptyFileBackedBlob) {
386 base::MessageLoopForIO message_loop;
388 base::FilePath test_blob_path;
389 ASSERT_TRUE(base::CreateTemporaryFile(&test_blob_path));
391 const uint64_t kZeroLength = 0;
392 base::Time blob_time;
393 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &blob_time);
394 ASSERT_TRUE(base::TouchFile(test_blob_path, blob_time, blob_time));
396 BlobStorageContext blob_storage_context;
398 // A blob created from an empty file added several times.
399 const std::string blob_id("id-0");
400 scoped_ptr<BlobDataBuilder> blob_data_builder(new BlobDataBuilder(blob_id));
401 blob_data_builder->AppendFile(test_blob_path, 0, kZeroLength, blob_time);
402 scoped_ptr<BlobDataHandle> handle =
403 blob_storage_context.AddFinishedBlob(blob_data_builder.get());
405 ResourceRequestBody::Element blob_element;
406 blob_element.SetToFilePathRange(test_blob_path, 0, kZeroLength, blob_time);
408 scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
409 scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
410 request_body.get(), &blob_storage_context, NULL,
411 base::ThreadTaskRunnerHandle::Get().get()));
413 request_body = new ResourceRequestBody();
414 request_body->AppendBlob(blob_id);
415 request_body->AppendBlob(blob_id);
416 request_body->AppendBlob(blob_id);
418 upload = UploadDataStreamBuilder::Build(
419 request_body.get(), &blob_storage_context, NULL,
420 base::ThreadTaskRunnerHandle::Get().get());
421 ASSERT_TRUE(upload->GetElementReaders());
422 const auto& readers = *upload->GetElementReaders();
423 ASSERT_EQ(3U, readers.size());
424 EXPECT_TRUE(AreElementsEqual(*readers[0], blob_element));
425 EXPECT_TRUE(AreElementsEqual(*readers[1], blob_element));
426 EXPECT_TRUE(AreElementsEqual(*readers[2], blob_element));
428 net::TestCompletionCallback init_callback;
429 ASSERT_EQ(net::ERR_IO_PENDING, upload->Init(init_callback.callback()));
430 EXPECT_EQ(net::OK, init_callback.WaitForResult());
432 EXPECT_EQ(kZeroLength, upload->size());
434 // Purposely (try to) read more than what is in the stream. If we try to
435 // read zero bytes then UploadDataStream::Read will fail a DCHECK.
436 int kBufferLength = kZeroLength + 1;
437 scoped_ptr<char[]> buffer(new char[kBufferLength]);
438 scoped_refptr<net::IOBuffer> io_buffer =
439 new net::WrappedIOBuffer(buffer.get());
440 net::TestCompletionCallback read_callback;
441 int result =
442 upload->Read(io_buffer.get(), kBufferLength, read_callback.callback());
443 EXPECT_EQ(static_cast<int>(kZeroLength), read_callback.GetResult(result));
445 base::DeleteFile(test_blob_path, false);
447 // Clean up for ASAN.
448 base::RunLoop().RunUntilIdle();
450 } // namespace content