OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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_async_builder_host.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/memory/shared_memory.h" |
| 10 #include "storage/common/blob_storage/blob_storage_constants.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 |
| 13 namespace storage { |
| 14 namespace { |
| 15 const std::string kBlobUUID = "blobUUIDYAY"; |
| 16 const std::string kFakeBlobUUID = "fakeBlob"; |
| 17 const std::string kBlobType = "blobtypeYAY"; |
| 18 |
| 19 constexpr size_t kTestBlobStorageIPCThresholdBytes = 5; |
| 20 constexpr size_t kTestBlobStorageMaxSharedMemoryBytes = 20; |
| 21 constexpr uint64_t kTestBlobStorageMaxFileSizeBytes = 100; |
| 22 constexpr size_t kTestBlobStorageMaxBlobMemorySize = 50; |
| 23 |
| 24 static void PopulateBytes(char* bytes, size_t start_num, size_t length) { |
| 25 for (size_t i = 0; i < length; i++) { |
| 26 bytes[i] = static_cast<char>(start_num + i); |
| 27 } |
| 28 } |
| 29 |
| 30 static void PopulateBytes(char* bytes, size_t length) { |
| 31 PopulateBytes(bytes, 0, length); |
| 32 } |
| 33 |
| 34 static void AddMemoryItem(size_t length, std::vector<DataElement>* out) { |
| 35 DataElement bytes; |
| 36 bytes.SetToBytesDescription(length); |
| 37 out->push_back(bytes); |
| 38 } |
| 39 |
| 40 static void AddShortcutMemoryItem(size_t length, |
| 41 std::vector<DataElement>* out) { |
| 42 DataElement bytes; |
| 43 bytes.SetToAllocatedBytes(length); |
| 44 PopulateBytes(bytes.mutable_bytes(), length); |
| 45 out->push_back(bytes); |
| 46 } |
| 47 |
| 48 static void AddShortcutMemoryItem(size_t length, BlobDataBuilder* out) { |
| 49 DataElement bytes; |
| 50 bytes.SetToAllocatedBytes(length); |
| 51 PopulateBytes(bytes.mutable_bytes(), length); |
| 52 out->AppendData(bytes.bytes(), length); |
| 53 } |
| 54 |
| 55 static void AddBlobItem(std::vector<DataElement>* out) { |
| 56 DataElement blob; |
| 57 blob.SetToBlob(kFakeBlobUUID); |
| 58 out->push_back(blob); |
| 59 } |
| 60 |
| 61 class BlobAsyncBuilderHostTest : public testing::Test { |
| 62 protected: |
| 63 BlobAsyncBuilderHostTest() |
| 64 : matching_builder_(nullptr), |
| 65 done_called_(false), |
| 66 cancel_called_(false), |
| 67 cancel_code_(IPCBlobCreationCancelCode::UNKNOWN), |
| 68 request_called_(false) {} |
| 69 ~BlobAsyncBuilderHostTest() override {} |
| 70 |
| 71 void SetUp() override { |
| 72 matching_builder_ = nullptr; |
| 73 done_called_ = false; |
| 74 cancel_called_ = false; |
| 75 cancel_code_ = IPCBlobCreationCancelCode::UNKNOWN; |
| 76 request_called_ = false; |
| 77 requests_.clear(); |
| 78 memory_handles_.clear(); |
| 79 file_handles_.clear(); |
| 80 host_.SetMemoryConstantsForTesting( |
| 81 kTestBlobStorageIPCThresholdBytes, kTestBlobStorageMaxSharedMemoryBytes, |
| 82 kTestBlobStorageMaxFileSizeBytes, kTestBlobStorageMaxBlobMemorySize); |
| 83 } |
| 84 |
| 85 void SetMatchingBuilder(BlobDataBuilder* builder) { |
| 86 matching_builder_ = builder; |
| 87 } |
| 88 |
| 89 void CancelCallback(IPCBlobCreationCancelCode code) { |
| 90 cancel_called_ = true; |
| 91 cancel_code_ = code; |
| 92 } |
| 93 |
| 94 void DoneCallback(BlobDataBuilder* builder) { |
| 95 ASSERT_TRUE(builder); |
| 96 if (matching_builder_) |
| 97 EXPECT_EQ(*matching_builder_, *builder); |
| 98 done_called_ = true; |
| 99 } |
| 100 |
| 101 void RequestMemoryCallback( |
| 102 const std::vector<storage::BlobItemBytesRequest>& requests, |
| 103 const std::vector<base::SharedMemoryHandle>& sms, |
| 104 const std::vector<IPC::PlatformFileForTransit>& pfs) { |
| 105 this->requests_ = requests; |
| 106 memory_handles_ = sms; |
| 107 file_handles_ = pfs; |
| 108 request_called_ = true; |
| 109 } |
| 110 |
| 111 void BuildBlobAsync(const std::vector<DataElement>& descriptions, |
| 112 size_t memory_available) { |
| 113 host_.BuildBlob( |
| 114 kBlobUUID, kBlobType, descriptions, memory_available, |
| 115 base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, |
| 116 base::Unretained(this)), |
| 117 base::Bind(&BlobAsyncBuilderHostTest::DoneCallback, |
| 118 base::Unretained(this)), |
| 119 base::Bind(&BlobAsyncBuilderHostTest::CancelCallback, |
| 120 base::Unretained(this))); |
| 121 } |
| 122 |
| 123 BlobDataBuilder* matching_builder_; |
| 124 BlobAsyncBuilderHost host_; |
| 125 bool done_called_; |
| 126 bool cancel_called_; |
| 127 IPCBlobCreationCancelCode cancel_code_; |
| 128 |
| 129 bool request_called_; |
| 130 std::vector<storage::BlobItemBytesRequest> requests_; |
| 131 std::vector<base::SharedMemoryHandle> memory_handles_; |
| 132 std::vector<IPC::PlatformFileForTransit> file_handles_; |
| 133 }; |
| 134 |
| 135 TEST_F(BlobAsyncBuilderHostTest, TestShortcut) { |
| 136 std::vector<DataElement> descriptions; |
| 137 |
| 138 AddShortcutMemoryItem(10, &descriptions); |
| 139 AddBlobItem(&descriptions); |
| 140 AddShortcutMemoryItem(5000, &descriptions); |
| 141 |
| 142 BlobDataBuilder expected(kBlobUUID); |
| 143 expected.set_content_type(kBlobType); |
| 144 AddShortcutMemoryItem(10, &expected); |
| 145 expected.AppendBlob(kFakeBlobUUID); |
| 146 AddShortcutMemoryItem(5000, &expected); |
| 147 SetMatchingBuilder(&expected); |
| 148 |
| 149 BuildBlobAsync(descriptions, 5010); |
| 150 |
| 151 EXPECT_TRUE(done_called_); |
| 152 EXPECT_FALSE(cancel_called_); |
| 153 EXPECT_FALSE(request_called_); |
| 154 EXPECT_EQ(0u, host_.blob_building_count()); |
| 155 }; |
| 156 |
| 157 TEST_F(BlobAsyncBuilderHostTest, TestSingleSharedMemRequest) { |
| 158 std::vector<DataElement> descriptions; |
| 159 const size_t kSize = kTestBlobStorageIPCThresholdBytes + 1; |
| 160 AddMemoryItem(kSize, &descriptions); |
| 161 |
| 162 BuildBlobAsync(descriptions, kTestBlobStorageIPCThresholdBytes + 1); |
| 163 |
| 164 EXPECT_FALSE(done_called_); |
| 165 EXPECT_FALSE(cancel_called_); |
| 166 EXPECT_TRUE(request_called_); |
| 167 EXPECT_EQ(1u, host_.blob_building_count()); |
| 168 ASSERT_EQ(1u, requests_.size()); |
| 169 request_called_ = false; |
| 170 |
| 171 EXPECT_EQ( |
| 172 BlobItemBytesRequest::CreateSharedMemoryRequest(0, 0, 0, kSize, 0, 0), |
| 173 requests_.at(0)); |
| 174 }; |
| 175 |
| 176 TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) { |
| 177 std::vector<DataElement> descriptions; |
| 178 const size_t kSize = kTestBlobStorageMaxSharedMemoryBytes + 1; |
| 179 const size_t kFirstBlockByte = 7; |
| 180 const size_t kSecondBlockByte = 19; |
| 181 AddMemoryItem(kSize, &descriptions); |
| 182 |
| 183 BlobDataBuilder expected(kBlobUUID); |
| 184 expected.set_content_type(kBlobType); |
| 185 char* data = new char[kSize]; |
| 186 char lastByte = kSecondBlockByte; |
| 187 memset(data, kFirstBlockByte, kTestBlobStorageMaxSharedMemoryBytes); |
| 188 expected.AppendData(data, kTestBlobStorageMaxSharedMemoryBytes); |
| 189 expected.AppendData(&lastByte, 1); |
| 190 delete[] data; |
| 191 SetMatchingBuilder(&expected); |
| 192 |
| 193 BuildBlobAsync(descriptions, kTestBlobStorageMaxSharedMemoryBytes + 1); |
| 194 |
| 195 EXPECT_FALSE(done_called_); |
| 196 EXPECT_FALSE(cancel_called_); |
| 197 EXPECT_TRUE(request_called_); |
| 198 EXPECT_EQ(1u, host_.blob_building_count()); |
| 199 ASSERT_EQ(1u, requests_.size()); |
| 200 request_called_ = false; |
| 201 |
| 202 // We need to grab a duplicate handle so we can have two blocks open at the |
| 203 // same time. |
| 204 base::SharedMemoryHandle handle = |
| 205 base::SharedMemory::DuplicateHandle(memory_handles_.at(0)); |
| 206 EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle)); |
| 207 base::SharedMemory shared_memory(handle, false); |
| 208 EXPECT_TRUE(shared_memory.Map(kTestBlobStorageMaxSharedMemoryBytes)); |
| 209 |
| 210 EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest( |
| 211 0, 0, 0, kTestBlobStorageMaxSharedMemoryBytes, 0, 0), |
| 212 requests_.at(0)); |
| 213 |
| 214 memset(shared_memory.memory(), kFirstBlockByte, |
| 215 kTestBlobStorageMaxSharedMemoryBytes); |
| 216 |
| 217 BlobItemBytesResponse response(0); |
| 218 std::vector<BlobItemBytesResponse> responses = {response}; |
| 219 host_.OnMemoryResponses(kBlobUUID, responses); |
| 220 |
| 221 EXPECT_FALSE(done_called_); |
| 222 EXPECT_FALSE(cancel_called_); |
| 223 EXPECT_TRUE(request_called_); |
| 224 EXPECT_EQ(1u, host_.blob_building_count()); |
| 225 ASSERT_EQ(1u, requests_.size()); |
| 226 request_called_ = false; |
| 227 |
| 228 EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest( |
| 229 1, 0, kTestBlobStorageMaxSharedMemoryBytes, 1, 0, 0), |
| 230 requests_.at(0)); |
| 231 |
| 232 memset(shared_memory.memory(), kSecondBlockByte, 1); |
| 233 |
| 234 response.request_number = 1; |
| 235 responses[0] = response; |
| 236 host_.OnMemoryResponses(kBlobUUID, responses); |
| 237 EXPECT_TRUE(done_called_); |
| 238 EXPECT_FALSE(cancel_called_); |
| 239 EXPECT_FALSE(request_called_); |
| 240 EXPECT_EQ(0u, host_.blob_building_count()); |
| 241 }; |
| 242 |
| 243 } // namespace |
| 244 } // namespace storage |
OLD | NEW |