Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / fileapi / blob_storage_context_unittest.cc
blob29270b7dea925fa75d576778d04d7cbb0ac927c9
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 "storage/browser/blob/blob_data_builder.h"
18 #include "storage/browser/blob/blob_data_handle.h"
19 #include "storage/browser/blob/blob_data_item.h"
20 #include "storage/browser/blob/blob_data_snapshot.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using storage::BlobDataBuilder;
24 using storage::BlobDataHandle;
25 using storage::BlobDataItem;
26 using storage::BlobDataSnapshot;
27 using storage::BlobStorageContext;
28 using storage::DataElement;
30 namespace content {
31 namespace {
33 void SetupBasicBlob(BlobStorageHost* host, const std::string& id) {
34 EXPECT_TRUE(host->StartBuildingBlob(id));
35 DataElement item;
36 item.SetToBytes("1", 1);
37 EXPECT_TRUE(host->AppendBlobDataItem(id, item));
38 EXPECT_TRUE(host->FinishBuildingBlob(id, "text/plain"));
39 EXPECT_FALSE(host->StartBuildingBlob(id));
42 } // namespace
44 TEST(BlobStorageContextTest, IncrementDecrementRef) {
45 BlobStorageContext context;
46 BlobStorageHost host(&context);
47 base::MessageLoop fake_io_message_loop;
49 // Build up a basic blob.
50 const std::string kId("id");
51 SetupBasicBlob(&host, kId);
53 // Make sure it's there, finish building implies a ref of one.
54 scoped_ptr<BlobDataHandle> blob_data_handle;
55 blob_data_handle = context.GetBlobDataFromUUID(kId);
56 EXPECT_TRUE(blob_data_handle);
57 blob_data_handle.reset();
58 base::RunLoop().RunUntilIdle();
60 // Make sure its still there after inc/dec.
61 EXPECT_TRUE(host.IncrementBlobRefCount(kId));
62 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
63 blob_data_handle = context.GetBlobDataFromUUID(kId);
64 EXPECT_TRUE(blob_data_handle);
65 blob_data_handle.reset();
66 base::RunLoop().RunUntilIdle();
68 // Make sure it goes away in the end.
69 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
70 blob_data_handle = context.GetBlobDataFromUUID(kId);
71 EXPECT_FALSE(blob_data_handle);
72 EXPECT_FALSE(host.DecrementBlobRefCount(kId));
73 EXPECT_FALSE(host.IncrementBlobRefCount(kId));
76 TEST(BlobStorageContextTest, CancelBuildingBlob) {
77 BlobStorageContext context;
78 BlobStorageHost host(&context);
79 base::MessageLoop fake_io_message_loop;
81 // Build up a basic blob.
82 const std::string kId("id");
83 EXPECT_TRUE(host.StartBuildingBlob(kId));
84 DataElement item;
85 item.SetToBytes("1", 1);
86 EXPECT_TRUE(host.AppendBlobDataItem(kId, item));
87 EXPECT_TRUE(host.CancelBuildingBlob(kId));
88 EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
89 EXPECT_TRUE(host.StartBuildingBlob(kId));
92 TEST(BlobStorageContextTest, BlobDataHandle) {
93 BlobStorageContext context;
94 BlobStorageHost host(&context);
95 base::MessageLoop fake_io_message_loop;
97 // Build up a basic blob.
98 const std::string kId("id");
99 SetupBasicBlob(&host, kId);
101 // Get a handle to it.
102 scoped_ptr<BlobDataHandle> blob_data_handle =
103 context.GetBlobDataFromUUID(kId);
104 EXPECT_TRUE(blob_data_handle);
106 // Drop the host's ref to it.
107 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
109 // Should still be there due to the handle.
110 scoped_ptr<BlobDataHandle> another_handle =
111 context.GetBlobDataFromUUID(kId);
112 EXPECT_TRUE(another_handle);
114 // Should disappear after dropping both handles.
115 blob_data_handle.reset();
116 another_handle.reset();
117 base::RunLoop().RunUntilIdle();
119 blob_data_handle = context.GetBlobDataFromUUID(kId);
120 EXPECT_FALSE(blob_data_handle);
123 TEST(BlobStorageContextTest, MemoryUsage) {
124 const std::string kId1("id1");
125 const std::string kId2("id2");
127 base::MessageLoop fake_io_message_loop;
129 BlobDataBuilder builder1(kId1);
130 BlobDataBuilder builder2(kId2);
131 builder1.AppendData("Data1Data2");
132 builder2.AppendBlob(kId1);
133 builder2.AppendBlob(kId1);
134 builder2.AppendBlob(kId1);
135 builder2.AppendBlob(kId1);
136 builder2.AppendBlob(kId1);
137 builder2.AppendBlob(kId1);
138 builder2.AppendBlob(kId1);
140 BlobStorageContext context;
141 EXPECT_EQ(0lu, context.memory_usage());
143 scoped_ptr<BlobDataHandle> blob_data_handle =
144 context.AddFinishedBlob(&builder1);
145 EXPECT_EQ(10lu, context.memory_usage());
146 scoped_ptr<BlobDataHandle> blob_data_handle2 =
147 context.AddFinishedBlob(&builder2);
148 EXPECT_EQ(10lu, context.memory_usage());
150 blob_data_handle.reset();
151 base::RunLoop().RunUntilIdle();
153 EXPECT_EQ(10lu, context.memory_usage());
154 blob_data_handle2.reset();
155 base::RunLoop().RunUntilIdle();
157 EXPECT_EQ(0lu, context.memory_usage());
160 TEST(BlobStorageContextTest, AddFinishedBlob) {
161 const std::string kId1("id1");
162 const std::string kId2("id12");
163 const std::string kId2Prime("id2.prime");
164 const std::string kId3("id3");
165 const std::string kId3Prime("id3.prime");
167 base::MessageLoop fake_io_message_loop;
169 BlobDataBuilder builder1(kId1);
170 BlobDataBuilder builder2(kId2);
171 BlobDataBuilder canonicalized_blob_data2(kId2Prime);
172 builder1.AppendData("Data1Data2");
173 builder2.AppendBlob(kId1, 5, 5);
174 builder2.AppendData(" is the best");
175 canonicalized_blob_data2.AppendData("Data2");
176 canonicalized_blob_data2.AppendData(" is the best");
178 BlobStorageContext context;
180 scoped_ptr<BlobDataHandle> blob_data_handle =
181 context.AddFinishedBlob(&builder1);
182 scoped_ptr<BlobDataHandle> blob_data_handle2 =
183 context.AddFinishedBlob(&builder2);
185 ASSERT_TRUE(blob_data_handle);
186 ASSERT_TRUE(blob_data_handle2);
187 scoped_ptr<BlobDataSnapshot> data1 = blob_data_handle->CreateSnapshot();
188 scoped_ptr<BlobDataSnapshot> data2 = blob_data_handle2->CreateSnapshot();
189 EXPECT_EQ(*data1, builder1);
190 EXPECT_EQ(*data2, canonicalized_blob_data2);
191 blob_data_handle.reset();
192 data2.reset();
194 base::RunLoop().RunUntilIdle();
196 blob_data_handle = context.GetBlobDataFromUUID(kId1);
197 EXPECT_FALSE(blob_data_handle);
198 EXPECT_TRUE(blob_data_handle2);
199 data2 = blob_data_handle2->CreateSnapshot();
200 EXPECT_EQ(*data2, canonicalized_blob_data2);
202 // Test shared elements stick around.
203 BlobDataBuilder builder3(kId3);
204 builder3.AppendBlob(kId2);
205 builder3.AppendBlob(kId2);
206 scoped_ptr<BlobDataHandle> blob_data_handle3 =
207 context.AddFinishedBlob(&builder3);
208 blob_data_handle2.reset();
209 base::RunLoop().RunUntilIdle();
211 blob_data_handle2 = context.GetBlobDataFromUUID(kId2);
212 EXPECT_FALSE(blob_data_handle2);
213 EXPECT_TRUE(blob_data_handle3);
214 scoped_ptr<BlobDataSnapshot> data3 = blob_data_handle3->CreateSnapshot();
216 BlobDataBuilder canonicalized_blob_data3(kId3Prime);
217 canonicalized_blob_data3.AppendData("Data2");
218 canonicalized_blob_data3.AppendData(" is the best");
219 canonicalized_blob_data3.AppendData("Data2");
220 canonicalized_blob_data3.AppendData(" is the best");
221 EXPECT_EQ(*data3, canonicalized_blob_data3);
223 blob_data_handle.reset();
224 blob_data_handle2.reset();
225 blob_data_handle3.reset();
226 base::RunLoop().RunUntilIdle();
229 TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
230 // A value which does not fit in a 4-byte data type. Used to confirm that
231 // large values are supported on 32-bit Chromium builds. Regression test for:
232 // crbug.com/458122.
233 const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max();
235 const uint64_t kBlobLength = 5;
236 const std::string kId1("id1");
237 const std::string kId2("id2");
238 base::MessageLoop fake_io_message_loop;
240 BlobDataBuilder builder1(kId1);
241 builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now());
243 BlobDataBuilder builder2(kId2);
244 builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength);
246 BlobStorageContext context;
247 scoped_ptr<BlobDataHandle> blob_data_handle1 =
248 context.AddFinishedBlob(&builder1);
249 scoped_ptr<BlobDataHandle> blob_data_handle2 =
250 context.AddFinishedBlob(&builder2);
252 ASSERT_TRUE(blob_data_handle1);
253 ASSERT_TRUE(blob_data_handle2);
254 scoped_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot();
255 ASSERT_EQ(1u, data->items().size());
256 const scoped_refptr<BlobDataItem> item = data->items()[0];
257 EXPECT_EQ(kLargeSize - kBlobLength, item->offset());
258 EXPECT_EQ(kBlobLength, item->length());
260 blob_data_handle1.reset();
261 blob_data_handle2.reset();
262 base::RunLoop().RunUntilIdle();
265 TEST(BlobStorageContextTest, CompoundBlobs) {
266 const std::string kId1("id1");
267 const std::string kId2("id2");
268 const std::string kId2Prime("id2.prime");
270 base::MessageLoop fake_io_message_loop;
272 // Setup a set of blob data for testing.
273 base::Time time1, time2;
274 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1);
275 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2);
277 BlobDataBuilder blob_data1(kId1);
278 blob_data1.AppendData("Data1");
279 blob_data1.AppendData("Data2");
280 blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10,
281 1024, time1);
283 BlobDataBuilder blob_data2(kId2);
284 blob_data2.AppendData("Data3");
285 blob_data2.AppendBlob(kId1, 8, 100);
286 blob_data2.AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20,
287 time2);
289 BlobDataBuilder canonicalized_blob_data2(kId2Prime);
290 canonicalized_blob_data2.AppendData("Data3");
291 canonicalized_blob_data2.AppendData("a2___", 2);
292 canonicalized_blob_data2.AppendFile(
293 base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, 98, time1);
294 canonicalized_blob_data2.AppendFile(
295 base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2);
297 BlobStorageContext context;
298 scoped_ptr<BlobDataHandle> blob_data_handle;
300 // Test a blob referring to only data and a file.
301 blob_data_handle = context.AddFinishedBlob(&blob_data1);
303 ASSERT_TRUE(blob_data_handle);
304 scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
305 ASSERT_TRUE(blob_data_handle);
306 EXPECT_EQ(*data, blob_data1);
308 // Test a blob composed in part with another blob.
309 blob_data_handle = context.AddFinishedBlob(&blob_data2);
310 data = blob_data_handle->CreateSnapshot();
311 ASSERT_TRUE(blob_data_handle);
312 ASSERT_TRUE(data);
313 EXPECT_EQ(*data, canonicalized_blob_data2);
315 blob_data_handle.reset();
316 base::RunLoop().RunUntilIdle();
319 TEST(BlobStorageContextTest, PublicBlobUrls) {
320 BlobStorageContext context;
321 BlobStorageHost host(&context);
322 base::MessageLoop fake_io_message_loop;
324 // Build up a basic blob.
325 const std::string kId("id");
326 SetupBasicBlob(&host, kId);
328 // Now register a url for that blob.
329 GURL kUrl("blob:id");
330 EXPECT_TRUE(host.RegisterPublicBlobURL(kUrl, kId));
331 scoped_ptr<BlobDataHandle> blob_data_handle =
332 context.GetBlobDataFromPublicURL(kUrl);
333 ASSERT_TRUE(blob_data_handle.get());
334 EXPECT_EQ(kId, blob_data_handle->uuid());
335 scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
336 blob_data_handle.reset();
337 base::RunLoop().RunUntilIdle();
339 // The url registration should keep the blob alive even after
340 // explicit references are dropped.
341 EXPECT_TRUE(host.DecrementBlobRefCount(kId));
342 blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
343 EXPECT_TRUE(blob_data_handle);
344 blob_data_handle.reset();
345 base::RunLoop().RunUntilIdle();
347 // Finally get rid of the url registration and the blob.
348 EXPECT_TRUE(host.RevokePublicBlobURL(kUrl));
349 blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
350 EXPECT_TRUE(!blob_data_handle.get());
351 EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
354 TEST(BlobStorageContextTest, HostCleanup) {
355 BlobStorageContext context;
356 scoped_ptr<BlobStorageHost> host(new BlobStorageHost(&context));
357 base::MessageLoop fake_io_message_loop;
359 // Build up a basic blob and register a url
360 const std::string kId("id");
361 GURL kUrl("blob:id");
362 SetupBasicBlob(host.get(), kId);
363 EXPECT_TRUE(host->RegisterPublicBlobURL(kUrl, kId));
365 // All should disappear upon host deletion.
366 host.reset();
367 scoped_ptr<BlobDataHandle> handle = context.GetBlobDataFromPublicURL(kUrl);
368 EXPECT_TRUE(!handle.get());
369 handle = context.GetBlobDataFromUUID(kId);
370 EXPECT_TRUE(!handle.get());
373 TEST(BlobStorageContextTest, EarlyContextDeletion) {
374 scoped_ptr<BlobStorageContext> context(new BlobStorageContext);
375 BlobStorageHost host(context.get());
376 base::MessageLoop fake_io_message_loop;
378 // Deleting the context should not induce crashes.
379 context.reset();
381 const std::string kId("id");
382 GURL kUrl("blob:id");
383 EXPECT_FALSE(host.StartBuildingBlob(kId));
384 DataElement item;
385 item.SetToBytes("1", 1);
386 EXPECT_FALSE(host.AppendBlobDataItem(kId, item));
387 EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
388 EXPECT_FALSE(host.RegisterPublicBlobURL(kUrl, kId));
389 EXPECT_FALSE(host.IncrementBlobRefCount(kId));
390 EXPECT_FALSE(host.DecrementBlobRefCount(kId));
391 EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
394 // TODO(michaeln): tests for the depcrecated url stuff
396 } // namespace content