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

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

Powered by Google App Engine
This is Rietveld 408576698