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)); |