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. 4 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_handle.h" 13#include "storage/browser/blob/blob_storage_context.h" 14#include "testing/gtest/include/gtest/gtest.h" 15 16using storage::BlobDataHandle; 17 18namespace content { 19 20namespace { 21void SetupBasicBlob(BlobStorageHost* host, const std::string& id) { 22 EXPECT_TRUE(host->StartBuildingBlob(id)); 23 BlobData::Item item; 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)); 28} 29} // namespace 30 31TEST(BlobStorageContextTest, IncrementDecrementRef) { 32 BlobStorageContext context; 33 BlobStorageHost host(&context); 34 base::MessageLoop fake_io_message_loop; 35 36 // Build up a basic blob. 37 const std::string kId("id"); 38 SetupBasicBlob(&host, kId); 39 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(); 48 } 49 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(); 59 } 60 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)); 67} 68 69TEST(BlobStorageContextTest, BlobDataHandle) { 70 BlobStorageContext context; 71 BlobStorageHost host(&context); 72 base::MessageLoop fake_io_message_loop; 73 74 // Build up a basic blob. 75 const std::string kId("id"); 76 SetupBasicBlob(&host, kId); 77 78 // Get a handle to it. 79 scoped_ptr<BlobDataHandle> blob_data_handle = 80 context.GetBlobDataFromUUID(kId); 81 EXPECT_TRUE(blob_data_handle); 82 83 // Drop the host's ref to it. 84 EXPECT_TRUE(host.DecrementBlobRefCount(kId)); 85 86 // Should still be there due to the handle. 87 scoped_ptr<BlobDataHandle> another_handle = 88 context.GetBlobDataFromUUID(kId); 89 EXPECT_TRUE(another_handle); 90 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(); 97 } 98 blob_data_handle = context.GetBlobDataFromUUID(kId); 99 EXPECT_FALSE(blob_data_handle); 100} 101 102TEST(BlobStorageContextTest, CompoundBlobs) { 103 const std::string kId1("id1"); 104 const std::string kId2("id2"); 105 const std::string kId2Prime("id2.prime"); 106 107 base::MessageLoop fake_io_message_loop; 108 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); 113 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")), 118 10, 1024, time1); 119 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")), 124 0, 20, time2); 125 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")), 131 10, 98, time1); 132 canonicalized_blob_data2->AppendFile( 133 base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2); 134 135 BlobStorageContext context; 136 scoped_ptr<BlobDataHandle> blob_data_handle; 137 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()); 142 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()); 147 148 blob_data_handle.reset(); 149 { // Clean up for ASAN 150 base::RunLoop run_loop; 151 run_loop.RunUntilIdle(); 152 } 153} 154 155TEST(BlobStorageContextTest, PublicBlobUrls) { 156 BlobStorageContext context; 157 BlobStorageHost host(&context); 158 base::MessageLoop fake_io_message_loop; 159 160 // Build up a basic blob. 161 const std::string kId("id"); 162 SetupBasicBlob(&host, kId); 163 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(); 175 } 176 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(); 186 } 187 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)); 193} 194 195TEST(BlobStorageContextTest, HostCleanup) { 196 BlobStorageContext context; 197 scoped_ptr<BlobStorageHost> host(new BlobStorageHost(&context)); 198 base::MessageLoop fake_io_message_loop; 199 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)); 205 206 // All should disappear upon host deletion. 207 host.reset(); 208 scoped_ptr<BlobDataHandle> handle = context.GetBlobDataFromPublicURL(kUrl); 209 EXPECT_TRUE(!handle.get()); 210 handle = context.GetBlobDataFromUUID(kId); 211 EXPECT_TRUE(!handle.get()); 212} 213 214TEST(BlobStorageContextTest, EarlyContextDeletion) { 215 scoped_ptr<BlobStorageContext> context(new BlobStorageContext); 216 BlobStorageHost host(context.get()); 217 base::MessageLoop fake_io_message_loop; 218 219 // Deleting the context should not induce crashes. 220 context.reset(); 221 222 const std::string kId("id"); 223 GURL kUrl("blob:id"); 224 EXPECT_FALSE(host.StartBuildingBlob(kId)); 225 BlobData::Item item; 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)); 233} 234 235// TODO(michaeln): tests for the depcrecated url stuff 236 237} // namespace content 238