1 // Copyright 2014 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.
5 #include "content/browser/cache_storage/cache_storage_cache.h"
7 #include "base/files/file_path.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_split.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "content/browser/fileapi/chrome_blob_storage_context.h"
15 #include "content/browser/fileapi/mock_url_request_delegate.h"
16 #include "content/browser/quota/mock_quota_manager_proxy.h"
17 #include "content/common/cache_storage/cache_storage_types.h"
18 #include "content/common/service_worker/service_worker_types.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/common/referrer.h"
21 #include "content/public/test/test_browser_context.h"
22 #include "content/public/test/test_browser_thread_bundle.h"
23 #include "net/base/test_completion_callback.h"
24 #include "net/url_request/url_request_context.h"
25 #include "net/url_request/url_request_context_getter.h"
26 #include "net/url_request/url_request_job_factory_impl.h"
27 #include "storage/browser/blob/blob_data_builder.h"
28 #include "storage/browser/blob/blob_data_handle.h"
29 #include "storage/browser/blob/blob_data_snapshot.h"
30 #include "storage/browser/blob/blob_storage_context.h"
31 #include "storage/browser/blob/blob_url_request_job_factory.h"
32 #include "storage/browser/quota/quota_manager_proxy.h"
33 #include "testing/gtest/include/gtest/gtest.h"
38 const char kTestData
[] = "Hello World";
40 // Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
42 scoped_ptr
<storage::BlobProtocolHandler
> CreateMockBlobProtocolHandler(
43 storage::BlobStorageContext
* blob_storage_context
) {
44 // The FileSystemContext and thread task runner are not actually used but a
45 // task runner is needed to avoid a DCHECK in BlobURLRequestJob ctor.
46 return make_scoped_ptr(new storage::BlobProtocolHandler(
47 blob_storage_context
, NULL
, base::ThreadTaskRunnerHandle::Get().get()));
50 // A disk_cache::Backend wrapper that can delay operations.
51 class DelayableBackend
: public disk_cache::Backend
{
53 DelayableBackend(scoped_ptr
<disk_cache::Backend
> backend
)
54 : backend_(backend
.Pass()), delay_open_(false) {}
56 // disk_cache::Backend overrides
57 net::CacheType
GetCacheType() const override
{
58 return backend_
->GetCacheType();
60 int32
GetEntryCount() const override
{ return backend_
->GetEntryCount(); }
61 int OpenEntry(const std::string
& key
,
62 disk_cache::Entry
** entry
,
63 const CompletionCallback
& callback
) override
{
65 open_entry_callback_
=
66 base::Bind(&DelayableBackend::OpenEntryDelayedImpl
,
67 base::Unretained(this), key
, entry
, callback
);
68 return net::ERR_IO_PENDING
;
71 return backend_
->OpenEntry(key
, entry
, callback
);
73 int CreateEntry(const std::string
& key
,
74 disk_cache::Entry
** entry
,
75 const CompletionCallback
& callback
) override
{
76 return backend_
->CreateEntry(key
, entry
, callback
);
78 int DoomEntry(const std::string
& key
,
79 const CompletionCallback
& callback
) override
{
80 return backend_
->DoomEntry(key
, callback
);
82 int DoomAllEntries(const CompletionCallback
& callback
) override
{
83 return backend_
->DoomAllEntries(callback
);
85 int DoomEntriesBetween(base::Time initial_time
,
87 const CompletionCallback
& callback
) override
{
88 return backend_
->DoomEntriesBetween(initial_time
, end_time
, callback
);
90 int DoomEntriesSince(base::Time initial_time
,
91 const CompletionCallback
& callback
) override
{
92 return backend_
->DoomEntriesSince(initial_time
, callback
);
94 scoped_ptr
<Iterator
> CreateIterator() override
{
95 return backend_
->CreateIterator();
97 void GetStats(base::StringPairs
* stats
) override
{
98 return backend_
->GetStats(stats
);
100 void OnExternalCacheHit(const std::string
& key
) override
{
101 return backend_
->OnExternalCacheHit(key
);
104 // Call to continue a delayed open.
105 void OpenEntryContinue() {
106 EXPECT_FALSE(open_entry_callback_
.is_null());
107 open_entry_callback_
.Run();
110 void set_delay_open(bool value
) { delay_open_
= value
; }
113 void OpenEntryDelayedImpl(const std::string
& key
,
114 disk_cache::Entry
** entry
,
115 const CompletionCallback
& callback
) {
116 int rv
= backend_
->OpenEntry(key
, entry
, callback
);
117 if (rv
!= net::ERR_IO_PENDING
)
121 scoped_ptr
<disk_cache::Backend
> backend_
;
123 base::Closure open_entry_callback_
;
126 void CopyBody(const storage::BlobDataHandle
& blob_handle
, std::string
* output
) {
127 *output
= std::string();
128 scoped_ptr
<storage::BlobDataSnapshot
> data
= blob_handle
.CreateSnapshot();
129 const auto& items
= data
->items();
130 for (const auto& item
: items
) {
131 switch (item
->type()) {
132 case storage::DataElement::TYPE_BYTES
: {
133 output
->append(item
->bytes(), item
->length());
136 case storage::DataElement::TYPE_DISK_CACHE_ENTRY
: {
137 disk_cache::Entry
* entry
= item
->disk_cache_entry();
138 int32 body_size
= entry
->GetDataSize(item
->disk_cache_stream_index());
140 scoped_refptr
<net::IOBuffer
> io_buffer
= new net::IOBuffer(body_size
);
141 net::TestCompletionCallback callback
;
143 entry
->ReadData(item
->disk_cache_stream_index(), 0, io_buffer
.get(),
144 body_size
, callback
.callback());
145 if (rv
== net::ERR_IO_PENDING
)
146 rv
= callback
.WaitForResult();
147 EXPECT_EQ(body_size
, rv
);
149 output
->append(io_buffer
->data(), rv
);
152 default: { ADD_FAILURE() << "invalid response blob type"; } break;
157 bool ResponseMetadataEqual(const ServiceWorkerResponse
& expected
,
158 const ServiceWorkerResponse
& actual
) {
159 EXPECT_EQ(expected
.status_code
, actual
.status_code
);
160 if (expected
.status_code
!= actual
.status_code
)
162 EXPECT_EQ(expected
.status_text
, actual
.status_text
);
163 if (expected
.status_text
!= actual
.status_text
)
165 EXPECT_EQ(expected
.url
, actual
.url
);
166 if (expected
.url
!= actual
.url
)
168 EXPECT_EQ(expected
.blob_size
, actual
.blob_size
);
169 if (expected
.blob_size
!= actual
.blob_size
)
172 if (expected
.blob_size
== 0) {
173 EXPECT_STREQ("", actual
.blob_uuid
.c_str());
174 if (!actual
.blob_uuid
.empty())
177 EXPECT_STRNE("", actual
.blob_uuid
.c_str());
178 if (actual
.blob_uuid
.empty())
185 bool ResponseBodiesEqual(const std::string
& expected_body
,
186 const storage::BlobDataHandle
& actual_body_handle
) {
187 std::string actual_body
;
188 CopyBody(actual_body_handle
, &actual_body
);
189 return expected_body
== actual_body
;
194 // A CacheStorageCache that can optionally delay during backend creation.
195 class TestCacheStorageCache
: public CacheStorageCache
{
197 TestCacheStorageCache(
199 const base::FilePath
& path
,
200 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
201 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
202 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
203 : CacheStorageCache(origin
,
205 request_context_getter
,
208 delay_backend_creation_(false) {}
210 void CreateBackend(const ErrorCallback
& callback
) override
{
211 backend_creation_callback_
= callback
;
212 if (delay_backend_creation_
)
214 ContinueCreateBackend();
217 void ContinueCreateBackend() {
218 CacheStorageCache::CreateBackend(backend_creation_callback_
);
221 void set_delay_backend_creation(bool delay
) {
222 delay_backend_creation_
= delay
;
225 // Swap the existing backend with a delayable one. The backend must have been
226 // created before calling this.
227 DelayableBackend
* UseDelayableBackend() {
228 EXPECT_TRUE(backend_
);
229 DelayableBackend
* delayable_backend
= new DelayableBackend(backend_
.Pass());
230 backend_
.reset(delayable_backend
);
231 return delayable_backend
;
235 ~TestCacheStorageCache() override
{}
237 bool delay_backend_creation_
;
238 ErrorCallback backend_creation_callback_
;
240 DISALLOW_COPY_AND_ASSIGN(TestCacheStorageCache
);
243 class CacheStorageCacheTest
: public testing::Test
{
245 CacheStorageCacheTest()
246 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
247 callback_error_(CACHE_STORAGE_OK
),
248 callback_closed_(false) {}
250 void SetUp() override
{
251 ChromeBlobStorageContext
* blob_storage_context
=
252 ChromeBlobStorageContext::GetFor(&browser_context_
);
253 // Wait for chrome_blob_storage_context to finish initializing.
254 base::RunLoop().RunUntilIdle();
255 blob_storage_context_
= blob_storage_context
->context();
257 quota_manager_proxy_
= new MockQuotaManagerProxy(
258 nullptr, base::ThreadTaskRunnerHandle::Get().get());
260 url_request_job_factory_
.reset(new net::URLRequestJobFactoryImpl
);
261 url_request_job_factory_
->SetProtocolHandler(
262 "blob", CreateMockBlobProtocolHandler(blob_storage_context
->context()));
264 net::URLRequestContext
* url_request_context
=
265 browser_context_
.GetRequestContext()->GetURLRequestContext();
267 url_request_context
->set_job_factory(url_request_job_factory_
.get());
269 CreateRequests(blob_storage_context
);
272 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
273 base::FilePath path
= MemoryOnly() ? base::FilePath() : temp_dir_
.path();
275 cache_
= make_scoped_refptr(new TestCacheStorageCache(
276 GURL("http://example.com"), path
, browser_context_
.GetRequestContext(),
277 quota_manager_proxy_
, blob_storage_context
->context()->AsWeakPtr()));
280 void TearDown() override
{
281 quota_manager_proxy_
->SimulateQuotaManagerDestroyed();
282 base::RunLoop().RunUntilIdle();
285 void CreateRequests(ChromeBlobStorageContext
* blob_storage_context
) {
286 ServiceWorkerHeaderMap headers
;
287 headers
.insert(std::make_pair("a", "a"));
288 headers
.insert(std::make_pair("b", "b"));
290 ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET",
291 headers
, Referrer(), false);
293 ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
294 "GET", headers
, Referrer(), false);
296 std::string expected_response
;
297 for (int i
= 0; i
< 100; ++i
)
298 expected_blob_data_
+= kTestData
;
300 scoped_ptr
<storage::BlobDataBuilder
> blob_data(
301 new storage::BlobDataBuilder("blob-id:myblob"));
302 blob_data
->AppendData(expected_blob_data_
);
305 blob_storage_context
->context()->AddFinishedBlob(blob_data
.get());
307 body_response_
= ServiceWorkerResponse(
308 GURL("http://example.com/body.html"), 200, "OK",
309 blink::WebServiceWorkerResponseTypeDefault
, headers
,
310 blob_handle_
->uuid(), expected_blob_data_
.size(), GURL(),
311 blink::WebServiceWorkerResponseErrorUnknown
);
313 no_body_response_
= ServiceWorkerResponse(
314 GURL("http://example.com/no_body.html"), 200, "OK",
315 blink::WebServiceWorkerResponseTypeDefault
, headers
, "", 0, GURL(),
316 blink::WebServiceWorkerResponseErrorUnknown
);
319 scoped_ptr
<ServiceWorkerFetchRequest
> CopyFetchRequest(
320 const ServiceWorkerFetchRequest
& request
) {
321 return make_scoped_ptr(new ServiceWorkerFetchRequest(
322 request
.url
, request
.method
, request
.headers
, request
.referrer
,
326 CacheStorageError
BatchOperation(
327 const std::vector
<CacheStorageBatchOperation
>& operations
) {
328 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
330 cache_
->BatchOperation(
332 base::Bind(&CacheStorageCacheTest::ErrorTypeCallback
,
333 base::Unretained(this), base::Unretained(loop
.get())));
334 // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
335 // once the cache uses a passed in task runner instead of the CACHE thread.
338 return callback_error_
;
341 bool Put(const ServiceWorkerFetchRequest
& request
,
342 const ServiceWorkerResponse
& response
) {
343 CacheStorageBatchOperation operation
;
344 operation
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
345 operation
.request
= request
;
346 operation
.response
= response
;
348 CacheStorageError error
=
349 BatchOperation(std::vector
<CacheStorageBatchOperation
>(1, operation
));
350 return error
== CACHE_STORAGE_OK
;
353 bool Match(const ServiceWorkerFetchRequest
& request
) {
354 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
357 CopyFetchRequest(request
),
358 base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback
,
359 base::Unretained(this), base::Unretained(loop
.get())));
362 return callback_error_
== CACHE_STORAGE_OK
;
365 bool MatchAll(scoped_ptr
<CacheStorageCache::Responses
>* responses
,
366 scoped_ptr
<CacheStorageCache::BlobDataHandles
>* body_handles
) {
368 cache_
->MatchAll(base::Bind(
369 &CacheStorageCacheTest::ResponsesAndErrorCallback
,
370 base::Unretained(this), loop
.QuitClosure(), responses
, body_handles
));
372 return callback_error_
== CACHE_STORAGE_OK
;
375 bool Delete(const ServiceWorkerFetchRequest
& request
) {
376 CacheStorageBatchOperation operation
;
377 operation
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE
;
378 operation
.request
= request
;
380 CacheStorageError error
=
381 BatchOperation(std::vector
<CacheStorageBatchOperation
>(1, operation
));
382 return error
== CACHE_STORAGE_OK
;
386 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
388 cache_
->Keys(base::Bind(&CacheStorageCacheTest::RequestsCallback
,
389 base::Unretained(this),
390 base::Unretained(loop
.get())));
393 return callback_error_
== CACHE_STORAGE_OK
;
397 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
399 cache_
->Close(base::Bind(&CacheStorageCacheTest::CloseCallback
,
400 base::Unretained(this),
401 base::Unretained(loop
.get())));
403 return callback_closed_
;
406 void RequestsCallback(base::RunLoop
* run_loop
,
407 CacheStorageError error
,
408 scoped_ptr
<CacheStorageCache::Requests
> requests
) {
409 callback_error_
= error
;
410 callback_strings_
.clear();
412 for (size_t i
= 0u; i
< requests
->size(); ++i
)
413 callback_strings_
.push_back(requests
->at(i
).url
.spec());
419 void ErrorTypeCallback(base::RunLoop
* run_loop
, CacheStorageError error
) {
420 callback_error_
= error
;
425 void SequenceCallback(int sequence
,
427 base::RunLoop
* run_loop
,
428 CacheStorageError error
) {
429 *sequence_out
= sequence
;
430 callback_error_
= error
;
435 void ResponseAndErrorCallback(
436 base::RunLoop
* run_loop
,
437 CacheStorageError error
,
438 scoped_ptr
<ServiceWorkerResponse
> response
,
439 scoped_ptr
<storage::BlobDataHandle
> body_handle
) {
440 callback_error_
= error
;
441 callback_response_
= response
.Pass();
442 callback_response_data_
.reset();
443 if (error
== CACHE_STORAGE_OK
&& !callback_response_
->blob_uuid
.empty())
444 callback_response_data_
= body_handle
.Pass();
450 void ResponsesAndErrorCallback(
451 const base::Closure
& quit_closure
,
452 scoped_ptr
<CacheStorageCache::Responses
>* responses_out
,
453 scoped_ptr
<CacheStorageCache::BlobDataHandles
>* body_handles_out
,
454 CacheStorageError error
,
455 scoped_ptr
<CacheStorageCache::Responses
> responses
,
456 scoped_ptr
<CacheStorageCache::BlobDataHandles
> body_handles
) {
457 callback_error_
= error
;
458 responses_out
->swap(responses
);
459 body_handles_out
->swap(body_handles
);
463 void CloseCallback(base::RunLoop
* run_loop
) {
464 EXPECT_FALSE(callback_closed_
);
465 callback_closed_
= true;
470 bool VerifyKeys(const std::vector
<std::string
>& expected_keys
) {
471 if (expected_keys
.size() != callback_strings_
.size())
474 std::set
<std::string
> found_set
;
475 for (int i
= 0, max
= callback_strings_
.size(); i
< max
; ++i
)
476 found_set
.insert(callback_strings_
[i
]);
478 for (int i
= 0, max
= expected_keys
.size(); i
< max
; ++i
) {
479 if (found_set
.find(expected_keys
[i
]) == found_set
.end())
485 bool TestResponseType(blink::WebServiceWorkerResponseType response_type
) {
486 body_response_
.response_type
= response_type
;
487 EXPECT_TRUE(Put(body_request_
, body_response_
));
488 EXPECT_TRUE(Match(body_request_
));
489 EXPECT_TRUE(Delete(body_request_
));
490 return response_type
== callback_response_
->response_type
;
493 void VerifyAllOpsFail() {
494 EXPECT_FALSE(Put(no_body_request_
, no_body_response_
));
495 EXPECT_FALSE(Match(no_body_request_
));
496 EXPECT_FALSE(Delete(body_request_
));
497 EXPECT_FALSE(Keys());
500 virtual bool MemoryOnly() { return false; }
503 TestBrowserContext browser_context_
;
504 TestBrowserThreadBundle browser_thread_bundle_
;
505 scoped_ptr
<net::URLRequestJobFactoryImpl
> url_request_job_factory_
;
506 scoped_refptr
<MockQuotaManagerProxy
> quota_manager_proxy_
;
507 storage::BlobStorageContext
* blob_storage_context_
;
509 base::ScopedTempDir temp_dir_
;
510 scoped_refptr
<TestCacheStorageCache
> cache_
;
512 ServiceWorkerFetchRequest body_request_
;
513 ServiceWorkerResponse body_response_
;
514 ServiceWorkerFetchRequest no_body_request_
;
515 ServiceWorkerResponse no_body_response_
;
516 scoped_ptr
<storage::BlobDataHandle
> blob_handle_
;
517 std::string expected_blob_data_
;
519 CacheStorageError callback_error_
;
520 scoped_ptr
<ServiceWorkerResponse
> callback_response_
;
521 scoped_ptr
<storage::BlobDataHandle
> callback_response_data_
;
522 std::vector
<std::string
> callback_strings_
;
523 bool callback_closed_
;
526 class CacheStorageCacheTestP
: public CacheStorageCacheTest
,
527 public testing::WithParamInterface
<bool> {
528 bool MemoryOnly() override
{ return !GetParam(); }
531 class CacheStorageCacheMemoryOnlyTest
532 : public CacheStorageCacheTest
,
533 public testing::WithParamInterface
<bool> {
534 bool MemoryOnly() override
{ return true; }
537 TEST_P(CacheStorageCacheTestP
, PutNoBody
) {
538 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
541 TEST_P(CacheStorageCacheTestP
, PutBody
) {
542 EXPECT_TRUE(Put(body_request_
, body_response_
));
545 TEST_P(CacheStorageCacheTestP
, PutBody_Multiple
) {
546 CacheStorageBatchOperation operation1
;
547 operation1
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
548 operation1
.request
= body_request_
;
549 operation1
.request
.url
= GURL("http://example.com/1");
550 operation1
.response
= body_response_
;
551 operation1
.response
.url
= GURL("http://example.com/1");
553 CacheStorageBatchOperation operation2
;
554 operation2
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
555 operation2
.request
= body_request_
;
556 operation2
.request
.url
= GURL("http://example.com/2");
557 operation2
.response
= body_response_
;
558 operation2
.response
.url
= GURL("http://example.com/2");
560 CacheStorageBatchOperation operation3
;
561 operation3
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
562 operation3
.request
= body_request_
;
563 operation3
.request
.url
= GURL("http://example.com/3");
564 operation3
.response
= body_response_
;
565 operation3
.response
.url
= GURL("http://example.com/3");
567 std::vector
<CacheStorageBatchOperation
> operations
;
568 operations
.push_back(operation1
);
569 operations
.push_back(operation2
);
570 operations
.push_back(operation3
);
572 EXPECT_EQ(CACHE_STORAGE_OK
, BatchOperation(operations
));
573 EXPECT_TRUE(Match(operation1
.request
));
574 EXPECT_TRUE(Match(operation2
.request
));
575 EXPECT_TRUE(Match(operation3
.request
));
578 // TODO(nhiroki): Add a test for the case where one of PUT operations fails.
579 // Currently there is no handy way to fail only one operation in a batch.
580 // This could be easily achieved after adding some security checks in the
581 // browser side (http://crbug.com/425505).
583 TEST_P(CacheStorageCacheTestP
, ResponseURLDiffersFromRequestURL
) {
584 no_body_response_
.url
= GURL("http://example.com/foobar");
585 EXPECT_STRNE("http://example.com/foobar",
586 no_body_request_
.url
.spec().c_str());
587 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
588 EXPECT_TRUE(Match(no_body_request_
));
589 EXPECT_STREQ("http://example.com/foobar",
590 callback_response_
->url
.spec().c_str());
593 TEST_P(CacheStorageCacheTestP
, ResponseURLEmpty
) {
594 no_body_response_
.url
= GURL();
595 EXPECT_STRNE("", no_body_request_
.url
.spec().c_str());
596 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
597 EXPECT_TRUE(Match(no_body_request_
));
598 EXPECT_STREQ("", callback_response_
->url
.spec().c_str());
601 TEST_F(CacheStorageCacheTest
, PutBodyDropBlobRef
) {
602 CacheStorageBatchOperation operation
;
603 operation
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
604 operation
.request
= body_request_
;
605 operation
.response
= body_response_
;
607 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
608 cache_
->BatchOperation(
609 std::vector
<CacheStorageBatchOperation
>(1, operation
),
610 base::Bind(&CacheStorageCacheTestP::ErrorTypeCallback
,
611 base::Unretained(this), base::Unretained(loop
.get())));
612 // The handle should be held by the cache now so the deref here should be
614 blob_handle_
.reset();
617 EXPECT_EQ(CACHE_STORAGE_OK
, callback_error_
);
620 TEST_P(CacheStorageCacheTestP
, PutReplace
) {
621 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
622 EXPECT_TRUE(Match(body_request_
));
623 EXPECT_FALSE(callback_response_data_
);
625 EXPECT_TRUE(Put(body_request_
, body_response_
));
626 EXPECT_TRUE(Match(body_request_
));
627 EXPECT_TRUE(callback_response_data_
);
629 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
630 EXPECT_TRUE(Match(body_request_
));
631 EXPECT_FALSE(callback_response_data_
);
634 TEST_P(CacheStorageCacheTestP
, PutReplcaceInBatch
) {
635 CacheStorageBatchOperation operation1
;
636 operation1
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
637 operation1
.request
= body_request_
;
638 operation1
.response
= no_body_response_
;
640 CacheStorageBatchOperation operation2
;
641 operation2
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
642 operation2
.request
= body_request_
;
643 operation2
.response
= body_response_
;
645 std::vector
<CacheStorageBatchOperation
> operations
;
646 operations
.push_back(operation1
);
647 operations
.push_back(operation2
);
649 EXPECT_EQ(CACHE_STORAGE_OK
, BatchOperation(operations
));
651 // |operation2| should win.
652 EXPECT_TRUE(Match(operation2
.request
));
653 EXPECT_TRUE(callback_response_data_
);
656 TEST_P(CacheStorageCacheTestP
, MatchNoBody
) {
657 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
658 EXPECT_TRUE(Match(no_body_request_
));
659 EXPECT_TRUE(ResponseMetadataEqual(no_body_response_
, *callback_response_
));
660 EXPECT_FALSE(callback_response_data_
);
663 TEST_P(CacheStorageCacheTestP
, MatchBody
) {
664 EXPECT_TRUE(Put(body_request_
, body_response_
));
665 EXPECT_TRUE(Match(body_request_
));
666 EXPECT_TRUE(ResponseMetadataEqual(body_response_
, *callback_response_
));
668 ResponseBodiesEqual(expected_blob_data_
, *callback_response_data_
));
671 TEST_P(CacheStorageCacheTestP
, MatchAll_Empty
) {
672 scoped_ptr
<CacheStorageCache::Responses
> responses
;
673 scoped_ptr
<CacheStorageCache::BlobDataHandles
> body_handles
;
674 EXPECT_TRUE(MatchAll(&responses
, &body_handles
));
675 EXPECT_TRUE(responses
->empty());
676 EXPECT_TRUE(body_handles
->empty());
679 TEST_P(CacheStorageCacheTestP
, MatchAll_NoBody
) {
680 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
682 scoped_ptr
<CacheStorageCache::Responses
> responses
;
683 scoped_ptr
<CacheStorageCache::BlobDataHandles
> body_handles
;
684 EXPECT_TRUE(MatchAll(&responses
, &body_handles
));
686 ASSERT_EQ(1u, responses
->size());
687 EXPECT_TRUE(ResponseMetadataEqual(no_body_response_
, responses
->at(0)));
688 EXPECT_TRUE(body_handles
->empty());
691 TEST_P(CacheStorageCacheTestP
, MatchAll_Body
) {
692 EXPECT_TRUE(Put(body_request_
, body_response_
));
694 scoped_ptr
<CacheStorageCache::Responses
> responses
;
695 scoped_ptr
<CacheStorageCache::BlobDataHandles
> body_handles
;
696 EXPECT_TRUE(MatchAll(&responses
, &body_handles
));
698 ASSERT_EQ(1u, responses
->size());
699 ASSERT_EQ(1u, body_handles
->size());
700 EXPECT_TRUE(ResponseMetadataEqual(body_response_
, responses
->at(0)));
701 EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_
, body_handles
->at(0)));
704 TEST_P(CacheStorageCacheTestP
, MatchAll_TwoResponsesThenOne
) {
705 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
706 EXPECT_TRUE(Put(body_request_
, body_response_
));
708 scoped_ptr
<CacheStorageCache::Responses
> responses
;
709 scoped_ptr
<CacheStorageCache::BlobDataHandles
> body_handles
;
710 EXPECT_TRUE(MatchAll(&responses
, &body_handles
));
711 ASSERT_EQ(2u, responses
->size());
712 ASSERT_EQ(1u, body_handles
->size());
714 // Order of returned responses is not guaranteed.
715 std::set
<std::string
> matched_set
;
716 for (const ServiceWorkerResponse
& response
: *responses
) {
717 if (response
.url
.spec() == "http://example.com/no_body.html") {
718 EXPECT_TRUE(ResponseMetadataEqual(no_body_response_
, response
));
719 matched_set
.insert(response
.url
.spec());
720 } else if (response
.url
.spec() == "http://example.com/body.html") {
721 EXPECT_TRUE(ResponseMetadataEqual(body_response_
, response
));
723 ResponseBodiesEqual(expected_blob_data_
, body_handles
->at(0)));
724 matched_set
.insert(response
.url
.spec());
727 EXPECT_EQ(2u, matched_set
.size());
730 body_handles
->clear();
732 EXPECT_TRUE(Delete(body_request_
));
733 EXPECT_TRUE(MatchAll(&responses
, &body_handles
));
735 ASSERT_EQ(1u, responses
->size());
736 EXPECT_TRUE(ResponseMetadataEqual(no_body_response_
, responses
->at(0)));
737 EXPECT_TRUE(body_handles
->empty());
740 TEST_P(CacheStorageCacheTestP
, Vary
) {
741 body_request_
.headers
["vary_foo"] = "foo";
742 body_response_
.headers
["vary"] = "vary_foo";
743 EXPECT_TRUE(Put(body_request_
, body_response_
));
744 EXPECT_TRUE(Match(body_request_
));
746 body_request_
.headers
["vary_foo"] = "bar";
747 EXPECT_FALSE(Match(body_request_
));
749 body_request_
.headers
.erase("vary_foo");
750 EXPECT_FALSE(Match(body_request_
));
753 TEST_P(CacheStorageCacheTestP
, EmptyVary
) {
754 body_response_
.headers
["vary"] = "";
755 EXPECT_TRUE(Put(body_request_
, body_response_
));
756 EXPECT_TRUE(Match(body_request_
));
758 body_request_
.headers
["zoo"] = "zoo";
759 EXPECT_TRUE(Match(body_request_
));
762 TEST_P(CacheStorageCacheTestP
, NoVaryButDiffHeaders
) {
763 EXPECT_TRUE(Put(body_request_
, body_response_
));
764 EXPECT_TRUE(Match(body_request_
));
766 body_request_
.headers
["zoo"] = "zoo";
767 EXPECT_TRUE(Match(body_request_
));
770 TEST_P(CacheStorageCacheTestP
, VaryMultiple
) {
771 body_request_
.headers
["vary_foo"] = "foo";
772 body_request_
.headers
["vary_bar"] = "bar";
773 body_response_
.headers
["vary"] = " vary_foo , vary_bar";
774 EXPECT_TRUE(Put(body_request_
, body_response_
));
775 EXPECT_TRUE(Match(body_request_
));
777 body_request_
.headers
["vary_bar"] = "foo";
778 EXPECT_FALSE(Match(body_request_
));
780 body_request_
.headers
.erase("vary_bar");
781 EXPECT_FALSE(Match(body_request_
));
784 TEST_P(CacheStorageCacheTestP
, VaryNewHeader
) {
785 body_request_
.headers
["vary_foo"] = "foo";
786 body_response_
.headers
["vary"] = " vary_foo, vary_bar";
787 EXPECT_TRUE(Put(body_request_
, body_response_
));
788 EXPECT_TRUE(Match(body_request_
));
790 body_request_
.headers
["vary_bar"] = "bar";
791 EXPECT_FALSE(Match(body_request_
));
794 TEST_P(CacheStorageCacheTestP
, VaryStar
) {
795 body_response_
.headers
["vary"] = "*";
796 EXPECT_TRUE(Put(body_request_
, body_response_
));
797 EXPECT_FALSE(Match(body_request_
));
800 TEST_P(CacheStorageCacheTestP
, EmptyKeys
) {
802 EXPECT_EQ(0u, callback_strings_
.size());
805 TEST_P(CacheStorageCacheTestP
, TwoKeys
) {
806 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
807 EXPECT_TRUE(Put(body_request_
, body_response_
));
809 EXPECT_EQ(2u, callback_strings_
.size());
810 std::vector
<std::string
> expected_keys
;
811 expected_keys
.push_back(no_body_request_
.url
.spec());
812 expected_keys
.push_back(body_request_
.url
.spec());
813 EXPECT_TRUE(VerifyKeys(expected_keys
));
816 TEST_P(CacheStorageCacheTestP
, TwoKeysThenOne
) {
817 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
818 EXPECT_TRUE(Put(body_request_
, body_response_
));
820 EXPECT_EQ(2u, callback_strings_
.size());
821 std::vector
<std::string
> expected_keys
;
822 expected_keys
.push_back(no_body_request_
.url
.spec());
823 expected_keys
.push_back(body_request_
.url
.spec());
824 EXPECT_TRUE(VerifyKeys(expected_keys
));
826 EXPECT_TRUE(Delete(body_request_
));
828 EXPECT_EQ(1u, callback_strings_
.size());
829 std::vector
<std::string
> expected_key
;
830 expected_key
.push_back(no_body_request_
.url
.spec());
831 EXPECT_TRUE(VerifyKeys(expected_key
));
834 TEST_P(CacheStorageCacheTestP
, DeleteNoBody
) {
835 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
836 EXPECT_TRUE(Match(no_body_request_
));
837 EXPECT_TRUE(Delete(no_body_request_
));
838 EXPECT_FALSE(Match(no_body_request_
));
839 EXPECT_FALSE(Delete(no_body_request_
));
840 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
841 EXPECT_TRUE(Match(no_body_request_
));
842 EXPECT_TRUE(Delete(no_body_request_
));
845 TEST_P(CacheStorageCacheTestP
, DeleteBody
) {
846 EXPECT_TRUE(Put(body_request_
, body_response_
));
847 EXPECT_TRUE(Match(body_request_
));
848 EXPECT_TRUE(Delete(body_request_
));
849 EXPECT_FALSE(Match(body_request_
));
850 EXPECT_FALSE(Delete(body_request_
));
851 EXPECT_TRUE(Put(body_request_
, body_response_
));
852 EXPECT_TRUE(Match(body_request_
));
853 EXPECT_TRUE(Delete(body_request_
));
856 TEST_P(CacheStorageCacheTestP
, QuickStressNoBody
) {
857 for (int i
= 0; i
< 100; ++i
) {
858 EXPECT_FALSE(Match(no_body_request_
));
859 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
860 EXPECT_TRUE(Match(no_body_request_
));
861 EXPECT_TRUE(Delete(no_body_request_
));
865 TEST_P(CacheStorageCacheTestP
, QuickStressBody
) {
866 for (int i
= 0; i
< 100; ++i
) {
867 ASSERT_FALSE(Match(body_request_
));
868 ASSERT_TRUE(Put(body_request_
, body_response_
));
869 ASSERT_TRUE(Match(body_request_
));
870 ASSERT_TRUE(Delete(body_request_
));
874 TEST_P(CacheStorageCacheTestP
, PutResponseType
) {
875 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeBasic
));
876 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeCORS
));
877 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeDefault
));
878 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeError
));
879 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeOpaque
));
882 TEST_F(CacheStorageCacheTest
, CaselessServiceWorkerResponseHeaders
) {
883 // CacheStorageCache depends on ServiceWorkerResponse having caseless
884 // headers so that it can quickly lookup vary headers.
885 ServiceWorkerResponse
response(GURL("http://www.example.com"), 200, "OK",
886 blink::WebServiceWorkerResponseTypeDefault
,
887 ServiceWorkerHeaderMap(), "", 0, GURL(),
888 blink::WebServiceWorkerResponseErrorUnknown
);
889 response
.headers
["content-type"] = "foo";
890 response
.headers
["Content-Type"] = "bar";
891 EXPECT_EQ("bar", response
.headers
["content-type"]);
894 TEST_F(CacheStorageCacheTest
, CaselessServiceWorkerFetchRequestHeaders
) {
895 // CacheStorageCache depends on ServiceWorkerFetchRequest having caseless
896 // headers so that it can quickly lookup vary headers.
897 ServiceWorkerFetchRequest
request(GURL("http://www.example.com"), "GET",
898 ServiceWorkerHeaderMap(), Referrer(),
900 request
.headers
["content-type"] = "foo";
901 request
.headers
["Content-Type"] = "bar";
902 EXPECT_EQ("bar", request
.headers
["content-type"]);
905 TEST_P(CacheStorageCacheTestP
, QuotaManagerModified
) {
906 EXPECT_EQ(0, quota_manager_proxy_
->notify_storage_modified_count());
908 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
909 EXPECT_EQ(1, quota_manager_proxy_
->notify_storage_modified_count());
910 EXPECT_LT(0, quota_manager_proxy_
->last_notified_delta());
911 int64 sum_delta
= quota_manager_proxy_
->last_notified_delta();
913 EXPECT_TRUE(Put(body_request_
, body_response_
));
914 EXPECT_EQ(2, quota_manager_proxy_
->notify_storage_modified_count());
915 EXPECT_LT(sum_delta
, quota_manager_proxy_
->last_notified_delta());
916 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
918 EXPECT_TRUE(Delete(body_request_
));
919 EXPECT_EQ(3, quota_manager_proxy_
->notify_storage_modified_count());
920 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
922 EXPECT_TRUE(Delete(no_body_request_
));
923 EXPECT_EQ(4, quota_manager_proxy_
->notify_storage_modified_count());
924 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
926 EXPECT_EQ(0, sum_delta
);
929 TEST_F(CacheStorageCacheMemoryOnlyTest
, MemoryBackedSize
) {
930 EXPECT_EQ(0, cache_
->MemoryBackedSize());
931 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
932 EXPECT_LT(0, cache_
->MemoryBackedSize());
933 int64 no_body_size
= cache_
->MemoryBackedSize();
935 EXPECT_TRUE(Delete(no_body_request_
));
936 EXPECT_EQ(0, cache_
->MemoryBackedSize());
938 EXPECT_TRUE(Put(body_request_
, body_response_
));
939 EXPECT_LT(no_body_size
, cache_
->MemoryBackedSize());
941 EXPECT_TRUE(Delete(body_request_
));
942 EXPECT_EQ(0, cache_
->MemoryBackedSize());
945 TEST_F(CacheStorageCacheTest
, MemoryBackedSizePersistent
) {
946 EXPECT_EQ(0, cache_
->MemoryBackedSize());
947 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
948 EXPECT_EQ(0, cache_
->MemoryBackedSize());
951 TEST_P(CacheStorageCacheTestP
, OpsFailOnClosedBackendNeverCreated
) {
952 cache_
->set_delay_backend_creation(
953 true); // Will hang the test if a backend is created.
954 EXPECT_TRUE(Close());
958 TEST_P(CacheStorageCacheTestP
, OpsFailOnClosedBackend
) {
959 // Create the backend and put something in it.
960 EXPECT_TRUE(Put(body_request_
, body_response_
));
961 EXPECT_TRUE(Close());
965 TEST_P(CacheStorageCacheTestP
, VerifySerialScheduling
) {
966 // Start two operations, the first one is delayed but the second isn't. The
967 // second should wait for the first.
968 EXPECT_TRUE(Keys()); // Opens the backend.
969 DelayableBackend
* delayable_backend
= cache_
->UseDelayableBackend();
970 delayable_backend
->set_delay_open(true);
972 int sequence_out
= -1;
974 CacheStorageBatchOperation operation1
;
975 operation1
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
976 operation1
.request
= body_request_
;
977 operation1
.response
= body_response_
;
979 scoped_ptr
<base::RunLoop
> close_loop1(new base::RunLoop());
980 cache_
->BatchOperation(
981 std::vector
<CacheStorageBatchOperation
>(1, operation1
),
982 base::Bind(&CacheStorageCacheTest::SequenceCallback
,
983 base::Unretained(this), 1, &sequence_out
, close_loop1
.get()));
985 // Blocks on opening the cache entry.
986 base::RunLoop().RunUntilIdle();
988 CacheStorageBatchOperation operation2
;
989 operation2
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
990 operation2
.request
= body_request_
;
991 operation2
.response
= body_response_
;
993 delayable_backend
->set_delay_open(false);
994 scoped_ptr
<base::RunLoop
> close_loop2(new base::RunLoop());
995 cache_
->BatchOperation(
996 std::vector
<CacheStorageBatchOperation
>(1, operation2
),
997 base::Bind(&CacheStorageCacheTest::SequenceCallback
,
998 base::Unretained(this), 2, &sequence_out
, close_loop2
.get()));
1000 // The second put operation should wait for the first to complete.
1001 base::RunLoop().RunUntilIdle();
1002 EXPECT_FALSE(callback_response_
);
1004 delayable_backend
->OpenEntryContinue();
1006 EXPECT_EQ(1, sequence_out
);
1008 EXPECT_EQ(2, sequence_out
);
1011 INSTANTIATE_TEST_CASE_P(CacheStorageCacheTest
,
1012 CacheStorageCacheTestP
,
1013 ::testing::Values(false, true));
1015 } // namespace content