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/run_loop.h"
11 #include "base/strings/string_split.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "content/browser/fileapi/chrome_blob_storage_context.h"
14 #include "content/browser/fileapi/mock_url_request_delegate.h"
15 #include "content/browser/quota/mock_quota_manager_proxy.h"
16 #include "content/common/cache_storage/cache_storage_types.h"
17 #include "content/common/service_worker/service_worker_types.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/common/referrer.h"
20 #include "content/public/test/test_browser_context.h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "net/base/test_completion_callback.h"
23 #include "net/url_request/url_request_context.h"
24 #include "net/url_request/url_request_context_getter.h"
25 #include "net/url_request/url_request_job_factory_impl.h"
26 #include "storage/browser/blob/blob_data_builder.h"
27 #include "storage/browser/blob/blob_data_handle.h"
28 #include "storage/browser/blob/blob_data_snapshot.h"
29 #include "storage/browser/blob/blob_storage_context.h"
30 #include "storage/browser/blob/blob_url_request_job_factory.h"
31 #include "storage/browser/quota/quota_manager_proxy.h"
32 #include "testing/gtest/include/gtest/gtest.h"
37 const char kTestData
[] = "Hello World";
39 // Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
41 storage::BlobProtocolHandler
* CreateMockBlobProtocolHandler(
42 storage::BlobStorageContext
* blob_storage_context
) {
43 // The FileSystemContext and thread task runner are not actually used but a
44 // task runner is needed to avoid a DCHECK in BlobURLRequestJob ctor.
45 return new storage::BlobProtocolHandler(
46 blob_storage_context
, NULL
, base::ThreadTaskRunnerHandle::Get().get());
49 // A disk_cache::Backend wrapper that can delay operations.
50 class DelayableBackend
: public disk_cache::Backend
{
52 DelayableBackend(scoped_ptr
<disk_cache::Backend
> backend
)
53 : backend_(backend
.Pass()), delay_open_(false) {}
55 // disk_cache::Backend overrides
56 net::CacheType
GetCacheType() const override
{
57 return backend_
->GetCacheType();
59 int32
GetEntryCount() const override
{ return backend_
->GetEntryCount(); }
60 int OpenEntry(const std::string
& key
,
61 disk_cache::Entry
** entry
,
62 const CompletionCallback
& callback
) override
{
64 open_entry_callback_
=
65 base::Bind(&DelayableBackend::OpenEntryDelayedImpl
,
66 base::Unretained(this), key
, entry
, callback
);
67 return net::ERR_IO_PENDING
;
70 return backend_
->OpenEntry(key
, entry
, callback
);
72 int CreateEntry(const std::string
& key
,
73 disk_cache::Entry
** entry
,
74 const CompletionCallback
& callback
) override
{
75 return backend_
->CreateEntry(key
, entry
, callback
);
77 int DoomEntry(const std::string
& key
,
78 const CompletionCallback
& callback
) override
{
79 return backend_
->DoomEntry(key
, callback
);
81 int DoomAllEntries(const CompletionCallback
& callback
) override
{
82 return backend_
->DoomAllEntries(callback
);
84 int DoomEntriesBetween(base::Time initial_time
,
86 const CompletionCallback
& callback
) override
{
87 return backend_
->DoomEntriesBetween(initial_time
, end_time
, callback
);
89 int DoomEntriesSince(base::Time initial_time
,
90 const CompletionCallback
& callback
) override
{
91 return backend_
->DoomEntriesSince(initial_time
, callback
);
93 scoped_ptr
<Iterator
> CreateIterator() override
{
94 return backend_
->CreateIterator();
96 void GetStats(base::StringPairs
* stats
) override
{
97 return backend_
->GetStats(stats
);
99 void OnExternalCacheHit(const std::string
& key
) override
{
100 return backend_
->OnExternalCacheHit(key
);
103 // Call to continue a delayed open.
104 void OpenEntryContinue() {
105 EXPECT_FALSE(open_entry_callback_
.is_null());
106 open_entry_callback_
.Run();
109 void set_delay_open(bool value
) { delay_open_
= value
; }
112 void OpenEntryDelayedImpl(const std::string
& key
,
113 disk_cache::Entry
** entry
,
114 const CompletionCallback
& callback
) {
115 int rv
= backend_
->OpenEntry(key
, entry
, callback
);
116 if (rv
!= net::ERR_IO_PENDING
)
120 scoped_ptr
<disk_cache::Backend
> backend_
;
122 base::Closure open_entry_callback_
;
127 // A CacheStorageCache that can optionally delay during backend creation.
128 class TestCacheStorageCache
: public CacheStorageCache
{
130 TestCacheStorageCache(
132 const base::FilePath
& path
,
133 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
134 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
135 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
136 : CacheStorageCache(origin
,
138 request_context_getter
,
141 delay_backend_creation_(false) {}
143 void CreateBackend(const ErrorCallback
& callback
) override
{
144 backend_creation_callback_
= callback
;
145 if (delay_backend_creation_
)
147 ContinueCreateBackend();
150 void ContinueCreateBackend() {
151 CacheStorageCache::CreateBackend(backend_creation_callback_
);
154 void set_delay_backend_creation(bool delay
) {
155 delay_backend_creation_
= delay
;
158 // Swap the existing backend with a delayable one. The backend must have been
159 // created before calling this.
160 DelayableBackend
* UseDelayableBackend() {
161 EXPECT_TRUE(backend_
);
162 DelayableBackend
* delayable_backend
= new DelayableBackend(backend_
.Pass());
163 backend_
.reset(delayable_backend
);
164 return delayable_backend
;
168 ~TestCacheStorageCache() override
{}
170 bool delay_backend_creation_
;
171 ErrorCallback backend_creation_callback_
;
173 DISALLOW_COPY_AND_ASSIGN(TestCacheStorageCache
);
176 class CacheStorageCacheTest
: public testing::Test
{
178 CacheStorageCacheTest()
179 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
180 callback_error_(CACHE_STORAGE_OK
),
181 callback_closed_(false) {}
183 void SetUp() override
{
184 ChromeBlobStorageContext
* blob_storage_context
=
185 ChromeBlobStorageContext::GetFor(&browser_context_
);
186 // Wait for chrome_blob_storage_context to finish initializing.
187 base::RunLoop().RunUntilIdle();
188 blob_storage_context_
= blob_storage_context
->context();
190 quota_manager_proxy_
= new MockQuotaManagerProxy(
191 nullptr, base::ThreadTaskRunnerHandle::Get().get());
193 url_request_job_factory_
.reset(new net::URLRequestJobFactoryImpl
);
194 url_request_job_factory_
->SetProtocolHandler(
195 "blob", CreateMockBlobProtocolHandler(blob_storage_context
->context()));
197 net::URLRequestContext
* url_request_context
=
198 browser_context_
.GetRequestContext()->GetURLRequestContext();
200 url_request_context
->set_job_factory(url_request_job_factory_
.get());
202 CreateRequests(blob_storage_context
);
205 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
206 base::FilePath path
= MemoryOnly() ? base::FilePath() : temp_dir_
.path();
208 cache_
= make_scoped_refptr(new TestCacheStorageCache(
209 GURL("http://example.com"), path
, browser_context_
.GetRequestContext(),
210 quota_manager_proxy_
, blob_storage_context
->context()->AsWeakPtr()));
213 void TearDown() override
{
214 quota_manager_proxy_
->SimulateQuotaManagerDestroyed();
215 base::RunLoop().RunUntilIdle();
218 void CreateRequests(ChromeBlobStorageContext
* blob_storage_context
) {
219 ServiceWorkerHeaderMap headers
;
220 headers
.insert(std::make_pair("a", "a"));
221 headers
.insert(std::make_pair("b", "b"));
223 ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET",
224 headers
, Referrer(), false);
226 ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
227 "GET", headers
, Referrer(), false);
229 std::string expected_response
;
230 for (int i
= 0; i
< 100; ++i
)
231 expected_blob_data_
+= kTestData
;
233 scoped_ptr
<storage::BlobDataBuilder
> blob_data(
234 new storage::BlobDataBuilder("blob-id:myblob"));
235 blob_data
->AppendData(expected_blob_data_
);
238 blob_storage_context
->context()->AddFinishedBlob(blob_data
.get());
240 body_response_
= ServiceWorkerResponse(
241 GURL("http://example.com/body.html"), 200, "OK",
242 blink::WebServiceWorkerResponseTypeDefault
, headers
,
243 blob_handle_
->uuid(), expected_blob_data_
.size(), GURL(),
244 blink::WebServiceWorkerResponseErrorUnknown
);
246 no_body_response_
= ServiceWorkerResponse(
247 GURL("http://example.com/no_body.html"), 200, "OK",
248 blink::WebServiceWorkerResponseTypeDefault
, headers
, "", 0, GURL(),
249 blink::WebServiceWorkerResponseErrorUnknown
);
252 scoped_ptr
<ServiceWorkerFetchRequest
> CopyFetchRequest(
253 const ServiceWorkerFetchRequest
& request
) {
254 return make_scoped_ptr(new ServiceWorkerFetchRequest(
255 request
.url
, request
.method
, request
.headers
, request
.referrer
,
259 CacheStorageError
BatchOperation(
260 const std::vector
<CacheStorageBatchOperation
>& operations
) {
261 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
263 cache_
->BatchOperation(
265 base::Bind(&CacheStorageCacheTest::ErrorTypeCallback
,
266 base::Unretained(this), base::Unretained(loop
.get())));
267 // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
268 // once the cache uses a passed in task runner instead of the CACHE thread.
271 return callback_error_
;
274 bool Put(const ServiceWorkerFetchRequest
& request
,
275 const ServiceWorkerResponse
& response
) {
276 CacheStorageBatchOperation operation
;
277 operation
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
278 operation
.request
= request
;
279 operation
.response
= response
;
281 CacheStorageError error
=
282 BatchOperation(std::vector
<CacheStorageBatchOperation
>(1, operation
));
283 return error
== CACHE_STORAGE_OK
;
286 bool Match(const ServiceWorkerFetchRequest
& request
) {
287 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
290 CopyFetchRequest(request
),
291 base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback
,
292 base::Unretained(this), base::Unretained(loop
.get())));
295 return callback_error_
== CACHE_STORAGE_OK
;
298 bool Delete(const ServiceWorkerFetchRequest
& request
) {
299 CacheStorageBatchOperation operation
;
300 operation
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE
;
301 operation
.request
= request
;
303 CacheStorageError error
=
304 BatchOperation(std::vector
<CacheStorageBatchOperation
>(1, operation
));
305 return error
== CACHE_STORAGE_OK
;
309 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
311 cache_
->Keys(base::Bind(&CacheStorageCacheTest::RequestsCallback
,
312 base::Unretained(this),
313 base::Unretained(loop
.get())));
316 return callback_error_
== CACHE_STORAGE_OK
;
320 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
322 cache_
->Close(base::Bind(&CacheStorageCacheTest::CloseCallback
,
323 base::Unretained(this),
324 base::Unretained(loop
.get())));
326 return callback_closed_
;
329 void RequestsCallback(base::RunLoop
* run_loop
,
330 CacheStorageError error
,
331 scoped_ptr
<CacheStorageCache::Requests
> requests
) {
332 callback_error_
= error
;
333 callback_strings_
.clear();
335 for (size_t i
= 0u; i
< requests
->size(); ++i
)
336 callback_strings_
.push_back(requests
->at(i
).url
.spec());
342 void ErrorTypeCallback(base::RunLoop
* run_loop
, CacheStorageError error
) {
343 callback_error_
= error
;
348 void SequenceCallback(int sequence
,
350 base::RunLoop
* run_loop
,
351 CacheStorageError error
) {
352 *sequence_out
= sequence
;
353 callback_error_
= error
;
358 void ResponseAndErrorCallback(
359 base::RunLoop
* run_loop
,
360 CacheStorageError error
,
361 scoped_ptr
<ServiceWorkerResponse
> response
,
362 scoped_ptr
<storage::BlobDataHandle
> body_handle
) {
363 callback_error_
= error
;
364 callback_response_
= response
.Pass();
365 callback_response_data_
.reset();
366 if (error
== CACHE_STORAGE_OK
&& !callback_response_
->blob_uuid
.empty())
367 callback_response_data_
= body_handle
.Pass();
373 void CloseCallback(base::RunLoop
* run_loop
) {
374 EXPECT_FALSE(callback_closed_
);
375 callback_closed_
= true;
380 void CopyBody(storage::BlobDataHandle
* blob_handle
, std::string
* output
) {
381 *output
= std::string();
382 scoped_ptr
<storage::BlobDataSnapshot
> data
= blob_handle
->CreateSnapshot();
383 const auto& items
= data
->items();
384 for (const auto& item
: items
) {
385 switch (item
->type()) {
386 case storage::DataElement::TYPE_BYTES
: {
387 output
->append(item
->bytes(), item
->length());
390 case storage::DataElement::TYPE_DISK_CACHE_ENTRY
: {
391 disk_cache::Entry
* entry
= item
->disk_cache_entry();
392 int32 body_size
= entry
->GetDataSize(item
->disk_cache_stream_index());
394 scoped_refptr
<net::IOBuffer
> io_buffer
= new net::IOBuffer(body_size
);
395 net::TestCompletionCallback callback
;
397 entry
->ReadData(item
->disk_cache_stream_index(), 0,
398 io_buffer
.get(), body_size
, callback
.callback());
399 if (rv
== net::ERR_IO_PENDING
)
400 rv
= callback
.WaitForResult();
401 EXPECT_EQ(body_size
, rv
);
403 output
->append(io_buffer
->data(), rv
);
406 default: { ADD_FAILURE() << "invalid response blob type"; } break;
411 bool VerifyKeys(const std::vector
<std::string
>& expected_keys
) {
412 if (expected_keys
.size() != callback_strings_
.size())
415 std::set
<std::string
> found_set
;
416 for (int i
= 0, max
= callback_strings_
.size(); i
< max
; ++i
)
417 found_set
.insert(callback_strings_
[i
]);
419 for (int i
= 0, max
= expected_keys
.size(); i
< max
; ++i
) {
420 if (found_set
.find(expected_keys
[i
]) == found_set
.end())
426 bool TestResponseType(blink::WebServiceWorkerResponseType response_type
) {
427 body_response_
.response_type
= response_type
;
428 EXPECT_TRUE(Put(body_request_
, body_response_
));
429 EXPECT_TRUE(Match(body_request_
));
430 EXPECT_TRUE(Delete(body_request_
));
431 return response_type
== callback_response_
->response_type
;
434 void VerifyAllOpsFail() {
435 EXPECT_FALSE(Put(no_body_request_
, no_body_response_
));
436 EXPECT_FALSE(Match(no_body_request_
));
437 EXPECT_FALSE(Delete(body_request_
));
438 EXPECT_FALSE(Keys());
441 virtual bool MemoryOnly() { return false; }
444 TestBrowserContext browser_context_
;
445 TestBrowserThreadBundle browser_thread_bundle_
;
446 scoped_ptr
<net::URLRequestJobFactoryImpl
> url_request_job_factory_
;
447 scoped_refptr
<MockQuotaManagerProxy
> quota_manager_proxy_
;
448 storage::BlobStorageContext
* blob_storage_context_
;
450 base::ScopedTempDir temp_dir_
;
451 scoped_refptr
<TestCacheStorageCache
> cache_
;
453 ServiceWorkerFetchRequest body_request_
;
454 ServiceWorkerResponse body_response_
;
455 ServiceWorkerFetchRequest no_body_request_
;
456 ServiceWorkerResponse no_body_response_
;
457 scoped_ptr
<storage::BlobDataHandle
> blob_handle_
;
458 std::string expected_blob_data_
;
460 CacheStorageError callback_error_
;
461 scoped_ptr
<ServiceWorkerResponse
> callback_response_
;
462 scoped_ptr
<storage::BlobDataHandle
> callback_response_data_
;
463 std::vector
<std::string
> callback_strings_
;
464 bool callback_closed_
;
467 class CacheStorageCacheTestP
: public CacheStorageCacheTest
,
468 public testing::WithParamInterface
<bool> {
469 bool MemoryOnly() override
{ return !GetParam(); }
472 class CacheStorageCacheMemoryOnlyTest
473 : public CacheStorageCacheTest
,
474 public testing::WithParamInterface
<bool> {
475 bool MemoryOnly() override
{ return true; }
478 TEST_P(CacheStorageCacheTestP
, PutNoBody
) {
479 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
482 TEST_P(CacheStorageCacheTestP
, PutBody
) {
483 EXPECT_TRUE(Put(body_request_
, body_response_
));
486 TEST_P(CacheStorageCacheTestP
, PutBody_Multiple
) {
487 CacheStorageBatchOperation operation1
;
488 operation1
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
489 operation1
.request
= body_request_
;
490 operation1
.request
.url
= GURL("http://example.com/1");
491 operation1
.response
= body_response_
;
492 operation1
.response
.url
= GURL("http://example.com/1");
494 CacheStorageBatchOperation operation2
;
495 operation2
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
496 operation2
.request
= body_request_
;
497 operation2
.request
.url
= GURL("http://example.com/2");
498 operation2
.response
= body_response_
;
499 operation2
.response
.url
= GURL("http://example.com/2");
501 CacheStorageBatchOperation operation3
;
502 operation3
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
503 operation3
.request
= body_request_
;
504 operation3
.request
.url
= GURL("http://example.com/3");
505 operation3
.response
= body_response_
;
506 operation3
.response
.url
= GURL("http://example.com/3");
508 std::vector
<CacheStorageBatchOperation
> operations
;
509 operations
.push_back(operation1
);
510 operations
.push_back(operation2
);
511 operations
.push_back(operation3
);
513 EXPECT_EQ(CACHE_STORAGE_OK
, BatchOperation(operations
));
514 EXPECT_TRUE(Match(operation1
.request
));
515 EXPECT_TRUE(Match(operation2
.request
));
516 EXPECT_TRUE(Match(operation3
.request
));
519 // TODO(nhiroki): Add a test for the case where one of PUT operations fails.
520 // Currently there is no handy way to fail only one operation in a batch.
521 // This could be easily achieved after adding some security checks in the
522 // browser side (http://crbug.com/425505).
524 TEST_P(CacheStorageCacheTestP
, ResponseURLDiffersFromRequestURL
) {
525 no_body_response_
.url
= GURL("http://example.com/foobar");
526 EXPECT_STRNE("http://example.com/foobar",
527 no_body_request_
.url
.spec().c_str());
528 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
529 EXPECT_TRUE(Match(no_body_request_
));
530 EXPECT_STREQ("http://example.com/foobar",
531 callback_response_
->url
.spec().c_str());
534 TEST_P(CacheStorageCacheTestP
, ResponseURLEmpty
) {
535 no_body_response_
.url
= GURL();
536 EXPECT_STRNE("", no_body_request_
.url
.spec().c_str());
537 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
538 EXPECT_TRUE(Match(no_body_request_
));
539 EXPECT_STREQ("", callback_response_
->url
.spec().c_str());
542 TEST_F(CacheStorageCacheTest
, PutBodyDropBlobRef
) {
543 CacheStorageBatchOperation operation
;
544 operation
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
545 operation
.request
= body_request_
;
546 operation
.response
= body_response_
;
548 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
549 cache_
->BatchOperation(
550 std::vector
<CacheStorageBatchOperation
>(1, operation
),
551 base::Bind(&CacheStorageCacheTestP::ErrorTypeCallback
,
552 base::Unretained(this), base::Unretained(loop
.get())));
553 // The handle should be held by the cache now so the deref here should be
555 blob_handle_
.reset();
558 EXPECT_EQ(CACHE_STORAGE_OK
, callback_error_
);
561 TEST_P(CacheStorageCacheTestP
, PutReplace
) {
562 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
563 EXPECT_TRUE(Match(body_request_
));
564 EXPECT_FALSE(callback_response_data_
);
566 EXPECT_TRUE(Put(body_request_
, body_response_
));
567 EXPECT_TRUE(Match(body_request_
));
568 EXPECT_TRUE(callback_response_data_
);
570 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
571 EXPECT_TRUE(Match(body_request_
));
572 EXPECT_FALSE(callback_response_data_
);
575 TEST_P(CacheStorageCacheTestP
, PutReplcaceInBatch
) {
576 CacheStorageBatchOperation operation1
;
577 operation1
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
578 operation1
.request
= body_request_
;
579 operation1
.response
= no_body_response_
;
581 CacheStorageBatchOperation operation2
;
582 operation2
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
583 operation2
.request
= body_request_
;
584 operation2
.response
= body_response_
;
586 std::vector
<CacheStorageBatchOperation
> operations
;
587 operations
.push_back(operation1
);
588 operations
.push_back(operation2
);
590 EXPECT_EQ(CACHE_STORAGE_OK
, BatchOperation(operations
));
592 // |operation2| should win.
593 EXPECT_TRUE(Match(operation2
.request
));
594 EXPECT_TRUE(callback_response_data_
);
597 TEST_P(CacheStorageCacheTestP
, MatchNoBody
) {
598 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
599 EXPECT_TRUE(Match(no_body_request_
));
600 EXPECT_EQ(200, callback_response_
->status_code
);
601 EXPECT_STREQ("OK", callback_response_
->status_text
.c_str());
602 EXPECT_STREQ("http://example.com/no_body.html",
603 callback_response_
->url
.spec().c_str());
604 EXPECT_STREQ("", callback_response_
->blob_uuid
.c_str());
605 EXPECT_EQ(0u, callback_response_
->blob_size
);
608 TEST_P(CacheStorageCacheTestP
, MatchBody
) {
609 EXPECT_TRUE(Put(body_request_
, body_response_
));
610 EXPECT_TRUE(Match(body_request_
));
611 EXPECT_EQ(200, callback_response_
->status_code
);
612 EXPECT_STREQ("OK", callback_response_
->status_text
.c_str());
613 EXPECT_STREQ("http://example.com/body.html",
614 callback_response_
->url
.spec().c_str());
615 EXPECT_STRNE("", callback_response_
->blob_uuid
.c_str());
616 EXPECT_EQ(expected_blob_data_
.size(), callback_response_
->blob_size
);
618 std::string response_body
;
619 CopyBody(callback_response_data_
.get(), &response_body
);
620 EXPECT_STREQ(expected_blob_data_
.c_str(), response_body
.c_str());
623 TEST_P(CacheStorageCacheTestP
, Vary
) {
624 body_request_
.headers
["vary_foo"] = "foo";
625 body_response_
.headers
["vary"] = "vary_foo";
626 EXPECT_TRUE(Put(body_request_
, body_response_
));
627 EXPECT_TRUE(Match(body_request_
));
629 body_request_
.headers
["vary_foo"] = "bar";
630 EXPECT_FALSE(Match(body_request_
));
632 body_request_
.headers
.erase("vary_foo");
633 EXPECT_FALSE(Match(body_request_
));
636 TEST_P(CacheStorageCacheTestP
, EmptyVary
) {
637 body_response_
.headers
["vary"] = "";
638 EXPECT_TRUE(Put(body_request_
, body_response_
));
639 EXPECT_TRUE(Match(body_request_
));
641 body_request_
.headers
["zoo"] = "zoo";
642 EXPECT_TRUE(Match(body_request_
));
645 TEST_P(CacheStorageCacheTestP
, NoVaryButDiffHeaders
) {
646 EXPECT_TRUE(Put(body_request_
, body_response_
));
647 EXPECT_TRUE(Match(body_request_
));
649 body_request_
.headers
["zoo"] = "zoo";
650 EXPECT_TRUE(Match(body_request_
));
653 TEST_P(CacheStorageCacheTestP
, VaryMultiple
) {
654 body_request_
.headers
["vary_foo"] = "foo";
655 body_request_
.headers
["vary_bar"] = "bar";
656 body_response_
.headers
["vary"] = " vary_foo , vary_bar";
657 EXPECT_TRUE(Put(body_request_
, body_response_
));
658 EXPECT_TRUE(Match(body_request_
));
660 body_request_
.headers
["vary_bar"] = "foo";
661 EXPECT_FALSE(Match(body_request_
));
663 body_request_
.headers
.erase("vary_bar");
664 EXPECT_FALSE(Match(body_request_
));
667 TEST_P(CacheStorageCacheTestP
, VaryNewHeader
) {
668 body_request_
.headers
["vary_foo"] = "foo";
669 body_response_
.headers
["vary"] = " vary_foo, vary_bar";
670 EXPECT_TRUE(Put(body_request_
, body_response_
));
671 EXPECT_TRUE(Match(body_request_
));
673 body_request_
.headers
["vary_bar"] = "bar";
674 EXPECT_FALSE(Match(body_request_
));
677 TEST_P(CacheStorageCacheTestP
, VaryStar
) {
678 body_response_
.headers
["vary"] = "*";
679 EXPECT_TRUE(Put(body_request_
, body_response_
));
680 EXPECT_FALSE(Match(body_request_
));
683 TEST_P(CacheStorageCacheTestP
, EmptyKeys
) {
685 EXPECT_EQ(0u, callback_strings_
.size());
688 TEST_P(CacheStorageCacheTestP
, TwoKeys
) {
689 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
690 EXPECT_TRUE(Put(body_request_
, body_response_
));
692 EXPECT_EQ(2u, callback_strings_
.size());
693 std::vector
<std::string
> expected_keys
;
694 expected_keys
.push_back(no_body_request_
.url
.spec());
695 expected_keys
.push_back(body_request_
.url
.spec());
696 EXPECT_TRUE(VerifyKeys(expected_keys
));
699 TEST_P(CacheStorageCacheTestP
, TwoKeysThenOne
) {
700 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
701 EXPECT_TRUE(Put(body_request_
, body_response_
));
703 EXPECT_EQ(2u, callback_strings_
.size());
704 std::vector
<std::string
> expected_keys
;
705 expected_keys
.push_back(no_body_request_
.url
.spec());
706 expected_keys
.push_back(body_request_
.url
.spec());
707 EXPECT_TRUE(VerifyKeys(expected_keys
));
709 EXPECT_TRUE(Delete(body_request_
));
711 EXPECT_EQ(1u, callback_strings_
.size());
712 std::vector
<std::string
> expected_key
;
713 expected_key
.push_back(no_body_request_
.url
.spec());
714 EXPECT_TRUE(VerifyKeys(expected_key
));
717 TEST_P(CacheStorageCacheTestP
, DeleteNoBody
) {
718 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
719 EXPECT_TRUE(Match(no_body_request_
));
720 EXPECT_TRUE(Delete(no_body_request_
));
721 EXPECT_FALSE(Match(no_body_request_
));
722 EXPECT_FALSE(Delete(no_body_request_
));
723 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
724 EXPECT_TRUE(Match(no_body_request_
));
725 EXPECT_TRUE(Delete(no_body_request_
));
728 TEST_P(CacheStorageCacheTestP
, DeleteBody
) {
729 EXPECT_TRUE(Put(body_request_
, body_response_
));
730 EXPECT_TRUE(Match(body_request_
));
731 EXPECT_TRUE(Delete(body_request_
));
732 EXPECT_FALSE(Match(body_request_
));
733 EXPECT_FALSE(Delete(body_request_
));
734 EXPECT_TRUE(Put(body_request_
, body_response_
));
735 EXPECT_TRUE(Match(body_request_
));
736 EXPECT_TRUE(Delete(body_request_
));
739 TEST_P(CacheStorageCacheTestP
, QuickStressNoBody
) {
740 for (int i
= 0; i
< 100; ++i
) {
741 EXPECT_FALSE(Match(no_body_request_
));
742 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
743 EXPECT_TRUE(Match(no_body_request_
));
744 EXPECT_TRUE(Delete(no_body_request_
));
748 TEST_P(CacheStorageCacheTestP
, QuickStressBody
) {
749 for (int i
= 0; i
< 100; ++i
) {
750 ASSERT_FALSE(Match(body_request_
));
751 ASSERT_TRUE(Put(body_request_
, body_response_
));
752 ASSERT_TRUE(Match(body_request_
));
753 ASSERT_TRUE(Delete(body_request_
));
757 TEST_P(CacheStorageCacheTestP
, PutResponseType
) {
758 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeBasic
));
759 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeCORS
));
760 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeDefault
));
761 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeError
));
762 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeOpaque
));
765 TEST_F(CacheStorageCacheTest
, CaselessServiceWorkerResponseHeaders
) {
766 // CacheStorageCache depends on ServiceWorkerResponse having caseless
767 // headers so that it can quickly lookup vary headers.
768 ServiceWorkerResponse
response(GURL("http://www.example.com"), 200, "OK",
769 blink::WebServiceWorkerResponseTypeDefault
,
770 ServiceWorkerHeaderMap(), "", 0, GURL(),
771 blink::WebServiceWorkerResponseErrorUnknown
);
772 response
.headers
["content-type"] = "foo";
773 response
.headers
["Content-Type"] = "bar";
774 EXPECT_EQ("bar", response
.headers
["content-type"]);
777 TEST_F(CacheStorageCacheTest
, CaselessServiceWorkerFetchRequestHeaders
) {
778 // CacheStorageCache depends on ServiceWorkerFetchRequest having caseless
779 // headers so that it can quickly lookup vary headers.
780 ServiceWorkerFetchRequest
request(GURL("http://www.example.com"), "GET",
781 ServiceWorkerHeaderMap(), Referrer(),
783 request
.headers
["content-type"] = "foo";
784 request
.headers
["Content-Type"] = "bar";
785 EXPECT_EQ("bar", request
.headers
["content-type"]);
788 TEST_P(CacheStorageCacheTestP
, QuotaManagerModified
) {
789 EXPECT_EQ(0, quota_manager_proxy_
->notify_storage_modified_count());
791 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
792 EXPECT_EQ(1, quota_manager_proxy_
->notify_storage_modified_count());
793 EXPECT_LT(0, quota_manager_proxy_
->last_notified_delta());
794 int64 sum_delta
= quota_manager_proxy_
->last_notified_delta();
796 EXPECT_TRUE(Put(body_request_
, body_response_
));
797 EXPECT_EQ(2, quota_manager_proxy_
->notify_storage_modified_count());
798 EXPECT_LT(sum_delta
, quota_manager_proxy_
->last_notified_delta());
799 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
801 EXPECT_TRUE(Delete(body_request_
));
802 EXPECT_EQ(3, quota_manager_proxy_
->notify_storage_modified_count());
803 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
805 EXPECT_TRUE(Delete(no_body_request_
));
806 EXPECT_EQ(4, quota_manager_proxy_
->notify_storage_modified_count());
807 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
809 EXPECT_EQ(0, sum_delta
);
812 TEST_F(CacheStorageCacheMemoryOnlyTest
, MemoryBackedSize
) {
813 EXPECT_EQ(0, cache_
->MemoryBackedSize());
814 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
815 EXPECT_LT(0, cache_
->MemoryBackedSize());
816 int64 no_body_size
= cache_
->MemoryBackedSize();
818 EXPECT_TRUE(Delete(no_body_request_
));
819 EXPECT_EQ(0, cache_
->MemoryBackedSize());
821 EXPECT_TRUE(Put(body_request_
, body_response_
));
822 EXPECT_LT(no_body_size
, cache_
->MemoryBackedSize());
824 EXPECT_TRUE(Delete(body_request_
));
825 EXPECT_EQ(0, cache_
->MemoryBackedSize());
828 TEST_F(CacheStorageCacheTest
, MemoryBackedSizePersistent
) {
829 EXPECT_EQ(0, cache_
->MemoryBackedSize());
830 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
831 EXPECT_EQ(0, cache_
->MemoryBackedSize());
834 TEST_P(CacheStorageCacheTestP
, OpsFailOnClosedBackendNeverCreated
) {
835 cache_
->set_delay_backend_creation(
836 true); // Will hang the test if a backend is created.
837 EXPECT_TRUE(Close());
841 TEST_P(CacheStorageCacheTestP
, OpsFailOnClosedBackend
) {
842 // Create the backend and put something in it.
843 EXPECT_TRUE(Put(body_request_
, body_response_
));
844 EXPECT_TRUE(Close());
848 TEST_P(CacheStorageCacheTestP
, VerifySerialScheduling
) {
849 // Start two operations, the first one is delayed but the second isn't. The
850 // second should wait for the first.
851 EXPECT_TRUE(Keys()); // Opens the backend.
852 DelayableBackend
* delayable_backend
= cache_
->UseDelayableBackend();
853 delayable_backend
->set_delay_open(true);
855 int sequence_out
= -1;
857 CacheStorageBatchOperation operation1
;
858 operation1
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
859 operation1
.request
= body_request_
;
860 operation1
.response
= body_response_
;
862 scoped_ptr
<base::RunLoop
> close_loop1(new base::RunLoop());
863 cache_
->BatchOperation(
864 std::vector
<CacheStorageBatchOperation
>(1, operation1
),
865 base::Bind(&CacheStorageCacheTest::SequenceCallback
,
866 base::Unretained(this), 1, &sequence_out
, close_loop1
.get()));
868 // Blocks on opening the cache entry.
869 base::RunLoop().RunUntilIdle();
871 CacheStorageBatchOperation operation2
;
872 operation2
.operation_type
= CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
;
873 operation2
.request
= body_request_
;
874 operation2
.response
= body_response_
;
876 delayable_backend
->set_delay_open(false);
877 scoped_ptr
<base::RunLoop
> close_loop2(new base::RunLoop());
878 cache_
->BatchOperation(
879 std::vector
<CacheStorageBatchOperation
>(1, operation2
),
880 base::Bind(&CacheStorageCacheTest::SequenceCallback
,
881 base::Unretained(this), 2, &sequence_out
, close_loop2
.get()));
883 // The second put operation should wait for the first to complete.
884 base::RunLoop().RunUntilIdle();
885 EXPECT_FALSE(callback_response_
);
887 delayable_backend
->OpenEntryContinue();
889 EXPECT_EQ(1, sequence_out
);
891 EXPECT_EQ(2, sequence_out
);
894 INSTANTIATE_TEST_CASE_P(CacheStorageCacheTest
,
895 CacheStorageCacheTestP
,
896 ::testing::Values(false, true));
898 } // namespace content