Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: content/browser/blob_storage/blob_dispatcher_host_unittest.cc

Issue 1234813004: [BlobAsync] Asynchronous Blob Construction Final Patch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@blob-protocol-change
Patch Set: comments/fixes Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 "content/browser/blob_storage/blob_dispatcher_host.h"
6
7 #include <vector>
8
9 #include "base/command_line.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/tuple.h"
13 #include "content/browser/fileapi/chrome_blob_storage_context.h"
14 #include "content/common/fileapi/webblob_messages.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/test/test_browser_context.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "ipc/ipc_sender.h"
19 #include "ipc/ipc_test_sink.h"
20 #include "ipc/message_filter.h"
21 #include "storage/browser/blob/blob_data_builder.h"
22 #include "storage/browser/blob/blob_data_handle.h"
23 #include "storage/browser/blob/blob_storage_context.h"
24 #include "storage/common/blob_storage/blob_item_bytes_request.h"
25 #include "storage/common/blob_storage/blob_item_bytes_response.h"
26 #include "storage/common/data_element.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 using storage::BlobDataBuilder;
31 using storage::BlobDataHandle;
32 using storage::BlobItemBytesRequest;
33 using storage::BlobItemBytesResponse;
34 using storage::BlobStorageContext;
35 using storage::BlobTransportResult;
36 using storage::DataElement;
37 using RequestMemoryCallback =
38 storage::BlobAsyncBuilderHost::RequestMemoryCallback;
39
40 namespace content {
41 namespace {
42
43 const char kContentType[] = "text/plain";
44 const char kContentDisposition[] = "content_disposition";
45 const char kData[] = "data!!";
46 const size_t kDataSize = 6;
47
48 template <typename T>
49 void SetPointerValue(T* pointer, T value) {
50 *pointer = value;
51 }
52
53 class TestableBlobDispatcherHost : public BlobDispatcherHost {
54 public:
55 TestableBlobDispatcherHost(ChromeBlobStorageContext* blob_storage_context,
56 IPC::TestSink* sink)
57 : BlobDispatcherHost(blob_storage_context), sink_(sink) {}
58
59 bool Send(IPC::Message* message) override { return sink_->Send(message); }
60
61 void ShutdownForBadMessage() override { shutdown_for_bad_message_ = true; }
62
63 bool shutdown_for_bad_message_ = false;
64 IPC::TestSink* sink_;
65
66 protected:
67 ~TestableBlobDispatcherHost() override {}
68
69 private:
70 friend class base::RefCountedThreadSafe<TestableBlobDispatcherHost>;
71 };
72
73 } // namespace
74
75 class BlobDispatcherHostTest : public testing::Test {
76 protected:
77 BlobDispatcherHostTest()
78 : browser_thread_bundle_(),
79 browser_context_(),
80 chrome_blob_storage_context_(
81 ChromeBlobStorageContext::GetFor(&browser_context_)) {
82 host_ =
83 new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_);
84 }
85 ~BlobDispatcherHostTest() override {}
86
87 void SetUp() override {
88 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
89 if (!command_line->HasSwitch(switches::kDisableKillAfterBadIPC)) {
90 command_line->AppendSwitch(switches::kDisableKillAfterBadIPC);
91 }
92 // We run the run loop to initialize the chrome blob storage context.
93 base::RunLoop().RunUntilIdle();
94 context_ = chrome_blob_storage_context_->context();
95 DCHECK(context_);
96 }
97
98 void ExpectBlobNotExist(const std::string& id) {
99 EXPECT_FALSE(context_->registry().HasEntry(id));
100 EXPECT_FALSE(host_->IsInUseInHost(id));
101 EXPECT_FALSE(host_->IsBeingBuiltInHost(id));
102 }
103
104 void AsyncShortcutBlobTransfer(const std::string& id) {
105 sink_.ClearMessages();
106 ExpectBlobNotExist(id);
107 host_->OnRegisterBlobUUID(id, std::string(kContentType),
108 std::string(kContentDisposition));
109 EXPECT_FALSE(host_->shutdown_for_bad_message_);
110 DataElement element;
111 element.SetToBytes(kData, kDataSize);
112 std::vector<DataElement> elements = {element};
113 host_->OnStartBuildingBlob(id, elements);
114 EXPECT_FALSE(host_->shutdown_for_bad_message_);
115 ExpectDone(id);
116 sink_.ClearMessages();
117 }
118
119 void AsyncBlobTransfer(const std::string& id) {
120 sink_.ClearMessages();
121 ExpectBlobNotExist(id);
122 host_->OnRegisterBlobUUID(id, std::string(kContentType),
123 std::string(kContentDisposition));
124 EXPECT_FALSE(host_->shutdown_for_bad_message_);
125 DataElement element;
126 element.SetToBytesDescription(kDataSize);
127 std::vector<DataElement> elements = {element};
128 host_->OnStartBuildingBlob(id, elements);
129 EXPECT_FALSE(host_->shutdown_for_bad_message_);
130
131 // Expect our request.
132 std::vector<BlobItemBytesRequest> expected_requests = {
133 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
134 ExpectRequest(id, expected_requests);
135 sink_.ClearMessages();
136
137 // Send results;
138 BlobItemBytesResponse response(0);
139 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
140 std::vector<BlobItemBytesResponse> responses = {response};
141 host_->OnMemoryItemResponse(id, responses);
142 ExpectDone(id);
143 sink_.ClearMessages();
144 }
145
146 void ExpectAndResetBadMessage() {
147 EXPECT_TRUE(host_->shutdown_for_bad_message_);
148 host_->shutdown_for_bad_message_ = false;
149 }
150
151 void ExpectHandleEqualsData(BlobDataHandle* handle,
152 const std::vector<DataElement>& data) {
153 scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot();
154 EXPECT_FALSE(handle->IsBeingBuilt());
155 for (size_t i = 0; i < data.size(); i++) {
156 const DataElement& expected = data[i];
157 const DataElement& actual = snapshot->items()[i]->data_element();
158 EXPECT_EQ(expected, actual);
159 }
160 EXPECT_EQ(data.size(), snapshot->items().size());
161 }
162
163 void ExpectRequest(
164 const std::string& expected_uuid,
165 const std::vector<BlobItemBytesRequest>& expected_requests) {
166 EXPECT_FALSE(
167 sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
168 EXPECT_FALSE(
169 sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
170 const IPC::Message* message =
171 sink_.GetUniqueMessageMatching(BlobStorageMsg_RequestMemoryItem::ID);
172 ASSERT_TRUE(message);
173 base::Tuple<std::string, std::vector<storage::BlobItemBytesRequest>,
174 std::vector<base::SharedMemoryHandle>,
175 std::vector<IPC::PlatformFileForTransit>>
176 args;
177 BlobStorageMsg_RequestMemoryItem::Read(message, &args);
178 EXPECT_EQ(expected_uuid, base::get<0>(args));
179 std::vector<BlobItemBytesRequest> requests = base::get<1>(args);
180 ASSERT_EQ(requests.size(), expected_requests.size());
181 for (size_t i = 0; i < expected_requests.size(); ++i) {
182 EXPECT_EQ(expected_requests[i], requests[i]);
183 }
184 }
185
186 void ExpectCancel(const std::string& expected_uuid,
187 storage::IPCBlobCreationCancelCode code) {
188 EXPECT_FALSE(
189 sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID));
190 EXPECT_FALSE(
191 sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
192 const IPC::Message* message =
193 sink_.GetUniqueMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID);
194 ASSERT_TRUE(message);
195 base::Tuple<std::string, storage::IPCBlobCreationCancelCode> args;
196 BlobStorageMsg_CancelBuildingBlob::Read(message, &args);
197 EXPECT_EQ(expected_uuid, base::get<0>(args));
198 EXPECT_EQ(code, base::get<1>(args));
199 }
200
201 void ExpectDone(const std::string& expected_uuid) {
202 EXPECT_FALSE(
203 sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID));
204 EXPECT_FALSE(
205 sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
206 const IPC::Message* message =
207 sink_.GetUniqueMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID);
208 base::Tuple<std::string> args;
209 BlobStorageMsg_DoneBuildingBlob::Read(message, &args);
210 EXPECT_EQ(expected_uuid, base::get<0>(args));
211 }
212
213 IPC::TestSink sink_;
214 TestBrowserThreadBundle browser_thread_bundle_;
215 TestBrowserContext browser_context_;
216 ChromeBlobStorageContext* chrome_blob_storage_context_;
217 BlobStorageContext* context_ = nullptr;
218 scoped_refptr<TestableBlobDispatcherHost> host_;
219 };
220
221 TEST_F(BlobDispatcherHostTest, EmptyUUIDs) {
222 host_->OnRegisterBlobUUID("", "", "");
223 ExpectAndResetBadMessage();
224 host_->OnStartBuildingBlob("", std::vector<DataElement>());
225 ExpectAndResetBadMessage();
226 host_->OnMemoryItemResponse("", std::vector<BlobItemBytesResponse>());
227 ExpectAndResetBadMessage();
228 host_->OnCancelBuildingBlob("", storage::IPCBlobCreationCancelCode::UNKNOWN);
229 ExpectAndResetBadMessage();
230 }
231
232 TEST_F(BlobDispatcherHostTest, Shortcut) {
233 const std::string kId = "uuid1";
234 AsyncShortcutBlobTransfer(kId);
235 EXPECT_TRUE(context_->registry().HasEntry(kId));
236 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
237 EXPECT_TRUE(handle);
238
239 DataElement expected;
240 expected.SetToBytes(kData, kDataSize);
241 std::vector<DataElement> elements = {expected};
242 ExpectHandleEqualsData(handle.get(), elements);
243 }
244
245 TEST_F(BlobDispatcherHostTest, RegularTransfer) {
246 const std::string kId = "uuid1";
247 AsyncBlobTransfer(kId);
248 EXPECT_TRUE(context_->registry().HasEntry(kId));
249 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
250 EXPECT_TRUE(handle);
251
252 DataElement expected;
253 expected.SetToBytes(kData, kDataSize);
254 std::vector<DataElement> elements = {expected};
255 ExpectHandleEqualsData(handle.get(), elements);
256 }
257
258 TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
259 const std::string kId("id");
260 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
261 ExpectAndResetBadMessage();
262
263 // Start building blob.
264 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
265 std::string(kContentDisposition));
266 EXPECT_FALSE(host_->shutdown_for_bad_message_);
267 DataElement element;
268 element.SetToBytesDescription(kDataSize);
269 std::vector<DataElement> elements = {element};
270 host_->OnStartBuildingBlob(kId, elements);
271 // It should have requested memory here.
272 EXPECT_FALSE(host_->shutdown_for_bad_message_);
273 sink_.ClearMessages();
274
275 // Cancel in middle of construction.
276 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
277 EXPECT_TRUE(context_->registry().HasEntry(kId));
278 EXPECT_TRUE(host_->IsInUseInHost(kId));
279 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
280 // Check that's it's broken.
281 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
282 EXPECT_TRUE(handle->IsBroken());
283 handle.reset();
284 base::RunLoop().RunUntilIdle();
285
286 // Get rid of it in the host.
287 host_->OnDecrementBlobRefCount(kId);
288 ExpectBlobNotExist(kId);
289
290 // Create blob again to verify we don't have any old construction state lying
291 // around.
292 AsyncBlobTransfer(kId);
293
294 // Check data.
295 handle = context_->GetBlobDataFromUUID(kId);
296 EXPECT_TRUE(handle);
297 DataElement expected;
298 expected.SetToBytes(kData, kDataSize);
299 std::vector<DataElement> expecteds = {expected};
300 ExpectHandleEqualsData(handle.get(), expecteds);
301
302 // Verify we can't cancel after the fact.
303 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
304 ExpectAndResetBadMessage();
305 }
306
307 TEST_F(BlobDispatcherHostTest, BlobDataWithHostDeletion) {
308 // Build up a basic blob.
309 const std::string kId("id");
310 AsyncShortcutBlobTransfer(kId);
311 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
312 EXPECT_TRUE(handle);
313
314 // Kill the host.
315 host_ = nullptr;
316 base::RunLoop().RunUntilIdle();
317 // Should still be there due to the handle.
318 scoped_ptr<BlobDataHandle> another_handle =
319 context_->GetBlobDataFromUUID(kId);
320 EXPECT_TRUE(another_handle);
321
322 // Should disappear after dropping both handles.
323 handle.reset();
324 another_handle.reset();
325 base::RunLoop().RunUntilIdle();
326
327 handle = context_->GetBlobDataFromUUID(kId);
328 EXPECT_FALSE(handle);
329 }
330
331 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) {
332 const std::string kId("id");
333
334 // Start building blob.
335 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
336 std::string(kContentDisposition));
337 EXPECT_FALSE(host_->shutdown_for_bad_message_);
338
339 // Grab the handle.
340 scoped_ptr<BlobDataHandle> blob_data_handle =
341 context_->GetBlobDataFromUUID(kId);
342 EXPECT_TRUE(blob_data_handle);
343 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
344 bool built = false;
345 blob_data_handle->RunOnConstructionComplete(
346 base::Bind(&SetPointerValue<bool>, &built));
347
348 // Continue building.
349 DataElement element;
350 element.SetToBytesDescription(kDataSize);
351 std::vector<DataElement> elements = {element};
352 host_->OnStartBuildingBlob(kId, elements);
353 EXPECT_FALSE(host_->shutdown_for_bad_message_);
354 sink_.ClearMessages();
355
356 // Send data.
357 BlobItemBytesResponse response(0);
358 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
359 std::vector<BlobItemBytesResponse> responses = {response};
360 sink_.ClearMessages();
361 host_->OnMemoryItemResponse(kId, responses);
362
363 ExpectDone(kId);
364 base::RunLoop().RunUntilIdle();
365 EXPECT_TRUE(built);
366 }
367
368 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileShortcutConstructing) {
369 const std::string kId("id");
370
371 // Start building blob.
372 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
373 std::string(kContentDisposition));
374 EXPECT_FALSE(host_->shutdown_for_bad_message_);
375
376 // Grab the handle.
377 scoped_ptr<BlobDataHandle> blob_data_handle =
378 context_->GetBlobDataFromUUID(kId);
379 EXPECT_TRUE(blob_data_handle);
380 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
381 bool built = false;
382 blob_data_handle->RunOnConstructionComplete(
383 base::Bind(&SetPointerValue<bool>, &built));
384
385 // Continue building.
386 DataElement element;
387 element.SetToBytes(kData, kDataSize);
388 std::vector<DataElement> elements = {element};
389 host_->OnStartBuildingBlob(kId, elements);
390 EXPECT_FALSE(host_->shutdown_for_bad_message_);
391 ExpectDone(kId);
392 base::RunLoop().RunUntilIdle();
393 EXPECT_TRUE(built);
394 }
395
396 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructingCancelled) {
397 const std::string kId("id");
398
399 // Start building blob.
400 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
401 std::string(kContentDisposition));
402 EXPECT_FALSE(host_->shutdown_for_bad_message_);
403
404 // Grab the handle.
405 scoped_ptr<BlobDataHandle> blob_data_handle =
406 context_->GetBlobDataFromUUID(kId);
407 EXPECT_TRUE(blob_data_handle);
408 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
409 bool built = true;
410 blob_data_handle->RunOnConstructionComplete(
411 base::Bind(&SetPointerValue<bool>, &built));
412
413 // Cancel in middle of construction.
414 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
415 base::RunLoop().RunUntilIdle();
416 EXPECT_TRUE(context_->registry().HasEntry(kId));
417 EXPECT_FALSE(host_->shutdown_for_bad_message_);
418 EXPECT_TRUE(host_->IsInUseInHost(kId));
419 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
420 EXPECT_TRUE(blob_data_handle->IsBroken());
421 EXPECT_FALSE(built);
422 built = true;
423 blob_data_handle->RunOnConstructionComplete(
424 base::Bind(&SetPointerValue<bool>, &built));
425 EXPECT_FALSE(built);
426
427 // Remove it.
428 blob_data_handle.reset();
429 base::RunLoop().RunUntilIdle();
430 EXPECT_TRUE(context_->registry().HasEntry(kId));
431 host_->OnDecrementBlobRefCount(kId);
432 ExpectBlobNotExist(kId);
433 }
434
435 TEST_F(BlobDispatcherHostTest, BlobDestructionEdgeCases) {
436 const std::string kId("id");
437
438 // Start building blob.
439 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
440 std::string(kContentDisposition));
441 EXPECT_FALSE(host_->shutdown_for_bad_message_);
442
443 // Grab the handle.
444 scoped_ptr<BlobDataHandle> blob_data_handle =
445 context_->GetBlobDataFromUUID(kId);
446 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
447 bool built = true;
448 blob_data_handle->RunOnConstructionComplete(
449 base::Bind(&SetPointerValue<bool>, &built));
450
451 // Get rid of host, which was doing the constructing.
452 host_ = nullptr;
453
454 EXPECT_FALSE(blob_data_handle->IsBeingBuilt());
455 base::RunLoop().RunUntilIdle();
456
457 EXPECT_FALSE(built);
458
459 // Should still be there due to the handle.
460 scoped_ptr<BlobDataHandle> another_handle =
461 context_->GetBlobDataFromUUID(kId);
462 EXPECT_TRUE(another_handle);
463
464 // Should disappear after dropping both handles.
465 blob_data_handle.reset();
466 another_handle.reset();
467 base::RunLoop().RunUntilIdle();
468
469 EXPECT_FALSE(context_->registry().HasEntry(kId));
470 }
471
472 } // namespace contet
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698