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/message_loop/message_loop_proxy.h"
10 #include "base/run_loop.h"
11 #include "content/browser/fileapi/chrome_blob_storage_context.h"
12 #include "content/browser/fileapi/mock_url_request_delegate.h"
13 #include "content/browser/quota/mock_quota_manager_proxy.h"
14 #include "content/common/cache_storage/cache_storage_types.h"
15 #include "content/common/service_worker/service_worker_types.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/referrer.h"
18 #include "content/public/test/test_browser_context.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/url_request/url_request_context_getter.h"
22 #include "net/url_request/url_request_job_factory_impl.h"
23 #include "storage/browser/blob/blob_data_builder.h"
24 #include "storage/browser/blob/blob_data_handle.h"
25 #include "storage/browser/blob/blob_data_snapshot.h"
26 #include "storage/browser/blob/blob_storage_context.h"
27 #include "storage/browser/blob/blob_url_request_job_factory.h"
28 #include "storage/browser/quota/quota_manager_proxy.h"
29 #include "testing/gtest/include/gtest/gtest.h"
34 const char kTestData
[] = "Hello World";
36 // Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
38 storage::BlobProtocolHandler
* CreateMockBlobProtocolHandler(
39 storage::BlobStorageContext
* blob_storage_context
) {
40 // The FileSystemContext and MessageLoopProxy are not actually used but a
41 // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor.
42 return new storage::BlobProtocolHandler(
43 blob_storage_context
, NULL
, base::MessageLoopProxy::current().get());
46 // A disk_cache::Backend wrapper that can delay operations.
47 class DelayableBackend
: public disk_cache::Backend
{
49 DelayableBackend(scoped_ptr
<disk_cache::Backend
> backend
)
50 : backend_(backend
.Pass()), delay_open_(false) {}
52 // disk_cache::Backend overrides
53 net::CacheType
GetCacheType() const override
{
54 return backend_
->GetCacheType();
56 int32
GetEntryCount() const override
{ return backend_
->GetEntryCount(); }
57 int OpenEntry(const std::string
& key
,
58 disk_cache::Entry
** entry
,
59 const CompletionCallback
& callback
) override
{
61 open_entry_callback_
=
62 base::Bind(&DelayableBackend::OpenEntryDelayedImpl
,
63 base::Unretained(this), key
, entry
, callback
);
64 return net::ERR_IO_PENDING
;
67 return backend_
->OpenEntry(key
, entry
, callback
);
69 int CreateEntry(const std::string
& key
,
70 disk_cache::Entry
** entry
,
71 const CompletionCallback
& callback
) override
{
72 return backend_
->CreateEntry(key
, entry
, callback
);
74 int DoomEntry(const std::string
& key
,
75 const CompletionCallback
& callback
) override
{
76 return backend_
->DoomEntry(key
, callback
);
78 int DoomAllEntries(const CompletionCallback
& callback
) override
{
79 return backend_
->DoomAllEntries(callback
);
81 int DoomEntriesBetween(base::Time initial_time
,
83 const CompletionCallback
& callback
) override
{
84 return backend_
->DoomEntriesBetween(initial_time
, end_time
, callback
);
86 int DoomEntriesSince(base::Time initial_time
,
87 const CompletionCallback
& callback
) override
{
88 return backend_
->DoomEntriesSince(initial_time
, callback
);
90 scoped_ptr
<Iterator
> CreateIterator() override
{
91 return backend_
->CreateIterator();
94 std::vector
<std::pair
<std::string
, std::string
>>* stats
) override
{
95 return backend_
->GetStats(stats
);
97 void OnExternalCacheHit(const std::string
& key
) override
{
98 return backend_
->OnExternalCacheHit(key
);
101 // Call to continue a delayed open.
102 void OpenEntryContinue() {
103 EXPECT_FALSE(open_entry_callback_
.is_null());
104 open_entry_callback_
.Run();
107 void set_delay_open(bool value
) { delay_open_
= value
; }
110 void OpenEntryDelayedImpl(const std::string
& key
,
111 disk_cache::Entry
** entry
,
112 const CompletionCallback
& callback
) {
113 int rv
= backend_
->OpenEntry(key
, entry
, callback
);
114 if (rv
!= net::ERR_IO_PENDING
)
118 scoped_ptr
<disk_cache::Backend
> backend_
;
120 base::Closure open_entry_callback_
;
125 // A CacheStorageCache that can optionally delay during backend creation.
126 class TestCacheStorageCache
: public CacheStorageCache
{
128 TestCacheStorageCache(
130 const base::FilePath
& path
,
131 net::URLRequestContext
* request_context
,
132 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
133 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
134 : CacheStorageCache(origin
,
139 delay_backend_creation_(false) {}
141 void CreateBackend(const ErrorCallback
& callback
) override
{
142 backend_creation_callback_
= callback
;
143 if (delay_backend_creation_
)
145 ContinueCreateBackend();
148 void ContinueCreateBackend() {
149 CacheStorageCache::CreateBackend(backend_creation_callback_
);
152 void set_delay_backend_creation(bool delay
) {
153 delay_backend_creation_
= delay
;
156 // Swap the existing backend with a delayable one. The backend must have been
157 // created before calling this.
158 DelayableBackend
* UseDelayableBackend() {
159 EXPECT_TRUE(backend_
);
160 DelayableBackend
* delayable_backend
= new DelayableBackend(backend_
.Pass());
161 backend_
.reset(delayable_backend
);
162 return delayable_backend
;
166 ~TestCacheStorageCache() override
{}
168 bool delay_backend_creation_
;
169 ErrorCallback backend_creation_callback_
;
171 DISALLOW_COPY_AND_ASSIGN(TestCacheStorageCache
);
174 class CacheStorageCacheTest
: public testing::Test
{
176 CacheStorageCacheTest()
177 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
178 callback_error_(CacheStorageCache::ERROR_TYPE_OK
),
179 callback_closed_(false) {}
181 void SetUp() override
{
182 ChromeBlobStorageContext
* blob_storage_context
=
183 ChromeBlobStorageContext::GetFor(&browser_context_
);
184 // Wait for chrome_blob_storage_context to finish initializing.
185 base::RunLoop().RunUntilIdle();
186 blob_storage_context_
= blob_storage_context
->context();
188 quota_manager_proxy_
= new MockQuotaManagerProxy(
189 nullptr, base::MessageLoopProxy::current().get());
191 url_request_job_factory_
.reset(new net::URLRequestJobFactoryImpl
);
192 url_request_job_factory_
->SetProtocolHandler(
193 "blob", CreateMockBlobProtocolHandler(blob_storage_context
->context()));
195 net::URLRequestContext
* url_request_context
=
196 browser_context_
.GetRequestContext()->GetURLRequestContext();
198 url_request_context
->set_job_factory(url_request_job_factory_
.get());
200 CreateRequests(blob_storage_context
);
203 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
204 base::FilePath path
= MemoryOnly() ? base::FilePath() : temp_dir_
.path();
206 cache_
= make_scoped_refptr(new TestCacheStorageCache(
207 GURL("http://example.com"), path
, url_request_context
,
208 quota_manager_proxy_
, blob_storage_context
->context()->AsWeakPtr()));
211 void TearDown() override
{
212 quota_manager_proxy_
->SimulateQuotaManagerDestroyed();
213 base::RunLoop().RunUntilIdle();
216 void CreateRequests(ChromeBlobStorageContext
* blob_storage_context
) {
217 ServiceWorkerHeaderMap headers
;
218 headers
.insert(std::make_pair("a", "a"));
219 headers
.insert(std::make_pair("b", "b"));
221 ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET",
222 headers
, Referrer(), false);
224 ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
225 "GET", headers
, Referrer(), false);
227 std::string expected_response
;
228 for (int i
= 0; i
< 100; ++i
)
229 expected_blob_data_
+= kTestData
;
231 scoped_ptr
<storage::BlobDataBuilder
> blob_data(
232 new storage::BlobDataBuilder("blob-id:myblob"));
233 blob_data
->AppendData(expected_blob_data_
);
236 blob_storage_context
->context()->AddFinishedBlob(blob_data
.get());
238 body_response_
= ServiceWorkerResponse(
239 GURL("http://example.com/body.html"), 200, "OK",
240 blink::WebServiceWorkerResponseTypeDefault
, headers
,
241 blob_handle_
->uuid(), expected_blob_data_
.size(), GURL());
243 no_body_response_
= ServiceWorkerResponse(
244 GURL("http://example.com/no_body.html"), 200, "OK",
245 blink::WebServiceWorkerResponseTypeDefault
, headers
, "", 0, GURL());
248 scoped_ptr
<ServiceWorkerFetchRequest
> CopyFetchRequest(
249 const ServiceWorkerFetchRequest
& request
) {
250 return make_scoped_ptr(new ServiceWorkerFetchRequest(
251 request
.url
, request
.method
, request
.headers
, request
.referrer
,
255 scoped_ptr
<ServiceWorkerResponse
> CopyFetchResponse(
256 const ServiceWorkerResponse
& response
) {
257 scoped_ptr
<ServiceWorkerResponse
> sw_response(new ServiceWorkerResponse(
258 response
.url
, response
.status_code
, response
.status_text
,
259 response
.response_type
, response
.headers
, response
.blob_uuid
,
260 response
.blob_size
, response
.stream_url
));
261 return sw_response
.Pass();
264 bool Put(const ServiceWorkerFetchRequest
& request
,
265 const ServiceWorkerResponse
& response
) {
266 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
269 CopyFetchRequest(request
), CopyFetchResponse(response
),
270 base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback
,
271 base::Unretained(this), base::Unretained(loop
.get())));
272 // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
273 // once the cache uses a passed in MessageLoopProxy instead of the CACHE
277 return callback_error_
== CacheStorageCache::ERROR_TYPE_OK
;
280 bool Match(const ServiceWorkerFetchRequest
& request
) {
281 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
284 CopyFetchRequest(request
),
285 base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback
,
286 base::Unretained(this), base::Unretained(loop
.get())));
289 return callback_error_
== CacheStorageCache::ERROR_TYPE_OK
;
292 bool Delete(const ServiceWorkerFetchRequest
& request
) {
293 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
296 CopyFetchRequest(request
),
297 base::Bind(&CacheStorageCacheTest::ErrorTypeCallback
,
298 base::Unretained(this), base::Unretained(loop
.get())));
301 return callback_error_
== CacheStorageCache::ERROR_TYPE_OK
;
305 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
307 cache_
->Keys(base::Bind(&CacheStorageCacheTest::RequestsCallback
,
308 base::Unretained(this),
309 base::Unretained(loop
.get())));
312 return callback_error_
== CacheStorageCache::ERROR_TYPE_OK
;
316 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
318 cache_
->Close(base::Bind(&CacheStorageCacheTest::CloseCallback
,
319 base::Unretained(this),
320 base::Unretained(loop
.get())));
322 return callback_closed_
;
325 void RequestsCallback(base::RunLoop
* run_loop
,
326 CacheStorageCache::ErrorType error
,
327 scoped_ptr
<CacheStorageCache::Requests
> requests
) {
328 callback_error_
= error
;
329 callback_strings_
.clear();
331 for (size_t i
= 0u; i
< requests
->size(); ++i
)
332 callback_strings_
.push_back(requests
->at(i
).url
.spec());
338 void ErrorTypeCallback(base::RunLoop
* run_loop
,
339 CacheStorageCache::ErrorType error
) {
340 callback_error_
= error
;
345 void ResponseAndErrorCallback(
346 base::RunLoop
* run_loop
,
347 CacheStorageCache::ErrorType error
,
348 scoped_ptr
<ServiceWorkerResponse
> response
,
349 scoped_ptr
<storage::BlobDataHandle
> body_handle
) {
350 callback_error_
= error
;
351 callback_response_
= response
.Pass();
352 callback_response_data_
.reset();
353 if (error
== CacheStorageCache::ERROR_TYPE_OK
&&
354 !callback_response_
->blob_uuid
.empty()) {
355 callback_response_data_
= body_handle
.Pass();
362 void CloseCallback(base::RunLoop
* run_loop
) {
363 EXPECT_FALSE(callback_closed_
);
364 callback_closed_
= true;
369 void CopyBody(storage::BlobDataHandle
* blob_handle
, std::string
* output
) {
370 scoped_ptr
<storage::BlobDataSnapshot
> data
= blob_handle
->CreateSnapshot();
371 const auto& items
= data
->items();
372 for (const auto& item
: items
) {
373 output
->append(item
->bytes(), item
->length());
377 bool VerifyKeys(const std::vector
<std::string
>& expected_keys
) {
378 if (expected_keys
.size() != callback_strings_
.size())
381 std::set
<std::string
> found_set
;
382 for (int i
= 0, max
= callback_strings_
.size(); i
< max
; ++i
)
383 found_set
.insert(callback_strings_
[i
]);
385 for (int i
= 0, max
= expected_keys
.size(); i
< max
; ++i
) {
386 if (found_set
.find(expected_keys
[i
]) == found_set
.end())
392 bool TestResponseType(blink::WebServiceWorkerResponseType response_type
) {
393 body_response_
.response_type
= response_type
;
394 EXPECT_TRUE(Put(body_request_
, body_response_
));
395 EXPECT_TRUE(Match(body_request_
));
396 EXPECT_TRUE(Delete(body_request_
));
397 return response_type
== callback_response_
->response_type
;
400 void VerifyAllOpsFail() {
401 EXPECT_FALSE(Put(no_body_request_
, no_body_response_
));
402 EXPECT_FALSE(Match(no_body_request_
));
403 EXPECT_FALSE(Delete(body_request_
));
404 EXPECT_FALSE(Keys());
407 virtual bool MemoryOnly() { return false; }
410 TestBrowserContext browser_context_
;
411 TestBrowserThreadBundle browser_thread_bundle_
;
412 scoped_ptr
<net::URLRequestJobFactoryImpl
> url_request_job_factory_
;
413 scoped_refptr
<MockQuotaManagerProxy
> quota_manager_proxy_
;
414 storage::BlobStorageContext
* blob_storage_context_
;
416 base::ScopedTempDir temp_dir_
;
417 scoped_refptr
<TestCacheStorageCache
> cache_
;
419 ServiceWorkerFetchRequest body_request_
;
420 ServiceWorkerResponse body_response_
;
421 ServiceWorkerFetchRequest no_body_request_
;
422 ServiceWorkerResponse no_body_response_
;
423 scoped_ptr
<storage::BlobDataHandle
> blob_handle_
;
424 std::string expected_blob_data_
;
426 CacheStorageCache::ErrorType callback_error_
;
427 scoped_ptr
<ServiceWorkerResponse
> callback_response_
;
428 scoped_ptr
<storage::BlobDataHandle
> callback_response_data_
;
429 std::vector
<std::string
> callback_strings_
;
430 bool callback_closed_
;
433 class CacheStorageCacheTestP
: public CacheStorageCacheTest
,
434 public testing::WithParamInterface
<bool> {
435 bool MemoryOnly() override
{ return !GetParam(); }
438 class CacheStorageCacheMemoryOnlyTest
439 : public CacheStorageCacheTest
,
440 public testing::WithParamInterface
<bool> {
441 bool MemoryOnly() override
{ return true; }
444 TEST_P(CacheStorageCacheTestP
, PutNoBody
) {
445 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
446 EXPECT_TRUE(callback_response_
);
447 EXPECT_STREQ(no_body_response_
.url
.spec().c_str(),
448 callback_response_
->url
.spec().c_str());
449 EXPECT_FALSE(callback_response_data_
);
450 EXPECT_STREQ("", callback_response_
->blob_uuid
.c_str());
451 EXPECT_EQ(0u, callback_response_
->blob_size
);
454 TEST_P(CacheStorageCacheTestP
, PutBody
) {
455 EXPECT_TRUE(Put(body_request_
, body_response_
));
456 EXPECT_TRUE(callback_response_
);
457 EXPECT_STREQ(body_response_
.url
.spec().c_str(),
458 callback_response_
->url
.spec().c_str());
459 EXPECT_TRUE(callback_response_data_
);
460 EXPECT_STRNE("", callback_response_
->blob_uuid
.c_str());
461 EXPECT_EQ(expected_blob_data_
.size(), callback_response_
->blob_size
);
463 std::string response_body
;
464 CopyBody(callback_response_data_
.get(), &response_body
);
465 EXPECT_STREQ(expected_blob_data_
.c_str(), response_body
.c_str());
468 TEST_P(CacheStorageCacheTestP
, ResponseURLDiffersFromRequestURL
) {
469 no_body_response_
.url
= GURL("http://example.com/foobar");
470 EXPECT_STRNE("http://example.com/foobar",
471 no_body_request_
.url
.spec().c_str());
472 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
473 EXPECT_TRUE(Match(no_body_request_
));
474 EXPECT_STREQ("http://example.com/foobar",
475 callback_response_
->url
.spec().c_str());
478 TEST_P(CacheStorageCacheTestP
, ResponseURLEmpty
) {
479 no_body_response_
.url
= GURL();
480 EXPECT_STRNE("", no_body_request_
.url
.spec().c_str());
481 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
482 EXPECT_TRUE(Match(no_body_request_
));
483 EXPECT_STREQ("", callback_response_
->url
.spec().c_str());
486 TEST_F(CacheStorageCacheTest
, PutBodyDropBlobRef
) {
487 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
488 cache_
->Put(CopyFetchRequest(body_request_
),
489 CopyFetchResponse(body_response_
),
490 base::Bind(&CacheStorageCacheTestP::ResponseAndErrorCallback
,
491 base::Unretained(this), base::Unretained(loop
.get())));
492 // The handle should be held by the cache now so the deref here should be
494 blob_handle_
.reset();
497 EXPECT_EQ(CacheStorageCache::ERROR_TYPE_OK
, callback_error_
);
500 TEST_P(CacheStorageCacheTestP
, PutReplace
) {
501 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
502 EXPECT_TRUE(Match(body_request_
));
503 EXPECT_FALSE(callback_response_data_
);
505 EXPECT_TRUE(Put(body_request_
, body_response_
));
506 EXPECT_TRUE(Match(body_request_
));
507 EXPECT_TRUE(callback_response_data_
);
509 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
510 EXPECT_TRUE(Match(body_request_
));
511 EXPECT_FALSE(callback_response_data_
);
514 TEST_P(CacheStorageCacheTestP
, MatchNoBody
) {
515 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
516 EXPECT_TRUE(Match(no_body_request_
));
517 EXPECT_EQ(200, callback_response_
->status_code
);
518 EXPECT_STREQ("OK", callback_response_
->status_text
.c_str());
519 EXPECT_STREQ("http://example.com/no_body.html",
520 callback_response_
->url
.spec().c_str());
521 EXPECT_STREQ("", callback_response_
->blob_uuid
.c_str());
522 EXPECT_EQ(0u, callback_response_
->blob_size
);
525 TEST_P(CacheStorageCacheTestP
, MatchBody
) {
526 EXPECT_TRUE(Put(body_request_
, body_response_
));
527 EXPECT_TRUE(Match(body_request_
));
528 EXPECT_EQ(200, callback_response_
->status_code
);
529 EXPECT_STREQ("OK", callback_response_
->status_text
.c_str());
530 EXPECT_STREQ("http://example.com/body.html",
531 callback_response_
->url
.spec().c_str());
532 EXPECT_STRNE("", callback_response_
->blob_uuid
.c_str());
533 EXPECT_EQ(expected_blob_data_
.size(), callback_response_
->blob_size
);
535 std::string response_body
;
536 CopyBody(callback_response_data_
.get(), &response_body
);
537 EXPECT_STREQ(expected_blob_data_
.c_str(), response_body
.c_str());
540 TEST_P(CacheStorageCacheTestP
, Vary
) {
541 body_request_
.headers
["vary_foo"] = "foo";
542 body_response_
.headers
["vary"] = "vary_foo";
543 EXPECT_TRUE(Put(body_request_
, body_response_
));
544 EXPECT_TRUE(Match(body_request_
));
546 body_request_
.headers
["vary_foo"] = "bar";
547 EXPECT_FALSE(Match(body_request_
));
549 body_request_
.headers
.erase("vary_foo");
550 EXPECT_FALSE(Match(body_request_
));
553 TEST_P(CacheStorageCacheTestP
, EmptyVary
) {
554 body_response_
.headers
["vary"] = "";
555 EXPECT_TRUE(Put(body_request_
, body_response_
));
556 EXPECT_TRUE(Match(body_request_
));
558 body_request_
.headers
["zoo"] = "zoo";
559 EXPECT_TRUE(Match(body_request_
));
562 TEST_P(CacheStorageCacheTestP
, NoVaryButDiffHeaders
) {
563 EXPECT_TRUE(Put(body_request_
, body_response_
));
564 EXPECT_TRUE(Match(body_request_
));
566 body_request_
.headers
["zoo"] = "zoo";
567 EXPECT_TRUE(Match(body_request_
));
570 TEST_P(CacheStorageCacheTestP
, VaryMultiple
) {
571 body_request_
.headers
["vary_foo"] = "foo";
572 body_request_
.headers
["vary_bar"] = "bar";
573 body_response_
.headers
["vary"] = " vary_foo , vary_bar";
574 EXPECT_TRUE(Put(body_request_
, body_response_
));
575 EXPECT_TRUE(Match(body_request_
));
577 body_request_
.headers
["vary_bar"] = "foo";
578 EXPECT_FALSE(Match(body_request_
));
580 body_request_
.headers
.erase("vary_bar");
581 EXPECT_FALSE(Match(body_request_
));
584 TEST_P(CacheStorageCacheTestP
, VaryNewHeader
) {
585 body_request_
.headers
["vary_foo"] = "foo";
586 body_response_
.headers
["vary"] = " vary_foo, vary_bar";
587 EXPECT_TRUE(Put(body_request_
, body_response_
));
588 EXPECT_TRUE(Match(body_request_
));
590 body_request_
.headers
["vary_bar"] = "bar";
591 EXPECT_FALSE(Match(body_request_
));
594 TEST_P(CacheStorageCacheTestP
, VaryStar
) {
595 body_response_
.headers
["vary"] = "*";
596 EXPECT_TRUE(Put(body_request_
, body_response_
));
597 EXPECT_FALSE(Match(body_request_
));
600 TEST_P(CacheStorageCacheTestP
, EmptyKeys
) {
602 EXPECT_EQ(0u, callback_strings_
.size());
605 TEST_P(CacheStorageCacheTestP
, TwoKeys
) {
606 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
607 EXPECT_TRUE(Put(body_request_
, body_response_
));
609 EXPECT_EQ(2u, callback_strings_
.size());
610 std::vector
<std::string
> expected_keys
;
611 expected_keys
.push_back(no_body_request_
.url
.spec());
612 expected_keys
.push_back(body_request_
.url
.spec());
613 EXPECT_TRUE(VerifyKeys(expected_keys
));
616 TEST_P(CacheStorageCacheTestP
, TwoKeysThenOne
) {
617 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
618 EXPECT_TRUE(Put(body_request_
, body_response_
));
620 EXPECT_EQ(2u, callback_strings_
.size());
621 std::vector
<std::string
> expected_keys
;
622 expected_keys
.push_back(no_body_request_
.url
.spec());
623 expected_keys
.push_back(body_request_
.url
.spec());
624 EXPECT_TRUE(VerifyKeys(expected_keys
));
626 EXPECT_TRUE(Delete(body_request_
));
628 EXPECT_EQ(1u, callback_strings_
.size());
629 std::vector
<std::string
> expected_key
;
630 expected_key
.push_back(no_body_request_
.url
.spec());
631 EXPECT_TRUE(VerifyKeys(expected_key
));
634 TEST_P(CacheStorageCacheTestP
, DeleteNoBody
) {
635 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
636 EXPECT_TRUE(Match(no_body_request_
));
637 EXPECT_TRUE(Delete(no_body_request_
));
638 EXPECT_FALSE(Match(no_body_request_
));
639 EXPECT_FALSE(Delete(no_body_request_
));
640 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
641 EXPECT_TRUE(Match(no_body_request_
));
642 EXPECT_TRUE(Delete(no_body_request_
));
645 TEST_P(CacheStorageCacheTestP
, DeleteBody
) {
646 EXPECT_TRUE(Put(body_request_
, body_response_
));
647 EXPECT_TRUE(Match(body_request_
));
648 EXPECT_TRUE(Delete(body_request_
));
649 EXPECT_FALSE(Match(body_request_
));
650 EXPECT_FALSE(Delete(body_request_
));
651 EXPECT_TRUE(Put(body_request_
, body_response_
));
652 EXPECT_TRUE(Match(body_request_
));
653 EXPECT_TRUE(Delete(body_request_
));
656 TEST_P(CacheStorageCacheTestP
, QuickStressNoBody
) {
657 for (int i
= 0; i
< 100; ++i
) {
658 EXPECT_FALSE(Match(no_body_request_
));
659 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
660 EXPECT_TRUE(Match(no_body_request_
));
661 EXPECT_TRUE(Delete(no_body_request_
));
665 TEST_P(CacheStorageCacheTestP
, QuickStressBody
) {
666 for (int i
= 0; i
< 100; ++i
) {
667 ASSERT_FALSE(Match(body_request_
));
668 ASSERT_TRUE(Put(body_request_
, body_response_
));
669 ASSERT_TRUE(Match(body_request_
));
670 ASSERT_TRUE(Delete(body_request_
));
674 TEST_P(CacheStorageCacheTestP
, PutResponseType
) {
675 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeBasic
));
676 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeCORS
));
677 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeDefault
));
678 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeError
));
679 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeOpaque
));
682 TEST_F(CacheStorageCacheTest
, CaselessServiceWorkerResponseHeaders
) {
683 // CacheStorageCache depends on ServiceWorkerResponse having caseless
684 // headers so that it can quickly lookup vary headers.
685 ServiceWorkerResponse
response(GURL("http://www.example.com"), 200, "OK",
686 blink::WebServiceWorkerResponseTypeDefault
,
687 ServiceWorkerHeaderMap(), "", 0, GURL());
688 response
.headers
["content-type"] = "foo";
689 response
.headers
["Content-Type"] = "bar";
690 EXPECT_EQ("bar", response
.headers
["content-type"]);
693 TEST_F(CacheStorageCacheTest
, CaselessServiceWorkerFetchRequestHeaders
) {
694 // CacheStorageCache depends on ServiceWorkerFetchRequest having caseless
695 // headers so that it can quickly lookup vary headers.
696 ServiceWorkerFetchRequest
request(GURL("http://www.example.com"), "GET",
697 ServiceWorkerHeaderMap(), Referrer(),
699 request
.headers
["content-type"] = "foo";
700 request
.headers
["Content-Type"] = "bar";
701 EXPECT_EQ("bar", request
.headers
["content-type"]);
704 TEST_P(CacheStorageCacheTestP
, QuotaManagerModified
) {
705 EXPECT_EQ(0, quota_manager_proxy_
->notify_storage_modified_count());
707 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
708 EXPECT_EQ(1, quota_manager_proxy_
->notify_storage_modified_count());
709 EXPECT_LT(0, quota_manager_proxy_
->last_notified_delta());
710 int64 sum_delta
= quota_manager_proxy_
->last_notified_delta();
712 EXPECT_TRUE(Put(body_request_
, body_response_
));
713 EXPECT_EQ(2, quota_manager_proxy_
->notify_storage_modified_count());
714 EXPECT_LT(sum_delta
, quota_manager_proxy_
->last_notified_delta());
715 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
717 EXPECT_TRUE(Delete(body_request_
));
718 EXPECT_EQ(3, quota_manager_proxy_
->notify_storage_modified_count());
719 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
721 EXPECT_TRUE(Delete(no_body_request_
));
722 EXPECT_EQ(4, quota_manager_proxy_
->notify_storage_modified_count());
723 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
725 EXPECT_EQ(0, sum_delta
);
728 TEST_F(CacheStorageCacheMemoryOnlyTest
, MemoryBackedSize
) {
729 EXPECT_EQ(0, cache_
->MemoryBackedSize());
730 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
731 EXPECT_LT(0, cache_
->MemoryBackedSize());
732 int64 no_body_size
= cache_
->MemoryBackedSize();
734 EXPECT_TRUE(Delete(no_body_request_
));
735 EXPECT_EQ(0, cache_
->MemoryBackedSize());
737 EXPECT_TRUE(Put(body_request_
, body_response_
));
738 EXPECT_LT(no_body_size
, cache_
->MemoryBackedSize());
740 EXPECT_TRUE(Delete(body_request_
));
741 EXPECT_EQ(0, cache_
->MemoryBackedSize());
744 TEST_F(CacheStorageCacheTest
, MemoryBackedSizePersistent
) {
745 EXPECT_EQ(0, cache_
->MemoryBackedSize());
746 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
747 EXPECT_EQ(0, cache_
->MemoryBackedSize());
750 TEST_P(CacheStorageCacheTestP
, OpsFailOnClosedBackendNeverCreated
) {
751 cache_
->set_delay_backend_creation(
752 true); // Will hang the test if a backend is created.
753 EXPECT_TRUE(Close());
757 TEST_P(CacheStorageCacheTestP
, OpsFailOnClosedBackend
) {
758 // Create the backend and put something in it.
759 EXPECT_TRUE(Put(body_request_
, body_response_
));
760 EXPECT_TRUE(Close());
764 TEST_P(CacheStorageCacheTestP
, VerifySerialScheduling
) {
765 // Start two operations, the first one is delayed but the second isn't. The
766 // second should wait for the first.
767 EXPECT_TRUE(Keys()); // Opens the backend.
768 DelayableBackend
* delayable_backend
= cache_
->UseDelayableBackend();
769 delayable_backend
->set_delay_open(true);
771 scoped_ptr
<ServiceWorkerResponse
> response1
=
772 CopyFetchResponse(body_response_
);
773 response1
->status_code
= 1;
775 scoped_ptr
<base::RunLoop
> close_loop1(new base::RunLoop());
776 cache_
->Put(CopyFetchRequest(body_request_
), response1
.Pass(),
777 base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback
,
778 base::Unretained(this), close_loop1
.get()));
780 // Blocks on opening the cache entry.
781 base::RunLoop().RunUntilIdle();
783 delayable_backend
->set_delay_open(false);
784 scoped_ptr
<ServiceWorkerResponse
> response2
=
785 CopyFetchResponse(body_response_
);
786 response2
->status_code
= 2;
787 scoped_ptr
<base::RunLoop
> close_loop2(new base::RunLoop());
788 cache_
->Put(CopyFetchRequest(body_request_
), response2
.Pass(),
789 base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback
,
790 base::Unretained(this), close_loop2
.get()));
792 // The second put operation should wait for the first to complete.
793 base::RunLoop().RunUntilIdle();
794 EXPECT_FALSE(callback_response_
);
796 delayable_backend
->OpenEntryContinue();
798 EXPECT_EQ(1, callback_response_
->status_code
);
800 EXPECT_EQ(2, callback_response_
->status_code
);
803 INSTANTIATE_TEST_CASE_P(CacheStorageCacheTest
,
804 CacheStorageCacheTestP
,
805 ::testing::Values(false, true));
807 } // namespace content