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 "base/files/file_path.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/time/time.h"
11 #include "content/browser/fileapi/blob_storage_host.h"
12 #include "storage/browser/blob/blob_data_builder.h"
13 #include "storage/browser/blob/blob_data_handle.h"
14 #include "storage/browser/blob/blob_data_snapshot.h"
15 #include "storage/browser/blob/blob_storage_context.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using storage::BlobDataBuilder
;
19 using storage::BlobDataHandle
;
20 using storage::BlobDataSnapshot
;
21 using storage::BlobStorageContext
;
22 using storage::DataElement
;
27 // This is necessary to clean up the blobs after the handles are released.
28 void RunEventLoopTillIdle() {
29 base::RunLoop run_loop
;
30 run_loop
.RunUntilIdle();
33 void SetupBasicBlob(BlobStorageHost
* host
, const std::string
& id
) {
34 EXPECT_TRUE(host
->StartBuildingBlob(id
));
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
));
43 TEST(BlobStorageContextTest
, IncrementDecrementRef
) {
44 BlobStorageContext context
;
45 BlobStorageHost
host(&context
);
46 base::MessageLoop fake_io_message_loop
;
48 // Build up a basic blob.
49 const std::string
kId("id");
50 SetupBasicBlob(&host
, kId
);
52 // Make sure it's there, finish building implies a ref of one.
53 scoped_ptr
<BlobDataHandle
> blob_data_handle
;
54 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
55 EXPECT_TRUE(blob_data_handle
);
56 blob_data_handle
.reset();
57 RunEventLoopTillIdle();
59 // Make sure its still there after inc/dec.
60 EXPECT_TRUE(host
.IncrementBlobRefCount(kId
));
61 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
62 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
63 EXPECT_TRUE(blob_data_handle
);
64 blob_data_handle
.reset();
65 RunEventLoopTillIdle();
67 // Make sure it goes away in the end.
68 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
69 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
70 EXPECT_FALSE(blob_data_handle
);
71 EXPECT_FALSE(host
.DecrementBlobRefCount(kId
));
72 EXPECT_FALSE(host
.IncrementBlobRefCount(kId
));
75 TEST(BlobStorageContextTest
, CancelBuildingBlob
) {
76 BlobStorageContext context
;
77 BlobStorageHost
host(&context
);
78 base::MessageLoop fake_io_message_loop
;
80 // Build up a basic blob.
81 const std::string
kId("id");
82 EXPECT_TRUE(host
.StartBuildingBlob(kId
));
84 item
.SetToBytes("1", 1);
85 EXPECT_TRUE(host
.AppendBlobDataItem(kId
, item
));
86 EXPECT_TRUE(host
.CancelBuildingBlob(kId
));
87 EXPECT_FALSE(host
.FinishBuildingBlob(kId
, "text/plain"));
88 EXPECT_TRUE(host
.StartBuildingBlob(kId
));
91 TEST(BlobStorageContextTest
, BlobDataHandle
) {
92 BlobStorageContext context
;
93 BlobStorageHost
host(&context
);
94 base::MessageLoop fake_io_message_loop
;
96 // Build up a basic blob.
97 const std::string
kId("id");
98 SetupBasicBlob(&host
, kId
);
100 // Get a handle to it.
101 scoped_ptr
<BlobDataHandle
> blob_data_handle
=
102 context
.GetBlobDataFromUUID(kId
);
103 EXPECT_TRUE(blob_data_handle
);
105 // Drop the host's ref to it.
106 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
108 // Should still be there due to the handle.
109 scoped_ptr
<BlobDataHandle
> another_handle
=
110 context
.GetBlobDataFromUUID(kId
);
111 EXPECT_TRUE(another_handle
);
113 // Should disappear after dropping both handles.
114 blob_data_handle
.reset();
115 another_handle
.reset();
116 RunEventLoopTillIdle();
118 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
119 EXPECT_FALSE(blob_data_handle
);
122 TEST(BlobStorageContextTest
, MemoryUsage
) {
123 const std::string
kId1("id1");
124 const std::string
kId2("id2");
126 base::MessageLoop fake_io_message_loop
;
128 BlobDataBuilder
builder1(kId1
);
129 BlobDataBuilder
builder2(kId2
);
130 builder1
.AppendData("Data1Data2");
131 builder2
.AppendBlob(kId1
);
132 builder2
.AppendBlob(kId1
);
133 builder2
.AppendBlob(kId1
);
134 builder2
.AppendBlob(kId1
);
135 builder2
.AppendBlob(kId1
);
136 builder2
.AppendBlob(kId1
);
137 builder2
.AppendBlob(kId1
);
139 BlobStorageContext context
;
140 EXPECT_EQ(0lu, context
.memory_usage());
142 scoped_ptr
<BlobDataHandle
> blob_data_handle
=
143 context
.AddFinishedBlob(&builder1
);
144 EXPECT_EQ(10lu, context
.memory_usage());
145 scoped_ptr
<BlobDataHandle
> blob_data_handle2
=
146 context
.AddFinishedBlob(&builder2
);
147 EXPECT_EQ(10lu, context
.memory_usage());
149 blob_data_handle
.reset();
150 RunEventLoopTillIdle();
152 EXPECT_EQ(10lu, context
.memory_usage());
153 blob_data_handle2
.reset();
154 RunEventLoopTillIdle();
156 EXPECT_EQ(0lu, context
.memory_usage());
159 TEST(BlobStorageContextTest
, AddFinishedBlob
) {
160 const std::string
kId1("id1");
161 const std::string
kId2("id12");
162 const std::string
kId2Prime("id2.prime");
163 const std::string
kId3("id3");
164 const std::string
kId3Prime("id3.prime");
166 base::MessageLoop fake_io_message_loop
;
168 BlobDataBuilder
builder1(kId1
);
169 BlobDataBuilder
builder2(kId2
);
170 BlobDataBuilder
canonicalized_blob_data2(kId2Prime
);
171 builder1
.AppendData("Data1Data2");
172 builder2
.AppendBlob(kId1
, 5, 5);
173 builder2
.AppendData(" is the best");
174 canonicalized_blob_data2
.AppendData("Data2");
175 canonicalized_blob_data2
.AppendData(" is the best");
177 BlobStorageContext context
;
179 scoped_ptr
<BlobDataHandle
> blob_data_handle
=
180 context
.AddFinishedBlob(&builder1
);
181 scoped_ptr
<BlobDataHandle
> blob_data_handle2
=
182 context
.AddFinishedBlob(&builder2
);
184 ASSERT_TRUE(blob_data_handle
);
185 ASSERT_TRUE(blob_data_handle2
);
186 scoped_ptr
<BlobDataSnapshot
> data1
= blob_data_handle
->CreateSnapshot();
187 scoped_ptr
<BlobDataSnapshot
> data2
= blob_data_handle2
->CreateSnapshot();
188 EXPECT_EQ(*data1
, builder1
);
189 EXPECT_EQ(*data2
, canonicalized_blob_data2
);
190 blob_data_handle
.reset();
193 RunEventLoopTillIdle();
195 blob_data_handle
= context
.GetBlobDataFromUUID(kId1
);
196 EXPECT_FALSE(blob_data_handle
);
197 EXPECT_TRUE(blob_data_handle2
);
198 data2
= blob_data_handle2
->CreateSnapshot();
199 EXPECT_EQ(*data2
, canonicalized_blob_data2
);
201 // Test shared elements stick around.
202 BlobDataBuilder
builder3(kId3
);
203 builder3
.AppendBlob(kId2
);
204 builder3
.AppendBlob(kId2
);
205 scoped_ptr
<BlobDataHandle
> blob_data_handle3
=
206 context
.AddFinishedBlob(&builder3
);
207 blob_data_handle2
.reset();
208 RunEventLoopTillIdle();
210 blob_data_handle2
= context
.GetBlobDataFromUUID(kId2
);
211 EXPECT_FALSE(blob_data_handle2
);
212 EXPECT_TRUE(blob_data_handle3
);
213 scoped_ptr
<BlobDataSnapshot
> data3
= blob_data_handle3
->CreateSnapshot();
215 BlobDataBuilder
canonicalized_blob_data3(kId3Prime
);
216 canonicalized_blob_data3
.AppendData("Data2");
217 canonicalized_blob_data3
.AppendData(" is the best");
218 canonicalized_blob_data3
.AppendData("Data2");
219 canonicalized_blob_data3
.AppendData(" is the best");
220 EXPECT_EQ(*data3
, canonicalized_blob_data3
);
222 blob_data_handle
.reset();
223 blob_data_handle2
.reset();
224 blob_data_handle3
.reset();
225 RunEventLoopTillIdle();
228 TEST(BlobStorageContextTest
, CompoundBlobs
) {
229 const std::string
kId1("id1");
230 const std::string
kId2("id2");
231 const std::string
kId2Prime("id2.prime");
233 base::MessageLoop fake_io_message_loop
;
235 // Setup a set of blob data for testing.
236 base::Time time1
, time2
;
237 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1
);
238 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2
);
240 BlobDataBuilder
blob_data1(kId1
);
241 blob_data1
.AppendData("Data1");
242 blob_data1
.AppendData("Data2");
243 blob_data1
.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10,
246 BlobDataBuilder
blob_data2(kId2
);
247 blob_data2
.AppendData("Data3");
248 blob_data2
.AppendBlob(kId1
, 8, 100);
249 blob_data2
.AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20,
252 BlobDataBuilder
canonicalized_blob_data2(kId2Prime
);
253 canonicalized_blob_data2
.AppendData("Data3");
254 canonicalized_blob_data2
.AppendData("a2___", 2);
255 canonicalized_blob_data2
.AppendFile(
256 base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, 98, time1
);
257 canonicalized_blob_data2
.AppendFile(
258 base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2
);
260 BlobStorageContext context
;
261 scoped_ptr
<BlobDataHandle
> blob_data_handle
;
263 // Test a blob referring to only data and a file.
264 blob_data_handle
= context
.AddFinishedBlob(&blob_data1
);
266 ASSERT_TRUE(blob_data_handle
);
267 scoped_ptr
<BlobDataSnapshot
> data
= blob_data_handle
->CreateSnapshot();
268 ASSERT_TRUE(blob_data_handle
);
269 EXPECT_EQ(*data
, blob_data1
);
271 // Test a blob composed in part with another blob.
272 blob_data_handle
= context
.AddFinishedBlob(&blob_data2
);
273 data
= blob_data_handle
->CreateSnapshot();
274 ASSERT_TRUE(blob_data_handle
);
276 EXPECT_EQ(*data
, canonicalized_blob_data2
);
278 blob_data_handle
.reset();
279 RunEventLoopTillIdle();
282 TEST(BlobStorageContextTest
, PublicBlobUrls
) {
283 BlobStorageContext context
;
284 BlobStorageHost
host(&context
);
285 base::MessageLoop fake_io_message_loop
;
287 // Build up a basic blob.
288 const std::string
kId("id");
289 SetupBasicBlob(&host
, kId
);
291 // Now register a url for that blob.
292 GURL
kUrl("blob:id");
293 EXPECT_TRUE(host
.RegisterPublicBlobURL(kUrl
, kId
));
294 scoped_ptr
<BlobDataHandle
> blob_data_handle
=
295 context
.GetBlobDataFromPublicURL(kUrl
);
296 ASSERT_TRUE(blob_data_handle
.get());
297 EXPECT_EQ(kId
, blob_data_handle
->uuid());
298 scoped_ptr
<BlobDataSnapshot
> data
= blob_data_handle
->CreateSnapshot();
299 blob_data_handle
.reset();
300 RunEventLoopTillIdle();
302 // The url registration should keep the blob alive even after
303 // explicit references are dropped.
304 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
305 blob_data_handle
= context
.GetBlobDataFromPublicURL(kUrl
);
306 EXPECT_TRUE(blob_data_handle
);
307 blob_data_handle
.reset();
308 RunEventLoopTillIdle();
310 // Finally get rid of the url registration and the blob.
311 EXPECT_TRUE(host
.RevokePublicBlobURL(kUrl
));
312 blob_data_handle
= context
.GetBlobDataFromPublicURL(kUrl
);
313 EXPECT_TRUE(!blob_data_handle
.get());
314 EXPECT_FALSE(host
.RevokePublicBlobURL(kUrl
));
317 TEST(BlobStorageContextTest
, HostCleanup
) {
318 BlobStorageContext context
;
319 scoped_ptr
<BlobStorageHost
> host(new BlobStorageHost(&context
));
320 base::MessageLoop fake_io_message_loop
;
322 // Build up a basic blob and register a url
323 const std::string
kId("id");
324 GURL
kUrl("blob:id");
325 SetupBasicBlob(host
.get(), kId
);
326 EXPECT_TRUE(host
->RegisterPublicBlobURL(kUrl
, kId
));
328 // All should disappear upon host deletion.
330 scoped_ptr
<BlobDataHandle
> handle
= context
.GetBlobDataFromPublicURL(kUrl
);
331 EXPECT_TRUE(!handle
.get());
332 handle
= context
.GetBlobDataFromUUID(kId
);
333 EXPECT_TRUE(!handle
.get());
336 TEST(BlobStorageContextTest
, EarlyContextDeletion
) {
337 scoped_ptr
<BlobStorageContext
> context(new BlobStorageContext
);
338 BlobStorageHost
host(context
.get());
339 base::MessageLoop fake_io_message_loop
;
341 // Deleting the context should not induce crashes.
344 const std::string
kId("id");
345 GURL
kUrl("blob:id");
346 EXPECT_FALSE(host
.StartBuildingBlob(kId
));
348 item
.SetToBytes("1", 1);
349 EXPECT_FALSE(host
.AppendBlobDataItem(kId
, item
));
350 EXPECT_FALSE(host
.FinishBuildingBlob(kId
, "text/plain"));
351 EXPECT_FALSE(host
.RegisterPublicBlobURL(kUrl
, kId
));
352 EXPECT_FALSE(host
.IncrementBlobRefCount(kId
));
353 EXPECT_FALSE(host
.DecrementBlobRefCount(kId
));
354 EXPECT_FALSE(host
.RevokePublicBlobURL(kUrl
));
357 // TODO(michaeln): tests for the depcrecated url stuff
359 } // namespace content