Index: content/browser/blob_storage/blob_async_builder_host_unittest.cc |
diff --git a/content/browser/blob_storage/blob_async_builder_host_unittest.cc b/content/browser/blob_storage/blob_async_builder_host_unittest.cc |
index 934e0db887b87a229834bbdf16c6e6b81ffef846..c5caaafb7da7b4a323462073c7cefb04d0599254 100644 |
--- a/content/browser/blob_storage/blob_async_builder_host_unittest.cc |
+++ b/content/browser/blob_storage/blob_async_builder_host_unittest.cc |
@@ -11,14 +11,21 @@ |
#include "base/bind.h" |
#include "base/logging.h" |
#include "base/memory/shared_memory.h" |
+#include "base/run_loop.h" |
+#include "content/public/test/test_browser_thread_bundle.h" |
+#include "storage/browser/blob/blob_data_builder.h" |
+#include "storage/browser/blob/blob_data_handle.h" |
+#include "storage/browser/blob/blob_storage_context.h" |
#include "storage/common/blob_storage/blob_storage_constants.h" |
#include "testing/gtest/include/gtest/gtest.h" |
namespace storage { |
namespace { |
const std::string kBlobUUID = "blobUUIDYAY"; |
-const std::string kFakeBlobUUID = "fakeBlob"; |
-const std::string kBlobType = "blobtypeYAY"; |
+const std::string kContentType = "content_type"; |
+const std::string kContentDisposition = "content_disposition"; |
+const std::string kCompletedBlobUUID = "completedBlob"; |
+const std::string kCompletedBlobData = "completedBlobData"; |
const size_t kTestBlobStorageIPCThresholdBytes = 5; |
const size_t kTestBlobStorageMaxSharedMemoryBytes = 20; |
@@ -52,85 +59,68 @@ void AddShortcutMemoryItem(size_t length, BlobDataBuilder* out) { |
void AddBlobItem(std::vector<DataElement>* out) { |
DataElement blob; |
- blob.SetToBlob(kFakeBlobUUID); |
+ blob.SetToBlob(kCompletedBlobUUID); |
out->push_back(blob); |
} |
+} // namespace |
class BlobAsyncBuilderHostTest : public testing::Test { |
- protected: |
+ public: |
BlobAsyncBuilderHostTest() |
- : matching_builder_(nullptr), |
- done_called_(false), |
- cancel_called_(false), |
- cancel_code_(IPCBlobCreationCancelCode::UNKNOWN), |
+ : cancel_code_(IPCBlobCreationCancelCode::UNKNOWN), |
request_called_(false) {} |
~BlobAsyncBuilderHostTest() override {} |
void SetUp() override { |
- matching_builder_ = nullptr; |
- done_called_ = false; |
- cancel_called_ = false; |
cancel_code_ = IPCBlobCreationCancelCode::UNKNOWN; |
request_called_ = false; |
requests_.clear(); |
memory_handles_.clear(); |
- file_handles_.clear(); |
host_.SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes, |
kTestBlobStorageMaxSharedMemoryBytes, |
kTestBlobStorageMaxFileSizeBytes); |
- } |
- |
- void SetMatchingBuilder(BlobDataBuilder* builder) { |
- matching_builder_ = builder; |
- } |
- |
- void CancelCallback(IPCBlobCreationCancelCode code) { |
- cancel_called_ = true; |
- cancel_code_ = code; |
- } |
- |
- void DoneCallback(const BlobDataBuilder& builder) { |
- // This does a deep comparison, including internal data items. |
- if (matching_builder_) |
- EXPECT_EQ(*matching_builder_, builder); |
- done_called_ = true; |
+ BlobDataBuilder builder(kCompletedBlobUUID); |
+ builder.AppendData(kCompletedBlobData); |
+ completed_blob_handle_ = context_.AddFinishedBlob(builder); |
} |
void RequestMemoryCallback( |
const std::vector<storage::BlobItemBytesRequest>& requests, |
const std::vector<base::SharedMemoryHandle>& shared_memory_handles, |
- const std::vector<uint64_t>& file_sizes) { |
+ std::vector<base::File>* files) { |
this->requests_ = requests; |
memory_handles_ = shared_memory_handles; |
- file_handles_ = file_sizes; |
request_called_ = true; |
} |
- bool BuildBlobAsync(const std::vector<DataElement>& descriptions, |
- size_t memory_available) { |
- done_called_ = false; |
- cancel_called_ = false; |
+ BlobTransportResult BuildBlobAsync( |
+ const std::vector<DataElement>& descriptions, |
+ size_t memory_available) { |
request_called_ = false; |
+ if (!host_.RegisterBlobUUID(kBlobUUID, kContentType, kContentDisposition, |
+ &context_)) { |
+ return BlobTransportResult::BAD_IPC; |
+ } |
return host_.StartBuildingBlob( |
- kBlobUUID, kBlobType, descriptions, memory_available, |
+ kBlobUUID, descriptions, memory_available, &context_, |
base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
- base::Unretained(this)), |
- base::Bind(&BlobAsyncBuilderHostTest::DoneCallback, |
- base::Unretained(this)), |
- base::Bind(&BlobAsyncBuilderHostTest::CancelCallback, |
base::Unretained(this))); |
} |
- BlobDataBuilder* matching_builder_; |
+ void DecrementBlobRefCount(const std::string& uuid) { |
+ context_.DecrementBlobRefCount(uuid); |
+ } |
+ |
+ content::TestBrowserThreadBundle browser_thread_bundle_; |
+ BlobStorageContext context_; |
BlobAsyncBuilderHost host_; |
- bool done_called_; |
- bool cancel_called_; |
IPCBlobCreationCancelCode cancel_code_; |
bool request_called_; |
std::vector<storage::BlobItemBytesRequest> requests_; |
std::vector<base::SharedMemoryHandle> memory_handles_; |
- std::vector<uint64_t> file_handles_; |
+ |
+ scoped_ptr<BlobDataHandle> completed_blob_handle_; |
}; |
TEST_F(BlobAsyncBuilderHostTest, TestShortcut) { |
@@ -141,16 +131,36 @@ TEST_F(BlobAsyncBuilderHostTest, TestShortcut) { |
AddShortcutMemoryItem(5000, &descriptions); |
BlobDataBuilder expected(kBlobUUID); |
- expected.set_content_type(kBlobType); |
+ expected.set_content_type(kContentType); |
+ expected.set_content_disposition(kContentDisposition); |
AddShortcutMemoryItem(10, &expected); |
- expected.AppendBlob(kFakeBlobUUID); |
+ expected.AppendData(kCompletedBlobData); |
AddShortcutMemoryItem(5000, &expected); |
- SetMatchingBuilder(&expected); |
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); |
+ EXPECT_EQ(BlobTransportResult::DONE, BuildBlobAsync(descriptions, 5010)); |
+ |
+ EXPECT_FALSE(request_called_); |
+ EXPECT_EQ(0u, host_.blob_building_count()); |
+ scoped_ptr<BlobDataHandle> handle = context_.GetBlobDataFromUUID(kBlobUUID); |
+ EXPECT_FALSE(handle->IsBeingBuilt()); |
+ EXPECT_FALSE(handle->IsBroken()); |
+ scoped_ptr<BlobDataSnapshot> data = handle->CreateSnapshot(); |
+ EXPECT_EQ(expected, *data); |
+ data.reset(); |
+ handle.reset(); |
+ base::RunLoop().RunUntilIdle(); |
+}; |
+ |
+TEST_F(BlobAsyncBuilderHostTest, TestShortcutNoRoom) { |
+ std::vector<DataElement> descriptions; |
+ |
+ AddShortcutMemoryItem(10, &descriptions); |
+ AddBlobItem(&descriptions); |
+ AddShortcutMemoryItem(5000, &descriptions); |
+ |
+ EXPECT_EQ(BlobTransportResult::CANCEL_MEMORY_FULL, |
+ BuildBlobAsync(descriptions, 5000)); |
- EXPECT_TRUE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
EXPECT_FALSE(request_called_); |
EXPECT_EQ(0u, host_.blob_building_count()); |
}; |
@@ -160,11 +170,10 @@ TEST_F(BlobAsyncBuilderHostTest, TestSingleSharedMemRequest) { |
const size_t kSize = kTestBlobStorageIPCThresholdBytes + 1; |
AddMemoryItem(kSize, &descriptions); |
- EXPECT_TRUE( |
+ EXPECT_EQ( |
+ BlobTransportResult::PENDING_RESPONSES, |
BuildBlobAsync(descriptions, kTestBlobStorageIPCThresholdBytes + 1)); |
- EXPECT_FALSE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
EXPECT_TRUE(request_called_); |
EXPECT_EQ(1u, host_.blob_building_count()); |
ASSERT_EQ(1u, requests_.size()); |
@@ -183,18 +192,17 @@ TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) { |
AddMemoryItem(kSize, &descriptions); |
BlobDataBuilder expected(kBlobUUID); |
- expected.set_content_type(kBlobType); |
+ expected.set_content_type(kContentType); |
+ expected.set_content_disposition(kContentDisposition); |
char data[kSize]; |
memset(data, kFirstBlockByte, kTestBlobStorageMaxSharedMemoryBytes); |
expected.AppendData(data, kTestBlobStorageMaxSharedMemoryBytes); |
expected.AppendData(&kSecondBlockByte, 1); |
- SetMatchingBuilder(&expected); |
- EXPECT_TRUE( |
+ EXPECT_EQ( |
+ BlobTransportResult::PENDING_RESPONSES, |
BuildBlobAsync(descriptions, kTestBlobStorageMaxSharedMemoryBytes + 1)); |
- EXPECT_FALSE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
EXPECT_TRUE(request_called_); |
EXPECT_EQ(1u, host_.blob_building_count()); |
ASSERT_EQ(1u, requests_.size()); |
@@ -217,10 +225,9 @@ TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) { |
BlobItemBytesResponse response(0); |
std::vector<BlobItemBytesResponse> responses = {response}; |
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_)); |
- EXPECT_FALSE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
EXPECT_TRUE(request_called_); |
EXPECT_EQ(1u, host_.blob_building_count()); |
ASSERT_EQ(1u, requests_.size()); |
@@ -234,11 +241,16 @@ TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) { |
response.request_number = 1; |
responses[0] = response; |
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); |
- EXPECT_TRUE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_)); |
EXPECT_FALSE(request_called_); |
EXPECT_EQ(0u, host_.blob_building_count()); |
+ scoped_ptr<BlobDataHandle> blob_handle = |
+ context_.GetBlobDataFromUUID(kBlobUUID); |
+ EXPECT_FALSE(blob_handle->IsBeingBuilt()); |
+ EXPECT_FALSE(blob_handle->IsBroken()); |
+ scoped_ptr<BlobDataSnapshot> blob_data = blob_handle->CreateSnapshot(); |
+ EXPECT_EQ(expected, *blob_data); |
}; |
TEST_F(BlobAsyncBuilderHostTest, TestBasicIPCAndStopBuilding) { |
@@ -249,18 +261,32 @@ TEST_F(BlobAsyncBuilderHostTest, TestBasicIPCAndStopBuilding) { |
AddMemoryItem(2, &descriptions); |
BlobDataBuilder expected(kBlobUUID); |
- expected.set_content_type(kBlobType); |
+ expected.set_content_type(kContentType); |
+ expected.set_content_disposition(kContentDisposition); |
AddShortcutMemoryItem(2, &expected); |
- expected.AppendBlob(kFakeBlobUUID); |
+ expected.AppendData(kCompletedBlobData); |
AddShortcutMemoryItem(2, &expected); |
- SetMatchingBuilder(&expected); |
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); |
- host_.StopBuildingBlob(kBlobUUID); |
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ BuildBlobAsync(descriptions, 5010)); |
+ host_.MaybeCancelBuildingBlob(kBlobUUID, IPCBlobCreationCancelCode::UNKNOWN, |
+ &context_); |
+ |
+ // Check that we're broken, and then remove the blob. |
+ scoped_ptr<BlobDataHandle> blob_handle = |
+ context_.GetBlobDataFromUUID(kBlobUUID); |
+ EXPECT_FALSE(blob_handle->IsBeingBuilt()); |
+ EXPECT_TRUE(blob_handle->IsBroken()); |
+ blob_handle.reset(); |
+ DecrementBlobRefCount(kBlobUUID); |
+ base::RunLoop().RunUntilIdle(); |
+ blob_handle = context_.GetBlobDataFromUUID(kBlobUUID); |
+ EXPECT_FALSE(blob_handle.get()); |
+ |
+ // This should succeed because we've removed all references to the blob. |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ BuildBlobAsync(descriptions, 5010)); |
- EXPECT_FALSE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
EXPECT_TRUE(request_called_); |
EXPECT_EQ(1u, host_.blob_building_count()); |
request_called_ = false; |
@@ -270,58 +296,121 @@ TEST_F(BlobAsyncBuilderHostTest, TestBasicIPCAndStopBuilding) { |
BlobItemBytesResponse response2(1); |
PopulateBytes(response2.allocate_mutable_data(2), 2); |
std::vector<BlobItemBytesResponse> responses = {response1, response2}; |
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); |
- EXPECT_TRUE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
+ |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_)); |
EXPECT_FALSE(request_called_); |
EXPECT_EQ(0u, host_.blob_building_count()); |
+ blob_handle = context_.GetBlobDataFromUUID(kBlobUUID); |
+ EXPECT_FALSE(blob_handle->IsBeingBuilt()); |
+ EXPECT_FALSE(blob_handle->IsBroken()); |
+ scoped_ptr<BlobDataSnapshot> blob_data = blob_handle->CreateSnapshot(); |
+ EXPECT_EQ(expected, *blob_data); |
+}; |
+ |
+TEST_F(BlobAsyncBuilderHostTest, TestBreakingAllBuilding) { |
+ const std::string& kBlob1 = "blob1"; |
+ const std::string& kBlob2 = "blob2"; |
+ const std::string& kBlob3 = "blob3"; |
+ |
+ // Register blobs. |
+ EXPECT_TRUE(host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition, |
+ &context_)); |
+ EXPECT_TRUE(host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition, |
+ &context_)); |
+ EXPECT_TRUE(host_.RegisterBlobUUID(kBlob3, kContentType, kContentDisposition, |
+ &context_)); |
+ |
+ // Start building one of them. |
+ std::vector<DataElement> descriptions; |
+ AddMemoryItem(2, &descriptions); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ host_.StartBuildingBlob( |
+ kBlob1, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_TRUE(request_called_); |
+ |
+ scoped_ptr<BlobDataHandle> blob_handle1 = |
+ context_.GetBlobDataFromUUID(kBlob1); |
+ scoped_ptr<BlobDataHandle> blob_handle2 = |
+ context_.GetBlobDataFromUUID(kBlob2); |
+ scoped_ptr<BlobDataHandle> blob_handle3 = |
+ context_.GetBlobDataFromUUID(kBlob2); |
+ EXPECT_TRUE(blob_handle1->IsBeingBuilt() && blob_handle2->IsBeingBuilt() && |
+ blob_handle3->IsBeingBuilt()); |
+ EXPECT_FALSE(blob_handle1->IsBroken() || blob_handle2->IsBroken() || |
+ blob_handle3->IsBroken()); |
+ |
+ host_.ClearAndBreakPendingBlobConstruction(&context_); |
+ |
+ EXPECT_FALSE(blob_handle1->IsBeingBuilt() || blob_handle2->IsBeingBuilt() || |
+ blob_handle3->IsBeingBuilt()); |
+ EXPECT_TRUE(blob_handle1->IsBroken() && blob_handle2->IsBroken() && |
+ blob_handle3->IsBroken()); |
+ blob_handle1.reset(); |
+ blob_handle2.reset(); |
+ blob_handle3.reset(); |
+ base::RunLoop().RunUntilIdle(); |
}; |
TEST_F(BlobAsyncBuilderHostTest, TestBadIPCs) { |
std::vector<DataElement> descriptions; |
// Test reusing same blob uuid. |
- SetMatchingBuilder(nullptr); |
AddMemoryItem(10, &descriptions); |
AddBlobItem(&descriptions); |
AddMemoryItem(5000, &descriptions); |
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); |
- EXPECT_FALSE(BuildBlobAsync(descriptions, 5010)); |
- EXPECT_FALSE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ BuildBlobAsync(descriptions, 5010)); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, BuildBlobAsync(descriptions, 5010)); |
EXPECT_FALSE(request_called_); |
- host_.StopBuildingBlob(kBlobUUID); |
+ host_.MaybeCancelBuildingBlob(kBlobUUID, IPCBlobCreationCancelCode::UNKNOWN, |
+ &context_); |
+ DecrementBlobRefCount(kBlobUUID); |
+ EXPECT_FALSE(context_.GetBlobDataFromUUID(kBlobUUID).get()); |
- // Test we're _not_ an error if we get a bad uuid for responses. |
+ // Test we're an error if we get a bad uuid for responses. |
BlobItemBytesResponse response(0); |
std::vector<BlobItemBytesResponse> responses = {response}; |
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_)); |
// Test empty responses. |
responses.clear(); |
- EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses)); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_)); |
// Test response problems below here. |
descriptions.clear(); |
AddMemoryItem(2, &descriptions); |
AddBlobItem(&descriptions); |
AddMemoryItem(2, &descriptions); |
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ BuildBlobAsync(descriptions, 5010)); |
// Invalid request number. |
BlobItemBytesResponse response1(3); |
PopulateBytes(response1.allocate_mutable_data(2), 2); |
responses = {response1}; |
- EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses)); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlobUUID)->IsBroken()); |
+ DecrementBlobRefCount(kBlobUUID); |
+ base::RunLoop().RunUntilIdle(); |
// Duplicate request number responses. |
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ BuildBlobAsync(descriptions, 5010)); |
response1.request_number = 0; |
BlobItemBytesResponse response2(0); |
PopulateBytes(response2.allocate_mutable_data(2), 2); |
responses = {response1, response2}; |
- EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses)); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlobUUID)->IsBroken()); |
+ DecrementBlobRefCount(kBlobUUID); |
+ base::RunLoop().RunUntilIdle(); |
}; |
-} // namespace |
} // namespace storage |