| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "storage/browser/blob/blob_storage_context.h" | 5 #include "storage/browser/blob/blob_storage_context.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <memory> | 10 #include <memory> |
| 11 #include <string> | 11 #include <string> |
| 12 | 12 |
| 13 #include "base/bind.h" |
| 13 #include "base/files/file.h" | 14 #include "base/files/file.h" |
| 14 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
| 16 #include "base/files/file_util.h" |
| 15 #include "base/memory/ref_counted.h" | 17 #include "base/memory/ref_counted.h" |
| 16 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
| 17 #include "base/run_loop.h" | 19 #include "base/run_loop.h" |
| 20 #include "base/strings/string_number_conversions.h" |
| 21 #include "base/test/test_simple_task_runner.h" |
| 22 #include "base/threading/thread_task_runner_handle.h" |
| 18 #include "base/time/time.h" | 23 #include "base/time/time.h" |
| 19 #include "content/browser/blob_storage/blob_dispatcher_host.h" | 24 #include "content/browser/blob_storage/blob_dispatcher_host.h" |
| 20 #include "content/browser/blob_storage/chrome_blob_storage_context.h" | 25 #include "content/browser/blob_storage/chrome_blob_storage_context.h" |
| 21 #include "content/public/test/test_browser_context.h" | 26 #include "content/public/test/test_browser_context.h" |
| 22 #include "net/base/io_buffer.h" | 27 #include "net/base/io_buffer.h" |
| 23 #include "net/base/test_completion_callback.h" | 28 #include "net/base/test_completion_callback.h" |
| 24 #include "net/disk_cache/disk_cache.h" | 29 #include "net/disk_cache/disk_cache.h" |
| 25 #include "storage/browser/blob/blob_async_builder_host.h" | 30 #include "storage/browser/blob/blob_async_builder_host.h" |
| 26 #include "storage/browser/blob/blob_data_builder.h" | 31 #include "storage/browser/blob/blob_data_builder.h" |
| 27 #include "storage/browser/blob/blob_data_handle.h" | 32 #include "storage/browser/blob/blob_data_handle.h" |
| 28 #include "storage/browser/blob/blob_data_item.h" | 33 #include "storage/browser/blob/blob_data_item.h" |
| 29 #include "storage/browser/blob/blob_data_snapshot.h" | 34 #include "storage/browser/blob/blob_data_snapshot.h" |
| 30 #include "storage/browser/blob/blob_transport_result.h" | |
| 31 #include "storage/common/blob_storage/blob_item_bytes_request.h" | 35 #include "storage/common/blob_storage/blob_item_bytes_request.h" |
| 32 #include "storage/common/blob_storage/blob_item_bytes_response.h" | 36 #include "storage/common/blob_storage/blob_item_bytes_response.h" |
| 33 #include "testing/gtest/include/gtest/gtest.h" | 37 #include "testing/gtest/include/gtest/gtest.h" |
| 34 | 38 |
| 35 using RequestMemoryCallback = | 39 using RequestMemoryCallback = |
| 36 storage::BlobAsyncBuilderHost::RequestMemoryCallback; | 40 storage::BlobAsyncBuilderHost::RequestMemoryCallback; |
| 37 | 41 |
| 38 namespace storage { | 42 namespace storage { |
| 39 namespace { | 43 namespace { |
| 44 using base::TestSimpleTaskRunner; |
| 40 | 45 |
| 41 const char kContentType[] = "text/plain"; | |
| 42 const char kContentDisposition[] = "content_disposition"; | |
| 43 const int kTestDiskCacheStreamIndex = 0; | 46 const int kTestDiskCacheStreamIndex = 0; |
| 44 | 47 |
| 48 const std::string kBlobStorageDirectory = "blob_storage"; |
| 49 const size_t kTestBlobStorageIPCThresholdBytes = 20; |
| 50 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50; |
| 51 |
| 52 const size_t kTestBlobStorageMaxBlobMemorySize = 400; |
| 53 const size_t kTestBlobStorageMaxMemoryUsage = 500; |
| 54 const uint64_t kTestBlobStorageMaxDiskSpace = 4000; |
| 55 const size_t kTestBlobStorageInFlightMemory = 10; |
| 56 const uint64_t kTestBlobStorageMinFileSizeBytes = 10; |
| 57 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100; |
| 58 |
| 45 // Our disk cache tests don't need a real data handle since the tests themselves | 59 // Our disk cache tests don't need a real data handle since the tests themselves |
| 46 // scope the disk cache and entries. | 60 // scope the disk cache and entries. |
| 47 class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle { | 61 class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle { |
| 48 private: | 62 private: |
| 49 ~EmptyDataHandle() override {} | 63 ~EmptyDataHandle() override {} |
| 50 }; | 64 }; |
| 51 | 65 |
| 52 std::unique_ptr<disk_cache::Backend> CreateInMemoryDiskCache() { | 66 std::unique_ptr<disk_cache::Backend> CreateInMemoryDiskCache() { |
| 53 std::unique_ptr<disk_cache::Backend> cache; | 67 std::unique_ptr<disk_cache::Backend> cache; |
| 54 net::TestCompletionCallback callback; | 68 net::TestCompletionCallback callback; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 72 return nullptr; | 86 return nullptr; |
| 73 disk_cache::ScopedEntryPtr entry(temp_entry); | 87 disk_cache::ScopedEntryPtr entry(temp_entry); |
| 74 | 88 |
| 75 scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data); | 89 scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data); |
| 76 rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(), | 90 rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(), |
| 77 iobuffer->size(), callback.callback(), false); | 91 iobuffer->size(), callback.callback(), false); |
| 78 EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv)); | 92 EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv)); |
| 79 return entry; | 93 return entry; |
| 80 } | 94 } |
| 81 | 95 |
| 96 void SaveBlobStatus(BlobStatus* status_ptr, BlobStatus status) { |
| 97 *status_ptr = status; |
| 98 } |
| 99 |
| 100 void IncrementPointer(size_t* number, BlobStatus status) { |
| 101 EXPECT_EQ(BlobStatus::DONE, status); |
| 102 *number = *number + 1; |
| 103 } |
| 82 | 104 |
| 83 } // namespace | 105 } // namespace |
| 84 | 106 |
| 85 class BlobStorageContextTest : public testing::Test { | 107 class BlobStorageContextTest : public testing::Test { |
| 86 protected: | 108 protected: |
| 87 BlobStorageContextTest() {} | 109 BlobStorageContextTest() {} |
| 88 ~BlobStorageContextTest() override {} | 110 ~BlobStorageContextTest() override {} |
| 89 | 111 |
| 112 void TearDown() override { |
| 113 // Make sure we clean up the files. |
| 114 base::RunLoop().RunUntilIdle(); |
| 115 file_runner_->RunPendingTasks(); |
| 116 ASSERT_EQ(true, base::DeleteFile(temp_dir_, true)); |
| 117 } |
| 118 |
| 90 std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) { | 119 std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) { |
| 91 BlobDataBuilder builder(id); | 120 BlobDataBuilder builder(id); |
| 92 builder.AppendData("1", 1); | 121 builder.AppendData("1", 1); |
| 93 builder.set_content_type("text/plain"); | 122 builder.set_content_type("text/plain"); |
| 94 return context_.AddFinishedBlob(builder); | 123 return context_.AddFinishedBlob(builder); |
| 95 } | 124 } |
| 96 | 125 |
| 126 void SetTestMemoryLimits() { |
| 127 context_.mutable_memory_controller()->SetMemoryConstantsForTesting( |
| 128 kTestBlobStorageIPCThresholdBytes, kTestBlobStorageMaxSharedMemoryBytes, |
| 129 kTestBlobStorageMaxBlobMemorySize, kTestBlobStorageMaxMemoryUsage, |
| 130 kTestBlobStorageMaxDiskSpace, kTestBlobStorageInFlightMemory, |
| 131 kTestBlobStorageMinFileSizeBytes, kTestBlobStorageMaxFileSizeBytes); |
| 132 } |
| 133 |
| 134 base::FilePath temp_dir_; |
| 135 scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner(); |
| 136 |
| 137 base::MessageLoop fake_io_message_loop; |
| 97 BlobStorageContext context_; | 138 BlobStorageContext context_; |
| 98 }; | 139 }; |
| 99 | 140 |
| 141 TEST_F(BlobStorageContextTest, BuildBlobAsync) { |
| 142 const std::string kId("id"); |
| 143 const size_t kSize = 10u; |
| 144 BlobStatus status = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 145 |
| 146 BlobDataBuilder builder(kId); |
| 147 builder.AppendFutureData(kSize); |
| 148 builder.set_content_type("text/plain"); |
| 149 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 150 std::unique_ptr<BlobDataHandle> handle = |
| 151 context_.BuildBlob(builder, base::Bind(&SaveBlobStatus, &status)); |
| 152 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 153 EXPECT_TRUE(handle->IsBeingBuilt()); |
| 154 EXPECT_EQ(BlobStatus::PENDING, status); |
| 155 |
| 156 BlobStatus construction_done = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 157 handle->RunOnConstructionComplete( |
| 158 base::Bind(&SaveBlobStatus, &construction_done)); |
| 159 |
| 160 EXPECT_EQ(10u, context_.memory_controller().memory_usage()); |
| 161 |
| 162 builder.PopulateFutureData(0, "abcdefghij", 0, 10u); |
| 163 context_.FinishedPopulatingBlob(kId); |
| 164 |
| 165 // Check we're done. |
| 166 EXPECT_EQ(BlobStatus::DONE, context_.GetBlobStatus(kId)); |
| 167 base::RunLoop().RunUntilIdle(); |
| 168 EXPECT_EQ(BlobStatus::DONE, construction_done); |
| 169 |
| 170 EXPECT_EQ(builder, *context_.CreateSnapshot(kId)); |
| 171 |
| 172 handle.reset(); |
| 173 base::RunLoop().RunUntilIdle(); |
| 174 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 175 } |
| 176 |
| 177 TEST_F(BlobStorageContextTest, BuildBlobAndCancel) { |
| 178 const std::string kId("id"); |
| 179 const size_t kSize = 10u; |
| 180 BlobStatus status = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 181 |
| 182 BlobDataBuilder builder(kId); |
| 183 builder.AppendFutureData(kSize); |
| 184 builder.set_content_type("text/plain"); |
| 185 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 186 std::unique_ptr<BlobDataHandle> handle = |
| 187 context_.BuildBlob(builder, base::Bind(&SaveBlobStatus, &status)); |
| 188 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 189 EXPECT_TRUE(handle->IsBeingBuilt()); |
| 190 EXPECT_EQ(BlobStatus::PENDING, status); |
| 191 EXPECT_EQ(10u, context_.memory_controller().memory_usage()); |
| 192 |
| 193 BlobStatus construction_done = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 194 handle->RunOnConstructionComplete( |
| 195 base::Bind(&SaveBlobStatus, &construction_done)); |
| 196 |
| 197 context_.BreakAndFinishBlob(kId, BlobStatus::SOURCE_DIED_IN_TRANSIT); |
| 198 EXPECT_TRUE(handle->IsBroken()); |
| 199 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 200 |
| 201 // Check we're broken. |
| 202 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, context_.GetBlobStatus(kId)); |
| 203 base::RunLoop().RunUntilIdle(); |
| 204 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, construction_done); |
| 205 } |
| 206 |
| 207 TEST_F(BlobStorageContextTest, BuildBlobFuzzish) { |
| 208 const std::string kId("id"); |
| 209 const size_t kTotalRawBlobs = 200; |
| 210 const size_t kTotalSlicedBlobs = 100; |
| 211 SetTestMemoryLimits(); |
| 212 |
| 213 // This tests mixed blob content, both async and synchronous content, and |
| 214 |
| 215 std::vector<std::unique_ptr<BlobDataBuilder>> builders; |
| 216 std::vector<size_t> sizes; |
| 217 |
| 218 for (size_t i = 0; i < kTotalRawBlobs; i++) { |
| 219 builders.emplace_back(new BlobDataBuilder(base::SizeTToString(i))); |
| 220 auto& builder = *builders.back(); |
| 221 size_t size = 0; |
| 222 if (i % 2 != 0) { |
| 223 builder.AppendFutureData(5u); |
| 224 size += 5u; |
| 225 } |
| 226 if (i % 5 != 0) { |
| 227 builder.AppendFile(base::FilePath(base::SizeTToString(i)), 0ul, 20ul, |
| 228 base::Time::Max()); |
| 229 size += 20u; |
| 230 } |
| 231 if (i % 3 != 0) { |
| 232 builder.AppendData("abcdefghij", 4u); |
| 233 size += 4u; |
| 234 } |
| 235 if (i % 3 == 0) { |
| 236 builder.AppendFutureData(1u); |
| 237 size += 1u; |
| 238 } |
| 239 if (i % 7 == 0) { |
| 240 builder.AppendFutureFile(0lu, 3lu); |
| 241 size += 3u; |
| 242 } |
| 243 sizes.push_back(size); |
| 244 } |
| 245 |
| 246 for (size_t i = 0; i < kTotalSlicedBlobs; i++) { |
| 247 builders.emplace_back( |
| 248 new BlobDataBuilder(base::SizeTToString(i + kTotalRawBlobs))); |
| 249 size_t source_size = sizes[i]; |
| 250 size_t offset = sizes[i] == 1 ? 0 : i % (source_size - 1); |
| 251 size_t size = (i % (source_size - offset)) + 1; |
| 252 builders.back()->AppendBlob(base::SizeTToString(i), offset, size); |
| 253 sizes.push_back(size); |
| 254 } |
| 255 |
| 256 size_t total_finished_blobs = 0; |
| 257 std::vector<std::unique_ptr<BlobDataHandle>> handles; |
| 258 std::vector<BlobStatus> statuses; |
| 259 std::vector<bool> populated; |
| 260 statuses.resize(kTotalRawBlobs, BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS); |
| 261 populated.resize(kTotalRawBlobs, false); |
| 262 context_.EnableDisk(temp_dir_, file_runner_); |
| 263 |
| 264 for (size_t i = 0; i < builders.size(); i++) { |
| 265 BlobDataBuilder& builder = *builders[i]; |
| 266 builder.set_content_type("text/plain"); |
| 267 bool has_pending_memory = |
| 268 i < kTotalRawBlobs && (i % 3 == 0 || i % 2 != 0 || i % 7 == 0); |
| 269 std::unique_ptr<BlobDataHandle> handle = context_.BuildBlob( |
| 270 builder, has_pending_memory |
| 271 ? base::Bind(&SaveBlobStatus, &statuses[0] + i) |
| 272 : BlobStatusCallback()); |
| 273 handle->RunOnConstructionComplete( |
| 274 base::Bind(&IncrementPointer, &total_finished_blobs)); |
| 275 handles.push_back(std::move(handle)); |
| 276 } |
| 277 base::RunLoop().RunUntilIdle(); |
| 278 |
| 279 // We should be needing to send a page or two to disk. |
| 280 EXPECT_TRUE(file_runner_->HasPendingTask()); |
| 281 |
| 282 do { |
| 283 file_runner_->RunPendingTasks(); |
| 284 base::RunLoop().RunUntilIdle(); |
| 285 |
| 286 // Continue populating data for items that can fit. |
| 287 for (size_t i = 0; i < kTotalRawBlobs; i++) { |
| 288 auto& builder = *builders[i]; |
| 289 bool has_pending_memory = i % 3 == 0 || i % 2 != 0 || i % 7 == 0; |
| 290 if (has_pending_memory && !populated[i] && |
| 291 statuses[i] == BlobStatus::PENDING) { |
| 292 if (i % 2 != 0) { |
| 293 builder.PopulateFutureData(0, "abcde", 0, 5); |
| 294 } |
| 295 if (i % 3 == 0) { |
| 296 size_t index = i % 7 == 0 ? builder.items_.size() - 2 |
| 297 : builder.items_.size() - 1; |
| 298 builder.PopulateFutureData(index, "z", 0, 1); |
| 299 } |
| 300 if (i % 7 == 0) { |
| 301 scoped_refptr<ShareableFileReference> file_ref = |
| 302 ShareableFileReference::GetOrCreate( |
| 303 base::FilePath(base::SizeTToString(i + kTotalRawBlobs)), |
| 304 ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE, |
| 305 file_runner_.get()); |
| 306 builder.PopulateFutureFile(builder.items_.size() - 1, file_ref, |
| 307 base::Time::Max()); |
| 308 } |
| 309 context_.FinishedPopulatingBlob(base::SizeTToString(i)); |
| 310 populated[i] = true; |
| 311 } |
| 312 } |
| 313 base::RunLoop().RunUntilIdle(); |
| 314 } while (file_runner_->HasPendingTask()); |
| 315 |
| 316 // We should be completely built now. |
| 317 EXPECT_EQ(kTotalRawBlobs + kTotalSlicedBlobs, total_finished_blobs); |
| 318 |
| 319 handles.clear(); |
| 320 base::RunLoop().RunUntilIdle(); |
| 321 // We should have file cleanup tasks. |
| 322 EXPECT_TRUE(file_runner_->HasPendingTask()); |
| 323 file_runner_->RunPendingTasks(); |
| 324 |
| 325 for (size_t i = 0; i < kTotalRawBlobs; i++) { |
| 326 bool has_pending_memory = i % 3 == 0 || i % 2 != 0; |
| 327 if (has_pending_memory) |
| 328 EXPECT_EQ(BlobStatus::PENDING, statuses[i]) << i; |
| 329 } |
| 330 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 331 EXPECT_EQ(0lu, context_.memory_controller().disk_usage()); |
| 332 } |
| 333 |
| 334 TEST_F(BlobStorageContextTest, TestErrors) { |
| 335 // bad slice offset & size |
| 336 // Finish before finished |
| 337 } |
| 338 |
| 100 TEST_F(BlobStorageContextTest, IncrementDecrementRef) { | 339 TEST_F(BlobStorageContextTest, IncrementDecrementRef) { |
| 101 base::MessageLoop fake_io_message_loop; | |
| 102 | |
| 103 // Build up a basic blob. | 340 // Build up a basic blob. |
| 104 const std::string kId("id"); | 341 const std::string kId("id"); |
| 105 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); | 342 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); |
| 106 | 343 |
| 107 // Do an extra increment to keep it around after we kill the handle. | 344 // Do an extra increment to keep it around after we kill the handle. |
| 108 context_.IncrementBlobRefCount(kId); | 345 context_.IncrementBlobRefCount(kId); |
| 109 context_.IncrementBlobRefCount(kId); | 346 context_.IncrementBlobRefCount(kId); |
| 110 context_.DecrementBlobRefCount(kId); | 347 context_.DecrementBlobRefCount(kId); |
| 111 blob_data_handle = context_.GetBlobDataFromUUID(kId); | 348 blob_data_handle = context_.GetBlobDataFromUUID(kId); |
| 112 EXPECT_TRUE(blob_data_handle); | 349 EXPECT_TRUE(blob_data_handle); |
| 113 blob_data_handle.reset(); | 350 blob_data_handle.reset(); |
| 114 base::RunLoop().RunUntilIdle(); | 351 base::RunLoop().RunUntilIdle(); |
| 115 | 352 |
| 116 EXPECT_TRUE(context_.registry().HasEntry(kId)); | 353 EXPECT_TRUE(context_.registry().HasEntry(kId)); |
| 117 context_.DecrementBlobRefCount(kId); | 354 context_.DecrementBlobRefCount(kId); |
| 118 EXPECT_FALSE(context_.registry().HasEntry(kId)); | 355 EXPECT_FALSE(context_.registry().HasEntry(kId)); |
| 119 | 356 |
| 120 // Make sure it goes away in the end. | 357 // Make sure it goes away in the end. |
| 121 blob_data_handle = context_.GetBlobDataFromUUID(kId); | 358 blob_data_handle = context_.GetBlobDataFromUUID(kId); |
| 122 EXPECT_FALSE(blob_data_handle); | 359 EXPECT_FALSE(blob_data_handle); |
| 123 } | 360 } |
| 124 | 361 |
| 125 TEST_F(BlobStorageContextTest, OnCancelBuildingBlob) { | |
| 126 base::MessageLoop fake_io_message_loop; | |
| 127 | |
| 128 // Build up a basic blob. | |
| 129 const std::string kId("id"); | |
| 130 context_.CreatePendingBlob(kId, std::string(kContentType), | |
| 131 std::string(kContentDisposition)); | |
| 132 EXPECT_TRUE(context_.IsBeingBuilt(kId)); | |
| 133 context_.CancelPendingBlob(kId, IPCBlobCreationCancelCode::OUT_OF_MEMORY); | |
| 134 EXPECT_TRUE(context_.registry().HasEntry(kId)); | |
| 135 EXPECT_FALSE(context_.IsBeingBuilt(kId)); | |
| 136 EXPECT_TRUE(context_.IsBroken(kId)); | |
| 137 } | |
| 138 | |
| 139 TEST_F(BlobStorageContextTest, BlobDataHandle) { | 362 TEST_F(BlobStorageContextTest, BlobDataHandle) { |
| 140 base::MessageLoop fake_io_message_loop; | |
| 141 | |
| 142 // Build up a basic blob. | 363 // Build up a basic blob. |
| 143 const std::string kId("id"); | 364 const std::string kId("id"); |
| 144 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); | 365 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); |
| 145 EXPECT_TRUE(blob_data_handle); | 366 EXPECT_TRUE(blob_data_handle); |
| 146 | 367 |
| 147 // Get another handle | 368 // Get another handle |
| 148 std::unique_ptr<BlobDataHandle> another_handle = | 369 std::unique_ptr<BlobDataHandle> another_handle = |
| 149 context_.GetBlobDataFromUUID(kId); | 370 context_.GetBlobDataFromUUID(kId); |
| 150 EXPECT_TRUE(another_handle); | 371 EXPECT_TRUE(another_handle); |
| 151 | 372 |
| 152 // Should disappear after dropping both handles. | 373 // Should disappear after dropping both handles. |
| 153 blob_data_handle.reset(); | 374 blob_data_handle.reset(); |
| 154 base::RunLoop().RunUntilIdle(); | 375 base::RunLoop().RunUntilIdle(); |
| 155 | 376 |
| 156 EXPECT_TRUE(context_.registry().HasEntry(kId)); | 377 EXPECT_TRUE(context_.registry().HasEntry(kId)); |
| 157 | 378 |
| 158 another_handle.reset(); | 379 another_handle.reset(); |
| 159 base::RunLoop().RunUntilIdle(); | 380 base::RunLoop().RunUntilIdle(); |
| 160 | 381 |
| 161 blob_data_handle = context_.GetBlobDataFromUUID(kId); | 382 blob_data_handle = context_.GetBlobDataFromUUID(kId); |
| 162 EXPECT_FALSE(blob_data_handle); | 383 EXPECT_FALSE(blob_data_handle); |
| 163 } | 384 } |
| 164 | 385 |
| 165 TEST_F(BlobStorageContextTest, MemoryUsage) { | 386 TEST_F(BlobStorageContextTest, MemoryUsage) { |
| 166 const std::string kId1("id1"); | 387 const std::string kId1("id1"); |
| 167 const std::string kId2("id2"); | 388 const std::string kId2("id2"); |
| 168 | 389 |
| 169 base::MessageLoop fake_io_message_loop; | |
| 170 | |
| 171 BlobDataBuilder builder1(kId1); | 390 BlobDataBuilder builder1(kId1); |
| 172 BlobDataBuilder builder2(kId2); | 391 BlobDataBuilder builder2(kId2); |
| 173 builder1.AppendData("Data1Data2"); | 392 builder1.AppendData("Data1Data2"); |
| 174 builder2.AppendBlob(kId1); | 393 builder2.AppendBlob(kId1); |
| 175 builder2.AppendBlob(kId1); | 394 builder2.AppendBlob(kId1); |
| 176 builder2.AppendBlob(kId1); | 395 builder2.AppendBlob(kId1); |
| 177 builder2.AppendBlob(kId1); | 396 builder2.AppendBlob(kId1); |
| 178 builder2.AppendBlob(kId1); | 397 builder2.AppendBlob(kId1); |
| 179 builder2.AppendBlob(kId1); | 398 builder2.AppendBlob(kId1); |
| 180 builder2.AppendBlob(kId1); | 399 builder2.AppendBlob(kId1); |
| 181 | 400 |
| 182 EXPECT_EQ(0lu, context_.memory_usage()); | 401 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 183 | 402 |
| 184 std::unique_ptr<BlobDataHandle> blob_data_handle = | 403 std::unique_ptr<BlobDataHandle> blob_data_handle = |
| 185 context_.AddFinishedBlob(&builder1); | 404 context_.AddFinishedBlob(&builder1); |
| 186 EXPECT_EQ(10lu, context_.memory_usage()); | 405 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 187 std::unique_ptr<BlobDataHandle> blob_data_handle2 = | 406 std::unique_ptr<BlobDataHandle> blob_data_handle2 = |
| 188 context_.AddFinishedBlob(&builder2); | 407 context_.AddFinishedBlob(&builder2); |
| 189 EXPECT_EQ(10lu, context_.memory_usage()); | 408 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 190 | 409 |
| 191 EXPECT_EQ(2u, context_.registry().blob_count()); | 410 EXPECT_EQ(2u, context_.registry().blob_count()); |
| 192 | 411 |
| 193 blob_data_handle.reset(); | 412 blob_data_handle.reset(); |
| 194 base::RunLoop().RunUntilIdle(); | 413 base::RunLoop().RunUntilIdle(); |
| 195 | 414 |
| 196 EXPECT_EQ(10lu, context_.memory_usage()); | 415 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 197 EXPECT_EQ(1u, context_.registry().blob_count()); | 416 EXPECT_EQ(1u, context_.registry().blob_count()); |
| 198 blob_data_handle2.reset(); | 417 blob_data_handle2.reset(); |
| 199 base::RunLoop().RunUntilIdle(); | 418 base::RunLoop().RunUntilIdle(); |
| 200 | 419 |
| 201 EXPECT_EQ(0lu, context_.memory_usage()); | 420 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 202 EXPECT_EQ(0u, context_.registry().blob_count()); | 421 EXPECT_EQ(0u, context_.registry().blob_count()); |
| 203 } | 422 } |
| 204 | 423 |
| 205 TEST_F(BlobStorageContextTest, AddFinishedBlob) { | 424 TEST_F(BlobStorageContextTest, AddFinishedBlob) { |
| 206 const std::string kId1("id1"); | 425 const std::string kId1("id1"); |
| 207 const std::string kId2("id12"); | 426 const std::string kId2("id12"); |
| 208 const std::string kId2Prime("id2.prime"); | 427 const std::string kId2Prime("id2.prime"); |
| 209 const std::string kId3("id3"); | 428 const std::string kId3("id3"); |
| 210 const std::string kId3Prime("id3.prime"); | 429 const std::string kId3Prime("id3.prime"); |
| 211 | 430 |
| 212 base::MessageLoop fake_io_message_loop; | |
| 213 | |
| 214 BlobDataBuilder builder1(kId1); | 431 BlobDataBuilder builder1(kId1); |
| 215 BlobDataBuilder builder2(kId2); | 432 BlobDataBuilder builder2(kId2); |
| 216 BlobDataBuilder canonicalized_blob_data2(kId2Prime); | 433 BlobDataBuilder canonicalized_blob_data2(kId2Prime); |
| 217 builder1.AppendData("Data1Data2"); | 434 builder1.AppendData("Data1Data2"); |
| 218 builder2.AppendBlob(kId1, 5, 5); | 435 builder2.AppendBlob(kId1, 5, 5); |
| 219 builder2.AppendData(" is the best"); | 436 builder2.AppendData(" is the best"); |
| 220 canonicalized_blob_data2.AppendData("Data2"); | 437 canonicalized_blob_data2.AppendData("Data2"); |
| 221 canonicalized_blob_data2.AppendData(" is the best"); | 438 canonicalized_blob_data2.AppendData(" is the best"); |
| 222 | 439 |
| 223 BlobStorageContext context; | 440 BlobStorageContext context; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 blob_data_handle.reset(); | 485 blob_data_handle.reset(); |
| 269 blob_data_handle2.reset(); | 486 blob_data_handle2.reset(); |
| 270 blob_data_handle3.reset(); | 487 blob_data_handle3.reset(); |
| 271 base::RunLoop().RunUntilIdle(); | 488 base::RunLoop().RunUntilIdle(); |
| 272 } | 489 } |
| 273 | 490 |
| 274 TEST_F(BlobStorageContextTest, AddFinishedBlob_LargeOffset) { | 491 TEST_F(BlobStorageContextTest, AddFinishedBlob_LargeOffset) { |
| 275 // A value which does not fit in a 4-byte data type. Used to confirm that | 492 // A value which does not fit in a 4-byte data type. Used to confirm that |
| 276 // large values are supported on 32-bit Chromium builds. Regression test for: | 493 // large values are supported on 32-bit Chromium builds. Regression test for: |
| 277 // crbug.com/458122. | 494 // crbug.com/458122. |
| 278 const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max(); | 495 const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max() - 1; |
| 279 | 496 |
| 280 const uint64_t kBlobLength = 5; | 497 const uint64_t kBlobLength = 5; |
| 281 const std::string kId1("id1"); | 498 const std::string kId1("id1"); |
| 282 const std::string kId2("id2"); | 499 const std::string kId2("id2"); |
| 283 base::MessageLoop fake_io_message_loop; | |
| 284 | 500 |
| 285 BlobDataBuilder builder1(kId1); | 501 BlobDataBuilder builder1(kId1); |
| 286 builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now()); | 502 builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now()); |
| 287 | 503 |
| 288 BlobDataBuilder builder2(kId2); | 504 BlobDataBuilder builder2(kId2); |
| 289 builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength); | 505 builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength); |
| 290 | 506 |
| 291 std::unique_ptr<BlobDataHandle> blob_data_handle1 = | 507 std::unique_ptr<BlobDataHandle> blob_data_handle1 = |
| 292 context_.AddFinishedBlob(&builder1); | 508 context_.AddFinishedBlob(&builder1); |
| 293 std::unique_ptr<BlobDataHandle> blob_data_handle2 = | 509 std::unique_ptr<BlobDataHandle> blob_data_handle2 = |
| 294 context_.AddFinishedBlob(&builder2); | 510 context_.AddFinishedBlob(&builder2); |
| 295 | 511 |
| 296 ASSERT_TRUE(blob_data_handle1); | 512 ASSERT_TRUE(blob_data_handle1); |
| 297 ASSERT_TRUE(blob_data_handle2); | 513 ASSERT_TRUE(blob_data_handle2); |
| 298 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot(); | 514 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot(); |
| 299 ASSERT_EQ(1u, data->items().size()); | 515 ASSERT_EQ(1u, data->items().size()); |
| 300 const scoped_refptr<BlobDataItem> item = data->items()[0]; | 516 const scoped_refptr<BlobDataItem> item = data->items()[0]; |
| 301 EXPECT_EQ(kLargeSize - kBlobLength, item->offset()); | 517 EXPECT_EQ(kLargeSize - kBlobLength, item->offset()); |
| 302 EXPECT_EQ(kBlobLength, item->length()); | 518 EXPECT_EQ(kBlobLength, item->length()); |
| 303 | 519 |
| 304 blob_data_handle1.reset(); | 520 blob_data_handle1.reset(); |
| 305 blob_data_handle2.reset(); | 521 blob_data_handle2.reset(); |
| 306 base::RunLoop().RunUntilIdle(); | 522 base::RunLoop().RunUntilIdle(); |
| 307 } | 523 } |
| 308 | 524 |
| 309 TEST_F(BlobStorageContextTest, BuildDiskCacheBlob) { | 525 TEST_F(BlobStorageContextTest, BuildDiskCacheBlob) { |
| 310 base::MessageLoop fake_io_message_loop; | |
| 311 scoped_refptr<BlobDataBuilder::DataHandle> | 526 scoped_refptr<BlobDataBuilder::DataHandle> |
| 312 data_handle = new EmptyDataHandle(); | 527 data_handle = new EmptyDataHandle(); |
| 313 | 528 |
| 314 { | 529 { |
| 315 BlobStorageContext context; | 530 BlobStorageContext context; |
| 316 | 531 |
| 317 std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache(); | 532 std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache(); |
| 318 ASSERT_TRUE(cache); | 533 ASSERT_TRUE(cache); |
| 319 | 534 |
| 320 const std::string kTestBlobData = "Test Blob Data"; | 535 const std::string kTestBlobData = "Test Blob Data"; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 342 << "Data handle was not destructed along with blob storage context."; | 557 << "Data handle was not destructed along with blob storage context."; |
| 343 base::RunLoop().RunUntilIdle(); | 558 base::RunLoop().RunUntilIdle(); |
| 344 } | 559 } |
| 345 | 560 |
| 346 TEST_F(BlobStorageContextTest, CompoundBlobs) { | 561 TEST_F(BlobStorageContextTest, CompoundBlobs) { |
| 347 const std::string kId1("id1"); | 562 const std::string kId1("id1"); |
| 348 const std::string kId2("id2"); | 563 const std::string kId2("id2"); |
| 349 const std::string kId3("id3"); | 564 const std::string kId3("id3"); |
| 350 const std::string kId2Prime("id2.prime"); | 565 const std::string kId2Prime("id2.prime"); |
| 351 | 566 |
| 352 base::MessageLoop fake_io_message_loop; | |
| 353 | |
| 354 // Setup a set of blob data for testing. | 567 // Setup a set of blob data for testing. |
| 355 base::Time time1, time2; | 568 base::Time time1, time2; |
| 356 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1); | 569 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1); |
| 357 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2); | 570 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2); |
| 358 | 571 |
| 359 BlobDataBuilder blob_data1(kId1); | 572 BlobDataBuilder blob_data1(kId1); |
| 360 blob_data1.AppendData("Data1"); | 573 blob_data1.AppendData("Data1"); |
| 361 blob_data1.AppendData("Data2"); | 574 blob_data1.AppendData("Data2"); |
| 362 blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, | 575 blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, |
| 363 1024, time1); | 576 1024, time1); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 blob_data_handle = context_.AddFinishedBlob(&blob_data3); | 620 blob_data_handle = context_.AddFinishedBlob(&blob_data3); |
| 408 data = blob_data_handle->CreateSnapshot(); | 621 data = blob_data_handle->CreateSnapshot(); |
| 409 ASSERT_TRUE(blob_data_handle); | 622 ASSERT_TRUE(blob_data_handle); |
| 410 EXPECT_EQ(*data, blob_data3); | 623 EXPECT_EQ(*data, blob_data3); |
| 411 | 624 |
| 412 blob_data_handle.reset(); | 625 blob_data_handle.reset(); |
| 413 base::RunLoop().RunUntilIdle(); | 626 base::RunLoop().RunUntilIdle(); |
| 414 } | 627 } |
| 415 | 628 |
| 416 TEST_F(BlobStorageContextTest, PublicBlobUrls) { | 629 TEST_F(BlobStorageContextTest, PublicBlobUrls) { |
| 417 base::MessageLoop fake_io_message_loop; | |
| 418 | |
| 419 // Build up a basic blob. | 630 // Build up a basic blob. |
| 420 const std::string kId("id"); | 631 const std::string kId("id"); |
| 421 std::unique_ptr<BlobDataHandle> first_handle = SetupBasicBlob(kId); | 632 std::unique_ptr<BlobDataHandle> first_handle = SetupBasicBlob(kId); |
| 422 | 633 |
| 423 // Now register a url for that blob. | 634 // Now register a url for that blob. |
| 424 GURL kUrl("blob:id"); | 635 GURL kUrl("blob:id"); |
| 425 context_.RegisterPublicBlobURL(kUrl, kId); | 636 context_.RegisterPublicBlobURL(kUrl, kId); |
| 426 std::unique_ptr<BlobDataHandle> blob_data_handle = | 637 std::unique_ptr<BlobDataHandle> blob_data_handle = |
| 427 context_.GetBlobDataFromPublicURL(kUrl); | 638 context_.GetBlobDataFromPublicURL(kUrl); |
| 428 ASSERT_TRUE(blob_data_handle.get()); | 639 ASSERT_TRUE(blob_data_handle.get()); |
| 429 EXPECT_EQ(kId, blob_data_handle->uuid()); | 640 EXPECT_EQ(kId, blob_data_handle->uuid()); |
| 430 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot(); | 641 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot(); |
| 431 blob_data_handle.reset(); | 642 blob_data_handle.reset(); |
| 432 first_handle.reset(); | 643 first_handle.reset(); |
| 433 base::RunLoop().RunUntilIdle(); | 644 base::RunLoop().RunUntilIdle(); |
| 434 | 645 |
| 435 // The url registration should keep the blob alive even after | 646 // The url registration should keep the blob alive even after |
| 436 // explicit references are dropped. | 647 // explicit references are dropped. |
| 437 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); | 648 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); |
| 438 EXPECT_TRUE(blob_data_handle); | 649 EXPECT_TRUE(blob_data_handle); |
| 439 blob_data_handle.reset(); | 650 blob_data_handle.reset(); |
| 651 |
| 440 base::RunLoop().RunUntilIdle(); | 652 base::RunLoop().RunUntilIdle(); |
| 441 | |
| 442 // Finally get rid of the url registration and the blob. | 653 // Finally get rid of the url registration and the blob. |
| 443 context_.RevokePublicBlobURL(kUrl); | 654 context_.RevokePublicBlobURL(kUrl); |
| 444 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); | 655 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); |
| 445 EXPECT_FALSE(blob_data_handle.get()); | 656 EXPECT_FALSE(blob_data_handle.get()); |
| 446 EXPECT_FALSE(context_.registry().HasEntry(kId)); | 657 EXPECT_FALSE(context_.registry().HasEntry(kId)); |
| 447 } | 658 } |
| 448 | 659 |
| 449 TEST_F(BlobStorageContextTest, TestUnknownBrokenAndBuildingBlobReference) { | 660 TEST_F(BlobStorageContextTest, TestUnknownBrokenAndBuildingBlobReference) { |
| 450 base::MessageLoop fake_io_message_loop; | |
| 451 const std::string kBrokenId("broken_id"); | 661 const std::string kBrokenId("broken_id"); |
| 452 const std::string kBuildingId("building_id"); | 662 const std::string kBuildingId("building_id"); |
| 453 const std::string kReferencingId("referencing_id"); | 663 const std::string kReferencingId("referencing_id"); |
| 454 const std::string kUnknownId("unknown_id"); | 664 const std::string kUnknownId("unknown_id"); |
| 455 | 665 |
| 456 // Create a broken blob and a building blob. | 666 // Create a broken blob. |
| 457 context_.CreatePendingBlob(kBuildingId, "", ""); | 667 std::unique_ptr<BlobDataHandle> broken_handle = |
| 458 context_.CreatePendingBlob(kBrokenId, "", ""); | 668 context_.BuildBrokenBlob(kBrokenId, "", "", BlobStatus::OUT_OF_MEMORY); |
| 459 context_.CancelPendingBlob(kBrokenId, IPCBlobCreationCancelCode::UNKNOWN); | 669 EXPECT_TRUE(context_.GetBlobStatus(kBrokenId) == BlobStatus::OUT_OF_MEMORY); |
| 460 EXPECT_TRUE(context_.IsBroken(kBrokenId)); | |
| 461 EXPECT_TRUE(context_.registry().HasEntry(kBrokenId)); | 670 EXPECT_TRUE(context_.registry().HasEntry(kBrokenId)); |
| 462 | 671 |
| 463 // Try to create a blob with a reference to an unknown blob. | 672 // Try to create a blob with a reference to an unknown blob. |
| 464 BlobDataBuilder builder(kReferencingId); | 673 BlobDataBuilder builder(kReferencingId); |
| 465 builder.AppendData("data"); | 674 builder.AppendData("data"); |
| 466 builder.AppendBlob(kUnknownId); | 675 builder.AppendBlob(kUnknownId); |
| 467 std::unique_ptr<BlobDataHandle> handle = context_.AddFinishedBlob(builder); | 676 std::unique_ptr<BlobDataHandle> handle = context_.AddFinishedBlob(builder); |
| 468 EXPECT_TRUE(handle->IsBroken()); | 677 EXPECT_TRUE(handle->IsBroken()); |
| 469 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); | 678 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); |
| 470 handle.reset(); | 679 handle.reset(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 490 EXPECT_TRUE(handle->IsBroken()); | 699 EXPECT_TRUE(handle->IsBroken()); |
| 491 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); | 700 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); |
| 492 handle.reset(); | 701 handle.reset(); |
| 493 base::RunLoop().RunUntilIdle(); | 702 base::RunLoop().RunUntilIdle(); |
| 494 EXPECT_FALSE(context_.registry().HasEntry(kReferencingId)); | 703 EXPECT_FALSE(context_.registry().HasEntry(kReferencingId)); |
| 495 } | 704 } |
| 496 | 705 |
| 497 // TODO(michaeln): tests for the depcrecated url stuff | 706 // TODO(michaeln): tests for the depcrecated url stuff |
| 498 | 707 |
| 499 } // namespace content | 708 } // namespace content |
| OLD | NEW |