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

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 Created 4 years, 9 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 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 "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/memory/shared_memory.h"
12 #include "base/run_loop.h"
13 #include "base/tuple.h"
14 #include "content/browser/fileapi/chrome_blob_storage_context.h"
15 #include "content/common/fileapi/webblob_messages.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/test/test_browser_context.h"
18 #include "content/public/test/test_browser_thread_bundle.h"
19 #include "ipc/ipc_sender.h"
20 #include "ipc/ipc_test_sink.h"
21 #include "ipc/message_filter.h"
22 #include "storage/browser/blob/blob_data_builder.h"
23 #include "storage/browser/blob/blob_data_handle.h"
24 #include "storage/browser/blob/blob_storage_context.h"
25 #include "storage/common/blob_storage/blob_item_bytes_request.h"
26 #include "storage/common/blob_storage/blob_item_bytes_response.h"
27 #include "storage/common/data_element.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 using storage::BlobDataBuilder;
32 using storage::BlobDataHandle;
33 using storage::BlobItemBytesRequest;
34 using storage::BlobItemBytesResponse;
35 using storage::BlobStorageContext;
36 using storage::BlobTransportResult;
37 using storage::DataElement;
38 using storage::IPCBlobCreationCancelCode;
39 using RequestMemoryCallback =
40 storage::BlobAsyncBuilderHost::RequestMemoryCallback;
41
42 namespace content {
43 namespace {
44
45 const char kContentType[] = "text/plain";
46 const char kContentDisposition[] = "content_disposition";
47 const char kData[] = "data!!";
48 const size_t kDataSize = 6;
49
50 const size_t kTestBlobStorageIPCThresholdBytes = 20;
51 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
52 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
53
54 template <typename T>
55 void SetPointerValue(T* pointer, T value) {
56 *pointer = value;
57 }
58
59 class TestableBlobDispatcherHost : public BlobDispatcherHost {
60 public:
61 TestableBlobDispatcherHost(ChromeBlobStorageContext* blob_storage_context,
62 IPC::TestSink* sink)
63 : BlobDispatcherHost(blob_storage_context), sink_(sink) {
64 this->SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes,
65 kTestBlobStorageMaxSharedMemoryBytes,
66 kTestBlobStorageMaxFileSizeBytes);
67 }
68
69 bool Send(IPC::Message* message) override { return sink_->Send(message); }
70
71 void ShutdownForBadMessage() override { shutdown_for_bad_message_ = true; }
72
73 bool shutdown_for_bad_message_ = false;
74
75 protected:
76 ~TestableBlobDispatcherHost() override {}
77
78 private:
79 friend class base::RefCountedThreadSafe<TestableBlobDispatcherHost>;
80
81 IPC::TestSink* sink_;
82 };
83
84 } // namespace
85
86 class BlobDispatcherHostTest : public testing::Test {
87 protected:
88 BlobDispatcherHostTest()
89 : chrome_blob_storage_context_(
90 ChromeBlobStorageContext::GetFor(&browser_context_)) {
91 host_ =
92 new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_);
93 }
94 ~BlobDispatcherHostTest() override {}
95
96 void SetUp() override {
97 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
98 if (!command_line->HasSwitch(switches::kDisableKillAfterBadIPC)) {
99 command_line->AppendSwitch(switches::kDisableKillAfterBadIPC);
100 }
101 // We run the run loop to initialize the chrome blob storage context.
102 base::RunLoop().RunUntilIdle();
103 context_ = chrome_blob_storage_context_->context();
104 DCHECK(context_);
105 }
106
107 void ExpectBlobNotExist(const std::string& id) {
108 EXPECT_FALSE(context_->registry().HasEntry(id));
109 EXPECT_FALSE(host_->IsInUseInHost(id));
110 EXPECT_FALSE(IsBeingBuiltInHost(id));
111 }
112
113 void AsyncShortcutBlobTransfer(const std::string& id) {
114 sink_.ClearMessages();
115 ExpectBlobNotExist(id);
116 host_->OnRegisterBlobUUID(id, std::string(kContentType),
117 std::string(kContentDisposition),
118 std::set<std::string>());
119 EXPECT_FALSE(host_->shutdown_for_bad_message_);
120 DataElement element;
121 element.SetToBytes(kData, kDataSize);
122 std::vector<DataElement> elements = {element};
123 host_->OnStartBuildingBlob(id, elements);
124 EXPECT_FALSE(host_->shutdown_for_bad_message_);
125 ExpectDone(id);
126 sink_.ClearMessages();
127 }
128
129 void AsyncBlobTransfer(const std::string& id) {
130 sink_.ClearMessages();
131 ExpectBlobNotExist(id);
132 host_->OnRegisterBlobUUID(id, std::string(kContentType),
133 std::string(kContentDisposition),
134 std::set<std::string>());
135 EXPECT_FALSE(host_->shutdown_for_bad_message_);
136 DataElement element;
137 element.SetToBytesDescription(kDataSize);
138 std::vector<DataElement> elements = {element};
139 host_->OnStartBuildingBlob(id, elements);
140 EXPECT_FALSE(host_->shutdown_for_bad_message_);
141
142 // Expect our request.
143 std::vector<BlobItemBytesRequest> expected_requests = {
144 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
145 ExpectRequest(id, expected_requests);
146 sink_.ClearMessages();
147
148 // Send results;
149 BlobItemBytesResponse response(0);
150 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
151 std::vector<BlobItemBytesResponse> responses = {response};
152 host_->OnMemoryItemResponse(id, responses);
153 ExpectDone(id);
154 sink_.ClearMessages();
155 }
156
157 void ExpectAndResetBadMessage() {
158 EXPECT_TRUE(host_->shutdown_for_bad_message_);
159 host_->shutdown_for_bad_message_ = false;
160 }
161
162 void ExpectHandleEqualsData(BlobDataHandle* handle,
163 const std::vector<DataElement>& data) {
164 scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot();
165 EXPECT_FALSE(handle->IsBeingBuilt());
166 for (size_t i = 0; i < data.size(); i++) {
167 const DataElement& expected = data[i];
168 const DataElement& actual = snapshot->items()[i]->data_element();
169 EXPECT_EQ(expected, actual);
170 }
171 EXPECT_EQ(data.size(), snapshot->items().size());
172 }
173
174 void ExpectRequest(
175 const std::string& expected_uuid,
176 const std::vector<BlobItemBytesRequest>& expected_requests) {
177 EXPECT_FALSE(
178 sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
179 EXPECT_FALSE(
180 sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
181 const IPC::Message* message =
182 sink_.GetUniqueMessageMatching(BlobStorageMsg_RequestMemoryItem::ID);
183 ASSERT_TRUE(message);
184 base::Tuple<std::string, std::vector<storage::BlobItemBytesRequest>,
185 std::vector<base::SharedMemoryHandle>,
186 std::vector<IPC::PlatformFileForTransit>>
187 args;
188 BlobStorageMsg_RequestMemoryItem::Read(message, &args);
189 EXPECT_EQ(expected_uuid, base::get<0>(args));
190 std::vector<BlobItemBytesRequest> requests = base::get<1>(args);
191 ASSERT_EQ(requests.size(), expected_requests.size());
192 for (size_t i = 0; i < expected_requests.size(); ++i) {
193 EXPECT_EQ(expected_requests[i], requests[i]);
194 }
195 }
196
197 void ExpectRequestWithSharedMemoryHandles(
198 const std::string& expected_uuid,
199 const std::vector<BlobItemBytesRequest>& expected_requests,
200 std::vector<base::SharedMemoryHandle>* shared_memory_handles) {
201 EXPECT_FALSE(
202 sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
203 EXPECT_FALSE(
204 sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
205 const IPC::Message* message =
206 sink_.GetUniqueMessageMatching(BlobStorageMsg_RequestMemoryItem::ID);
207 ASSERT_TRUE(message);
208 base::Tuple<std::string, std::vector<storage::BlobItemBytesRequest>,
209 std::vector<base::SharedMemoryHandle>,
210 std::vector<IPC::PlatformFileForTransit>>
211 args;
212 BlobStorageMsg_RequestMemoryItem::Read(message, &args);
213 EXPECT_EQ(expected_uuid, base::get<0>(args));
214 std::vector<BlobItemBytesRequest> requests = base::get<1>(args);
215 ASSERT_EQ(requests.size(), expected_requests.size());
216 for (size_t i = 0; i < expected_requests.size(); ++i) {
217 EXPECT_EQ(expected_requests[i], requests[i]);
218 }
219 *shared_memory_handles = std::move(base::get<2>(args));
220 }
221
222 void ExpectCancel(const std::string& expected_uuid,
223 IPCBlobCreationCancelCode code) {
224 EXPECT_FALSE(
225 sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID));
226 EXPECT_FALSE(
227 sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
228 const IPC::Message* message =
229 sink_.GetUniqueMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID);
230 ASSERT_TRUE(message);
231 base::Tuple<std::string, IPCBlobCreationCancelCode> args;
232 BlobStorageMsg_CancelBuildingBlob::Read(message, &args);
233 EXPECT_EQ(expected_uuid, base::get<0>(args));
234 EXPECT_EQ(code, base::get<1>(args));
235 }
236
237 void ExpectDone(const std::string& expected_uuid) {
238 EXPECT_FALSE(
239 sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID));
240 EXPECT_FALSE(
241 sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
242 const IPC::Message* message =
243 sink_.GetUniqueMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID);
244 base::Tuple<std::string> args;
245 BlobStorageMsg_DoneBuildingBlob::Read(message, &args);
246 EXPECT_EQ(expected_uuid, base::get<0>(args));
247 }
248
249 bool IsBeingBuiltInHost(const std::string& uuid) {
250 return host_->async_builder_.IsBeingBuilt(uuid);
251 }
252
253 IPC::TestSink sink_;
254 TestBrowserThreadBundle browser_thread_bundle_;
255 TestBrowserContext browser_context_;
256 ChromeBlobStorageContext* chrome_blob_storage_context_;
257 BlobStorageContext* context_ = nullptr;
258 scoped_refptr<TestableBlobDispatcherHost> host_;
259 };
260
261 TEST_F(BlobDispatcherHostTest, EmptyUUIDs) {
262 host_->OnRegisterBlobUUID("", "", "", std::set<std::string>());
263 ExpectAndResetBadMessage();
264 host_->OnStartBuildingBlob("", std::vector<DataElement>());
265 ExpectAndResetBadMessage();
266 host_->OnMemoryItemResponse("", std::vector<BlobItemBytesResponse>());
267 ExpectAndResetBadMessage();
268 host_->OnCancelBuildingBlob("", IPCBlobCreationCancelCode::UNKNOWN);
269 ExpectAndResetBadMessage();
270 }
271
272 TEST_F(BlobDispatcherHostTest, Shortcut) {
273 const std::string kId = "uuid1";
274 AsyncShortcutBlobTransfer(kId);
275 EXPECT_TRUE(context_->registry().HasEntry(kId));
276 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
277 EXPECT_TRUE(handle);
278
279 DataElement expected;
280 expected.SetToBytes(kData, kDataSize);
281 std::vector<DataElement> elements = {expected};
282 ExpectHandleEqualsData(handle.get(), elements);
283 }
284
285 TEST_F(BlobDispatcherHostTest, RegularTransfer) {
286 const std::string kId = "uuid1";
287 AsyncBlobTransfer(kId);
288 EXPECT_TRUE(context_->registry().HasEntry(kId));
289 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
290 EXPECT_TRUE(handle);
291
292 DataElement expected;
293 expected.SetToBytes(kData, kDataSize);
294 std::vector<DataElement> elements = {expected};
295 ExpectHandleEqualsData(handle.get(), elements);
296 }
297
298 TEST_F(BlobDispatcherHostTest, SharedMemoryTransfer) {
299 const std::string kId = "uuid1";
300 const size_t kLargeSize = kTestBlobStorageMaxSharedMemoryBytes * 2;
301 std::vector<base::SharedMemoryHandle> shared_memory_handles;
302
303 ExpectBlobNotExist(kId);
304 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
305 std::string(kContentDisposition),
306 std::set<std::string>());
307 // Grab the handle.
308 scoped_ptr<BlobDataHandle> blob_data_handle =
309 context_->GetBlobDataFromUUID(kId);
310 bool built = false;
311 blob_data_handle->RunOnConstructionComplete(
312 base::Bind(&SetPointerValue<bool>, &built));
313 EXPECT_FALSE(built);
314
315 EXPECT_FALSE(host_->shutdown_for_bad_message_);
316 DataElement element;
317 element.SetToBytesDescription(kLargeSize);
318 std::vector<DataElement> elements = {element};
319 host_->OnStartBuildingBlob(kId, elements);
320 EXPECT_FALSE(host_->shutdown_for_bad_message_);
321
322 // Expect our first request.
323 std::vector<BlobItemBytesRequest> expected_requests = {
324 BlobItemBytesRequest::CreateSharedMemoryRequest(
325 0 /* request_number */, 0 /* renderer_item_index */,
326 0 /* renderer_item_offset */,
327 static_cast<uint64_t>(
328 kTestBlobStorageMaxSharedMemoryBytes) /* size */,
329 0 /* handle_index */, 0 /* handle_offset */)};
330 ExpectRequestWithSharedMemoryHandles(kId, expected_requests,
331 &shared_memory_handles);
332 sink_.ClearMessages();
333
334 // Populate the shared memory.
335 EXPECT_EQ(1u, shared_memory_handles.size());
336 EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0]));
337 {
338 base::SharedMemory memory(
339 base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false);
340 memory.Map(kTestBlobStorageMaxSharedMemoryBytes);
341 std::memset(memory.memory(), 'X', kTestBlobStorageMaxSharedMemoryBytes);
342 memory.Close();
343 }
344
345 // Send the confirmation.
346 std::vector<BlobItemBytesResponse> responses = {BlobItemBytesResponse(0)};
347 host_->OnMemoryItemResponse(kId, responses);
348
349 // Expect our second request.
350 expected_requests = {BlobItemBytesRequest::CreateSharedMemoryRequest(
351 1 /* request_number */, 0 /* renderer_item_index */,
352 static_cast<uint64_t>(
353 kTestBlobStorageMaxSharedMemoryBytes) /* renderer_item_offset */,
354 static_cast<uint64_t>(kTestBlobStorageMaxSharedMemoryBytes) /* size */,
355 0 /* handle_index */, 0 /* handle_offset */)};
356 ExpectRequestWithSharedMemoryHandles(kId, expected_requests,
357 &shared_memory_handles);
358 sink_.ClearMessages();
359
360 // Populate the shared memory.
361 EXPECT_EQ(1u, shared_memory_handles.size());
362 EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0]));
363 {
364 base::SharedMemory memory(
365 base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false);
366 memory.Map(kTestBlobStorageMaxSharedMemoryBytes);
367 std::memset(memory.memory(), 'Z', kTestBlobStorageMaxSharedMemoryBytes);
368 memory.Close();
369 }
370 // Send the confirmation.
371 responses = {BlobItemBytesResponse(1)};
372 host_->OnMemoryItemResponse(kId, responses);
373
374 ExpectDone(kId);
375 sink_.ClearMessages();
376 base::RunLoop().RunUntilIdle();
377 EXPECT_TRUE(built);
378 EXPECT_TRUE(context_->registry().HasEntry(kId));
379 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
380 EXPECT_TRUE(handle);
381
382 DataElement expected;
383 expected.SetToAllocatedBytes(kLargeSize / 2);
384 std::memset(expected.mutable_bytes(), 'X', kLargeSize / 2);
385 elements = {expected};
386 std::memset(expected.mutable_bytes(), 'Z', kLargeSize / 2);
387 elements.push_back(expected);
388 ExpectHandleEqualsData(handle.get(), elements);
389 }
390
391 TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
392 const std::string kId("id");
393 // We ignore blobs that are unknown, as it could have been cancelled earlier
394 // and the renderer didn't know about it yet.
395 host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
396 EXPECT_FALSE(host_->shutdown_for_bad_message_);
397
398 // Start building blob.
399 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
400 std::string(kContentDisposition),
401 std::set<std::string>());
402 EXPECT_FALSE(host_->shutdown_for_bad_message_);
403 DataElement element;
404 element.SetToBytesDescription(kDataSize);
405 std::vector<DataElement> elements = {element};
406 host_->OnStartBuildingBlob(kId, elements);
407 // It should have requested memory here.
408 EXPECT_FALSE(host_->shutdown_for_bad_message_);
409 sink_.ClearMessages();
410
411 // Cancel in middle of construction.
412 host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
413 EXPECT_TRUE(context_->registry().HasEntry(kId));
414 EXPECT_TRUE(host_->IsInUseInHost(kId));
415 EXPECT_FALSE(IsBeingBuiltInHost(kId));
416 // Check that's it's broken.
417 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
418 EXPECT_TRUE(handle->IsBroken());
419 handle.reset();
420 base::RunLoop().RunUntilIdle();
421
422 // Get rid of it in the host.
423 host_->OnDecrementBlobRefCount(kId);
424 ExpectBlobNotExist(kId);
425
426 // Create blob again to verify we don't have any old construction state lying
427 // around.
428 AsyncBlobTransfer(kId);
429
430 // Check data.
431 handle = context_->GetBlobDataFromUUID(kId);
432 EXPECT_TRUE(handle);
433 DataElement expected;
434 expected.SetToBytes(kData, kDataSize);
435 std::vector<DataElement> expecteds = {expected};
436 ExpectHandleEqualsData(handle.get(), expecteds);
437
438 // Verify we can't cancel after the fact.
439 host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
440 ExpectAndResetBadMessage();
441 }
442
443 TEST_F(BlobDispatcherHostTest, BlobDataWithHostDeletion) {
444 // Build up a basic blob.
445 const std::string kId("id");
446 AsyncShortcutBlobTransfer(kId);
447 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
448 EXPECT_TRUE(handle);
449
450 // Kill the host.
451 host_ = nullptr;
452 base::RunLoop().RunUntilIdle();
453 // Should still be there due to the handle.
454 scoped_ptr<BlobDataHandle> another_handle =
455 context_->GetBlobDataFromUUID(kId);
456 EXPECT_TRUE(another_handle);
457
458 // Should disappear after dropping both handles.
459 handle.reset();
460 another_handle.reset();
461 base::RunLoop().RunUntilIdle();
462
463 handle = context_->GetBlobDataFromUUID(kId);
464 EXPECT_FALSE(handle);
465 }
466
467 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) {
468 const std::string kId("id");
469
470 // Start building blob.
471 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
472 std::string(kContentDisposition),
473 std::set<std::string>());
474
475 // Grab the handle.
476 scoped_ptr<BlobDataHandle> blob_data_handle =
477 context_->GetBlobDataFromUUID(kId);
478 EXPECT_TRUE(blob_data_handle);
479 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
480 bool built = false;
481 blob_data_handle->RunOnConstructionComplete(
482 base::Bind(&SetPointerValue<bool>, &built));
483
484 // Continue building.
485 DataElement element;
486 element.SetToBytesDescription(kDataSize);
487 std::vector<DataElement> elements = {element};
488 host_->OnStartBuildingBlob(kId, elements);
489 sink_.ClearMessages();
490
491 // Send data.
492 BlobItemBytesResponse response(0);
493 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
494 std::vector<BlobItemBytesResponse> responses = {response};
495 sink_.ClearMessages();
496 host_->OnMemoryItemResponse(kId, responses);
497
498 ExpectDone(kId);
499 base::RunLoop().RunUntilIdle();
500 EXPECT_TRUE(built);
501 }
502
503 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileShortcutConstructing) {
504 const std::string kId("id");
505
506 // Start building blob.
507 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
508 std::string(kContentDisposition),
509 std::set<std::string>());
510
511 // Grab the handle.
512 scoped_ptr<BlobDataHandle> blob_data_handle =
513 context_->GetBlobDataFromUUID(kId);
514 EXPECT_TRUE(blob_data_handle);
515 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
516 bool built = false;
517 blob_data_handle->RunOnConstructionComplete(
518 base::Bind(&SetPointerValue<bool>, &built));
519
520 // Continue building.
521 DataElement element;
522 element.SetToBytes(kData, kDataSize);
523 std::vector<DataElement> elements = {element};
524 host_->OnStartBuildingBlob(kId, elements);
525 ExpectDone(kId);
526 base::RunLoop().RunUntilIdle();
527 EXPECT_TRUE(built);
528 }
529
530 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructingCancelled) {
531 const std::string kId("id");
532
533 // Start building blob.
534 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
535 std::string(kContentDisposition),
536 std::set<std::string>());
537
538 // Grab the handle.
539 scoped_ptr<BlobDataHandle> blob_data_handle =
540 context_->GetBlobDataFromUUID(kId);
541 EXPECT_TRUE(blob_data_handle);
542 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
543 bool built = true;
544 blob_data_handle->RunOnConstructionComplete(
545 base::Bind(&SetPointerValue<bool>, &built));
546
547 // Cancel in middle of construction.
548 host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
549 base::RunLoop().RunUntilIdle();
550 EXPECT_TRUE(context_->registry().HasEntry(kId));
551 EXPECT_TRUE(host_->IsInUseInHost(kId));
552 EXPECT_FALSE(IsBeingBuiltInHost(kId));
553 EXPECT_TRUE(blob_data_handle->IsBroken());
554 EXPECT_FALSE(built);
555 built = true;
556 blob_data_handle->RunOnConstructionComplete(
557 base::Bind(&SetPointerValue<bool>, &built));
558 EXPECT_FALSE(built);
559
560 // Remove it.
561 blob_data_handle.reset();
562 base::RunLoop().RunUntilIdle();
563 EXPECT_TRUE(context_->registry().HasEntry(kId));
564 host_->OnDecrementBlobRefCount(kId);
565 ExpectBlobNotExist(kId);
566 }
567
568 TEST_F(BlobDispatcherHostTest, DecrementRefAfterRegister) {
569 const std::string kId("id");
570 // Decrement the refcount while building (renderer blob gc'd before
571 // construction was completed).
572 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
573 std::string(kContentDisposition),
574 std::set<std::string>());
575 EXPECT_TRUE(context_->registry().HasEntry(kId));
576 host_->OnDecrementBlobRefCount(kId);
577 EXPECT_FALSE(context_->registry().HasEntry(kId));
578 EXPECT_FALSE(IsBeingBuiltInHost(kId));
579 ExpectCancel(kId,
580 IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
581 sink_.ClearMessages();
582
583 // Do the same, but this time grab a handle before we decrement.
584 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
585 std::string(kContentDisposition),
586 std::set<std::string>());
587 scoped_ptr<BlobDataHandle> blob_data_handle =
588 context_->GetBlobDataFromUUID(kId);
589 host_->OnDecrementBlobRefCount(kId);
590 EXPECT_TRUE(context_->registry().HasEntry(kId));
591 EXPECT_TRUE(IsBeingBuiltInHost(kId));
592
593 // Finish up the blob, and verify we got the done message.
594 DataElement element;
595 element.SetToBytes(kData, kDataSize);
596 std::vector<DataElement> elements = {element};
597 host_->OnStartBuildingBlob(kId, elements);
598 EXPECT_FALSE(host_->shutdown_for_bad_message_);
599 ExpectDone(kId);
600 sink_.ClearMessages();
601 // Get rid of the handle, and verify it's gone.
602 blob_data_handle.reset();
603 base::RunLoop().RunUntilIdle();
604 // Check that it's no longer around.
605 EXPECT_FALSE(context_->registry().HasEntry(kId));
606 EXPECT_FALSE(IsBeingBuiltInHost(kId));
607 }
608
609 TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) {
610 const std::string kId("id");
611
612 // Decrement the refcount while building, after we call OnStartBuildlingBlob.
613 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
614 std::string(kContentDisposition),
615 std::set<std::string>());
616 EXPECT_FALSE(host_->shutdown_for_bad_message_);
617 DataElement element;
618 element.SetToBytesDescription(kDataSize);
619 std::vector<DataElement> elements = {element};
620 host_->OnStartBuildingBlob(kId, elements);
621 EXPECT_FALSE(host_->shutdown_for_bad_message_);
622
623 std::vector<BlobItemBytesRequest> expected_requests = {
624 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
625 ExpectRequest(kId, expected_requests);
626 sink_.ClearMessages();
627 EXPECT_TRUE(context_->registry().HasEntry(kId));
628 host_->OnDecrementBlobRefCount(kId);
629 EXPECT_FALSE(context_->registry().HasEntry(kId));
630 EXPECT_FALSE(IsBeingBuiltInHost(kId));
631 ExpectCancel(kId,
632 IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
633 sink_.ClearMessages();
634
635 // Do the same, but this time grab a handle to keep it alive.
636 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
637 std::string(kContentDisposition),
638 std::set<std::string>());
639 EXPECT_FALSE(host_->shutdown_for_bad_message_);
640 host_->OnStartBuildingBlob(kId, elements);
641 EXPECT_FALSE(host_->shutdown_for_bad_message_);
642 ExpectRequest(kId, expected_requests);
643 sink_.ClearMessages();
644 EXPECT_TRUE(context_->registry().HasEntry(kId));
645 // Grab the handle before decrementing.
646 scoped_ptr<BlobDataHandle> blob_data_handle =
647 context_->GetBlobDataFromUUID(kId);
648 host_->OnDecrementBlobRefCount(kId);
649 EXPECT_TRUE(context_->registry().HasEntry(kId));
650 EXPECT_TRUE(IsBeingBuiltInHost(kId));
651
652 // We finish the blob, and verify that we send 'Done' back to the renderer.
653 BlobItemBytesResponse response(0);
654 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
655 std::vector<BlobItemBytesResponse> responses = {response};
656 host_->OnMemoryItemResponse(kId, responses);
657 ExpectDone(kId);
658 sink_.ClearMessages();
659 // Check that it's still around.
660 EXPECT_TRUE(context_->registry().HasEntry(kId));
661 EXPECT_FALSE(IsBeingBuiltInHost(kId));
662
663 // Get rid of the handle, and verify it's gone.
664 blob_data_handle.reset();
665 base::RunLoop().RunUntilIdle();
666 // Check that it's no longer around.
667 EXPECT_FALSE(context_->registry().HasEntry(kId));
668 EXPECT_FALSE(IsBeingBuiltInHost(kId));
669 }
670
671 TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStartWithHandle) {
672 const std::string kId("id");
673 // Decrement the refcount while building, after we call
674 // OnStartBuildlingBlob, except we have another handle.
675 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
676 std::string(kContentDisposition),
677 std::set<std::string>());
678 EXPECT_FALSE(host_->shutdown_for_bad_message_);
679
680 scoped_ptr<BlobDataHandle> blob_data_handle =
681 context_->GetBlobDataFromUUID(kId);
682 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
683 bool built = true;
684 blob_data_handle->RunOnConstructionComplete(
685 base::Bind(&SetPointerValue<bool>, &built));
686
687 DataElement element;
688 element.SetToBytesDescription(kDataSize);
689 std::vector<DataElement> elements = {element};
690 host_->OnStartBuildingBlob(kId, elements);
691 EXPECT_FALSE(host_->shutdown_for_bad_message_);
692
693 // Check that we got the expected request.
694 std::vector<BlobItemBytesRequest> expected_requests = {
695 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
696 ExpectRequest(kId, expected_requests);
697 sink_.ClearMessages();
698 EXPECT_TRUE(context_->registry().HasEntry(kId));
699 EXPECT_TRUE(IsBeingBuiltInHost(kId));
700 // Decrement, simulating where the ref goes out of scope in renderer.
701 host_->OnDecrementBlobRefCount(kId);
702 // We still have the blob as it's not done.
703 EXPECT_TRUE(context_->registry().HasEntry(kId));
704 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
705 EXPECT_TRUE(IsBeingBuiltInHost(kId));
706 // Cancel to clean up.
707 host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
708 // Run loop to propagate the handle decrement in the host.
709 base::RunLoop().RunUntilIdle();
710 // We still have the entry because of our earlier handle.
711 EXPECT_TRUE(context_->registry().HasEntry(kId));
712 EXPECT_FALSE(IsBeingBuiltInHost(kId));
713 sink_.ClearMessages();
714
715 // Should disappear after dropping the handle.
716 EXPECT_TRUE(blob_data_handle->IsBroken());
717 blob_data_handle.reset();
718 base::RunLoop().RunUntilIdle();
719 EXPECT_FALSE(context_->registry().HasEntry(kId));
720 }
721
722 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterRegisterWithHandle) {
723 const std::string kId("id");
724
725 // Delete host with a handle to the blob.
726 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
727 std::string(kContentDisposition),
728 std::set<std::string>());
729
730 scoped_ptr<BlobDataHandle> blob_data_handle =
731 context_->GetBlobDataFromUUID(kId);
732 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
733 bool built = true;
734 blob_data_handle->RunOnConstructionComplete(
735 base::Bind(&SetPointerValue<bool>, &built));
736 // Get rid of host, which was doing the constructing.
737 host_ = nullptr;
738 EXPECT_FALSE(blob_data_handle->IsBeingBuilt());
739 base::RunLoop().RunUntilIdle();
740 EXPECT_FALSE(built);
741
742 // Should still be there due to the handle.
743 scoped_ptr<BlobDataHandle> another_handle =
744 context_->GetBlobDataFromUUID(kId);
745 EXPECT_TRUE(another_handle);
746
747 // Should disappear after dropping both handles.
748 blob_data_handle.reset();
749 another_handle.reset();
750 base::RunLoop().RunUntilIdle();
751 EXPECT_FALSE(context_->registry().HasEntry(kId));
752 }
753
754 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnStart) {
755 const std::string kId("id");
756
757 // Host deleted after OnStartBuilding.
758 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
759 std::string(kContentDisposition),
760 std::set<std::string>());
761
762 DataElement element;
763 element.SetToBytesDescription(kDataSize);
764 std::vector<DataElement> elements = {element};
765 host_->OnStartBuildingBlob(kId, elements);
766
767 std::vector<BlobItemBytesRequest> expected_requests = {
768 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
769 ExpectRequest(kId, expected_requests);
770 sink_.ClearMessages();
771 host_ = nullptr;
772 // We need to run the message loop because of the handle in the async builder.
773 base::RunLoop().RunUntilIdle();
774 EXPECT_FALSE(context_->registry().HasEntry(kId));
775 }
776
777 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnMemoryResponse) {
778 const std::string kId("id");
779
780 // Host deleted after OnMemoryItemResponse.
781 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
782 std::string(kContentDisposition),
783 std::set<std::string>());
784
785 // Create list of two items.
786 DataElement element;
787 element.SetToBytesDescription(kDataSize);
788 std::vector<DataElement> elements = {element, element};
789 host_->OnStartBuildingBlob(kId, elements);
790 std::vector<BlobItemBytesRequest> expected_requests = {
791 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize),
792 BlobItemBytesRequest::CreateIPCRequest(1, 1, 0, kDataSize)};
793 ExpectRequest(kId, expected_requests);
794 sink_.ClearMessages();
795
796 // Send just one response so the blob isn't 'done' yet.
797 BlobItemBytesResponse response(0);
798 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
799 std::vector<BlobItemBytesResponse> responses = {response};
800 host_->OnMemoryItemResponse(kId, responses);
801 EXPECT_EQ(0u, sink_.message_count());
802
803 host_ = nullptr;
804 base::RunLoop().RunUntilIdle();
805 EXPECT_FALSE(context_->registry().HasEntry(kId));
806 }
807
808 TEST_F(BlobDispatcherHostTest, CreateBlobWithBrokenReference) {
809 const std::string kBrokenId("id1");
810 const std::string kReferencingId("id2");
811
812 // First, let's test a circular reference.
813 const std::string kCircularId("id1");
814 host_->OnRegisterBlobUUID(kCircularId, std::string(kContentType),
815 std::string(kContentDisposition), {kCircularId});
816 ExpectAndResetBadMessage();
817
818 // Next, test a blob that references a broken blob.
819 host_->OnRegisterBlobUUID(kBrokenId, std::string(kContentType),
820 std::string(kContentDisposition),
821 std::set<std::string>());
822 host_->OnCancelBuildingBlob(kBrokenId, IPCBlobCreationCancelCode::UNKNOWN);
823 EXPECT_FALSE(host_->shutdown_for_bad_message_);
824 EXPECT_TRUE(context_->GetBlobDataFromUUID(kBrokenId)->IsBroken());
825
826 // Create referencing blob. We should be broken right away, but also ignore
827 // the subsequent OnStart message.
828 host_->OnRegisterBlobUUID(kReferencingId, std::string(kContentType),
829 std::string(kContentDisposition), {kBrokenId});
830 EXPECT_TRUE(context_->GetBlobDataFromUUID(kReferencingId)->IsBroken());
831 EXPECT_FALSE(IsBeingBuiltInHost(kReferencingId));
832 EXPECT_TRUE(context_->registry().HasEntry(kReferencingId));
833 ExpectCancel(kReferencingId,
834 IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN);
835 sink_.ClearMessages();
836
837 DataElement element;
838 element.SetToBytesDescription(kDataSize);
839 std::vector<DataElement> elements = {element};
840 element.SetToBlob(kBrokenId);
841 elements.push_back(element);
842 host_->OnStartBuildingBlob(kReferencingId, elements);
843 EXPECT_EQ(0u, sink_.message_count());
844 base::RunLoop().RunUntilIdle();
845 }
846
847 TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) {
848 const std::string kId("id");
849 // Data elements for our transfer & checking messages.
850 DataElement element;
851 element.SetToBytesDescription(kDataSize);
852 std::vector<DataElement> elements = {element};
853 std::vector<BlobItemBytesRequest> expected_requests = {
854 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
855 BlobItemBytesResponse response(0);
856 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
857 std::vector<BlobItemBytesResponse> responses = {response};
858
859 scoped_refptr<TestableBlobDispatcherHost> host2(
860 new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_));
861
862 // Delete host with another host having a referencing, then dereference on
863 // second host. Verify we're still building it on first host, and then
864 // verify that a building message from the renderer will kill it.
865
866 // Test OnStartBuilding after double dereference.
867 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
868 std::string(kContentDisposition),
869 std::set<std::string>());
870 host2->OnIncrementBlobRefCount(kId);
871 host_->OnDecrementBlobRefCount(kId);
872 EXPECT_FALSE(host_->IsInUseInHost(kId));
873 host2->OnDecrementBlobRefCount(kId);
874 // So no more blob in the context, but we're still being built in host 1.
875 EXPECT_FALSE(context_->registry().HasEntry(kId));
876 EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
877 host_->OnStartBuildingBlob(kId, elements);
878 EXPECT_FALSE(host_->shutdown_for_bad_message_);
879 // We should be cleaned up.
880 EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
881 ExpectCancel(kId,
882 IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
883 sink_.ClearMessages();
884
885 // Same as above, but test OnMemoryItemResponse after double dereference.
886 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
887 std::string(kContentDisposition),
888 std::set<std::string>());
889 host2->OnIncrementBlobRefCount(kId);
890 host_->OnDecrementBlobRefCount(kId);
891 EXPECT_FALSE(host_->IsInUseInHost(kId));
892 host_->OnStartBuildingBlob(kId, elements);
893 ExpectRequest(kId, expected_requests);
894 sink_.ClearMessages();
895
896 host2->OnDecrementBlobRefCount(kId);
897 // So no more blob in the context, but we're still being built in host 1.
898 EXPECT_FALSE(context_->registry().HasEntry(kId));
899 EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
900 host_->OnMemoryItemResponse(kId, responses);
901 EXPECT_FALSE(host_->shutdown_for_bad_message_);
902 // We should be cleaned up.
903 EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
904 ExpectCancel(kId,
905 IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
906 sink_.ClearMessages();
907
908 // Same, but now for OnCancel.
909 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
910 std::string(kContentDisposition),
911 std::set<std::string>());
912 host2->OnIncrementBlobRefCount(kId);
913 host_->OnDecrementBlobRefCount(kId);
914 EXPECT_FALSE(host_->IsInUseInHost(kId));
915 host_->OnStartBuildingBlob(kId, elements);
916 ExpectRequest(kId, expected_requests);
917 sink_.ClearMessages();
918
919 host2->OnDecrementBlobRefCount(kId);
920 // So no more blob in the context, but we're still being built in host 1.
921 EXPECT_FALSE(context_->registry().HasEntry(kId));
922 EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
923 host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
924 EXPECT_FALSE(host_->shutdown_for_bad_message_);
925 // We should be cleaned up.
926 EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
927 }
928
929 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698