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..4086a90b69afe399cd9f4275d3eb253983b3c3ee 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,87 +59,81 @@ 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); |
+ completed_blob_uuid_set_ = {kCompletedBlobUUID}; |
} |
void RequestMemoryCallback( |
- const std::vector<storage::BlobItemBytesRequest>& requests, |
- const std::vector<base::SharedMemoryHandle>& shared_memory_handles, |
- const std::vector<uint64_t>& file_sizes) { |
- this->requests_ = requests; |
- memory_handles_ = shared_memory_handles; |
- file_handles_ = file_sizes; |
+ scoped_ptr<std::vector<storage::BlobItemBytesRequest>> requests, |
+ scoped_ptr<std::vector<base::SharedMemoryHandle>> shared_memory_handles, |
+ scoped_ptr<std::vector<base::File>> files) { |
+ requests_ = std::move(*requests); |
+ memory_handles_ = std::move(*shared_memory_handles); |
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, |
+ const std::set<std::string>& referenced_blob_uuids, |
+ size_t memory_available) { |
request_called_ = false; |
+ BlobTransportResult register_result = |
+ host_.RegisterBlobUUID(kBlobUUID, kContentType, kContentDisposition, |
+ referenced_blob_uuids, &context_); |
+ if (register_result != BlobTransportResult::DONE) { |
+ return register_result; |
+ } |
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); |
+ } |
+ |
+ bool IsBeingBuiltInContext(const std::string& uuid) { |
+ return context_.IsBeingBuilt(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_; |
+ std::set<std::string> completed_blob_uuid_set_; |
+ |
+ scoped_ptr<BlobDataHandle> completed_blob_handle_; |
}; |
+// The 'shortcut' method is when the data is included in the initial IPCs and |
+// the browser uses that instead of requesting the memory. |
TEST_F(BlobAsyncBuilderHostTest, TestShortcut) { |
std::vector<DataElement> descriptions; |
@@ -141,16 +142,37 @@ 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, completed_blob_uuid_set_, 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, completed_blob_uuid_set_, 5000)); |
- EXPECT_TRUE(done_called_); |
- EXPECT_FALSE(cancel_called_); |
EXPECT_FALSE(request_called_); |
EXPECT_EQ(0u, host_.blob_building_count()); |
}; |
@@ -160,11 +182,10 @@ TEST_F(BlobAsyncBuilderHostTest, TestSingleSharedMemRequest) { |
const size_t kSize = kTestBlobStorageIPCThresholdBytes + 1; |
AddMemoryItem(kSize, &descriptions); |
- EXPECT_TRUE( |
- BuildBlobAsync(descriptions, kTestBlobStorageIPCThresholdBytes + 1)); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ BuildBlobAsync(descriptions, std::set<std::string>(), |
+ 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 +204,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( |
- BuildBlobAsync(descriptions, kTestBlobStorageMaxSharedMemoryBytes + 1)); |
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES, |
+ BuildBlobAsync(descriptions, std::set<std::string>(), |
+ 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 +237,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 +253,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 +273,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, completed_blob_uuid_set_, 5010)); |
+ host_.CancelBuildingBlob(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, completed_blob_uuid_set_, 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 +308,333 @@ 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_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob3, kContentType, kContentDisposition, |
+ std::set<std::string>(), &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_.CancelAll(&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, completed_blob_uuid_set_, 5010)); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010)); |
EXPECT_FALSE(request_called_); |
- host_.StopBuildingBlob(kBlobUUID); |
+ host_.CancelBuildingBlob(kBlobUUID, IPCBlobCreationCancelCode::UNKNOWN, |
+ &context_); |
+ base::RunLoop().RunUntilIdle(); |
+ 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, completed_blob_uuid_set_, 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, completed_blob_uuid_set_, 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(); |
+}; |
+ |
+TEST_F(BlobAsyncBuilderHostTest, WaitOnReferencedBlob) { |
+ const std::string& kBlob1 = "blob1"; |
+ const std::string& kBlob2 = "blob2"; |
+ const std::string& kBlob3 = "blob3"; |
+ |
+ // Register blobs. |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob3, kContentType, kContentDisposition, |
+ {kBlob1, kBlob2}, &context_)); |
+ |
+ // Finish the third one, with a reference to the first and second blob. |
+ std::vector<DataElement> descriptions; |
+ AddShortcutMemoryItem(2, &descriptions); |
+ DataElement element; |
+ element.SetToBlob(kBlob1); |
+ descriptions.push_back(element); |
+ element.SetToBlob(kBlob2); |
+ descriptions.push_back(element); |
+ |
+ // Finish the third, but we should still be 'building' it. |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.StartBuildingBlob( |
+ kBlob3, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_FALSE(request_called_); |
+ EXPECT_TRUE(host_.IsBeingBuilt(kBlob3)); |
+ EXPECT_TRUE(IsBeingBuiltInContext(kBlob3)); |
+ |
+ // Finish the first. |
+ descriptions.clear(); |
+ AddShortcutMemoryItem(2, &descriptions); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.StartBuildingBlob( |
+ kBlob1, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_FALSE(request_called_); |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob1)); |
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob1)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob1)); |
+ |
+ // Run the message loop so we propogate the construction complete callbacks. |
+ base::RunLoop().RunUntilIdle(); |
+ // Verify we're not done. |
+ EXPECT_TRUE(host_.IsBeingBuilt(kBlob3)); |
+ EXPECT_TRUE(IsBeingBuiltInContext(kBlob3)); |
+ |
+ // Finish the second. |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.StartBuildingBlob( |
+ kBlob2, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_FALSE(request_called_); |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2)); |
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob2)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob2)); |
+ |
+ // Run the message loop so we propogate the construction complete callbacks. |
+ base::RunLoop().RunUntilIdle(); |
+ // Finally, we should be finished with third blob. |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob3)); |
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob3)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob3)); |
+}; |
+ |
+TEST_F(BlobAsyncBuilderHostTest, IncorrectBlobDependencies) { |
+ const std::string& kGoodBlob = "goodBlob"; |
+ const std::string& kBlob1 = "blob1"; |
+ const std::string& kBlob2 = "blob2"; |
+ const std::string& kBlob3 = "blob3"; |
+ |
+ // Register blobs. Blob 1 has a reference to itself, Blob 2 has a reference |
+ // but doesn't use it, and blob 3 doesn't list it's reference. |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kGoodBlob, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition, |
+ {kBlob1}, &context_)); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition, |
+ {kGoodBlob}, &context_)); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob3, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ |
+ // The first blob shouldn't be building anymore. |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob1)); |
+ // Test we get BAD_IPC. |
+ std::vector<DataElement> descriptions; |
+ AddShortcutMemoryItem(2, &descriptions); |
+ DataElement element; |
+ element.SetToBlob(kBlob1); |
+ descriptions.push_back(element); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.StartBuildingBlob( |
+ kBlob1, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ |
+ // Try to finish the second one, without a reference to the first. |
+ descriptions.clear(); |
+ AddShortcutMemoryItem(2, &descriptions); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.StartBuildingBlob( |
+ kBlob2, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2)); |
+ |
+ // Try to finish the third one with the reference we didn't declare earlier. |
+ descriptions.clear(); |
+ AddShortcutMemoryItem(2, &descriptions); |
+ element.SetToBlob(kGoodBlob); |
+ descriptions.push_back(element); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.StartBuildingBlob( |
+ kBlob3, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob3)); |
+}; |
+ |
+TEST_F(BlobAsyncBuilderHostTest, BlobBreaksWhenReferenceBreaks) { |
+ const std::string& kBlob1 = "blob1"; |
+ const std::string& kBlob2 = "blob2"; |
+ |
+ // Register blobs. |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition, |
+ {kBlob1}, &context_)); |
+ |
+ // Finish the second one, with a reference to the first. |
+ std::vector<DataElement> descriptions; |
+ AddShortcutMemoryItem(2, &descriptions); |
+ DataElement element; |
+ element.SetToBlob(kBlob1); |
+ descriptions.push_back(element); |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.StartBuildingBlob( |
+ kBlob2, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_FALSE(request_called_); |
+ EXPECT_TRUE(host_.IsBeingBuilt(kBlob2)); |
+ EXPECT_TRUE(IsBeingBuiltInContext(kBlob2)); |
+ |
+ // Break the first. |
+ descriptions.clear(); |
+ host_.CancelBuildingBlob(kBlob1, IPCBlobCreationCancelCode::UNKNOWN, |
+ &context_); |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob1)); |
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob1)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob1)->IsBroken()); |
+ |
+ // Run the message loop so we propogate the construction complete callbacks. |
+ base::RunLoop().RunUntilIdle(); |
+ // We should be finished with third blob, and it should be broken. |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2)); |
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob2)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob2)->IsBroken()); |
+}; |
+ |
+TEST_F(BlobAsyncBuilderHostTest, BlobBreaksWhenReferenceBroken) { |
+ const std::string& kBlob1 = "blob1"; |
+ const std::string& kBlob2 = "blob2"; |
+ |
+ // Register blobs. |
+ EXPECT_EQ(BlobTransportResult::DONE, |
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition, |
+ std::set<std::string>(), &context_)); |
+ host_.CancelBuildingBlob(kBlob1, IPCBlobCreationCancelCode::UNKNOWN, |
+ &context_); |
+ EXPECT_EQ(BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN, |
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition, |
+ {kBlob1}, &context_)); |
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2)); |
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob2)); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob2)->IsBroken()); |
+ |
+ // Try to finish the second one, but we should get a BAD_IPC, as we are no |
+ // longer being constructed. |
+ std::vector<DataElement> descriptions; |
+ AddShortcutMemoryItem(2, &descriptions); |
+ DataElement element; |
+ element.SetToBlob(kBlob1); |
+ descriptions.push_back(element); |
+ EXPECT_EQ(BlobTransportResult::BAD_IPC, |
+ host_.StartBuildingBlob( |
+ kBlob2, descriptions, 2, &context_, |
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
+ base::Unretained(this)))); |
+ EXPECT_FALSE(request_called_); |
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob2)->IsBroken()); |
}; |
-} // namespace |
} // namespace storage |