| Index: content/browser/blob_storage/blob_dispatcher_host_unittest.cc
|
| diff --git a/content/browser/blob_storage/blob_dispatcher_host_unittest.cc b/content/browser/blob_storage/blob_dispatcher_host_unittest.cc
|
| index a9b7707949b56fca64b5fdb1a6e44fb15edb1100..5564f31791e9b4c27c10695b5583c84da4631c18 100644
|
| --- a/content/browser/blob_storage/blob_dispatcher_host_unittest.cc
|
| +++ b/content/browser/blob_storage/blob_dispatcher_host_unittest.cc
|
| @@ -56,11 +56,21 @@ void SetPointerValue(T* pointer, T value) {
|
| *pointer = value;
|
| }
|
|
|
| +void SetAndCheckBlobsBuilding(bool* blobs_building, bool set_can_terminate) {
|
| + EXPECT_NE(*blobs_building, !set_can_terminate)
|
| + << "We shouldn't set sudden termination the same way twice";
|
| + *blobs_building = !set_can_terminate;
|
| +}
|
| +
|
| class TestableBlobDispatcherHost : public BlobDispatcherHost {
|
| public:
|
| TestableBlobDispatcherHost(ChromeBlobStorageContext* blob_storage_context,
|
| - IPC::TestSink* sink)
|
| - : BlobDispatcherHost(blob_storage_context), sink_(sink) {
|
| + IPC::TestSink* sink,
|
| + bool* blobs_building)
|
| + : BlobDispatcherHost(
|
| + blob_storage_context,
|
| + base::Bind(&SetAndCheckBlobsBuilding, blobs_building)),
|
| + sink_(sink) {
|
| this->SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes,
|
| kTestBlobStorageMaxSharedMemoryBytes,
|
| kTestBlobStorageMaxFileSizeBytes);
|
| @@ -88,8 +98,8 @@ class BlobDispatcherHostTest : public testing::Test {
|
| BlobDispatcherHostTest()
|
| : chrome_blob_storage_context_(
|
| ChromeBlobStorageContext::GetFor(&browser_context_)) {
|
| - host_ =
|
| - new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_);
|
| + host_ = new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_,
|
| + &blobs_building_);
|
| }
|
| ~BlobDispatcherHostTest() override {}
|
|
|
| @@ -250,6 +260,7 @@ class BlobDispatcherHostTest : public testing::Test {
|
| return host_->async_builder_.IsBeingBuilt(uuid);
|
| }
|
|
|
| + bool blobs_building_ = false;
|
| IPC::TestSink sink_;
|
| TestBrowserThreadBundle browser_thread_bundle_;
|
| TestBrowserContext browser_context_;
|
| @@ -261,17 +272,23 @@ class BlobDispatcherHostTest : public testing::Test {
|
| TEST_F(BlobDispatcherHostTest, EmptyUUIDs) {
|
| host_->OnRegisterBlobUUID("", "", "", std::set<std::string>());
|
| ExpectAndResetBadMessage();
|
| + EXPECT_FALSE(blobs_building_);
|
| host_->OnStartBuildingBlob("", std::vector<DataElement>());
|
| ExpectAndResetBadMessage();
|
| + EXPECT_FALSE(blobs_building_);
|
| host_->OnMemoryItemResponse("", std::vector<BlobItemBytesResponse>());
|
| ExpectAndResetBadMessage();
|
| + EXPECT_FALSE(blobs_building_);
|
| host_->OnCancelBuildingBlob("", IPCBlobCreationCancelCode::UNKNOWN);
|
| ExpectAndResetBadMessage();
|
| + EXPECT_FALSE(blobs_building_);
|
| }
|
|
|
| TEST_F(BlobDispatcherHostTest, Shortcut) {
|
| const std::string kId = "uuid1";
|
| + EXPECT_FALSE(blobs_building_);
|
| AsyncShortcutBlobTransfer(kId);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
|
| EXPECT_TRUE(handle);
|
| @@ -285,6 +302,7 @@ TEST_F(BlobDispatcherHostTest, Shortcut) {
|
| TEST_F(BlobDispatcherHostTest, RegularTransfer) {
|
| const std::string kId = "uuid1";
|
| AsyncBlobTransfer(kId);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
|
| EXPECT_TRUE(handle);
|
| @@ -295,15 +313,64 @@ TEST_F(BlobDispatcherHostTest, RegularTransfer) {
|
| ExpectHandleEqualsData(handle.get(), elements);
|
| }
|
|
|
| +TEST_F(BlobDispatcherHostTest, MultipleTransfers) {
|
| + const std::string kId = "uuid";
|
| + const int kNumIters = 10;
|
| + EXPECT_FALSE(blobs_building_);
|
| + for (int i = 0; i < kNumIters; i++) {
|
| + std::string id = kId;
|
| + id += ('0' + i);
|
| + ExpectBlobNotExist(id);
|
| + host_->OnRegisterBlobUUID(id, std::string(kContentType),
|
| + std::string(kContentDisposition),
|
| + std::set<std::string>());
|
| + EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| + EXPECT_TRUE(blobs_building_);
|
| + }
|
| + sink_.ClearMessages();
|
| +
|
| + for (int i = 0; i < kNumIters; i++) {
|
| + std::string id = kId;
|
| + id += ('0' + i);
|
| + DataElement element;
|
| + element.SetToBytesDescription(kDataSize);
|
| + std::vector<DataElement> elements = {element};
|
| + host_->OnStartBuildingBlob(id, elements);
|
| + EXPECT_TRUE(blobs_building_);
|
| + EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| + // Expect our request.
|
| + std::vector<BlobItemBytesRequest> expected_requests = {
|
| + BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
|
| + ExpectRequest(id, expected_requests);
|
| + sink_.ClearMessages();
|
| + }
|
| +
|
| + for (int i = 0; i < kNumIters; i++) {
|
| + std::string id = kId;
|
| + id += ('0' + i);
|
| + // Send results;
|
| + BlobItemBytesResponse response(0);
|
| + std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
|
| + std::vector<BlobItemBytesResponse> responses = {response};
|
| + host_->OnMemoryItemResponse(id, responses);
|
| + ExpectDone(id);
|
| + sink_.ClearMessages();
|
| + }
|
| + EXPECT_FALSE(blobs_building_);
|
| +}
|
| +
|
| TEST_F(BlobDispatcherHostTest, SharedMemoryTransfer) {
|
| const std::string kId = "uuid1";
|
| const size_t kLargeSize = kTestBlobStorageMaxSharedMemoryBytes * 2;
|
| std::vector<base::SharedMemoryHandle> shared_memory_handles;
|
|
|
| ExpectBlobNotExist(kId);
|
| + EXPECT_FALSE(blobs_building_);
|
| host_->OnRegisterBlobUUID(kId, std::string(kContentType),
|
| std::string(kContentDisposition),
|
| std::set<std::string>());
|
| + EXPECT_TRUE(blobs_building_);
|
| +
|
| // Grab the handle.
|
| scoped_ptr<BlobDataHandle> blob_data_handle =
|
| context_->GetBlobDataFromUUID(kId);
|
| @@ -369,7 +436,9 @@ TEST_F(BlobDispatcherHostTest, SharedMemoryTransfer) {
|
| }
|
| // Send the confirmation.
|
| responses = {BlobItemBytesResponse(1)};
|
| + EXPECT_TRUE(blobs_building_);
|
| host_->OnMemoryItemResponse(kId, responses);
|
| + EXPECT_FALSE(blobs_building_);
|
|
|
| ExpectDone(kId);
|
| sink_.ClearMessages();
|
| @@ -396,9 +465,11 @@ TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
|
|
| // Start building blob.
|
| + EXPECT_FALSE(blobs_building_);
|
| host_->OnRegisterBlobUUID(kId, std::string(kContentType),
|
| std::string(kContentDisposition),
|
| std::set<std::string>());
|
| + EXPECT_TRUE(blobs_building_);
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| DataElement element;
|
| element.SetToBytesDescription(kDataSize);
|
| @@ -410,6 +481,7 @@ TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
|
|
|
| // Cancel in middle of construction.
|
| host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(host_->IsInUseInHost(kId));
|
| EXPECT_FALSE(IsBeingBuiltInHost(kId));
|
| @@ -421,11 +493,13 @@ TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
|
|
|
| // Get rid of it in the host.
|
| host_->OnDecrementBlobRefCount(kId);
|
| + EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| ExpectBlobNotExist(kId);
|
|
|
| // Create blob again to verify we don't have any old construction state lying
|
| // around.
|
| AsyncBlobTransfer(kId);
|
| + EXPECT_FALSE(blobs_building_);
|
|
|
| // Check data.
|
| handle = context_->GetBlobDataFromUUID(kId);
|
| @@ -438,6 +512,7 @@ TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
|
| // Verify we can't cancel after the fact.
|
| host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
|
| ExpectAndResetBadMessage();
|
| + EXPECT_FALSE(blobs_building_);
|
| }
|
|
|
| TEST_F(BlobDispatcherHostTest, BlobDataWithHostDeletion) {
|
| @@ -468,9 +543,11 @@ TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) {
|
| const std::string kId("id");
|
|
|
| // Start building blob.
|
| + EXPECT_FALSE(blobs_building_);
|
| host_->OnRegisterBlobUUID(kId, std::string(kContentType),
|
| std::string(kContentDisposition),
|
| std::set<std::string>());
|
| + EXPECT_TRUE(blobs_building_);
|
|
|
| // Grab the handle.
|
| scoped_ptr<BlobDataHandle> blob_data_handle =
|
| @@ -486,6 +563,7 @@ TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) {
|
| element.SetToBytesDescription(kDataSize);
|
| std::vector<DataElement> elements = {element};
|
| host_->OnStartBuildingBlob(kId, elements);
|
| + EXPECT_TRUE(blobs_building_);
|
| sink_.ClearMessages();
|
|
|
| // Send data.
|
| @@ -494,6 +572,7 @@ TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) {
|
| std::vector<BlobItemBytesResponse> responses = {response};
|
| sink_.ClearMessages();
|
| host_->OnMemoryItemResponse(kId, responses);
|
| + EXPECT_FALSE(blobs_building_);
|
|
|
| ExpectDone(kId);
|
| base::RunLoop().RunUntilIdle();
|
| @@ -546,6 +625,7 @@ TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructingCancelled) {
|
|
|
| // Cancel in middle of construction.
|
| host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
|
| + EXPECT_FALSE(blobs_building_);
|
| base::RunLoop().RunUntilIdle();
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(host_->IsInUseInHost(kId));
|
| @@ -574,6 +654,7 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterRegister) {
|
| std::set<std::string>());
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| host_->OnDecrementBlobRefCount(kId);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_FALSE(context_->registry().HasEntry(kId));
|
| EXPECT_FALSE(IsBeingBuiltInHost(kId));
|
| ExpectCancel(kId,
|
| @@ -587,6 +668,7 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterRegister) {
|
| scoped_ptr<BlobDataHandle> blob_data_handle =
|
| context_->GetBlobDataFromUUID(kId);
|
| host_->OnDecrementBlobRefCount(kId);
|
| + EXPECT_TRUE(blobs_building_);
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(IsBeingBuiltInHost(kId));
|
|
|
| @@ -595,6 +677,7 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterRegister) {
|
| element.SetToBytes(kData, kDataSize);
|
| std::vector<DataElement> elements = {element};
|
| host_->OnStartBuildingBlob(kId, elements);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| ExpectDone(kId);
|
| sink_.ClearMessages();
|
| @@ -618,6 +701,7 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) {
|
| element.SetToBytesDescription(kDataSize);
|
| std::vector<DataElement> elements = {element};
|
| host_->OnStartBuildingBlob(kId, elements);
|
| + EXPECT_TRUE(blobs_building_);
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
|
|
| std::vector<BlobItemBytesRequest> expected_requests = {
|
| @@ -626,6 +710,7 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) {
|
| sink_.ClearMessages();
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| host_->OnDecrementBlobRefCount(kId);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_FALSE(context_->registry().HasEntry(kId));
|
| EXPECT_FALSE(IsBeingBuiltInHost(kId));
|
| ExpectCancel(kId,
|
| @@ -646,6 +731,7 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) {
|
| scoped_ptr<BlobDataHandle> blob_data_handle =
|
| context_->GetBlobDataFromUUID(kId);
|
| host_->OnDecrementBlobRefCount(kId);
|
| + EXPECT_TRUE(blobs_building_);
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(IsBeingBuiltInHost(kId));
|
|
|
| @@ -654,6 +740,7 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) {
|
| std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
|
| std::vector<BlobItemBytesResponse> responses = {response};
|
| host_->OnMemoryItemResponse(kId, responses);
|
| + EXPECT_FALSE(blobs_building_);
|
| ExpectDone(kId);
|
| sink_.ClearMessages();
|
| // Check that it's still around.
|
| @@ -699,12 +786,14 @@ TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStartWithHandle) {
|
| EXPECT_TRUE(IsBeingBuiltInHost(kId));
|
| // Decrement, simulating where the ref goes out of scope in renderer.
|
| host_->OnDecrementBlobRefCount(kId);
|
| + EXPECT_TRUE(blobs_building_);
|
| // We still have the blob as it's not done.
|
| EXPECT_TRUE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
|
| EXPECT_TRUE(IsBeingBuiltInHost(kId));
|
| // Cancel to clean up.
|
| host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
|
| + EXPECT_FALSE(blobs_building_);
|
| // Run loop to propagate the handle decrement in the host.
|
| base::RunLoop().RunUntilIdle();
|
| // We still have the entry because of our earlier handle.
|
| @@ -768,7 +857,9 @@ TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnStart) {
|
| BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
|
| ExpectRequest(kId, expected_requests);
|
| sink_.ClearMessages();
|
| + EXPECT_TRUE(blobs_building_);
|
| host_ = nullptr;
|
| + EXPECT_FALSE(blobs_building_);
|
| // We need to run the message loop because of the handle in the async builder.
|
| base::RunLoop().RunUntilIdle();
|
| EXPECT_FALSE(context_->registry().HasEntry(kId));
|
| @@ -800,7 +891,9 @@ TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnMemoryResponse) {
|
| host_->OnMemoryItemResponse(kId, responses);
|
| EXPECT_EQ(0u, sink_.message_count());
|
|
|
| + EXPECT_TRUE(blobs_building_);
|
| host_ = nullptr;
|
| + EXPECT_FALSE(blobs_building_);
|
| base::RunLoop().RunUntilIdle();
|
| EXPECT_FALSE(context_->registry().HasEntry(kId));
|
| }
|
| @@ -820,6 +913,7 @@ TEST_F(BlobDispatcherHostTest, CreateBlobWithBrokenReference) {
|
| std::string(kContentDisposition),
|
| std::set<std::string>());
|
| host_->OnCancelBuildingBlob(kBrokenId, IPCBlobCreationCancelCode::UNKNOWN);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| EXPECT_TRUE(context_->GetBlobDataFromUUID(kBrokenId)->IsBroken());
|
|
|
| @@ -827,6 +921,8 @@ TEST_F(BlobDispatcherHostTest, CreateBlobWithBrokenReference) {
|
| // the subsequent OnStart message.
|
| host_->OnRegisterBlobUUID(kReferencingId, std::string(kContentType),
|
| std::string(kContentDisposition), {kBrokenId});
|
| + EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_TRUE(context_->GetBlobDataFromUUID(kReferencingId)->IsBroken());
|
| EXPECT_FALSE(IsBeingBuiltInHost(kReferencingId));
|
| EXPECT_TRUE(context_->registry().HasEntry(kReferencingId));
|
| @@ -856,8 +952,10 @@ TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) {
|
| std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
|
| std::vector<BlobItemBytesResponse> responses = {response};
|
|
|
| + bool host2_blobs_building = false;
|
| scoped_refptr<TestableBlobDispatcherHost> host2(
|
| - new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_));
|
| + new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_,
|
| + &host2_blobs_building));
|
|
|
| // Delete host with another host having a referencing, then dereference on
|
| // second host. Verify we're still building it on first host, and then
|
| @@ -867,14 +965,17 @@ TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) {
|
| host_->OnRegisterBlobUUID(kId, std::string(kContentType),
|
| std::string(kContentDisposition),
|
| std::set<std::string>());
|
| + EXPECT_TRUE(blobs_building_);
|
| host2->OnIncrementBlobRefCount(kId);
|
| host_->OnDecrementBlobRefCount(kId);
|
| EXPECT_FALSE(host_->IsInUseInHost(kId));
|
| host2->OnDecrementBlobRefCount(kId);
|
| + EXPECT_TRUE(blobs_building_);
|
| // So no more blob in the context, but we're still being built in host 1.
|
| EXPECT_FALSE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
|
| host_->OnStartBuildingBlob(kId, elements);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| // We should be cleaned up.
|
| EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
|
| @@ -886,6 +987,7 @@ TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) {
|
| host_->OnRegisterBlobUUID(kId, std::string(kContentType),
|
| std::string(kContentDisposition),
|
| std::set<std::string>());
|
| + EXPECT_TRUE(blobs_building_);
|
| host2->OnIncrementBlobRefCount(kId);
|
| host_->OnDecrementBlobRefCount(kId);
|
| EXPECT_FALSE(host_->IsInUseInHost(kId));
|
| @@ -897,7 +999,9 @@ TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) {
|
| // So no more blob in the context, but we're still being built in host 1.
|
| EXPECT_FALSE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
|
| + EXPECT_TRUE(blobs_building_);
|
| host_->OnMemoryItemResponse(kId, responses);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| // We should be cleaned up.
|
| EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
|
| @@ -920,7 +1024,9 @@ TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) {
|
| // So no more blob in the context, but we're still being built in host 1.
|
| EXPECT_FALSE(context_->registry().HasEntry(kId));
|
| EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
|
| + EXPECT_TRUE(blobs_building_);
|
| host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
|
| + EXPECT_FALSE(blobs_building_);
|
| EXPECT_FALSE(host_->shutdown_for_bad_message_);
|
| // We should be cleaned up.
|
| EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
|
|
|