Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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_memory_controller.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/files/file_util.h" | |
| 9 #include "base/message_loop/message_loop.h" | |
| 10 #include "base/run_loop.h" | |
| 11 #include "base/test/test_simple_task_runner.h" | |
| 12 #include "base/threading/thread_task_runner_handle.h" | |
| 13 #include "storage/browser/blob/blob_data_builder.h" | |
| 14 #include "storage/browser/blob/blob_data_item.h" | |
| 15 #include "storage/browser/blob/shareable_blob_data_item.h" | |
| 16 #include "storage/common/data_element.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 | |
| 19 namespace storage { | |
| 20 | |
| 21 using Strategy = BlobMemoryController::Strategy; | |
| 22 using FileCreationInfo = BlobMemoryController::FileCreationInfo; | |
| 23 using base::TestSimpleTaskRunner; | |
| 24 using ItemState = ShareableBlobDataItem::State; | |
| 25 | |
| 26 const std::string kBlobStorageDirectory = "blob_storage"; | |
| 27 const size_t kTestBlobStorageIPCThresholdBytes = 20; | |
| 28 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50; | |
| 29 const size_t kTestBlobStorageMaxBlobMemorySize = 400; | |
| 30 const size_t kTestBlobStorageInFlightMemory = 10; | |
| 31 const uint64_t kTestBlobStorageMaxDiskSpace = 1000; | |
| 32 const uint64_t kTestBlobStorageMinFileSizeBytes = 10; | |
| 33 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100; | |
| 34 | |
| 35 class BlobMemoryControllerTest : public testing::Test { | |
| 36 protected: | |
| 37 BlobMemoryControllerTest() {} | |
| 38 | |
| 39 void SetUp() override { | |
| 40 ASSERT_EQ(true, base::CreateNewTempDirectory("blob_storage", &temp_dir_)); | |
| 41 }; | |
| 42 | |
| 43 void TearDown() override { | |
| 44 files_created_.clear(); | |
| 45 // Make sure we clean up the files. | |
| 46 base::RunLoop().RunUntilIdle(); | |
| 47 file_runner_->RunPendingTasks(); | |
| 48 base::RunLoop().RunUntilIdle(); | |
| 49 ASSERT_EQ(true, base::DeleteFile(temp_dir_, true)); | |
| 50 } | |
| 51 | |
| 52 std::vector<scoped_refptr<ShareableBlobDataItem>> CreateSharedDataItems( | |
| 53 const BlobDataBuilder& builder, | |
| 54 const std::vector<ItemState>& states, | |
| 55 std::vector<ShareableBlobDataItem*>* pointers_out) { | |
| 56 std::vector<scoped_refptr<ShareableBlobDataItem>> result; | |
| 57 EXPECT_EQ(builder.items_.size(), states.size()); | |
| 58 for (size_t i = 0; i < builder.items_.size(); ++i) { | |
| 59 result.push_back(make_scoped_refptr(new ShareableBlobDataItem( | |
| 60 builder.uuid(), builder.items_[i], states[i]))); | |
| 61 pointers_out->push_back(result.back().get()); | |
| 62 } | |
| 63 return result; | |
| 64 } | |
| 65 | |
| 66 void SetTestMemoryLimits(BlobMemoryController* controller) { | |
| 67 BlobStorageLimits limits; | |
| 68 limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes; | |
| 69 limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes; | |
| 70 limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize; | |
| 71 limits.in_flight_space = kTestBlobStorageInFlightMemory; | |
| 72 limits.max_blob_disk_space = kTestBlobStorageMaxDiskSpace; | |
| 73 limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes; | |
| 74 limits.max_file_size = kTestBlobStorageMaxFileSizeBytes; | |
| 75 controller->SetLimitsForTesting(limits); | |
| 76 } | |
| 77 | |
| 78 void SaveFileCreationInfo(bool success, std::vector<FileCreationInfo> info) { | |
| 79 file_quota_result_ = success; | |
| 80 if (success) | |
| 81 files_created_.swap(info); | |
| 82 } | |
| 83 | |
| 84 void SaveMemoryRequest(bool success) { memory_quota_result_ = success; } | |
| 85 | |
| 86 BlobMemoryController::FileQuotaRequestCallback GetFileCreationCallback() { | |
| 87 return base::Bind(&BlobMemoryControllerTest::SaveFileCreationInfo, | |
| 88 base::Unretained(this)); | |
| 89 } | |
| 90 | |
| 91 BlobMemoryController::MemoryQuotaRequestCallback GetMemoryRequestCallback() { | |
| 92 return base::Bind(&BlobMemoryControllerTest::SaveMemoryRequest, | |
| 93 base::Unretained(this)); | |
| 94 } | |
| 95 | |
| 96 void SetItemState(ShareableBlobDataItem* item, ItemState state) { | |
| 97 item->state_ = state; | |
| 98 } | |
| 99 | |
| 100 bool file_quota_result_ = false; | |
| 101 base::FilePath temp_dir_; | |
| 102 std::vector<FileCreationInfo> files_created_; | |
| 103 bool memory_quota_result_ = false; | |
| 104 | |
| 105 scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner(); | |
| 106 | |
| 107 base::MessageLoop fake_io_message_loop_; | |
| 108 }; | |
| 109 | |
| 110 TEST_F(BlobMemoryControllerTest, Strategy) { | |
| 111 BlobMemoryController controller; | |
| 112 SetTestMemoryLimits(&controller); | |
| 113 | |
| 114 // No transportation needed. | |
| 115 EXPECT_EQ(Strategy::NONE_NEEDED, controller.DetermineStrategy(0, 0)); | |
| 116 | |
| 117 // IPC. | |
| 118 EXPECT_EQ(Strategy::IPC, | |
| 119 controller.DetermineStrategy(0, kTestBlobStorageIPCThresholdBytes)); | |
| 120 | |
| 121 // Shared Memory. | |
| 122 EXPECT_EQ(Strategy::SHARED_MEMORY, | |
| 123 controller.DetermineStrategy(kTestBlobStorageIPCThresholdBytes, | |
| 124 kTestBlobStorageMaxSharedMemoryBytes)); | |
| 125 | |
| 126 // Not too large, as disk isn't enabled. | |
| 127 EXPECT_EQ( | |
| 128 Strategy::SHARED_MEMORY, | |
| 129 controller.DetermineStrategy(0, kTestBlobStorageMaxBlobMemorySize + | |
| 130 kTestBlobStorageInFlightMemory)); | |
| 131 | |
| 132 // Too large. | |
| 133 EXPECT_EQ( | |
| 134 Strategy::TOO_LARGE, | |
| 135 controller.DetermineStrategy(0, kTestBlobStorageMaxBlobMemorySize + | |
| 136 kTestBlobStorageInFlightMemory + 1)); | |
| 137 | |
| 138 // Enable disk, and check file strategies. | |
| 139 controller.EnableFilePaging(temp_dir_, file_runner_); | |
| 140 EXPECT_EQ(Strategy::FILE, controller.DetermineStrategy( | |
| 141 0, kTestBlobStorageMaxBlobMemorySize + 1)); | |
| 142 | |
| 143 // Too large for disk. | |
| 144 controller.EnableFilePaging(temp_dir_, file_runner_); | |
| 145 EXPECT_EQ(Strategy::TOO_LARGE, | |
| 146 controller.DetermineStrategy(0, kTestBlobStorageMaxDiskSpace + 1)); | |
| 147 } | |
| 148 | |
| 149 TEST_F(BlobMemoryControllerTest, GrantMemory) { | |
| 150 const std::string kId = "id"; | |
| 151 BlobMemoryController controller; | |
| 152 SetTestMemoryLimits(&controller); | |
| 153 | |
| 154 BlobDataBuilder builder(kId); | |
| 155 builder.AppendFutureData(10); | |
| 156 builder.AppendFutureData(20); | |
| 157 builder.AppendFutureData(30); | |
| 158 | |
| 159 std::vector<ShareableBlobDataItem*> pointers; | |
| 160 std::vector<scoped_refptr<ShareableBlobDataItem>> items = | |
| 161 CreateSharedDataItems(builder, | |
| 162 {ItemState::QUOTA_NEEDED, ItemState::QUOTA_NEEDED, | |
| 163 ItemState::QUOTA_NEEDED}, | |
| 164 &pointers); | |
| 165 | |
| 166 controller.ReserveMemoryQuota(pointers, GetMemoryRequestCallback()); | |
| 167 EXPECT_EQ(true, memory_quota_result_); | |
| 168 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[0]->state()); | |
| 169 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[1]->state()); | |
| 170 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[2]->state()); | |
| 171 } | |
| 172 | |
| 173 TEST_F(BlobMemoryControllerTest, GrantMemoryWithPagingFileWaiting) { | |
| 174 const std::string kId = "id"; | |
| 175 BlobMemoryController controller; | |
| 176 SetTestMemoryLimits(&controller); | |
| 177 | |
| 178 char kData[kTestBlobStorageMaxBlobMemorySize]; | |
| 179 std::memset(kData, kTestBlobStorageMaxBlobMemorySize, 'e'); | |
| 180 | |
| 181 // Add memory item that is the memory quota. | |
| 182 BlobDataBuilder builder(kId); | |
| 183 builder.AppendFutureData(kTestBlobStorageMaxBlobMemorySize); | |
| 184 | |
| 185 std::vector<ShareableBlobDataItem*> pointers; | |
| 186 std::vector<scoped_refptr<ShareableBlobDataItem>> items = | |
| 187 CreateSharedDataItems(builder, {ItemState::QUOTA_NEEDED}, &pointers); | |
| 188 | |
| 189 controller.ReserveMemoryQuota(pointers, GetMemoryRequestCallback()); | |
| 190 EXPECT_EQ(true, memory_quota_result_); | |
| 191 memory_quota_result_ = false; | |
| 192 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[0]->state()); | |
| 193 | |
| 194 // Enable disk. | |
| 195 controller.EnableFilePaging(temp_dir_, file_runner_); | |
| 196 | |
| 197 // Create an item that is just a little too big. | |
| 198 BlobDataBuilder builder2(kId); | |
| 199 builder2.AppendFutureData(kTestBlobStorageInFlightMemory + 1); | |
| 200 | |
| 201 // Reserve memory, which should request successfuly but we can't fit it yet | |
| 202 // (no callback). | |
| 203 pointers.clear(); | |
| 204 std::vector<scoped_refptr<ShareableBlobDataItem>> items2 = | |
| 205 CreateSharedDataItems(builder2, {ItemState::QUOTA_NEEDED}, &pointers); | |
| 206 controller.ReserveMemoryQuota(pointers, GetMemoryRequestCallback()); | |
| 207 | |
| 208 EXPECT_EQ(false, memory_quota_result_); | |
| 209 EXPECT_EQ(ItemState::QUOTA_REQUESTED, items2[0]->state()); | |
| 210 EXPECT_FALSE(file_runner_->HasPendingTask()); | |
| 211 | |
| 212 // Add our original item as populated so it's paged to disk. | |
| 213 items[0]->item()->data_element_ptr()->SetToBytes( | |
| 214 kData, kTestBlobStorageMaxBlobMemorySize); | |
| 215 SetItemState(items[0].get(), ItemState::POPULATED_WITH_QUOTA); | |
| 216 controller.UpdateBlobItemInRecents(items[0].get()); | |
| 217 | |
| 218 EXPECT_TRUE(file_runner_->HasPendingTask()); | |
| 219 file_runner_->RunPendingTasks(); | |
| 220 base::RunLoop().RunUntilIdle(); | |
| 221 EXPECT_EQ(ItemState::QUOTA_GRANTED, items2[0]->state()); | |
| 222 EXPECT_EQ(DataElement::TYPE_FILE, items[0]->item()->type()); | |
| 223 } | |
| 224 | |
| 225 // TODO(dmurph): | |
|
pwnall
2016/09/21 09:03:35
Can you crbug this please?
dmurph
2016/09/21 23:45:52
This will be in this patch, no need for crbug. Jus
| |
| 226 // * Write test for memory request when quota is available. | |
| 227 // * Write test for memory request that fails because disk isn't enabled. | |
| 228 // * Write test for memory request when quota isn't available and we're waiting | |
| 229 // on disk paging. | |
| 230 // * Same as above but then we cancel it. | |
| 231 // * Write test for memory request that's pending, and then disk is disabled. | |
| 232 // * Write test for file request where we have quota. | |
| 233 // * Write test for file request where we don't have quota (and just fail). | |
| 234 // * Write test for file request and then we disable disk. | |
| 235 | |
| 236 } // namespace storage | |
| OLD | NEW |