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 uint64_t kTestBlobStorageMaxDiskSpace = 4000; |
| 54 const size_t kTestBlobStorageInFlightMemory = 10; |
| 55 const uint64_t kTestBlobStorageMinFileSizeBytes = 10; |
| 56 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100; |
| 57 |
45 // Our disk cache tests don't need a real data handle since the tests themselves | 58 // Our disk cache tests don't need a real data handle since the tests themselves |
46 // scope the disk cache and entries. | 59 // scope the disk cache and entries. |
47 class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle { | 60 class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle { |
48 private: | 61 private: |
49 ~EmptyDataHandle() override {} | 62 ~EmptyDataHandle() override {} |
50 }; | 63 }; |
51 | 64 |
52 std::unique_ptr<disk_cache::Backend> CreateInMemoryDiskCache() { | 65 std::unique_ptr<disk_cache::Backend> CreateInMemoryDiskCache() { |
53 std::unique_ptr<disk_cache::Backend> cache; | 66 std::unique_ptr<disk_cache::Backend> cache; |
54 net::TestCompletionCallback callback; | 67 net::TestCompletionCallback callback; |
(...skipping 17 matching lines...) Expand all Loading... |
72 return nullptr; | 85 return nullptr; |
73 disk_cache::ScopedEntryPtr entry(temp_entry); | 86 disk_cache::ScopedEntryPtr entry(temp_entry); |
74 | 87 |
75 scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data); | 88 scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data); |
76 rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(), | 89 rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(), |
77 iobuffer->size(), callback.callback(), false); | 90 iobuffer->size(), callback.callback(), false); |
78 EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv)); | 91 EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv)); |
79 return entry; | 92 return entry; |
80 } | 93 } |
81 | 94 |
| 95 void SaveBlobStatus(BlobStatus* status_ptr, BlobStatus status) { |
| 96 *status_ptr = status; |
| 97 } |
| 98 |
| 99 void IncrementPointer(size_t* number, BlobStatus status) { |
| 100 EXPECT_EQ(BlobStatus::DONE, status); |
| 101 *number = *number + 1; |
| 102 } |
82 | 103 |
83 } // namespace | 104 } // namespace |
84 | 105 |
85 class BlobStorageContextTest : public testing::Test { | 106 class BlobStorageContextTest : public testing::Test { |
86 protected: | 107 protected: |
87 BlobStorageContextTest() {} | 108 BlobStorageContextTest() {} |
88 ~BlobStorageContextTest() override {} | 109 ~BlobStorageContextTest() override {} |
89 | 110 |
| 111 void TearDown() override { |
| 112 // Make sure we clean up the files. |
| 113 base::RunLoop().RunUntilIdle(); |
| 114 file_runner_->RunPendingTasks(); |
| 115 ASSERT_EQ(true, base::DeleteFile(temp_dir_, true)); |
| 116 } |
| 117 |
90 std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) { | 118 std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) { |
91 BlobDataBuilder builder(id); | 119 BlobDataBuilder builder(id); |
92 builder.AppendData("1", 1); | 120 builder.AppendData("1", 1); |
93 builder.set_content_type("text/plain"); | 121 builder.set_content_type("text/plain"); |
94 return context_.AddFinishedBlob(builder); | 122 return context_.AddFinishedBlob(builder); |
95 } | 123 } |
96 | 124 |
| 125 void SetTestMemoryLimits() { |
| 126 context_.mutable_memory_controller()->SetMemoryConstantsForTesting( |
| 127 kTestBlobStorageIPCThresholdBytes, kTestBlobStorageMaxSharedMemoryBytes, |
| 128 kTestBlobStorageMaxBlobMemorySize, kTestBlobStorageMaxDiskSpace, |
| 129 kTestBlobStorageInFlightMemory, kTestBlobStorageMinFileSizeBytes, |
| 130 kTestBlobStorageMaxFileSizeBytes); |
| 131 } |
| 132 |
| 133 base::FilePath temp_dir_; |
| 134 scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner(); |
| 135 |
| 136 base::MessageLoop fake_io_message_loop; |
97 BlobStorageContext context_; | 137 BlobStorageContext context_; |
98 }; | 138 }; |
99 | 139 |
| 140 TEST_F(BlobStorageContextTest, BuildBlobAsync) { |
| 141 const std::string kId("id"); |
| 142 const size_t kSize = 10u; |
| 143 BlobStatus status = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 144 |
| 145 BlobDataBuilder builder(kId); |
| 146 builder.AppendFutureData(kSize); |
| 147 builder.set_content_type("text/plain"); |
| 148 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 149 std::unique_ptr<BlobDataHandle> handle = |
| 150 context_.BuildBlob(builder, base::Bind(&SaveBlobStatus, &status)); |
| 151 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 152 EXPECT_TRUE(handle->IsBeingBuilt()); |
| 153 EXPECT_EQ(BlobStatus::PENDING_DATA_POPULATION, status); |
| 154 |
| 155 BlobStatus construction_done = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 156 handle->RunOnConstructionComplete( |
| 157 base::Bind(&SaveBlobStatus, &construction_done)); |
| 158 |
| 159 EXPECT_EQ(10u, context_.memory_controller().memory_usage()); |
| 160 |
| 161 builder.PopulateFutureData(0, "abcdefghij", 0, 10u); |
| 162 context_.FinishedPopulatingPendingBlob(kId); |
| 163 |
| 164 // Check we're done. |
| 165 EXPECT_EQ(BlobStatus::DONE, context_.GetBlobStatus(kId)); |
| 166 base::RunLoop().RunUntilIdle(); |
| 167 EXPECT_EQ(BlobStatus::DONE, construction_done); |
| 168 |
| 169 EXPECT_EQ(builder, *context_.CreateSnapshot(kId)); |
| 170 |
| 171 handle.reset(); |
| 172 base::RunLoop().RunUntilIdle(); |
| 173 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 174 } |
| 175 |
| 176 TEST_F(BlobStorageContextTest, BuildBlobAndCancel) { |
| 177 const std::string kId("id"); |
| 178 const size_t kSize = 10u; |
| 179 BlobStatus status = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 180 |
| 181 BlobDataBuilder builder(kId); |
| 182 builder.AppendFutureData(kSize); |
| 183 builder.set_content_type("text/plain"); |
| 184 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 185 std::unique_ptr<BlobDataHandle> handle = |
| 186 context_.BuildBlob(builder, base::Bind(&SaveBlobStatus, &status)); |
| 187 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 188 EXPECT_TRUE(handle->IsBeingBuilt()); |
| 189 EXPECT_EQ(BlobStatus::PENDING_DATA_POPULATION, status); |
| 190 EXPECT_EQ(10u, context_.memory_controller().memory_usage()); |
| 191 |
| 192 BlobStatus construction_done = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 193 handle->RunOnConstructionComplete( |
| 194 base::Bind(&SaveBlobStatus, &construction_done)); |
| 195 |
| 196 context_.BreakAndFinishPendingBlob(kId, BlobStatus::SOURCE_DIED_IN_TRANSIT); |
| 197 EXPECT_TRUE(handle->IsBroken()); |
| 198 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 199 |
| 200 // Check we're broken. |
| 201 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, context_.GetBlobStatus(kId)); |
| 202 base::RunLoop().RunUntilIdle(); |
| 203 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, construction_done); |
| 204 } |
| 205 |
| 206 TEST_F(BlobStorageContextTest, BuildBlobFuzzish) { |
| 207 const std::string kId("id"); |
| 208 const size_t kTotalRawBlobs = 200; |
| 209 const size_t kTotalSlicedBlobs = 100; |
| 210 SetTestMemoryLimits(); |
| 211 |
| 212 // This tests mixed blob content, both async and synchronous content, and |
| 213 |
| 214 std::vector<std::unique_ptr<BlobDataBuilder>> builders; |
| 215 std::vector<size_t> sizes; |
| 216 |
| 217 for (size_t i = 0; i < kTotalRawBlobs; i++) { |
| 218 builders.emplace_back(new BlobDataBuilder(base::SizeTToString(i))); |
| 219 auto& builder = *builders.back(); |
| 220 size_t size = 0; |
| 221 if (i % 2 != 0) { |
| 222 builder.AppendFutureData(5u); |
| 223 size += 5u; |
| 224 } |
| 225 if (i % 5 != 0) { |
| 226 builder.AppendFile(base::FilePath(base::SizeTToString(i)), 0ul, 20ul, |
| 227 base::Time::Max()); |
| 228 size += 20u; |
| 229 } |
| 230 if (i % 3 != 0) { |
| 231 builder.AppendData("abcdefghij", 4u); |
| 232 size += 4u; |
| 233 } |
| 234 if (i % 3 == 0) { |
| 235 builder.AppendFutureData(1u); |
| 236 size += 1u; |
| 237 } |
| 238 if (i % 7 == 0) { |
| 239 builder.AppendFutureFile(0lu, 3lu); |
| 240 size += 3u; |
| 241 } |
| 242 sizes.push_back(size); |
| 243 } |
| 244 |
| 245 for (size_t i = 0; i < kTotalSlicedBlobs; i++) { |
| 246 builders.emplace_back( |
| 247 new BlobDataBuilder(base::SizeTToString(i + kTotalRawBlobs))); |
| 248 size_t source_size = sizes[i]; |
| 249 size_t offset = sizes[i] == 1 ? 0 : i % (source_size - 1); |
| 250 size_t size = (i % (source_size - offset)) + 1; |
| 251 builders.back()->AppendBlob(base::SizeTToString(i), offset, size); |
| 252 sizes.push_back(size); |
| 253 } |
| 254 |
| 255 size_t total_finished_blobs = 0; |
| 256 std::vector<std::unique_ptr<BlobDataHandle>> handles; |
| 257 std::vector<BlobStatus> statuses; |
| 258 std::vector<bool> populated; |
| 259 statuses.resize(kTotalRawBlobs, BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS); |
| 260 populated.resize(kTotalRawBlobs, false); |
| 261 context_.EnableDisk(temp_dir_, file_runner_); |
| 262 |
| 263 for (size_t i = 0; i < builders.size(); i++) { |
| 264 BlobDataBuilder& builder = *builders[i]; |
| 265 builder.set_content_type("text/plain"); |
| 266 bool has_pending_memory = |
| 267 i < kTotalRawBlobs && (i % 3 == 0 || i % 2 != 0 || i % 7 == 0); |
| 268 std::unique_ptr<BlobDataHandle> handle = context_.BuildBlob( |
| 269 builder, has_pending_memory |
| 270 ? base::Bind(&SaveBlobStatus, &statuses[0] + i) |
| 271 : BlobStatusCallback()); |
| 272 handle->RunOnConstructionComplete( |
| 273 base::Bind(&IncrementPointer, &total_finished_blobs)); |
| 274 handles.push_back(std::move(handle)); |
| 275 } |
| 276 base::RunLoop().RunUntilIdle(); |
| 277 |
| 278 // We should be needing to send a page or two to disk. |
| 279 EXPECT_TRUE(file_runner_->HasPendingTask()); |
| 280 |
| 281 do { |
| 282 file_runner_->RunPendingTasks(); |
| 283 base::RunLoop().RunUntilIdle(); |
| 284 |
| 285 // Continue populating data for items that can fit. |
| 286 for (size_t i = 0; i < kTotalRawBlobs; i++) { |
| 287 auto& builder = *builders[i]; |
| 288 bool has_pending_memory = i % 3 == 0 || i % 2 != 0 || i % 7 == 0; |
| 289 if (has_pending_memory && !populated[i] && |
| 290 statuses[i] == BlobStatus::PENDING_DATA_POPULATION) { |
| 291 if (i % 2 != 0) { |
| 292 builder.PopulateFutureData(0, "abcde", 0, 5); |
| 293 } |
| 294 if (i % 3 == 0) { |
| 295 size_t index = i % 7 == 0 ? builder.items_.size() - 2 |
| 296 : builder.items_.size() - 1; |
| 297 builder.PopulateFutureData(index, "z", 0, 1); |
| 298 } |
| 299 if (i % 7 == 0) { |
| 300 scoped_refptr<ShareableFileReference> file_ref = |
| 301 ShareableFileReference::GetOrCreate( |
| 302 base::FilePath(base::SizeTToString(i + kTotalRawBlobs)), |
| 303 ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE, |
| 304 file_runner_.get()); |
| 305 builder.PopulateFutureFile(builder.items_.size() - 1, file_ref, |
| 306 base::Time::Max()); |
| 307 } |
| 308 context_.FinishedPopulatingPendingBlob(base::SizeTToString(i)); |
| 309 populated[i] = true; |
| 310 } |
| 311 } |
| 312 base::RunLoop().RunUntilIdle(); |
| 313 } while (file_runner_->HasPendingTask()); |
| 314 |
| 315 // We should be completely built now. |
| 316 EXPECT_EQ(kTotalRawBlobs + kTotalSlicedBlobs, total_finished_blobs); |
| 317 |
| 318 handles.clear(); |
| 319 base::RunLoop().RunUntilIdle(); |
| 320 // We should have file cleanup tasks. |
| 321 EXPECT_TRUE(file_runner_->HasPendingTask()); |
| 322 file_runner_->RunPendingTasks(); |
| 323 |
| 324 for (size_t i = 0; i < kTotalRawBlobs; i++) { |
| 325 bool has_pending_memory = i % 3 == 0 || i % 2 != 0; |
| 326 if (has_pending_memory) |
| 327 EXPECT_EQ(BlobStatus::PENDING_DATA_POPULATION, statuses[i]) << i; |
| 328 } |
| 329 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 330 EXPECT_EQ(0lu, context_.memory_controller().disk_usage()); |
| 331 } |
| 332 |
| 333 TEST_F(BlobStorageContextTest, CancelledReference) { |
| 334 const std::string kId1("id1"); |
| 335 const std::string kId2("id2"); |
| 336 const size_t kSize = 10u; |
| 337 BlobStatus status = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 338 |
| 339 // Start our first blob. |
| 340 BlobDataBuilder builder(kId1); |
| 341 builder.AppendFutureData(kSize); |
| 342 builder.set_content_type("text/plain"); |
| 343 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 344 std::unique_ptr<BlobDataHandle> handle = |
| 345 context_.BuildBlob(builder, base::Bind(&SaveBlobStatus, &status)); |
| 346 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 347 EXPECT_TRUE(handle->IsBeingBuilt()); |
| 348 EXPECT_EQ(BlobStatus::PENDING_DATA_POPULATION, status); |
| 349 |
| 350 BlobStatus construction_done = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 351 handle->RunOnConstructionComplete( |
| 352 base::Bind(&SaveBlobStatus, &construction_done)); |
| 353 |
| 354 EXPECT_EQ(10u, context_.memory_controller().memory_usage()); |
| 355 |
| 356 // Create our second blob, which depends on the first. |
| 357 BlobDataBuilder builder2(kId2); |
| 358 builder2.AppendBlob(kId1); |
| 359 builder2.set_content_type("text/plain"); |
| 360 std::unique_ptr<BlobDataHandle> handle2 = |
| 361 context_.BuildBlob(builder2, BlobStatusCallback()); |
| 362 BlobStatus construction_done2 = BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS; |
| 363 handle->RunOnConstructionComplete( |
| 364 base::Bind(&SaveBlobStatus, &construction_done2)); |
| 365 EXPECT_TRUE(handle2->IsBeingBuilt()); |
| 366 |
| 367 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
| 368 |
| 369 // Cancel the first blob. |
| 370 context_.BreakAndFinishPendingBlob(kId1, BlobStatus::SOURCE_DIED_IN_TRANSIT); |
| 371 |
| 372 base::RunLoop().RunUntilIdle(); |
| 373 // Check we broke successfully. |
| 374 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, construction_done); |
| 375 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, handle->GetBlobStatus()); |
| 376 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
| 377 EXPECT_TRUE(handle->IsBroken()); |
| 378 |
| 379 // Check that it propagated. |
| 380 EXPECT_TRUE(handle2->IsBroken()); |
| 381 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, construction_done2); |
| 382 EXPECT_EQ(BlobStatus::SOURCE_DIED_IN_TRANSIT, handle->GetBlobStatus()); |
| 383 } |
| 384 |
| 385 TEST_F(BlobStorageContextTest, IncorrectSlice) { |
| 386 const std::string kId1("id1"); |
| 387 const std::string kId2("id2"); |
| 388 |
| 389 std::unique_ptr<BlobDataHandle> handle = SetupBasicBlob(kId1); |
| 390 |
| 391 EXPECT_EQ(1lu, context_.memory_controller().memory_usage()); |
| 392 |
| 393 BlobDataBuilder builder(kId2); |
| 394 builder.AppendBlob(kId1, 1, 10); |
| 395 std::unique_ptr<BlobDataHandle> handle2 = |
| 396 context_.BuildBlob(builder, BlobStatusCallback()); |
| 397 |
| 398 EXPECT_TRUE(handle2->IsBroken()); |
| 399 EXPECT_EQ(BlobStatus::INVALID_CONSTRUCTION_ARGUMENTS, |
| 400 handle2->GetBlobStatus()); |
| 401 } |
| 402 |
100 TEST_F(BlobStorageContextTest, IncrementDecrementRef) { | 403 TEST_F(BlobStorageContextTest, IncrementDecrementRef) { |
101 base::MessageLoop fake_io_message_loop; | |
102 | |
103 // Build up a basic blob. | 404 // Build up a basic blob. |
104 const std::string kId("id"); | 405 const std::string kId("id"); |
105 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); | 406 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); |
106 | 407 |
107 // Do an extra increment to keep it around after we kill the handle. | 408 // Do an extra increment to keep it around after we kill the handle. |
108 context_.IncrementBlobRefCount(kId); | 409 context_.IncrementBlobRefCount(kId); |
109 context_.IncrementBlobRefCount(kId); | 410 context_.IncrementBlobRefCount(kId); |
110 context_.DecrementBlobRefCount(kId); | 411 context_.DecrementBlobRefCount(kId); |
111 blob_data_handle = context_.GetBlobDataFromUUID(kId); | 412 blob_data_handle = context_.GetBlobDataFromUUID(kId); |
112 EXPECT_TRUE(blob_data_handle); | 413 EXPECT_TRUE(blob_data_handle); |
113 blob_data_handle.reset(); | 414 blob_data_handle.reset(); |
114 base::RunLoop().RunUntilIdle(); | 415 base::RunLoop().RunUntilIdle(); |
115 | 416 |
116 EXPECT_TRUE(context_.registry().HasEntry(kId)); | 417 EXPECT_TRUE(context_.registry().HasEntry(kId)); |
117 context_.DecrementBlobRefCount(kId); | 418 context_.DecrementBlobRefCount(kId); |
118 EXPECT_FALSE(context_.registry().HasEntry(kId)); | 419 EXPECT_FALSE(context_.registry().HasEntry(kId)); |
119 | 420 |
120 // Make sure it goes away in the end. | 421 // Make sure it goes away in the end. |
121 blob_data_handle = context_.GetBlobDataFromUUID(kId); | 422 blob_data_handle = context_.GetBlobDataFromUUID(kId); |
122 EXPECT_FALSE(blob_data_handle); | 423 EXPECT_FALSE(blob_data_handle); |
123 } | 424 } |
124 | 425 |
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) { | 426 TEST_F(BlobStorageContextTest, BlobDataHandle) { |
140 base::MessageLoop fake_io_message_loop; | |
141 | |
142 // Build up a basic blob. | 427 // Build up a basic blob. |
143 const std::string kId("id"); | 428 const std::string kId("id"); |
144 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); | 429 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId); |
145 EXPECT_TRUE(blob_data_handle); | 430 EXPECT_TRUE(blob_data_handle); |
146 | 431 |
147 // Get another handle | 432 // Get another handle |
148 std::unique_ptr<BlobDataHandle> another_handle = | 433 std::unique_ptr<BlobDataHandle> another_handle = |
149 context_.GetBlobDataFromUUID(kId); | 434 context_.GetBlobDataFromUUID(kId); |
150 EXPECT_TRUE(another_handle); | 435 EXPECT_TRUE(another_handle); |
151 | 436 |
152 // Should disappear after dropping both handles. | 437 // Should disappear after dropping both handles. |
153 blob_data_handle.reset(); | 438 blob_data_handle.reset(); |
154 base::RunLoop().RunUntilIdle(); | 439 base::RunLoop().RunUntilIdle(); |
155 | 440 |
156 EXPECT_TRUE(context_.registry().HasEntry(kId)); | 441 EXPECT_TRUE(context_.registry().HasEntry(kId)); |
157 | 442 |
158 another_handle.reset(); | 443 another_handle.reset(); |
159 base::RunLoop().RunUntilIdle(); | 444 base::RunLoop().RunUntilIdle(); |
160 | 445 |
161 blob_data_handle = context_.GetBlobDataFromUUID(kId); | 446 blob_data_handle = context_.GetBlobDataFromUUID(kId); |
162 EXPECT_FALSE(blob_data_handle); | 447 EXPECT_FALSE(blob_data_handle); |
163 } | 448 } |
164 | 449 |
165 TEST_F(BlobStorageContextTest, MemoryUsage) { | 450 TEST_F(BlobStorageContextTest, MemoryUsage) { |
166 const std::string kId1("id1"); | 451 const std::string kId1("id1"); |
167 const std::string kId2("id2"); | 452 const std::string kId2("id2"); |
168 | 453 |
169 base::MessageLoop fake_io_message_loop; | |
170 | |
171 BlobDataBuilder builder1(kId1); | 454 BlobDataBuilder builder1(kId1); |
172 BlobDataBuilder builder2(kId2); | 455 BlobDataBuilder builder2(kId2); |
173 builder1.AppendData("Data1Data2"); | 456 builder1.AppendData("Data1Data2"); |
174 builder2.AppendBlob(kId1); | 457 builder2.AppendBlob(kId1); |
175 builder2.AppendBlob(kId1); | 458 builder2.AppendBlob(kId1); |
176 builder2.AppendBlob(kId1); | 459 builder2.AppendBlob(kId1); |
177 builder2.AppendBlob(kId1); | 460 builder2.AppendBlob(kId1); |
178 builder2.AppendBlob(kId1); | 461 builder2.AppendBlob(kId1); |
179 builder2.AppendBlob(kId1); | 462 builder2.AppendBlob(kId1); |
180 builder2.AppendBlob(kId1); | 463 builder2.AppendBlob(kId1); |
181 | 464 |
182 EXPECT_EQ(0lu, context_.memory_usage()); | 465 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
183 | 466 |
184 std::unique_ptr<BlobDataHandle> blob_data_handle = | 467 std::unique_ptr<BlobDataHandle> blob_data_handle = |
185 context_.AddFinishedBlob(&builder1); | 468 context_.AddFinishedBlob(&builder1); |
186 EXPECT_EQ(10lu, context_.memory_usage()); | 469 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
187 std::unique_ptr<BlobDataHandle> blob_data_handle2 = | 470 std::unique_ptr<BlobDataHandle> blob_data_handle2 = |
188 context_.AddFinishedBlob(&builder2); | 471 context_.AddFinishedBlob(&builder2); |
189 EXPECT_EQ(10lu, context_.memory_usage()); | 472 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
190 | 473 |
191 EXPECT_EQ(2u, context_.registry().blob_count()); | 474 EXPECT_EQ(2u, context_.registry().blob_count()); |
192 | 475 |
193 blob_data_handle.reset(); | 476 blob_data_handle.reset(); |
194 base::RunLoop().RunUntilIdle(); | 477 base::RunLoop().RunUntilIdle(); |
195 | 478 |
196 EXPECT_EQ(10lu, context_.memory_usage()); | 479 EXPECT_EQ(10lu, context_.memory_controller().memory_usage()); |
197 EXPECT_EQ(1u, context_.registry().blob_count()); | 480 EXPECT_EQ(1u, context_.registry().blob_count()); |
198 blob_data_handle2.reset(); | 481 blob_data_handle2.reset(); |
199 base::RunLoop().RunUntilIdle(); | 482 base::RunLoop().RunUntilIdle(); |
200 | 483 |
201 EXPECT_EQ(0lu, context_.memory_usage()); | 484 EXPECT_EQ(0lu, context_.memory_controller().memory_usage()); |
202 EXPECT_EQ(0u, context_.registry().blob_count()); | 485 EXPECT_EQ(0u, context_.registry().blob_count()); |
203 } | 486 } |
204 | 487 |
205 TEST_F(BlobStorageContextTest, AddFinishedBlob) { | 488 TEST_F(BlobStorageContextTest, AddFinishedBlob) { |
206 const std::string kId1("id1"); | 489 const std::string kId1("id1"); |
207 const std::string kId2("id12"); | 490 const std::string kId2("id12"); |
208 const std::string kId2Prime("id2.prime"); | 491 const std::string kId2Prime("id2.prime"); |
209 const std::string kId3("id3"); | 492 const std::string kId3("id3"); |
210 const std::string kId3Prime("id3.prime"); | 493 const std::string kId3Prime("id3.prime"); |
211 | 494 |
212 base::MessageLoop fake_io_message_loop; | |
213 | |
214 BlobDataBuilder builder1(kId1); | 495 BlobDataBuilder builder1(kId1); |
215 BlobDataBuilder builder2(kId2); | 496 BlobDataBuilder builder2(kId2); |
216 BlobDataBuilder canonicalized_blob_data2(kId2Prime); | 497 BlobDataBuilder canonicalized_blob_data2(kId2Prime); |
217 builder1.AppendData("Data1Data2"); | 498 builder1.AppendData("Data1Data2"); |
218 builder2.AppendBlob(kId1, 5, 5); | 499 builder2.AppendBlob(kId1, 5, 5); |
219 builder2.AppendData(" is the best"); | 500 builder2.AppendData(" is the best"); |
220 canonicalized_blob_data2.AppendData("Data2"); | 501 canonicalized_blob_data2.AppendData("Data2"); |
221 canonicalized_blob_data2.AppendData(" is the best"); | 502 canonicalized_blob_data2.AppendData(" is the best"); |
222 | 503 |
223 BlobStorageContext context; | 504 BlobStorageContext context; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 blob_data_handle.reset(); | 549 blob_data_handle.reset(); |
269 blob_data_handle2.reset(); | 550 blob_data_handle2.reset(); |
270 blob_data_handle3.reset(); | 551 blob_data_handle3.reset(); |
271 base::RunLoop().RunUntilIdle(); | 552 base::RunLoop().RunUntilIdle(); |
272 } | 553 } |
273 | 554 |
274 TEST_F(BlobStorageContextTest, AddFinishedBlob_LargeOffset) { | 555 TEST_F(BlobStorageContextTest, AddFinishedBlob_LargeOffset) { |
275 // A value which does not fit in a 4-byte data type. Used to confirm that | 556 // 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: | 557 // large values are supported on 32-bit Chromium builds. Regression test for: |
277 // crbug.com/458122. | 558 // crbug.com/458122. |
278 const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max(); | 559 const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max() - 1; |
279 | 560 |
280 const uint64_t kBlobLength = 5; | 561 const uint64_t kBlobLength = 5; |
281 const std::string kId1("id1"); | 562 const std::string kId1("id1"); |
282 const std::string kId2("id2"); | 563 const std::string kId2("id2"); |
283 base::MessageLoop fake_io_message_loop; | |
284 | 564 |
285 BlobDataBuilder builder1(kId1); | 565 BlobDataBuilder builder1(kId1); |
286 builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now()); | 566 builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now()); |
287 | 567 |
288 BlobDataBuilder builder2(kId2); | 568 BlobDataBuilder builder2(kId2); |
289 builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength); | 569 builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength); |
290 | 570 |
291 std::unique_ptr<BlobDataHandle> blob_data_handle1 = | 571 std::unique_ptr<BlobDataHandle> blob_data_handle1 = |
292 context_.AddFinishedBlob(&builder1); | 572 context_.AddFinishedBlob(&builder1); |
293 std::unique_ptr<BlobDataHandle> blob_data_handle2 = | 573 std::unique_ptr<BlobDataHandle> blob_data_handle2 = |
294 context_.AddFinishedBlob(&builder2); | 574 context_.AddFinishedBlob(&builder2); |
295 | 575 |
296 ASSERT_TRUE(blob_data_handle1); | 576 ASSERT_TRUE(blob_data_handle1); |
297 ASSERT_TRUE(blob_data_handle2); | 577 ASSERT_TRUE(blob_data_handle2); |
298 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot(); | 578 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot(); |
299 ASSERT_EQ(1u, data->items().size()); | 579 ASSERT_EQ(1u, data->items().size()); |
300 const scoped_refptr<BlobDataItem> item = data->items()[0]; | 580 const scoped_refptr<BlobDataItem> item = data->items()[0]; |
301 EXPECT_EQ(kLargeSize - kBlobLength, item->offset()); | 581 EXPECT_EQ(kLargeSize - kBlobLength, item->offset()); |
302 EXPECT_EQ(kBlobLength, item->length()); | 582 EXPECT_EQ(kBlobLength, item->length()); |
303 | 583 |
304 blob_data_handle1.reset(); | 584 blob_data_handle1.reset(); |
305 blob_data_handle2.reset(); | 585 blob_data_handle2.reset(); |
306 base::RunLoop().RunUntilIdle(); | 586 base::RunLoop().RunUntilIdle(); |
307 } | 587 } |
308 | 588 |
309 TEST_F(BlobStorageContextTest, BuildDiskCacheBlob) { | 589 TEST_F(BlobStorageContextTest, BuildDiskCacheBlob) { |
310 base::MessageLoop fake_io_message_loop; | |
311 scoped_refptr<BlobDataBuilder::DataHandle> | 590 scoped_refptr<BlobDataBuilder::DataHandle> |
312 data_handle = new EmptyDataHandle(); | 591 data_handle = new EmptyDataHandle(); |
313 | 592 |
314 { | 593 { |
315 BlobStorageContext context; | 594 BlobStorageContext context; |
316 | 595 |
317 std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache(); | 596 std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache(); |
318 ASSERT_TRUE(cache); | 597 ASSERT_TRUE(cache); |
319 | 598 |
320 const std::string kTestBlobData = "Test Blob Data"; | 599 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."; | 621 << "Data handle was not destructed along with blob storage context."; |
343 base::RunLoop().RunUntilIdle(); | 622 base::RunLoop().RunUntilIdle(); |
344 } | 623 } |
345 | 624 |
346 TEST_F(BlobStorageContextTest, CompoundBlobs) { | 625 TEST_F(BlobStorageContextTest, CompoundBlobs) { |
347 const std::string kId1("id1"); | 626 const std::string kId1("id1"); |
348 const std::string kId2("id2"); | 627 const std::string kId2("id2"); |
349 const std::string kId3("id3"); | 628 const std::string kId3("id3"); |
350 const std::string kId2Prime("id2.prime"); | 629 const std::string kId2Prime("id2.prime"); |
351 | 630 |
352 base::MessageLoop fake_io_message_loop; | |
353 | |
354 // Setup a set of blob data for testing. | 631 // Setup a set of blob data for testing. |
355 base::Time time1, time2; | 632 base::Time time1, time2; |
356 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1); | 633 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); | 634 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2); |
358 | 635 |
359 BlobDataBuilder blob_data1(kId1); | 636 BlobDataBuilder blob_data1(kId1); |
360 blob_data1.AppendData("Data1"); | 637 blob_data1.AppendData("Data1"); |
361 blob_data1.AppendData("Data2"); | 638 blob_data1.AppendData("Data2"); |
362 blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, | 639 blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, |
363 1024, time1); | 640 1024, time1); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 blob_data_handle = context_.AddFinishedBlob(&blob_data3); | 684 blob_data_handle = context_.AddFinishedBlob(&blob_data3); |
408 data = blob_data_handle->CreateSnapshot(); | 685 data = blob_data_handle->CreateSnapshot(); |
409 ASSERT_TRUE(blob_data_handle); | 686 ASSERT_TRUE(blob_data_handle); |
410 EXPECT_EQ(*data, blob_data3); | 687 EXPECT_EQ(*data, blob_data3); |
411 | 688 |
412 blob_data_handle.reset(); | 689 blob_data_handle.reset(); |
413 base::RunLoop().RunUntilIdle(); | 690 base::RunLoop().RunUntilIdle(); |
414 } | 691 } |
415 | 692 |
416 TEST_F(BlobStorageContextTest, PublicBlobUrls) { | 693 TEST_F(BlobStorageContextTest, PublicBlobUrls) { |
417 base::MessageLoop fake_io_message_loop; | |
418 | |
419 // Build up a basic blob. | 694 // Build up a basic blob. |
420 const std::string kId("id"); | 695 const std::string kId("id"); |
421 std::unique_ptr<BlobDataHandle> first_handle = SetupBasicBlob(kId); | 696 std::unique_ptr<BlobDataHandle> first_handle = SetupBasicBlob(kId); |
422 | 697 |
423 // Now register a url for that blob. | 698 // Now register a url for that blob. |
424 GURL kUrl("blob:id"); | 699 GURL kUrl("blob:id"); |
425 context_.RegisterPublicBlobURL(kUrl, kId); | 700 context_.RegisterPublicBlobURL(kUrl, kId); |
426 std::unique_ptr<BlobDataHandle> blob_data_handle = | 701 std::unique_ptr<BlobDataHandle> blob_data_handle = |
427 context_.GetBlobDataFromPublicURL(kUrl); | 702 context_.GetBlobDataFromPublicURL(kUrl); |
428 ASSERT_TRUE(blob_data_handle.get()); | 703 ASSERT_TRUE(blob_data_handle.get()); |
429 EXPECT_EQ(kId, blob_data_handle->uuid()); | 704 EXPECT_EQ(kId, blob_data_handle->uuid()); |
430 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot(); | 705 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot(); |
431 blob_data_handle.reset(); | 706 blob_data_handle.reset(); |
432 first_handle.reset(); | 707 first_handle.reset(); |
433 base::RunLoop().RunUntilIdle(); | 708 base::RunLoop().RunUntilIdle(); |
434 | 709 |
435 // The url registration should keep the blob alive even after | 710 // The url registration should keep the blob alive even after |
436 // explicit references are dropped. | 711 // explicit references are dropped. |
437 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); | 712 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); |
438 EXPECT_TRUE(blob_data_handle); | 713 EXPECT_TRUE(blob_data_handle); |
439 blob_data_handle.reset(); | 714 blob_data_handle.reset(); |
| 715 |
440 base::RunLoop().RunUntilIdle(); | 716 base::RunLoop().RunUntilIdle(); |
441 | |
442 // Finally get rid of the url registration and the blob. | 717 // Finally get rid of the url registration and the blob. |
443 context_.RevokePublicBlobURL(kUrl); | 718 context_.RevokePublicBlobURL(kUrl); |
444 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); | 719 blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl); |
445 EXPECT_FALSE(blob_data_handle.get()); | 720 EXPECT_FALSE(blob_data_handle.get()); |
446 EXPECT_FALSE(context_.registry().HasEntry(kId)); | 721 EXPECT_FALSE(context_.registry().HasEntry(kId)); |
447 } | 722 } |
448 | 723 |
449 TEST_F(BlobStorageContextTest, TestUnknownBrokenAndBuildingBlobReference) { | 724 TEST_F(BlobStorageContextTest, TestUnknownBrokenAndBuildingBlobReference) { |
450 base::MessageLoop fake_io_message_loop; | |
451 const std::string kBrokenId("broken_id"); | 725 const std::string kBrokenId("broken_id"); |
452 const std::string kBuildingId("building_id"); | 726 const std::string kBuildingId("building_id"); |
453 const std::string kReferencingId("referencing_id"); | 727 const std::string kReferencingId("referencing_id"); |
454 const std::string kUnknownId("unknown_id"); | 728 const std::string kUnknownId("unknown_id"); |
455 | 729 |
456 // Create a broken blob and a building blob. | 730 // Create a broken blob. |
457 context_.CreatePendingBlob(kBuildingId, "", ""); | 731 std::unique_ptr<BlobDataHandle> broken_handle = |
458 context_.CreatePendingBlob(kBrokenId, "", ""); | 732 context_.AddBrokenBlob(kBrokenId, "", "", BlobStatus::OUT_OF_MEMORY); |
459 context_.CancelPendingBlob(kBrokenId, IPCBlobCreationCancelCode::UNKNOWN); | 733 EXPECT_TRUE(context_.GetBlobStatus(kBrokenId) == BlobStatus::OUT_OF_MEMORY); |
460 EXPECT_TRUE(context_.IsBroken(kBrokenId)); | |
461 EXPECT_TRUE(context_.registry().HasEntry(kBrokenId)); | 734 EXPECT_TRUE(context_.registry().HasEntry(kBrokenId)); |
462 | 735 |
463 // Try to create a blob with a reference to an unknown blob. | 736 // Try to create a blob with a reference to an unknown blob. |
464 BlobDataBuilder builder(kReferencingId); | 737 BlobDataBuilder builder(kReferencingId); |
465 builder.AppendData("data"); | 738 builder.AppendData("data"); |
466 builder.AppendBlob(kUnknownId); | 739 builder.AppendBlob(kUnknownId); |
467 std::unique_ptr<BlobDataHandle> handle = context_.AddFinishedBlob(builder); | 740 std::unique_ptr<BlobDataHandle> handle = context_.AddFinishedBlob(builder); |
468 EXPECT_TRUE(handle->IsBroken()); | 741 EXPECT_TRUE(handle->IsBroken()); |
469 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); | 742 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); |
470 handle.reset(); | 743 handle.reset(); |
(...skipping 19 matching lines...) Expand all Loading... |
490 EXPECT_TRUE(handle->IsBroken()); | 763 EXPECT_TRUE(handle->IsBroken()); |
491 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); | 764 EXPECT_TRUE(context_.registry().HasEntry(kReferencingId)); |
492 handle.reset(); | 765 handle.reset(); |
493 base::RunLoop().RunUntilIdle(); | 766 base::RunLoop().RunUntilIdle(); |
494 EXPECT_FALSE(context_.registry().HasEntry(kReferencingId)); | 767 EXPECT_FALSE(context_.registry().HasEntry(kReferencingId)); |
495 } | 768 } |
496 | 769 |
497 // TODO(michaeln): tests for the depcrecated url stuff | 770 // TODO(michaeln): tests for the depcrecated url stuff |
498 | 771 |
499 } // namespace content | 772 } // namespace content |
OLD | NEW |