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 "testing/gtest/include/gtest/gtest.h"
13 #include "webkit/browser/blob/blob_data_handle.h"
14 #include "webkit/browser/blob/blob_storage_context.h"
16 using webkit_blob::BlobDataHandle
;
21 void SetupBasicBlob(BlobStorageHost
* host
, const std::string
& id
) {
22 EXPECT_TRUE(host
->StartBuildingBlob(id
));
24 item
.SetToBytes("1", 1);
25 EXPECT_TRUE(host
->AppendBlobDataItem(id
, item
));
26 EXPECT_TRUE(host
->FinishBuildingBlob(id
, "text/plain"));
27 EXPECT_FALSE(host
->StartBuildingBlob(id
));
31 TEST(BlobStorageContextTest
, IncrementDecrementRef
) {
32 BlobStorageContext context
;
33 BlobStorageHost
host(&context
);
34 base::MessageLoop fake_io_message_loop
;
36 // Build up a basic blob.
37 const std::string
kId("id");
38 SetupBasicBlob(&host
, kId
);
40 // Make sure it's there, finish building implies a ref of one.
41 scoped_ptr
<BlobDataHandle
> blob_data_handle
;
42 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
43 EXPECT_TRUE(blob_data_handle
);
44 blob_data_handle
.reset();
45 { // Clean up for ASAN
46 base::RunLoop run_loop
;
47 run_loop
.RunUntilIdle();
50 // Make sure its still there after inc/dec.
51 EXPECT_TRUE(host
.IncrementBlobRefCount(kId
));
52 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
53 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
54 EXPECT_TRUE(blob_data_handle
);
55 blob_data_handle
.reset();
56 { // Clean up for ASAN
57 base::RunLoop run_loop
;
58 run_loop
.RunUntilIdle();
61 // Make sure it goes away in the end.
62 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
63 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
64 EXPECT_FALSE(blob_data_handle
);
65 EXPECT_FALSE(host
.DecrementBlobRefCount(kId
));
66 EXPECT_FALSE(host
.IncrementBlobRefCount(kId
));
69 TEST(BlobStorageContextTest
, BlobDataHandle
) {
70 BlobStorageContext context
;
71 BlobStorageHost
host(&context
);
72 base::MessageLoop fake_io_message_loop
;
74 // Build up a basic blob.
75 const std::string
kId("id");
76 SetupBasicBlob(&host
, kId
);
78 // Get a handle to it.
79 scoped_ptr
<BlobDataHandle
> blob_data_handle
=
80 context
.GetBlobDataFromUUID(kId
);
81 EXPECT_TRUE(blob_data_handle
);
83 // Drop the host's ref to it.
84 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
86 // Should still be there due to the handle.
87 scoped_ptr
<BlobDataHandle
> another_handle
=
88 context
.GetBlobDataFromUUID(kId
);
89 EXPECT_TRUE(another_handle
);
91 // Should disappear after dropping both handles.
92 blob_data_handle
.reset();
93 another_handle
.reset();
94 { // Clean up for ASAN
95 base::RunLoop run_loop
;
96 run_loop
.RunUntilIdle();
98 blob_data_handle
= context
.GetBlobDataFromUUID(kId
);
99 EXPECT_FALSE(blob_data_handle
);
102 TEST(BlobStorageContextTest
, CompoundBlobs
) {
103 const std::string
kId1("id1");
104 const std::string
kId2("id2");
105 const std::string
kId2Prime("id2.prime");
107 base::MessageLoop fake_io_message_loop
;
109 // Setup a set of blob data for testing.
110 base::Time time1
, time2
;
111 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1
);
112 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2
);
114 scoped_refptr
<BlobData
> blob_data1(new BlobData(kId1
));
115 blob_data1
->AppendData("Data1");
116 blob_data1
->AppendData("Data2");
117 blob_data1
->AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")),
120 scoped_refptr
<BlobData
> blob_data2(new BlobData(kId2
));
121 blob_data2
->AppendData("Data3");
122 blob_data2
->AppendBlob(kId1
, 8, 100);
123 blob_data2
->AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")),
126 scoped_refptr
<BlobData
> canonicalized_blob_data2(new BlobData(kId2Prime
));
127 canonicalized_blob_data2
->AppendData("Data3");
128 canonicalized_blob_data2
->AppendData("a2___", 2);
129 canonicalized_blob_data2
->AppendFile(
130 base::FilePath(FILE_PATH_LITERAL("File1.txt")),
132 canonicalized_blob_data2
->AppendFile(
133 base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2
);
135 BlobStorageContext context
;
136 scoped_ptr
<BlobDataHandle
> blob_data_handle
;
138 // Test a blob referring to only data and a file.
139 blob_data_handle
= context
.AddFinishedBlob(blob_data1
.get());
140 ASSERT_TRUE(blob_data_handle
.get());
141 EXPECT_TRUE(*(blob_data_handle
->data()) == *blob_data1
.get());
143 // Test a blob composed in part with another blob.
144 blob_data_handle
= context
.AddFinishedBlob(blob_data2
.get());
145 ASSERT_TRUE(blob_data_handle
.get());
146 EXPECT_TRUE(*(blob_data_handle
->data()) == *canonicalized_blob_data2
.get());
148 blob_data_handle
.reset();
149 { // Clean up for ASAN
150 base::RunLoop run_loop
;
151 run_loop
.RunUntilIdle();
155 TEST(BlobStorageContextTest
, PublicBlobUrls
) {
156 BlobStorageContext context
;
157 BlobStorageHost
host(&context
);
158 base::MessageLoop fake_io_message_loop
;
160 // Build up a basic blob.
161 const std::string
kId("id");
162 SetupBasicBlob(&host
, kId
);
164 // Now register a url for that blob.
165 GURL
kUrl("blob:id");
166 EXPECT_TRUE(host
.RegisterPublicBlobURL(kUrl
, kId
));
167 scoped_ptr
<BlobDataHandle
> blob_data_handle
=
168 context
.GetBlobDataFromPublicURL(kUrl
);
169 ASSERT_TRUE(blob_data_handle
.get());
170 EXPECT_EQ(kId
, blob_data_handle
->data()->uuid());
171 blob_data_handle
.reset();
172 { // Clean up for ASAN
173 base::RunLoop run_loop
;
174 run_loop
.RunUntilIdle();
177 // The url registration should keep the blob alive even after
178 // explicit references are dropped.
179 EXPECT_TRUE(host
.DecrementBlobRefCount(kId
));
180 blob_data_handle
= context
.GetBlobDataFromPublicURL(kUrl
);
181 EXPECT_TRUE(blob_data_handle
);
182 blob_data_handle
.reset();
183 { // Clean up for ASAN
184 base::RunLoop run_loop
;
185 run_loop
.RunUntilIdle();
188 // Finally get rid of the url registration and the blob.
189 EXPECT_TRUE(host
.RevokePublicBlobURL(kUrl
));
190 blob_data_handle
= context
.GetBlobDataFromPublicURL(kUrl
);
191 EXPECT_TRUE(!blob_data_handle
.get());
192 EXPECT_FALSE(host
.RevokePublicBlobURL(kUrl
));
195 TEST(BlobStorageContextTest
, HostCleanup
) {
196 BlobStorageContext context
;
197 scoped_ptr
<BlobStorageHost
> host(new BlobStorageHost(&context
));
198 base::MessageLoop fake_io_message_loop
;
200 // Build up a basic blob and register a url
201 const std::string
kId("id");
202 GURL
kUrl("blob:id");
203 SetupBasicBlob(host
.get(), kId
);
204 EXPECT_TRUE(host
->RegisterPublicBlobURL(kUrl
, kId
));
206 // All should disappear upon host deletion.
208 scoped_ptr
<BlobDataHandle
> handle
= context
.GetBlobDataFromPublicURL(kUrl
);
209 EXPECT_TRUE(!handle
.get());
210 handle
= context
.GetBlobDataFromUUID(kId
);
211 EXPECT_TRUE(!handle
.get());
214 TEST(BlobStorageContextTest
, EarlyContextDeletion
) {
215 scoped_ptr
<BlobStorageContext
> context(new BlobStorageContext
);
216 BlobStorageHost
host(context
.get());
217 base::MessageLoop fake_io_message_loop
;
219 // Deleting the context should not induce crashes.
222 const std::string
kId("id");
223 GURL
kUrl("blob:id");
224 EXPECT_FALSE(host
.StartBuildingBlob(kId
));
226 item
.SetToBytes("1", 1);
227 EXPECT_FALSE(host
.AppendBlobDataItem(kId
, item
));
228 EXPECT_FALSE(host
.FinishBuildingBlob(kId
, "text/plain"));
229 EXPECT_FALSE(host
.RegisterPublicBlobURL(kUrl
, kId
));
230 EXPECT_FALSE(host
.IncrementBlobRefCount(kId
));
231 EXPECT_FALSE(host
.DecrementBlobRefCount(kId
));
232 EXPECT_FALSE(host
.RevokePublicBlobURL(kUrl
));
235 // TODO(michaeln): tests for the depcrecated url stuff
237 } // namespace content