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

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 shared memory test, and fixed memory leak 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/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 RequestMemoryCallback =
39 storage::BlobAsyncBuilderHost::RequestMemoryCallback;
40
41 namespace content {
42 namespace {
43
44 const char kContentType[] = "text/plain";
45 const char kContentDisposition[] = "content_disposition";
46 const char kData[] = "data!!";
47 const size_t kDataSize = 6;
48
49 const size_t kTestBlobStorageIPCThresholdBytes = 20;
50 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
51 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
52
53 template <typename T>
54 void SetPointerValue(T* pointer, T value) {
55 *pointer = value;
56 }
57
58 class TestableBlobDispatcherHost : public BlobDispatcherHost {
59 public:
60 TestableBlobDispatcherHost(ChromeBlobStorageContext* blob_storage_context,
61 IPC::TestSink* sink)
62 : BlobDispatcherHost(blob_storage_context), sink_(sink) {
63 this->SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes,
64 kTestBlobStorageMaxSharedMemoryBytes,
65 kTestBlobStorageMaxFileSizeBytes);
66 }
67
68 bool Send(IPC::Message* message) override { return sink_->Send(message); }
69
70 void ShutdownForBadMessage() override { shutdown_for_bad_message_ = true; }
71
72 bool shutdown_for_bad_message_ = false;
73 IPC::TestSink* sink_;
74
75 protected:
76 ~TestableBlobDispatcherHost() override {}
77
78 private:
79 friend class base::RefCountedThreadSafe<TestableBlobDispatcherHost>;
80 };
81
82 } // namespace
83
84 class BlobDispatcherHostTest : public testing::Test {
85 protected:
86 BlobDispatcherHostTest()
87 : browser_thread_bundle_(),
88 browser_context_(),
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(host_->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 storage::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, storage::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 IPC::TestSink sink_;
250 TestBrowserThreadBundle browser_thread_bundle_;
251 TestBrowserContext browser_context_;
252 ChromeBlobStorageContext* chrome_blob_storage_context_;
253 BlobStorageContext* context_ = nullptr;
254 scoped_refptr<TestableBlobDispatcherHost> host_;
255 };
256
257 TEST_F(BlobDispatcherHostTest, EmptyUUIDs) {
258 host_->OnRegisterBlobUUID("", "", "", std::set<std::string>());
259 ExpectAndResetBadMessage();
260 host_->OnStartBuildingBlob("", std::vector<DataElement>());
261 ExpectAndResetBadMessage();
262 host_->OnMemoryItemResponse("", std::vector<BlobItemBytesResponse>());
263 ExpectAndResetBadMessage();
264 host_->OnCancelBuildingBlob("", storage::IPCBlobCreationCancelCode::UNKNOWN);
265 ExpectAndResetBadMessage();
266 }
267
268 TEST_F(BlobDispatcherHostTest, Shortcut) {
269 const std::string kId = "uuid1";
270 AsyncShortcutBlobTransfer(kId);
271 EXPECT_TRUE(context_->registry().HasEntry(kId));
272 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
273 EXPECT_TRUE(handle);
274
275 DataElement expected;
276 expected.SetToBytes(kData, kDataSize);
277 std::vector<DataElement> elements = {expected};
278 ExpectHandleEqualsData(handle.get(), elements);
279 }
280
281 TEST_F(BlobDispatcherHostTest, RegularTransfer) {
282 const std::string kId = "uuid1";
283 AsyncBlobTransfer(kId);
284 EXPECT_TRUE(context_->registry().HasEntry(kId));
285 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
286 EXPECT_TRUE(handle);
287
288 DataElement expected;
289 expected.SetToBytes(kData, kDataSize);
290 std::vector<DataElement> elements = {expected};
291 ExpectHandleEqualsData(handle.get(), elements);
292 }
293
294 TEST_F(BlobDispatcherHostTest, SharedMemoryTransfer) {
295 const std::string kId = "uuid1";
296 const size_t kLargeSize = kTestBlobStorageMaxSharedMemoryBytes * 2;
297 std::vector<base::SharedMemoryHandle> shared_memory_handles;
298
299 ExpectBlobNotExist(kId);
300 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
301 std::string(kContentDisposition),
302 std::set<std::string>());
303 // Grab the handle.
304 scoped_ptr<BlobDataHandle> blob_data_handle =
305 context_->GetBlobDataFromUUID(kId);
306 bool built = false;
307 blob_data_handle->RunOnConstructionComplete(
308 base::Bind(&SetPointerValue<bool>, &built));
309 EXPECT_FALSE(built);
310
311 EXPECT_FALSE(host_->shutdown_for_bad_message_);
312 DataElement element;
313 element.SetToBytesDescription(kLargeSize);
314 std::vector<DataElement> elements = {element};
315 host_->OnStartBuildingBlob(kId, elements);
316 EXPECT_FALSE(host_->shutdown_for_bad_message_);
317
318 // Expect our first request.
319 std::vector<BlobItemBytesRequest> expected_requests = {
320 BlobItemBytesRequest::CreateSharedMemoryRequest(
321 0 /* request_number */, 0 /* renderer_item_index */,
322 0 /* renderer_item_offset */,
323 static_cast<uint64_t>(
324 kTestBlobStorageMaxSharedMemoryBytes) /* size */,
325 0 /* handle_index */, 0 /* handle_offset */)};
326 ExpectRequestWithSharedMemoryHandles(kId, expected_requests,
327 &shared_memory_handles);
328 sink_.ClearMessages();
329
330 // Populate the shared memory.
331 EXPECT_EQ(1u, shared_memory_handles.size());
332 EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0]));
333 {
334 base::SharedMemory memory(
335 base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false);
336 memory.Map(kTestBlobStorageMaxSharedMemoryBytes);
337 std::memset(memory.memory(), 'X', kTestBlobStorageMaxSharedMemoryBytes);
338 memory.Close();
339 }
340
341 // Send the confirmation.
342 std::vector<BlobItemBytesResponse> responses = {BlobItemBytesResponse(0)};
343 host_->OnMemoryItemResponse(kId, responses);
344
345 // Expect our second request.
346 expected_requests = {BlobItemBytesRequest::CreateSharedMemoryRequest(
347 1 /* request_number */, 0 /* renderer_item_index */,
348 static_cast<uint64_t>(
349 kTestBlobStorageMaxSharedMemoryBytes) /* renderer_item_offset */,
350 static_cast<uint64_t>(kTestBlobStorageMaxSharedMemoryBytes) /* size */,
351 0 /* handle_index */, 0 /* handle_offset */)};
352 ExpectRequestWithSharedMemoryHandles(kId, expected_requests,
353 &shared_memory_handles);
354 sink_.ClearMessages();
355
356 // Populate the shared memory.
357 EXPECT_EQ(1u, shared_memory_handles.size());
358 EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0]));
359 {
360 base::SharedMemory memory(
361 base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false);
362 memory.Map(kTestBlobStorageMaxSharedMemoryBytes);
363 std::memset(memory.memory(), 'Z', kTestBlobStorageMaxSharedMemoryBytes);
364 memory.Close();
365 }
366 // Send the confirmation.
367 responses = {BlobItemBytesResponse(1)};
368 host_->OnMemoryItemResponse(kId, responses);
369
370 ExpectDone(kId);
371 sink_.ClearMessages();
372 base::RunLoop().RunUntilIdle();
373 EXPECT_TRUE(built);
374 EXPECT_TRUE(context_->registry().HasEntry(kId));
375 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
376 EXPECT_TRUE(handle);
377
378 DataElement expected;
379 expected.SetToAllocatedBytes(kLargeSize / 2);
380 std::memset(expected.mutable_bytes(), 'X', kLargeSize / 2);
381 elements = {expected};
382 std::memset(expected.mutable_bytes(), 'Z', kLargeSize / 2);
383 elements.push_back(expected);
384 ExpectHandleEqualsData(handle.get(), elements);
385 }
386
387 TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
388 const std::string kId("id");
389 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
390 ExpectAndResetBadMessage();
391
392 // Start building blob.
393 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
394 std::string(kContentDisposition),
395 std::set<std::string>());
396 EXPECT_FALSE(host_->shutdown_for_bad_message_);
397 DataElement element;
398 element.SetToBytesDescription(kDataSize);
399 std::vector<DataElement> elements = {element};
400 host_->OnStartBuildingBlob(kId, elements);
401 // It should have requested memory here.
402 EXPECT_FALSE(host_->shutdown_for_bad_message_);
403 sink_.ClearMessages();
404
405 // Cancel in middle of construction.
406 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
407 EXPECT_TRUE(context_->registry().HasEntry(kId));
408 EXPECT_TRUE(host_->IsInUseInHost(kId));
409 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
410 // Check that's it's broken.
411 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
412 EXPECT_TRUE(handle->IsBroken());
413 handle.reset();
414 base::RunLoop().RunUntilIdle();
415
416 // Get rid of it in the host.
417 host_->OnDecrementBlobRefCount(kId);
418 ExpectBlobNotExist(kId);
419
420 // Create blob again to verify we don't have any old construction state lying
421 // around.
422 AsyncBlobTransfer(kId);
423
424 // Check data.
425 handle = context_->GetBlobDataFromUUID(kId);
426 EXPECT_TRUE(handle);
427 DataElement expected;
428 expected.SetToBytes(kData, kDataSize);
429 std::vector<DataElement> expecteds = {expected};
430 ExpectHandleEqualsData(handle.get(), expecteds);
431
432 // Verify we can't cancel after the fact.
433 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
434 ExpectAndResetBadMessage();
435 }
436
437 TEST_F(BlobDispatcherHostTest, BlobDataWithHostDeletion) {
438 // Build up a basic blob.
439 const std::string kId("id");
440 AsyncShortcutBlobTransfer(kId);
441 scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
442 EXPECT_TRUE(handle);
443
444 // Kill the host.
445 host_ = nullptr;
446 base::RunLoop().RunUntilIdle();
447 // Should still be there due to the handle.
448 scoped_ptr<BlobDataHandle> another_handle =
449 context_->GetBlobDataFromUUID(kId);
450 EXPECT_TRUE(another_handle);
451
452 // Should disappear after dropping both handles.
453 handle.reset();
454 another_handle.reset();
455 base::RunLoop().RunUntilIdle();
456
457 handle = context_->GetBlobDataFromUUID(kId);
458 EXPECT_FALSE(handle);
459 }
460
461 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) {
462 const std::string kId("id");
463
464 // Start building blob.
465 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
466 std::string(kContentDisposition),
467 std::set<std::string>());
468
469 // Grab the handle.
470 scoped_ptr<BlobDataHandle> blob_data_handle =
471 context_->GetBlobDataFromUUID(kId);
472 EXPECT_TRUE(blob_data_handle);
473 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
474 bool built = false;
475 blob_data_handle->RunOnConstructionComplete(
476 base::Bind(&SetPointerValue<bool>, &built));
477
478 // Continue building.
479 DataElement element;
480 element.SetToBytesDescription(kDataSize);
481 std::vector<DataElement> elements = {element};
482 host_->OnStartBuildingBlob(kId, elements);
483 sink_.ClearMessages();
484
485 // Send data.
486 BlobItemBytesResponse response(0);
487 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
488 std::vector<BlobItemBytesResponse> responses = {response};
489 sink_.ClearMessages();
490 host_->OnMemoryItemResponse(kId, responses);
491
492 ExpectDone(kId);
493 base::RunLoop().RunUntilIdle();
494 EXPECT_TRUE(built);
495 }
496
497 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileShortcutConstructing) {
498 const std::string kId("id");
499
500 // Start building blob.
501 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
502 std::string(kContentDisposition),
503 std::set<std::string>());
504
505 // Grab the handle.
506 scoped_ptr<BlobDataHandle> blob_data_handle =
507 context_->GetBlobDataFromUUID(kId);
508 EXPECT_TRUE(blob_data_handle);
509 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
510 bool built = false;
511 blob_data_handle->RunOnConstructionComplete(
512 base::Bind(&SetPointerValue<bool>, &built));
513
514 // Continue building.
515 DataElement element;
516 element.SetToBytes(kData, kDataSize);
517 std::vector<DataElement> elements = {element};
518 host_->OnStartBuildingBlob(kId, elements);
519 ExpectDone(kId);
520 base::RunLoop().RunUntilIdle();
521 EXPECT_TRUE(built);
522 }
523
524 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructingCancelled) {
525 const std::string kId("id");
526
527 // Start building blob.
528 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
529 std::string(kContentDisposition),
530 std::set<std::string>());
531
532 // Grab the handle.
533 scoped_ptr<BlobDataHandle> blob_data_handle =
534 context_->GetBlobDataFromUUID(kId);
535 EXPECT_TRUE(blob_data_handle);
536 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
537 bool built = true;
538 blob_data_handle->RunOnConstructionComplete(
539 base::Bind(&SetPointerValue<bool>, &built));
540
541 // Cancel in middle of construction.
542 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
543 base::RunLoop().RunUntilIdle();
544 EXPECT_TRUE(context_->registry().HasEntry(kId));
545 EXPECT_TRUE(host_->IsInUseInHost(kId));
546 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
547 EXPECT_TRUE(blob_data_handle->IsBroken());
548 EXPECT_FALSE(built);
549 built = true;
550 blob_data_handle->RunOnConstructionComplete(
551 base::Bind(&SetPointerValue<bool>, &built));
552 EXPECT_FALSE(built);
553
554 // Remove it.
555 blob_data_handle.reset();
556 base::RunLoop().RunUntilIdle();
557 EXPECT_TRUE(context_->registry().HasEntry(kId));
558 host_->OnDecrementBlobRefCount(kId);
559 ExpectBlobNotExist(kId);
560 }
561
562 TEST_F(BlobDispatcherHostTest, DecrementRefAfterRegister) {
563 const std::string kId("id");
564 // Decrement the refcount while building (renderer blob gc'd before
565 // construction was completed).
566 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
567 std::string(kContentDisposition),
568 std::set<std::string>());
569 EXPECT_TRUE(context_->registry().HasEntry(kId));
570 host_->OnDecrementBlobRefCount(kId);
571 EXPECT_FALSE(context_->registry().HasEntry(kId));
572 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
573 ExpectCancel(
574 kId,
575 storage::IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
576 sink_.ClearMessages();
577
578 // Do the same, but this time grab a handle before we decrement.
579 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
580 std::string(kContentDisposition),
581 std::set<std::string>());
582 scoped_ptr<BlobDataHandle> blob_data_handle =
583 context_->GetBlobDataFromUUID(kId);
584 host_->OnDecrementBlobRefCount(kId);
585 EXPECT_TRUE(context_->registry().HasEntry(kId));
586 EXPECT_TRUE(host_->IsBeingBuiltInHost(kId));
587
588 // Finish up the blob, and verify we got the done message.
589 DataElement element;
590 element.SetToBytes(kData, kDataSize);
591 std::vector<DataElement> elements = {element};
592 host_->OnStartBuildingBlob(kId, elements);
593 EXPECT_FALSE(host_->shutdown_for_bad_message_);
594 ExpectDone(kId);
595 sink_.ClearMessages();
596 // Get rid of the handle, and verify it's gone.
597 blob_data_handle.reset();
598 base::RunLoop().RunUntilIdle();
599 // Check that it's no longer around.
600 EXPECT_FALSE(context_->registry().HasEntry(kId));
601 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
602 }
603
604 TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) {
605 const std::string kId("id");
606
607 // Decrement the refcount while building, after we call OnStartBuildlingBlob.
608 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
609 std::string(kContentDisposition),
610 std::set<std::string>());
611 EXPECT_FALSE(host_->shutdown_for_bad_message_);
612 DataElement element;
613 element.SetToBytesDescription(kDataSize);
614 std::vector<DataElement> elements = {element};
615 host_->OnStartBuildingBlob(kId, elements);
616 EXPECT_FALSE(host_->shutdown_for_bad_message_);
617
618 std::vector<BlobItemBytesRequest> expected_requests = {
619 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
620 ExpectRequest(kId, expected_requests);
621 sink_.ClearMessages();
622 EXPECT_TRUE(context_->registry().HasEntry(kId));
623 host_->OnDecrementBlobRefCount(kId);
624 EXPECT_FALSE(context_->registry().HasEntry(kId));
625 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
626 ExpectCancel(
627 kId,
628 storage::IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
629 sink_.ClearMessages();
630
631 // Do the same, but this time grab a handle to keep it alive.
632 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
633 std::string(kContentDisposition),
634 std::set<std::string>());
635 EXPECT_FALSE(host_->shutdown_for_bad_message_);
636 host_->OnStartBuildingBlob(kId, elements);
637 EXPECT_FALSE(host_->shutdown_for_bad_message_);
638 ExpectRequest(kId, expected_requests);
639 sink_.ClearMessages();
640 EXPECT_TRUE(context_->registry().HasEntry(kId));
641 // Grab the handle before decrementing.
642 scoped_ptr<BlobDataHandle> blob_data_handle =
643 context_->GetBlobDataFromUUID(kId);
644 host_->OnDecrementBlobRefCount(kId);
645 EXPECT_TRUE(context_->registry().HasEntry(kId));
646 EXPECT_TRUE(host_->IsBeingBuiltInHost(kId));
647
648 // We finish the blob, and verify that we send 'Done' back to the renderer.
649 BlobItemBytesResponse response(0);
650 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
651 std::vector<BlobItemBytesResponse> responses = {response};
652 host_->OnMemoryItemResponse(kId, responses);
653 ExpectDone(kId);
654 sink_.ClearMessages();
655 // Check that it's still around.
656 EXPECT_TRUE(context_->registry().HasEntry(kId));
657 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
658
659 // Get rid of the handle, and verify it's gone.
660 blob_data_handle.reset();
661 base::RunLoop().RunUntilIdle();
662 // Check that it's no longer around.
663 EXPECT_FALSE(context_->registry().HasEntry(kId));
664 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
665 }
666
667 TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStartWithHandle) {
668 const std::string kId("id");
669 // Case 3: Decrement the refcount while building, after we call
670 // OnStartBuildlingBlob, except we have another handle.
671 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
672 std::string(kContentDisposition),
673 std::set<std::string>());
674 EXPECT_FALSE(host_->shutdown_for_bad_message_);
675
676 scoped_ptr<BlobDataHandle> blob_data_handle =
677 context_->GetBlobDataFromUUID(kId);
678 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
679 bool built = true;
680 blob_data_handle->RunOnConstructionComplete(
681 base::Bind(&SetPointerValue<bool>, &built));
682
683 DataElement element;
684 element.SetToBytesDescription(kDataSize);
685 std::vector<DataElement> elements = {element};
686 host_->OnStartBuildingBlob(kId, elements);
687 EXPECT_FALSE(host_->shutdown_for_bad_message_);
688
689 // Check that we got the expected request.
690 std::vector<BlobItemBytesRequest> expected_requests = {
691 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
692 ExpectRequest(kId, expected_requests);
693 sink_.ClearMessages();
694 EXPECT_TRUE(context_->registry().HasEntry(kId));
695 EXPECT_TRUE(host_->IsBeingBuiltInHost(kId));
696 // Decrement, simulating where the ref goes out of scope in renderer.
697 host_->OnDecrementBlobRefCount(kId);
698 // We still have the blob as it's not done.
699 EXPECT_TRUE(context_->registry().HasEntry(kId));
700 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
701 EXPECT_TRUE(host_->IsBeingBuiltInHost(kId));
702 // Cancel to clean up.
703 host_->OnCancelBuildingBlob(kId, storage::IPCBlobCreationCancelCode::UNKNOWN);
704 // Run loop to propagate the handle decrement in the host.
705 base::RunLoop().RunUntilIdle();
706 // We still have the entry because of our earlier handle.
707 EXPECT_TRUE(context_->registry().HasEntry(kId));
708 EXPECT_FALSE(host_->IsBeingBuiltInHost(kId));
709 sink_.ClearMessages();
710
711 // Should disappear after dropping the handle.
712 EXPECT_TRUE(blob_data_handle->IsBroken());
713 blob_data_handle.reset();
714 base::RunLoop().RunUntilIdle();
715 EXPECT_FALSE(context_->registry().HasEntry(kId));
716 }
717
718 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterRegisterWithHandle) {
719 const std::string kId("id");
720
721 // Delete host with a handle to the blob.
722 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
723 std::string(kContentDisposition),
724 std::set<std::string>());
725
726 scoped_ptr<BlobDataHandle> blob_data_handle =
727 context_->GetBlobDataFromUUID(kId);
728 EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
729 bool built = true;
730 blob_data_handle->RunOnConstructionComplete(
731 base::Bind(&SetPointerValue<bool>, &built));
732 // Get rid of host, which was doing the constructing.
733 host_ = nullptr;
734 EXPECT_FALSE(blob_data_handle->IsBeingBuilt());
735 base::RunLoop().RunUntilIdle();
736 EXPECT_FALSE(built);
737
738 // Should still be there due to the handle.
739 scoped_ptr<BlobDataHandle> another_handle =
740 context_->GetBlobDataFromUUID(kId);
741 EXPECT_TRUE(another_handle);
742
743 // Should disappear after dropping both handles.
744 blob_data_handle.reset();
745 another_handle.reset();
746 base::RunLoop().RunUntilIdle();
747 EXPECT_FALSE(context_->registry().HasEntry(kId));
748 }
749
750 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnStart) {
751 const std::string kId("id");
752
753 // Host deleted after OnStartBuilding.
754 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
755 std::string(kContentDisposition),
756 std::set<std::string>());
757
758 DataElement element;
759 element.SetToBytesDescription(kDataSize);
760 std::vector<DataElement> elements = {element};
761 host_->OnStartBuildingBlob(kId, elements);
762
763 std::vector<BlobItemBytesRequest> expected_requests = {
764 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
765 ExpectRequest(kId, expected_requests);
766 sink_.ClearMessages();
767 host_ = nullptr;
768 // We need to run the message loop because of the handle in the async builder.
769 base::RunLoop().RunUntilIdle();
770 EXPECT_FALSE(context_->registry().HasEntry(kId));
771 }
772
773 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnMemoryResponse) {
774 const std::string kId("id");
775
776 // Host deleted after OnMemoryItemResponse.
777 host_->OnRegisterBlobUUID(kId, std::string(kContentType),
778 std::string(kContentDisposition),
779 std::set<std::string>());
780
781 // Create list of two items.
782 DataElement element;
783 element.SetToBytesDescription(kDataSize);
784 std::vector<DataElement> elements = {element, element};
785 host_->OnStartBuildingBlob(kId, elements);
786 std::vector<BlobItemBytesRequest> expected_requests = {
787 BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize),
788 BlobItemBytesRequest::CreateIPCRequest(1, 1, 0, kDataSize)};
789 ExpectRequest(kId, expected_requests);
790 sink_.ClearMessages();
791
792 // Send just one response so the blob isn't 'done' yet.
793 BlobItemBytesResponse response(0);
794 std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
795 std::vector<BlobItemBytesResponse> responses = {response};
796 host_->OnMemoryItemResponse(kId, responses);
797 EXPECT_EQ(0u, sink_.message_count());
798
799 host_ = nullptr;
800 base::RunLoop().RunUntilIdle();
801 EXPECT_FALSE(context_->registry().HasEntry(kId));
802 }
803
804 TEST_F(BlobDispatcherHostTest, CreateBlobWithBrokenReference) {
805 const std::string kBrokenId("id1");
806 const std::string kReferencingId("id2");
807
808 // First, let's test a circular reference.
809 const std::string kCircularId("id1");
810 host_->OnRegisterBlobUUID(kCircularId, std::string(kContentType),
811 std::string(kContentDisposition), {kCircularId});
812 ExpectAndResetBadMessage();
813
814 // Next, test a blob that references a broken blob.
815 host_->OnRegisterBlobUUID(kBrokenId, std::string(kContentType),
816 std::string(kContentDisposition),
817 std::set<std::string>());
818 host_->OnCancelBuildingBlob(kBrokenId,
819 storage::IPCBlobCreationCancelCode::UNKNOWN);
820 EXPECT_TRUE(context_->GetBlobDataFromUUID(kBrokenId)->IsBroken());
821
822 // Create referencing blob. We should be broken right away, but also ignore
823 // the subsequent OnStart message.
824 host_->OnRegisterBlobUUID(kReferencingId, std::string(kContentType),
825 std::string(kContentDisposition), {kBrokenId});
826 EXPECT_TRUE(context_->GetBlobDataFromUUID(kReferencingId)->IsBroken());
827 EXPECT_FALSE(host_->IsBeingBuiltInHost(kReferencingId));
828 EXPECT_TRUE(context_->registry().HasEntry(kReferencingId));
829 ExpectCancel(kReferencingId,
830 storage::IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN);
831 sink_.ClearMessages();
832
833 DataElement element;
834 element.SetToBytesDescription(kDataSize);
835 std::vector<DataElement> elements = {element};
836 element.SetToBlob(kBrokenId);
837 elements.push_back(element);
838 host_->OnStartBuildingBlob(kReferencingId, elements);
839 EXPECT_EQ(0u, sink_.message_count());
840 base::RunLoop().RunUntilIdle();
841 }
842
843 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698