Add ICU message format support
[chromium-blink-merge.git] / content / browser / fileapi / blob_storage_context_unittest.cc
blob5ae280e444e13e0ed2038812b27e0c1ea7d9f4f8
1 // Copyright 2014 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 "storage/browser/blob/blob_storage_context.h"
7 #include <limits>
8 #include <string>
10 #include "base/files/file_path.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/time/time.h"
16 #include "content/browser/fileapi/blob_storage_host.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/disk_cache/disk_cache.h"
20 #include "storage/browser/blob/blob_data_builder.h"
21 #include "storage/browser/blob/blob_data_handle.h"
22 #include "storage/browser/blob/blob_data_item.h"
23 #include "storage/browser/blob/blob_data_snapshot.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using storage::BlobDataBuilder;
27 using storage::BlobDataHandle;
28 using storage::BlobDataItem;
29 using storage::BlobDataSnapshot;
30 using storage::BlobStorageContext;
31 using storage::DataElement;
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 void SetupBasicBlob(BlobStorageHost* host, const std::string& id) {
76 EXPECT_TRUE(host->StartBuildingBlob(id));
77 DataElement item;
78 item.SetToBytes("1", 1);
79 EXPECT_TRUE(host->AppendBlobDataItem(id, item));
80 EXPECT_TRUE(host->FinishBuildingBlob(id, "text/plain"));
81 EXPECT_FALSE(host->StartBuildingBlob(id));
84 } // namespace
86 TEST(BlobStorageContextTest, IncrementDecrementRef) {
87 BlobStorageContext context;
88 BlobStorageHost host(&context);
89 base::MessageLoop fake_io_message_loop;
91 // Build up a basic blob.
92 const std::string kId("id");
93 SetupBasicBlob(&host, kId);
95 // Make sure it's there, finish building implies a ref of one.
96 scoped_ptr<BlobDataHandle> blob_data_handle;
97 blob_data_handle = context.GetBlobDataFromUUID(kId);
98 EXPECT_TRUE(blob_data_handle);
99 blob_data_handle.reset();
100 base::RunLoop().RunUntilIdle();
102 // Make sure its still there after inc/dec.
103 EXPECT_TRUE(host.IncrementBlobRefCount(kId));
104 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
105 blob_data_handle = context.GetBlobDataFromUUID(kId);
106 EXPECT_TRUE(blob_data_handle);
107 blob_data_handle.reset();
108 base::RunLoop().RunUntilIdle();
110 // Make sure it goes away in the end.
111 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
112 blob_data_handle = context.GetBlobDataFromUUID(kId);
113 EXPECT_FALSE(blob_data_handle);
114 EXPECT_FALSE(host.DecrementBlobRefCount(kId));
115 EXPECT_FALSE(host.IncrementBlobRefCount(kId));
118 TEST(BlobStorageContextTest, CancelBuildingBlob) {
119 BlobStorageContext context;
120 BlobStorageHost host(&context);
121 base::MessageLoop fake_io_message_loop;
123 // Build up a basic blob.
124 const std::string kId("id");
125 EXPECT_TRUE(host.StartBuildingBlob(kId));
126 DataElement item;
127 item.SetToBytes("1", 1);
128 EXPECT_TRUE(host.AppendBlobDataItem(kId, item));
129 EXPECT_TRUE(host.CancelBuildingBlob(kId));
130 EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
131 EXPECT_TRUE(host.StartBuildingBlob(kId));
134 TEST(BlobStorageContextTest, BlobDataHandle) {
135 BlobStorageContext context;
136 BlobStorageHost host(&context);
137 base::MessageLoop fake_io_message_loop;
139 // Build up a basic blob.
140 const std::string kId("id");
141 SetupBasicBlob(&host, kId);
143 // Get a handle to it.
144 scoped_ptr<BlobDataHandle> blob_data_handle =
145 context.GetBlobDataFromUUID(kId);
146 EXPECT_TRUE(blob_data_handle);
148 // Drop the host's ref to it.
149 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
151 // Should still be there due to the handle.
152 scoped_ptr<BlobDataHandle> another_handle =
153 context.GetBlobDataFromUUID(kId);
154 EXPECT_TRUE(another_handle);
156 // Should disappear after dropping both handles.
157 blob_data_handle.reset();
158 another_handle.reset();
159 base::RunLoop().RunUntilIdle();
161 blob_data_handle = context.GetBlobDataFromUUID(kId);
162 EXPECT_FALSE(blob_data_handle);
165 TEST(BlobStorageContextTest, MemoryUsage) {
166 const std::string kId1("id1");
167 const std::string kId2("id2");
169 base::MessageLoop fake_io_message_loop;
171 BlobDataBuilder builder1(kId1);
172 BlobDataBuilder builder2(kId2);
173 builder1.AppendData("Data1Data2");
174 builder2.AppendBlob(kId1);
175 builder2.AppendBlob(kId1);
176 builder2.AppendBlob(kId1);
177 builder2.AppendBlob(kId1);
178 builder2.AppendBlob(kId1);
179 builder2.AppendBlob(kId1);
180 builder2.AppendBlob(kId1);
182 BlobStorageContext context;
183 EXPECT_EQ(0lu, context.memory_usage());
185 scoped_ptr<BlobDataHandle> blob_data_handle =
186 context.AddFinishedBlob(&builder1);
187 EXPECT_EQ(10lu, context.memory_usage());
188 scoped_ptr<BlobDataHandle> blob_data_handle2 =
189 context.AddFinishedBlob(&builder2);
190 EXPECT_EQ(10lu, context.memory_usage());
192 blob_data_handle.reset();
193 base::RunLoop().RunUntilIdle();
195 EXPECT_EQ(10lu, context.memory_usage());
196 blob_data_handle2.reset();
197 base::RunLoop().RunUntilIdle();
199 EXPECT_EQ(0lu, context.memory_usage());
202 TEST(BlobStorageContextTest, AddFinishedBlob) {
203 const std::string kId1("id1");
204 const std::string kId2("id12");
205 const std::string kId2Prime("id2.prime");
206 const std::string kId3("id3");
207 const std::string kId3Prime("id3.prime");
209 base::MessageLoop fake_io_message_loop;
211 BlobDataBuilder builder1(kId1);
212 BlobDataBuilder builder2(kId2);
213 BlobDataBuilder canonicalized_blob_data2(kId2Prime);
214 builder1.AppendData("Data1Data2");
215 builder2.AppendBlob(kId1, 5, 5);
216 builder2.AppendData(" is the best");
217 canonicalized_blob_data2.AppendData("Data2");
218 canonicalized_blob_data2.AppendData(" is the best");
220 BlobStorageContext context;
222 scoped_ptr<BlobDataHandle> blob_data_handle =
223 context.AddFinishedBlob(&builder1);
224 scoped_ptr<BlobDataHandle> blob_data_handle2 =
225 context.AddFinishedBlob(&builder2);
227 ASSERT_TRUE(blob_data_handle);
228 ASSERT_TRUE(blob_data_handle2);
229 scoped_ptr<BlobDataSnapshot> data1 = blob_data_handle->CreateSnapshot();
230 scoped_ptr<BlobDataSnapshot> data2 = blob_data_handle2->CreateSnapshot();
231 EXPECT_EQ(*data1, builder1);
232 EXPECT_EQ(*data2, canonicalized_blob_data2);
233 blob_data_handle.reset();
234 data2.reset();
236 base::RunLoop().RunUntilIdle();
238 blob_data_handle = context.GetBlobDataFromUUID(kId1);
239 EXPECT_FALSE(blob_data_handle);
240 EXPECT_TRUE(blob_data_handle2);
241 data2 = blob_data_handle2->CreateSnapshot();
242 EXPECT_EQ(*data2, canonicalized_blob_data2);
244 // Test shared elements stick around.
245 BlobDataBuilder builder3(kId3);
246 builder3.AppendBlob(kId2);
247 builder3.AppendBlob(kId2);
248 scoped_ptr<BlobDataHandle> blob_data_handle3 =
249 context.AddFinishedBlob(&builder3);
250 blob_data_handle2.reset();
251 base::RunLoop().RunUntilIdle();
253 blob_data_handle2 = context.GetBlobDataFromUUID(kId2);
254 EXPECT_FALSE(blob_data_handle2);
255 EXPECT_TRUE(blob_data_handle3);
256 scoped_ptr<BlobDataSnapshot> data3 = blob_data_handle3->CreateSnapshot();
258 BlobDataBuilder canonicalized_blob_data3(kId3Prime);
259 canonicalized_blob_data3.AppendData("Data2");
260 canonicalized_blob_data3.AppendData(" is the best");
261 canonicalized_blob_data3.AppendData("Data2");
262 canonicalized_blob_data3.AppendData(" is the best");
263 EXPECT_EQ(*data3, canonicalized_blob_data3);
265 blob_data_handle.reset();
266 blob_data_handle2.reset();
267 blob_data_handle3.reset();
268 base::RunLoop().RunUntilIdle();
271 TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
272 // A value which does not fit in a 4-byte data type. Used to confirm that
273 // large values are supported on 32-bit Chromium builds. Regression test for:
274 // crbug.com/458122.
275 const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max();
277 const uint64_t kBlobLength = 5;
278 const std::string kId1("id1");
279 const std::string kId2("id2");
280 base::MessageLoop fake_io_message_loop;
282 BlobDataBuilder builder1(kId1);
283 builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now());
285 BlobDataBuilder builder2(kId2);
286 builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength);
288 BlobStorageContext context;
289 scoped_ptr<BlobDataHandle> blob_data_handle1 =
290 context.AddFinishedBlob(&builder1);
291 scoped_ptr<BlobDataHandle> blob_data_handle2 =
292 context.AddFinishedBlob(&builder2);
294 ASSERT_TRUE(blob_data_handle1);
295 ASSERT_TRUE(blob_data_handle2);
296 scoped_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot();
297 ASSERT_EQ(1u, data->items().size());
298 const scoped_refptr<BlobDataItem> item = data->items()[0];
299 EXPECT_EQ(kLargeSize - kBlobLength, item->offset());
300 EXPECT_EQ(kBlobLength, item->length());
302 blob_data_handle1.reset();
303 blob_data_handle2.reset();
304 base::RunLoop().RunUntilIdle();
307 TEST(BlobStorageContextTest, BuildDiskCacheBlob) {
308 base::MessageLoop fake_io_message_loop;
309 scoped_refptr<BlobDataBuilder::DataHandle>
310 data_handle = new EmptyDataHandle();
313 scoped_ptr<BlobStorageContext> context(new BlobStorageContext);
314 BlobStorageHost host(context.get());
316 scoped_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache();
317 ASSERT_TRUE(cache);
319 const std::string kTestBlobData = "Test Blob Data";
320 disk_cache::ScopedEntryPtr entry =
321 CreateDiskCacheEntry(cache.get(), "test entry", kTestBlobData);
323 const std::string kId1Prime("id1.prime");
324 BlobDataBuilder canonicalized_blob_data(kId1Prime);
325 canonicalized_blob_data.AppendData(kTestBlobData.c_str());
327 const std::string kId1("id1");
328 BlobDataBuilder builder(kId1);
330 builder.AppendDiskCacheEntry(
331 data_handle, entry.get(), kTestDiskCacheStreamIndex);
333 scoped_ptr<BlobDataHandle> blob_data_handle =
334 context->AddFinishedBlob(&builder);
335 scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
336 EXPECT_EQ(*data, builder);
337 EXPECT_FALSE(data_handle->HasOneRef())
338 << "Data handle was destructed while context and builder still exist.";
340 EXPECT_TRUE(data_handle->HasOneRef())
341 << "Data handle was not destructed along with blob storage context.";
342 base::RunLoop().RunUntilIdle();
345 TEST(BlobStorageContextTest, CompoundBlobs) {
346 const std::string kId1("id1");
347 const std::string kId2("id2");
348 const std::string kId3("id3");
349 const std::string kId2Prime("id2.prime");
351 base::MessageLoop fake_io_message_loop;
353 // Setup a set of blob data for testing.
354 base::Time time1, time2;
355 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1);
356 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2);
358 BlobDataBuilder blob_data1(kId1);
359 blob_data1.AppendData("Data1");
360 blob_data1.AppendData("Data2");
361 blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10,
362 1024, time1);
364 BlobDataBuilder blob_data2(kId2);
365 blob_data2.AppendData("Data3");
366 blob_data2.AppendBlob(kId1, 8, 100);
367 blob_data2.AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20,
368 time2);
370 BlobDataBuilder blob_data3(kId3);
371 blob_data3.AppendData("Data4");
372 scoped_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache();
373 ASSERT_TRUE(cache);
374 disk_cache::ScopedEntryPtr disk_cache_entry =
375 CreateDiskCacheEntry(cache.get(), "another key", "Data5");
376 blob_data3.AppendDiskCacheEntry(new EmptyDataHandle(), disk_cache_entry.get(),
377 kTestDiskCacheStreamIndex);
379 BlobDataBuilder canonicalized_blob_data2(kId2Prime);
380 canonicalized_blob_data2.AppendData("Data3");
381 canonicalized_blob_data2.AppendData("a2___", 2);
382 canonicalized_blob_data2.AppendFile(
383 base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, 98, time1);
384 canonicalized_blob_data2.AppendFile(
385 base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2);
387 BlobStorageContext context;
388 scoped_ptr<BlobDataHandle> blob_data_handle;
390 // Test a blob referring to only data and a file.
391 blob_data_handle = context.AddFinishedBlob(&blob_data1);
393 ASSERT_TRUE(blob_data_handle);
394 scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
395 ASSERT_TRUE(blob_data_handle);
396 EXPECT_EQ(*data, blob_data1);
398 // Test a blob composed in part with another blob.
399 blob_data_handle = context.AddFinishedBlob(&blob_data2);
400 data = blob_data_handle->CreateSnapshot();
401 ASSERT_TRUE(blob_data_handle);
402 ASSERT_TRUE(data);
403 EXPECT_EQ(*data, canonicalized_blob_data2);
405 // Test a blob referring to only data and a disk cache entry.
406 blob_data_handle = context.AddFinishedBlob(&blob_data3);
407 data = blob_data_handle->CreateSnapshot();
408 ASSERT_TRUE(blob_data_handle);
409 EXPECT_EQ(*data, blob_data3);
411 blob_data_handle.reset();
412 base::RunLoop().RunUntilIdle();
415 TEST(BlobStorageContextTest, PublicBlobUrls) {
416 BlobStorageContext context;
417 BlobStorageHost host(&context);
418 base::MessageLoop fake_io_message_loop;
420 // Build up a basic blob.
421 const std::string kId("id");
422 SetupBasicBlob(&host, kId);
424 // Now register a url for that blob.
425 GURL kUrl("blob:id");
426 EXPECT_TRUE(host.RegisterPublicBlobURL(kUrl, kId));
427 scoped_ptr<BlobDataHandle> blob_data_handle =
428 context.GetBlobDataFromPublicURL(kUrl);
429 ASSERT_TRUE(blob_data_handle.get());
430 EXPECT_EQ(kId, blob_data_handle->uuid());
431 scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
432 blob_data_handle.reset();
433 base::RunLoop().RunUntilIdle();
435 // The url registration should keep the blob alive even after
436 // explicit references are dropped.
437 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
438 blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
439 EXPECT_TRUE(blob_data_handle);
440 blob_data_handle.reset();
441 base::RunLoop().RunUntilIdle();
443 // Finally get rid of the url registration and the blob.
444 EXPECT_TRUE(host.RevokePublicBlobURL(kUrl));
445 blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
446 EXPECT_TRUE(!blob_data_handle.get());
447 EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
450 TEST(BlobStorageContextTest, HostCleanup) {
451 BlobStorageContext context;
452 scoped_ptr<BlobStorageHost> host(new BlobStorageHost(&context));
453 base::MessageLoop fake_io_message_loop;
455 // Build up a basic blob and register a url
456 const std::string kId("id");
457 GURL kUrl("blob:id");
458 SetupBasicBlob(host.get(), kId);
459 EXPECT_TRUE(host->RegisterPublicBlobURL(kUrl, kId));
461 // All should disappear upon host deletion.
462 host.reset();
463 scoped_ptr<BlobDataHandle> handle = context.GetBlobDataFromPublicURL(kUrl);
464 EXPECT_TRUE(!handle.get());
465 handle = context.GetBlobDataFromUUID(kId);
466 EXPECT_TRUE(!handle.get());
469 TEST(BlobStorageContextTest, EarlyContextDeletion) {
470 scoped_ptr<BlobStorageContext> context(new BlobStorageContext);
471 BlobStorageHost host(context.get());
472 base::MessageLoop fake_io_message_loop;
474 // Deleting the context should not induce crashes.
475 context.reset();
477 const std::string kId("id");
478 GURL kUrl("blob:id");
479 EXPECT_FALSE(host.StartBuildingBlob(kId));
480 DataElement item;
481 item.SetToBytes("1", 1);
482 EXPECT_FALSE(host.AppendBlobDataItem(kId, item));
483 EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
484 EXPECT_FALSE(host.RegisterPublicBlobURL(kUrl, kId));
485 EXPECT_FALSE(host.IncrementBlobRefCount(kId));
486 EXPECT_FALSE(host.DecrementBlobRefCount(kId));
487 EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
490 // TODO(michaeln): tests for the depcrecated url stuff
492 } // namespace content