Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: content/browser/blob_storage/blob_storage_context_unittest.cc

Issue 2788883003: Move storage test next to the file that it tests (Closed)
Patch Set: The actual move. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "storage/browser/blob/blob_storage_context.h"
6
7 #include <stdint.h>
8
9 #include <limits>
10 #include <memory>
11 #include <string>
12
13 #include "base/bind.h"
14 #include "base/files/file.h"
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/run_loop.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/test/test_simple_task_runner.h"
23 #include "base/threading/thread_task_runner_handle.h"
24 #include "base/time/time.h"
25 #include "content/browser/blob_storage/blob_dispatcher_host.h"
26 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
27 #include "content/public/test/test_browser_context.h"
28 #include "net/base/io_buffer.h"
29 #include "net/base/test_completion_callback.h"
30 #include "net/disk_cache/disk_cache.h"
31 #include "storage/browser/blob/blob_data_builder.h"
32 #include "storage/browser/blob/blob_data_handle.h"
33 #include "storage/browser/blob/blob_data_item.h"
34 #include "storage/browser/blob/blob_data_snapshot.h"
35 #include "storage/browser/blob/blob_transport_host.h"
36 #include "storage/common/blob_storage/blob_item_bytes_request.h"
37 #include "storage/common/blob_storage/blob_item_bytes_response.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39
40 using RequestMemoryCallback = storage::BlobTransportHost::RequestMemoryCallback;
41 using FileCreationInfo = storage::BlobMemoryController::FileCreationInfo;
42
43 namespace storage {
44 namespace {
45 using base::TestSimpleTaskRunner;
46
47 const int kTestDiskCacheStreamIndex = 0;
48
49 const std::string kBlobStorageDirectory = "blob_storage";
50 const size_t kTestBlobStorageIPCThresholdBytes = 20;
51 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
52
53 const size_t kTestBlobStorageMaxBlobMemorySize = 400;
54 const uint64_t kTestBlobStorageMaxDiskSpace = 4000;
55 const uint64_t kTestBlobStorageMinFileSizeBytes = 10;
56 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
57
58 // Our disk cache tests don't need a real data handle since the tests themselves
59 // scope the disk cache and entries.
60 class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle {
61 private:
62 ~EmptyDataHandle() override {}
63 };
64
65 std::unique_ptr<disk_cache::Backend> CreateInMemoryDiskCache() {
66 std::unique_ptr<disk_cache::Backend> cache;
67 net::TestCompletionCallback callback;
68 int rv = disk_cache::CreateCacheBackend(net::MEMORY_CACHE,
69 net::CACHE_BACKEND_DEFAULT,
70 base::FilePath(), 0,
71 false, nullptr, nullptr, &cache,
72 callback.callback());
73 EXPECT_EQ(net::OK, callback.GetResult(rv));
74
75 return cache;
76 }
77
78 disk_cache::ScopedEntryPtr CreateDiskCacheEntry(disk_cache::Backend* cache,
79 const char* key,
80 const std::string& data) {
81 disk_cache::Entry* temp_entry = nullptr;
82 net::TestCompletionCallback callback;
83 int rv = cache->CreateEntry(key, &temp_entry, callback.callback());
84 if (callback.GetResult(rv) != net::OK)
85 return nullptr;
86 disk_cache::ScopedEntryPtr entry(temp_entry);
87
88 scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data);
89 rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(),
90 iobuffer->size(), callback.callback(), false);
91 EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv));
92 return entry;
93 }
94
95 void SaveBlobStatus(BlobStatus* status_ptr, BlobStatus status) {
96 *status_ptr = status;
97 }
98
99 void SaveBlobStatusAndFiles(BlobStatus* status_ptr,
100 std::vector<FileCreationInfo>* files_ptr,
101 BlobStatus status,
102 std::vector<FileCreationInfo> files) {
103 EXPECT_FALSE(BlobStatusIsError(status));
104 *status_ptr = status;
105 for (FileCreationInfo& info : files) {
106 files_ptr->push_back(std::move(info));
107 }
108 }
109
110 void IncrementNumber(size_t* number, BlobStatus status) {
111 EXPECT_EQ(BlobStatus::DONE, status);
112 *number = *number + 1;
113 }
114
115 } // namespace
116
117 class BlobStorageContextTest : public testing::Test {
118 protected:
119 BlobStorageContextTest() {}
120 ~BlobStorageContextTest() override {}
121
122 void SetUp() override {
123 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
124 context_ = base::MakeUnique<BlobStorageContext>();
125 }
126
127 void TearDown() override {
128 base::RunLoop().RunUntilIdle();
129 file_runner_->RunPendingTasks();
130 ASSERT_TRUE(temp_dir_.Delete());
131 }
132
133 std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) {
134 BlobDataBuilder builder(id);
135 builder.AppendData("1", 1);
136 builder.set_content_type("text/plain");
137 return context_->AddFinishedBlob(builder);
138 }
139
140 void SetTestMemoryLimits() {
141 BlobStorageLimits limits;
142 limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
143 limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
144 limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
145 limits.desired_max_disk_space = kTestBlobStorageMaxDiskSpace;
146 limits.effective_max_disk_space = kTestBlobStorageMaxDiskSpace;
147 limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
148 limits.max_file_size = kTestBlobStorageMaxFileSizeBytes;
149 context_->mutable_memory_controller()->set_limits_for_testing(limits);
150 }
151
152 void IncrementRefCount(const std::string& uuid) {
153 context_->IncrementBlobRefCount(uuid);
154 }
155
156 void DecrementRefCount(const std::string& uuid) {
157 context_->DecrementBlobRefCount(uuid);
158 }
159
160 std::vector<FileCreationInfo> files_;
161 base::ScopedTempDir temp_dir_;
162 scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner();
163
164 base::MessageLoop fake_io_message_loop_;
165 std::unique_ptr<BlobStorageContext> context_;
166 };
167
168 TEST_F(BlobStorageContextTest, BuildBlobAsync) {
169 const std::string kId("id");
170 const size_t kSize = 10u;
171 BlobStatus status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
172
173 BlobDataBuilder builder(kId);
174 builder.AppendFutureData(kSize);
175 builder.set_content_type("text/plain");
176 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
177 std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
178 builder, base::Bind(&SaveBlobStatusAndFiles, &status, &files_));
179 EXPECT_EQ(10lu, context_->memory_controller().memory_usage());
180 EXPECT_TRUE(handle->IsBeingBuilt())
181 << static_cast<int>(handle->GetBlobStatus());
182 EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, status);
183
184 BlobStatus construction_done = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
185 handle->RunOnConstructionComplete(
186 base::Bind(&SaveBlobStatus, &construction_done));
187
188 EXPECT_EQ(10u, context_->memory_controller().memory_usage());
189
190 builder.PopulateFutureData(0, "abcdefghij", 0, 10u);
191 context_->NotifyTransportComplete(kId);
192
193 // Check we're done.
194 EXPECT_EQ(BlobStatus::DONE, handle->GetBlobStatus());
195 base::RunLoop().RunUntilIdle();
196 EXPECT_EQ(BlobStatus::DONE, construction_done);
197
198 EXPECT_EQ(builder, *handle->CreateSnapshot());
199
200 handle.reset();
201 base::RunLoop().RunUntilIdle();
202 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
203 }
204
205 TEST_F(BlobStorageContextTest, BuildBlobAndCancel) {
206 const std::string kId("id");
207 const size_t kSize = 10u;
208 BlobStatus status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
209
210 BlobDataBuilder builder(kId);
211 builder.AppendFutureData(kSize);
212 builder.set_content_type("text/plain");
213 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
214 std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
215 builder, base::Bind(&SaveBlobStatusAndFiles, &status, &files_));
216 EXPECT_EQ(10lu, context_->memory_controller().memory_usage());
217 EXPECT_TRUE(handle->IsBeingBuilt());
218 EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, status);
219 EXPECT_EQ(10u, context_->memory_controller().memory_usage());
220
221 BlobStatus construction_done = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
222 handle->RunOnConstructionComplete(
223 base::Bind(&SaveBlobStatus, &construction_done));
224
225 context_->CancelBuildingBlob(kId, BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT);
226 EXPECT_TRUE(handle->IsBroken());
227 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
228
229 // Check we're broken.
230 EXPECT_EQ(BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT, handle->GetBlobStatus());
231 base::RunLoop().RunUntilIdle();
232 EXPECT_EQ(BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT, construction_done);
233 }
234
235 TEST_F(BlobStorageContextTest, CancelledReference) {
236 const std::string kId1("id1");
237 const std::string kId2("id2");
238 const size_t kSize = 10u;
239 BlobStatus status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
240
241 // Start our first blob.
242 BlobDataBuilder builder(kId1);
243 builder.AppendFutureData(kSize);
244 builder.set_content_type("text/plain");
245 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
246 std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
247 builder, base::Bind(&SaveBlobStatusAndFiles, &status, &files_));
248 EXPECT_EQ(10lu, context_->memory_controller().memory_usage());
249 EXPECT_TRUE(handle->IsBeingBuilt());
250 EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, status);
251
252 BlobStatus construction_done = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
253 handle->RunOnConstructionComplete(
254 base::Bind(&SaveBlobStatus, &construction_done));
255
256 EXPECT_EQ(10u, context_->memory_controller().memory_usage());
257
258 // Create our second blob, which depends on the first.
259 BlobDataBuilder builder2(kId2);
260 builder2.AppendBlob(kId1);
261 builder2.set_content_type("text/plain");
262 std::unique_ptr<BlobDataHandle> handle2 = context_->BuildBlob(
263 builder2, BlobStorageContext::TransportAllowedCallback());
264 BlobStatus construction_done2 =
265 BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
266 handle->RunOnConstructionComplete(
267 base::Bind(&SaveBlobStatus, &construction_done2));
268 EXPECT_TRUE(handle2->IsBeingBuilt());
269
270 EXPECT_EQ(10lu, context_->memory_controller().memory_usage());
271
272 // Cancel the first blob.
273 context_->CancelBuildingBlob(kId1, BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT);
274
275 base::RunLoop().RunUntilIdle();
276 // Check we broke successfully.
277 EXPECT_EQ(BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT, construction_done);
278 EXPECT_EQ(BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT, handle->GetBlobStatus());
279 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
280 EXPECT_TRUE(handle->IsBroken());
281
282 // Check that it propagated.
283 EXPECT_TRUE(handle2->IsBroken());
284 EXPECT_EQ(BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT, construction_done2);
285 EXPECT_EQ(BlobStatus::ERR_SOURCE_DIED_IN_TRANSIT, handle->GetBlobStatus());
286 }
287
288 TEST_F(BlobStorageContextTest, IncorrectSlice) {
289 const std::string kId1("id1");
290 const std::string kId2("id2");
291
292 std::unique_ptr<BlobDataHandle> handle = SetupBasicBlob(kId1);
293
294 EXPECT_EQ(1lu, context_->memory_controller().memory_usage());
295
296 BlobDataBuilder builder(kId2);
297 builder.AppendBlob(kId1, 1, 10);
298 std::unique_ptr<BlobDataHandle> handle2 = context_->BuildBlob(
299 builder, BlobStorageContext::TransportAllowedCallback());
300
301 EXPECT_TRUE(handle2->IsBroken());
302 EXPECT_EQ(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS,
303 handle2->GetBlobStatus());
304 }
305
306 TEST_F(BlobStorageContextTest, IncrementDecrementRef) {
307 // Build up a basic blob.
308 const std::string kId("id");
309 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId);
310
311 // Do an extra increment to keep it around after we kill the handle.
312 IncrementRefCount(kId);
313 IncrementRefCount(kId);
314 DecrementRefCount(kId);
315 blob_data_handle = context_->GetBlobDataFromUUID(kId);
316 EXPECT_TRUE(blob_data_handle);
317 blob_data_handle.reset();
318 base::RunLoop().RunUntilIdle();
319
320 EXPECT_TRUE(context_->registry().HasEntry(kId));
321 DecrementRefCount(kId);
322 EXPECT_FALSE(context_->registry().HasEntry(kId));
323
324 // Make sure it goes away in the end.
325 blob_data_handle = context_->GetBlobDataFromUUID(kId);
326 EXPECT_FALSE(blob_data_handle);
327 }
328
329 TEST_F(BlobStorageContextTest, BlobDataHandle) {
330 // Build up a basic blob.
331 const std::string kId("id");
332 std::unique_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId);
333 EXPECT_TRUE(blob_data_handle);
334
335 // Get another handle
336 std::unique_ptr<BlobDataHandle> another_handle =
337 context_->GetBlobDataFromUUID(kId);
338 EXPECT_TRUE(another_handle);
339
340 // Should disappear after dropping both handles.
341 blob_data_handle.reset();
342 base::RunLoop().RunUntilIdle();
343
344 EXPECT_TRUE(context_->registry().HasEntry(kId));
345
346 another_handle.reset();
347 base::RunLoop().RunUntilIdle();
348
349 blob_data_handle = context_->GetBlobDataFromUUID(kId);
350 EXPECT_FALSE(blob_data_handle);
351 }
352
353 TEST_F(BlobStorageContextTest, MemoryUsage) {
354 const std::string kId1("id1");
355 const std::string kId2("id2");
356
357 BlobDataBuilder builder1(kId1);
358 BlobDataBuilder builder2(kId2);
359 builder1.AppendData("Data1Data2");
360 builder2.AppendBlob(kId1);
361 builder2.AppendBlob(kId1);
362 builder2.AppendBlob(kId1);
363 builder2.AppendBlob(kId1);
364 builder2.AppendBlob(kId1);
365 builder2.AppendBlob(kId1);
366 builder2.AppendBlob(kId1);
367
368 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
369
370 std::unique_ptr<BlobDataHandle> blob_data_handle =
371 context_->AddFinishedBlob(&builder1);
372 EXPECT_EQ(10lu, context_->memory_controller().memory_usage());
373 std::unique_ptr<BlobDataHandle> blob_data_handle2 =
374 context_->AddFinishedBlob(&builder2);
375 EXPECT_EQ(10lu, context_->memory_controller().memory_usage());
376
377 EXPECT_EQ(2u, context_->registry().blob_count());
378
379 blob_data_handle.reset();
380 base::RunLoop().RunUntilIdle();
381
382 EXPECT_EQ(10lu, context_->memory_controller().memory_usage());
383 EXPECT_EQ(1u, context_->registry().blob_count());
384 blob_data_handle2.reset();
385 base::RunLoop().RunUntilIdle();
386
387 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
388 EXPECT_EQ(0u, context_->registry().blob_count());
389 }
390
391 TEST_F(BlobStorageContextTest, AddFinishedBlob) {
392 const std::string kId1("id1");
393 const std::string kId2("id12");
394 const std::string kId3("id3");
395
396 BlobDataBuilder builder1(kId1);
397 BlobDataBuilder builder2(kId2);
398 BlobDataBuilder canonicalized_blob_data2(kId2);
399 builder1.AppendData("Data1Data2");
400 builder2.AppendBlob(kId1, 5, 5);
401 builder2.AppendData(" is the best");
402 canonicalized_blob_data2.AppendData("Data2");
403 canonicalized_blob_data2.AppendData(" is the best");
404
405 BlobStorageContext context;
406
407 std::unique_ptr<BlobDataHandle> blob_data_handle =
408 context_->AddFinishedBlob(&builder1);
409 std::unique_ptr<BlobDataHandle> blob_data_handle2 =
410 context_->AddFinishedBlob(&builder2);
411
412 EXPECT_EQ(10u + 12u + 5u, context_->memory_controller().memory_usage());
413
414 ASSERT_TRUE(blob_data_handle);
415 ASSERT_TRUE(blob_data_handle2);
416 std::unique_ptr<BlobDataSnapshot> data1 = blob_data_handle->CreateSnapshot();
417 std::unique_ptr<BlobDataSnapshot> data2 = blob_data_handle2->CreateSnapshot();
418 EXPECT_EQ(*data1, builder1);
419 EXPECT_EQ(*data2, canonicalized_blob_data2);
420 blob_data_handle.reset();
421 data2.reset();
422
423 base::RunLoop().RunUntilIdle();
424
425 EXPECT_EQ(12u + 5u, context_->memory_controller().memory_usage());
426
427 blob_data_handle = context_->GetBlobDataFromUUID(kId1);
428 EXPECT_FALSE(blob_data_handle);
429 EXPECT_TRUE(blob_data_handle2);
430 data2 = blob_data_handle2->CreateSnapshot();
431 EXPECT_EQ(*data2, canonicalized_blob_data2);
432
433 // Test shared elements stick around.
434 BlobDataBuilder builder3(kId3);
435 builder3.AppendBlob(kId2);
436 builder3.AppendBlob(kId2);
437 std::unique_ptr<BlobDataHandle> blob_data_handle3 =
438 context_->AddFinishedBlob(&builder3);
439 EXPECT_FALSE(blob_data_handle3->IsBeingBuilt());
440 blob_data_handle2.reset();
441 base::RunLoop().RunUntilIdle();
442
443 EXPECT_EQ(12u + 5u, context_->memory_controller().memory_usage());
444
445 blob_data_handle2 = context_->GetBlobDataFromUUID(kId2);
446 EXPECT_FALSE(blob_data_handle2);
447 EXPECT_TRUE(blob_data_handle3);
448 std::unique_ptr<BlobDataSnapshot> data3 = blob_data_handle3->CreateSnapshot();
449
450 BlobDataBuilder canonicalized_blob_data3(kId3);
451 canonicalized_blob_data3.AppendData("Data2");
452 canonicalized_blob_data3.AppendData(" is the best");
453 canonicalized_blob_data3.AppendData("Data2");
454 canonicalized_blob_data3.AppendData(" is the best");
455 EXPECT_EQ(*data3, canonicalized_blob_data3);
456
457 blob_data_handle.reset();
458 blob_data_handle2.reset();
459 blob_data_handle3.reset();
460 base::RunLoop().RunUntilIdle();
461 }
462
463 TEST_F(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
464 // A value which does not fit in a 4-byte data type. Used to confirm that
465 // large values are supported on 32-bit Chromium builds. Regression test for:
466 // crbug.com/458122.
467 const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max() - 1;
468
469 const uint64_t kBlobLength = 5;
470 const std::string kId1("id1");
471 const std::string kId2("id2");
472
473 BlobDataBuilder builder1(kId1);
474 builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now());
475
476 BlobDataBuilder builder2(kId2);
477 builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength);
478
479 std::unique_ptr<BlobDataHandle> blob_data_handle1 =
480 context_->AddFinishedBlob(&builder1);
481 std::unique_ptr<BlobDataHandle> blob_data_handle2 =
482 context_->AddFinishedBlob(&builder2);
483
484 ASSERT_TRUE(blob_data_handle1);
485 ASSERT_TRUE(blob_data_handle2);
486 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot();
487 ASSERT_EQ(1u, data->items().size());
488 const scoped_refptr<BlobDataItem> item = data->items()[0];
489 EXPECT_EQ(kLargeSize - kBlobLength, item->offset());
490 EXPECT_EQ(kBlobLength, item->length());
491
492 blob_data_handle1.reset();
493 blob_data_handle2.reset();
494 base::RunLoop().RunUntilIdle();
495 }
496
497 TEST_F(BlobStorageContextTest, BuildDiskCacheBlob) {
498 scoped_refptr<BlobDataBuilder::DataHandle>
499 data_handle = new EmptyDataHandle();
500
501 {
502 BlobStorageContext context;
503
504 std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache();
505 ASSERT_TRUE(cache);
506
507 const std::string kTestBlobData = "Test Blob Data";
508 disk_cache::ScopedEntryPtr entry =
509 CreateDiskCacheEntry(cache.get(), "test entry", kTestBlobData);
510
511 const std::string kId1Prime("id1.prime");
512 BlobDataBuilder canonicalized_blob_data(kId1Prime);
513 canonicalized_blob_data.AppendData(kTestBlobData.c_str());
514
515 const std::string kId1("id1");
516 BlobDataBuilder builder(kId1);
517
518 builder.AppendDiskCacheEntry(
519 data_handle, entry.get(), kTestDiskCacheStreamIndex);
520
521 std::unique_ptr<BlobDataHandle> blob_data_handle =
522 context.AddFinishedBlob(&builder);
523 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
524 EXPECT_EQ(*data, builder);
525 EXPECT_FALSE(data_handle->HasOneRef())
526 << "Data handle was destructed while context and builder still exist.";
527 }
528 EXPECT_TRUE(data_handle->HasOneRef())
529 << "Data handle was not destructed along with blob storage context.";
530 base::RunLoop().RunUntilIdle();
531 }
532
533 TEST_F(BlobStorageContextTest, BuildFutureFileOnlyBlob) {
534 const std::string kId1("id1");
535 context_ =
536 base::MakeUnique<BlobStorageContext>(temp_dir_.GetPath(), file_runner_);
537 SetTestMemoryLimits();
538
539 BlobDataBuilder builder(kId1);
540 builder.set_content_type("text/plain");
541 builder.AppendFutureFile(0, 10, 0);
542
543 BlobStatus status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
544 std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
545 builder, base::Bind(&SaveBlobStatusAndFiles, &status, &files_));
546
547 size_t blobs_finished = 0;
548 EXPECT_EQ(BlobStatus::PENDING_QUOTA, handle->GetBlobStatus());
549 EXPECT_EQ(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS, status);
550 handle->RunOnConstructionComplete(
551 base::Bind(&IncrementNumber, &blobs_finished));
552 EXPECT_EQ(0u, blobs_finished);
553
554 EXPECT_TRUE(file_runner_->HasPendingTask());
555 file_runner_->RunPendingTasks();
556 EXPECT_EQ(0u, blobs_finished);
557 EXPECT_EQ(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS, status);
558 EXPECT_EQ(BlobStatus::PENDING_QUOTA, handle->GetBlobStatus());
559 base::RunLoop().RunUntilIdle();
560
561 EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, status);
562 EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, handle->GetBlobStatus());
563 EXPECT_EQ(0u, blobs_finished);
564
565 ASSERT_EQ(1u, files_.size());
566
567 builder.PopulateFutureFile(0, files_[0].file_reference, base::Time::Max());
568 context_->NotifyTransportComplete(kId1);
569
570 EXPECT_EQ(BlobStatus::DONE, handle->GetBlobStatus());
571 EXPECT_EQ(0u, blobs_finished);
572 base::RunLoop().RunUntilIdle();
573 EXPECT_EQ(1u, blobs_finished);
574
575 builder.Clear();
576 handle.reset();
577 files_.clear();
578 base::RunLoop().RunUntilIdle();
579 // We should have file cleanup tasks.
580 EXPECT_TRUE(file_runner_->HasPendingTask());
581 file_runner_->RunPendingTasks();
582 base::RunLoop().RunUntilIdle();
583 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
584 EXPECT_EQ(0lu, context_->memory_controller().disk_usage());
585 }
586
587 TEST_F(BlobStorageContextTest, CompoundBlobs) {
588 const std::string kId1("id1");
589 const std::string kId2("id2");
590 const std::string kId3("id3");
591
592 // Setup a set of blob data for testing.
593 base::Time time1, time2;
594 ASSERT_TRUE(base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1));
595 ASSERT_TRUE(base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2));
596
597 BlobDataBuilder blob_data1(kId1);
598 blob_data1.AppendData("Data1");
599 blob_data1.AppendData("Data2");
600 blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10,
601 1024, time1);
602
603 BlobDataBuilder blob_data2(kId2);
604 blob_data2.AppendData("Data3");
605 blob_data2.AppendBlob(kId1, 8, 100);
606 blob_data2.AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20,
607 time2);
608
609 BlobDataBuilder blob_data3(kId3);
610 blob_data3.AppendData("Data4");
611 std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache();
612 ASSERT_TRUE(cache);
613 disk_cache::ScopedEntryPtr disk_cache_entry =
614 CreateDiskCacheEntry(cache.get(), "another key", "Data5");
615 blob_data3.AppendDiskCacheEntry(new EmptyDataHandle(), disk_cache_entry.get(),
616 kTestDiskCacheStreamIndex);
617
618 BlobDataBuilder canonicalized_blob_data2(kId2);
619 canonicalized_blob_data2.AppendData("Data3");
620 canonicalized_blob_data2.AppendData("a2___", 2);
621 canonicalized_blob_data2.AppendFile(
622 base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, 98, time1);
623 canonicalized_blob_data2.AppendFile(
624 base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2);
625
626 BlobStorageContext context;
627 std::unique_ptr<BlobDataHandle> blob_data_handle;
628
629 // Test a blob referring to only data and a file.
630 blob_data_handle = context_->AddFinishedBlob(&blob_data1);
631
632 ASSERT_TRUE(blob_data_handle);
633 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
634 ASSERT_TRUE(blob_data_handle);
635 EXPECT_EQ(*data, blob_data1);
636
637 // Test a blob composed in part with another blob.
638 blob_data_handle = context_->AddFinishedBlob(&blob_data2);
639 data = blob_data_handle->CreateSnapshot();
640 ASSERT_TRUE(blob_data_handle);
641 ASSERT_TRUE(data);
642 EXPECT_EQ(*data, canonicalized_blob_data2);
643
644 // Test a blob referring to only data and a disk cache entry.
645 blob_data_handle = context_->AddFinishedBlob(&blob_data3);
646 data = blob_data_handle->CreateSnapshot();
647 ASSERT_TRUE(blob_data_handle);
648 EXPECT_EQ(*data, blob_data3);
649
650 blob_data_handle.reset();
651 base::RunLoop().RunUntilIdle();
652 }
653
654 TEST_F(BlobStorageContextTest, PublicBlobUrls) {
655 // Build up a basic blob.
656 const std::string kId("id");
657 std::unique_ptr<BlobDataHandle> first_handle = SetupBasicBlob(kId);
658
659 // Now register a url for that blob.
660 GURL kUrl("blob:id");
661 context_->RegisterPublicBlobURL(kUrl, kId);
662 std::unique_ptr<BlobDataHandle> blob_data_handle =
663 context_->GetBlobDataFromPublicURL(kUrl);
664 ASSERT_TRUE(blob_data_handle.get());
665 EXPECT_EQ(kId, blob_data_handle->uuid());
666 std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
667 blob_data_handle.reset();
668 first_handle.reset();
669 base::RunLoop().RunUntilIdle();
670
671 // The url registration should keep the blob alive even after
672 // explicit references are dropped.
673 blob_data_handle = context_->GetBlobDataFromPublicURL(kUrl);
674 EXPECT_TRUE(blob_data_handle);
675 blob_data_handle.reset();
676
677 base::RunLoop().RunUntilIdle();
678 // Finally get rid of the url registration and the blob.
679 context_->RevokePublicBlobURL(kUrl);
680 blob_data_handle = context_->GetBlobDataFromPublicURL(kUrl);
681 EXPECT_FALSE(blob_data_handle.get());
682 EXPECT_FALSE(context_->registry().HasEntry(kId));
683 }
684
685 TEST_F(BlobStorageContextTest, TestUnknownBrokenAndBuildingBlobReference) {
686 const std::string kBrokenId("broken_id");
687 const std::string kBuildingId("building_id");
688 const std::string kReferencingId("referencing_id");
689 const std::string kUnknownId("unknown_id");
690
691 // Create a broken blob.
692 std::unique_ptr<BlobDataHandle> broken_handle =
693 context_->AddBrokenBlob(kBrokenId, "", "", BlobStatus::ERR_OUT_OF_MEMORY);
694 EXPECT_TRUE(broken_handle->GetBlobStatus() == BlobStatus::ERR_OUT_OF_MEMORY);
695 EXPECT_TRUE(context_->registry().HasEntry(kBrokenId));
696
697 // Try to create a blob with a reference to an unknown blob.
698 BlobDataBuilder builder(kReferencingId);
699 builder.AppendData("data");
700 builder.AppendBlob(kUnknownId);
701 std::unique_ptr<BlobDataHandle> handle = context_->AddFinishedBlob(builder);
702 EXPECT_TRUE(handle->IsBroken());
703 EXPECT_TRUE(context_->registry().HasEntry(kReferencingId));
704 handle.reset();
705 base::RunLoop().RunUntilIdle();
706 EXPECT_FALSE(context_->registry().HasEntry(kReferencingId));
707
708 // Try to create a blob with a reference to the broken blob.
709 BlobDataBuilder builder2(kReferencingId);
710 builder2.AppendData("data");
711 builder2.AppendBlob(kBrokenId);
712 handle = context_->AddFinishedBlob(builder2);
713 EXPECT_TRUE(handle->IsBroken());
714 EXPECT_TRUE(context_->registry().HasEntry(kReferencingId));
715 handle.reset();
716 base::RunLoop().RunUntilIdle();
717 EXPECT_FALSE(context_->registry().HasEntry(kReferencingId));
718
719 // Try to create a blob with a reference to the building blob.
720 BlobDataBuilder builder3(kReferencingId);
721 builder3.AppendData("data");
722 builder3.AppendBlob(kBuildingId);
723 handle = context_->AddFinishedBlob(builder3);
724 EXPECT_TRUE(handle->IsBroken());
725 EXPECT_TRUE(context_->registry().HasEntry(kReferencingId));
726 handle.reset();
727 base::RunLoop().RunUntilIdle();
728 EXPECT_FALSE(context_->registry().HasEntry(kReferencingId));
729 }
730
731 namespace {
732 constexpr size_t kTotalRawBlobs = 200;
733 constexpr size_t kTotalSlicedBlobs = 100;
734 constexpr char kTestDiskCacheData[] = "Test Blob Data";
735
736 // Appends data and data types that depend on the index. This is designed to
737 // exercise all types of combinations of data, future data, files, future files,
738 // and disk cache entries.
739 size_t AppendDataInBuilder(BlobDataBuilder* builder,
740 size_t index,
741 disk_cache::Entry* cache_entry) {
742 size_t size = 0;
743 // We can't have both future data and future files, so split those up.
744 if (index % 2 != 0) {
745 builder->AppendFutureData(5u);
746 size += 5u;
747 if (index % 3 == 1) {
748 builder->AppendData("abcdefghij", 4u);
749 size += 4u;
750 }
751 if (index % 3 == 0) {
752 builder->AppendFutureData(1u);
753 size += 1u;
754 }
755 } else if (index % 3 == 0) {
756 builder->AppendFutureFile(0lu, 3lu, 0);
757 size += 3u;
758 }
759 if (index % 5 != 0) {
760 builder->AppendFile(
761 base::FilePath::FromUTF8Unsafe(base::SizeTToString(index)), 0ul, 20ul,
762 base::Time::Max());
763 size += 20u;
764 }
765 if (index % 3 != 0) {
766 scoped_refptr<BlobDataBuilder::DataHandle> disk_cache_data_handle =
767 new EmptyDataHandle();
768 builder->AppendDiskCacheEntry(disk_cache_data_handle, cache_entry,
769 kTestDiskCacheStreamIndex);
770 size += strlen(kTestDiskCacheData);
771 }
772 return size;
773 }
774
775 bool DoesBuilderHaveFutureData(size_t index) {
776 return index < kTotalRawBlobs && (index % 2 != 0 || index % 3 == 0);
777 }
778
779 void PopulateDataInBuilder(BlobDataBuilder* builder,
780 size_t index,
781 base::TaskRunner* file_runner) {
782 if (index % 2 != 0) {
783 builder->PopulateFutureData(0, "abcde", 0, 5);
784 if (index % 3 == 0) {
785 builder->PopulateFutureData(1, "z", 0, 1);
786 }
787 } else if (index % 3 == 0) {
788 scoped_refptr<ShareableFileReference> file_ref =
789 ShareableFileReference::GetOrCreate(
790 base::FilePath::FromUTF8Unsafe(
791 base::SizeTToString(index + kTotalRawBlobs)),
792 ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE, file_runner);
793 builder->PopulateFutureFile(0, file_ref, base::Time::Max());
794 }
795 }
796 } // namespace
797
798 TEST_F(BlobStorageContextTest, BuildBlobCombinations) {
799 const std::string kId("id");
800
801 context_ =
802 base::MakeUnique<BlobStorageContext>(temp_dir_.GetPath(), file_runner_);
803
804 SetTestMemoryLimits();
805 std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache();
806 ASSERT_TRUE(cache);
807 disk_cache::ScopedEntryPtr entry =
808 CreateDiskCacheEntry(cache.get(), "test entry", kTestDiskCacheData);
809
810 // This tests mixed blob content with both synchronous and asynchronous
811 // construction. Blobs should also be paged to disk during execution.
812 std::vector<std::unique_ptr<BlobDataBuilder>> builders;
813 std::vector<size_t> sizes;
814 for (size_t i = 0; i < kTotalRawBlobs; i++) {
815 builders.emplace_back(new BlobDataBuilder(base::SizeTToString(i)));
816 auto& builder = *builders.back();
817 size_t size = AppendDataInBuilder(&builder, i, entry.get());
818 EXPECT_NE(0u, size);
819 sizes.push_back(size);
820 }
821
822 for (size_t i = 0; i < kTotalSlicedBlobs; i++) {
823 builders.emplace_back(
824 new BlobDataBuilder(base::SizeTToString(i + kTotalRawBlobs)));
825 size_t source_size = sizes[i];
826 size_t offset = source_size == 1 ? 0 : i % (source_size - 1);
827 size_t size = (i % (source_size - offset)) + 1;
828 builders.back()->AppendBlob(base::SizeTToString(i), offset, size);
829 }
830
831 size_t total_finished_blobs = 0;
832 std::vector<std::unique_ptr<BlobDataHandle>> handles;
833 std::vector<BlobStatus> statuses;
834 std::vector<bool> populated;
835 statuses.resize(kTotalRawBlobs,
836 BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
837 populated.resize(kTotalRawBlobs, false);
838 for (size_t i = 0; i < builders.size(); i++) {
839 BlobDataBuilder& builder = *builders[i];
840 builder.set_content_type("text/plain");
841 bool has_pending_memory = DoesBuilderHaveFutureData(i);
842 std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
843 builder,
844 has_pending_memory
845 ? base::Bind(&SaveBlobStatusAndFiles, &statuses[0] + i, &files_)
846 : BlobStorageContext::TransportAllowedCallback());
847 handle->RunOnConstructionComplete(
848 base::Bind(&IncrementNumber, &total_finished_blobs));
849 handles.push_back(std::move(handle));
850 }
851 base::RunLoop().RunUntilIdle();
852
853 // We should be needing to send a page or two to disk.
854 EXPECT_TRUE(file_runner_->HasPendingTask());
855 do {
856 file_runner_->RunPendingTasks();
857 base::RunLoop().RunUntilIdle();
858 // Continue populating data for items that can fit.
859 for (size_t i = 0; i < kTotalRawBlobs; i++) {
860 BlobDataBuilder* builder = builders[i].get();
861 if (DoesBuilderHaveFutureData(i) && !populated[i] &&
862 statuses[i] == BlobStatus::PENDING_TRANSPORT) {
863 PopulateDataInBuilder(builder, i, file_runner_.get());
864 context_->NotifyTransportComplete(base::SizeTToString(i));
865 populated[i] = true;
866 }
867 }
868 base::RunLoop().RunUntilIdle();
869 } while (file_runner_->HasPendingTask());
870
871 // Check all builders with future items were signalled and populated.
872 for (size_t i = 0; i < populated.size(); i++) {
873 if (DoesBuilderHaveFutureData(i)) {
874 EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, statuses[i]) << i;
875 EXPECT_TRUE(populated[i]) << i;
876 }
877 }
878 base::RunLoop().RunUntilIdle();
879
880 // We should be completely built now.
881 EXPECT_EQ(kTotalRawBlobs + kTotalSlicedBlobs, total_finished_blobs);
882 for (std::unique_ptr<BlobDataHandle>& handle : handles) {
883 EXPECT_EQ(BlobStatus::DONE, handle->GetBlobStatus());
884 }
885 handles.clear();
886 base::RunLoop().RunUntilIdle();
887 files_.clear();
888 // We should have file cleanup tasks.
889 EXPECT_TRUE(file_runner_->HasPendingTask());
890 file_runner_->RunPendingTasks();
891 base::RunLoop().RunUntilIdle();
892 EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
893 EXPECT_EQ(0lu, context_->memory_controller().disk_usage());
894 }
895
896 // TODO(michaeln): tests for the deprecated url stuff
897
898 } // namespace storage
OLDNEW
« no previous file with comments | « no previous file | content/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698