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/service_worker/service_worker_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/service_worker/service_worker_types.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/common/referrer.h"
17 #include "content/public/test/test_browser_context.h"
18 #include "content/public/test/test_browser_thread_bundle.h"
19 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_context_getter.h"
21 #include "net/url_request/url_request_job_factory_impl.h"
22 #include "storage/browser/blob/blob_data_builder.h"
23 #include "storage/browser/blob/blob_data_handle.h"
24 #include "storage/browser/blob/blob_data_snapshot.h"
25 #include "storage/browser/blob/blob_storage_context.h"
26 #include "storage/browser/blob/blob_url_request_job_factory.h"
27 #include "storage/browser/quota/quota_manager_proxy.h"
28 #include "testing/gtest/include/gtest/gtest.h"
33 const char kTestData
[] = "Hello World";
35 // Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
37 storage::BlobProtocolHandler
* CreateMockBlobProtocolHandler(
38 storage::BlobStorageContext
* blob_storage_context
) {
39 // The FileSystemContext and MessageLoopProxy are not actually used but a
40 // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor.
41 return new storage::BlobProtocolHandler(
42 blob_storage_context
, NULL
, base::MessageLoopProxy::current().get());
45 // A disk_cache::Backend wrapper that can delay operations.
46 class DelayableBackend
: public disk_cache::Backend
{
48 DelayableBackend(scoped_ptr
<disk_cache::Backend
> backend
)
49 : backend_(backend
.Pass()), delay_open_(false) {}
51 // disk_cache::Backend overrides
52 net::CacheType
GetCacheType() const override
{
53 return backend_
->GetCacheType();
55 int32
GetEntryCount() const override
{ return backend_
->GetEntryCount(); }
56 int OpenEntry(const std::string
& key
,
57 disk_cache::Entry
** entry
,
58 const CompletionCallback
& callback
) override
{
60 open_entry_callback_
=
61 base::Bind(&DelayableBackend::OpenEntryDelayedImpl
,
62 base::Unretained(this), key
, entry
, callback
);
63 return net::ERR_IO_PENDING
;
66 return backend_
->OpenEntry(key
, entry
, callback
);
68 int CreateEntry(const std::string
& key
,
69 disk_cache::Entry
** entry
,
70 const CompletionCallback
& callback
) override
{
71 return backend_
->CreateEntry(key
, entry
, callback
);
73 int DoomEntry(const std::string
& key
,
74 const CompletionCallback
& callback
) override
{
75 return backend_
->DoomEntry(key
, callback
);
77 int DoomAllEntries(const CompletionCallback
& callback
) override
{
78 return backend_
->DoomAllEntries(callback
);
80 int DoomEntriesBetween(base::Time initial_time
,
82 const CompletionCallback
& callback
) override
{
83 return backend_
->DoomEntriesBetween(initial_time
, end_time
, callback
);
85 int DoomEntriesSince(base::Time initial_time
,
86 const CompletionCallback
& callback
) override
{
87 return backend_
->DoomEntriesSince(initial_time
, callback
);
89 scoped_ptr
<Iterator
> CreateIterator() override
{
90 return backend_
->CreateIterator();
93 std::vector
<std::pair
<std::string
, std::string
>>* stats
) override
{
94 return backend_
->GetStats(stats
);
96 void OnExternalCacheHit(const std::string
& key
) override
{
97 return backend_
->OnExternalCacheHit(key
);
100 // Call to continue a delayed open.
101 void OpenEntryContinue() {
102 EXPECT_FALSE(open_entry_callback_
.is_null());
103 open_entry_callback_
.Run();
106 void set_delay_open(bool value
) { delay_open_
= value
; }
109 void OpenEntryDelayedImpl(const std::string
& key
,
110 disk_cache::Entry
** entry
,
111 const CompletionCallback
& callback
) {
112 int rv
= backend_
->OpenEntry(key
, entry
, callback
);
113 if (rv
!= net::ERR_IO_PENDING
)
117 scoped_ptr
<disk_cache::Backend
> backend_
;
119 base::Closure open_entry_callback_
;
124 // A ServiceWorkerCache that can optionally delay during backend creation.
125 class TestServiceWorkerCache
: public ServiceWorkerCache
{
127 TestServiceWorkerCache(
129 const base::FilePath
& path
,
130 net::URLRequestContext
* request_context
,
131 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
132 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
133 : ServiceWorkerCache(origin
,
138 delay_backend_creation_(false) {}
140 void CreateBackend(const ErrorCallback
& callback
) override
{
141 backend_creation_callback_
= callback
;
142 if (delay_backend_creation_
)
144 ContinueCreateBackend();
147 void ContinueCreateBackend() {
148 ServiceWorkerCache::CreateBackend(backend_creation_callback_
);
151 void set_delay_backend_creation(bool delay
) {
152 delay_backend_creation_
= delay
;
155 // Swap the existing backend with a delayable one. The backend must have been
156 // created before calling this.
157 DelayableBackend
* UseDelayableBackend() {
158 EXPECT_TRUE(backend_
);
159 DelayableBackend
* delayable_backend
= new DelayableBackend(backend_
.Pass());
160 backend_
.reset(delayable_backend
);
161 return delayable_backend
;
165 ~TestServiceWorkerCache() override
{}
167 bool delay_backend_creation_
;
168 ErrorCallback backend_creation_callback_
;
170 DISALLOW_COPY_AND_ASSIGN(TestServiceWorkerCache
);
173 class ServiceWorkerCacheTest
: public testing::Test
{
175 ServiceWorkerCacheTest()
176 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
177 callback_error_(ServiceWorkerCache::ErrorTypeOK
),
178 callback_closed_(false) {}
180 void SetUp() override
{
181 ChromeBlobStorageContext
* blob_storage_context
=
182 ChromeBlobStorageContext::GetFor(&browser_context_
);
183 // Wait for chrome_blob_storage_context to finish initializing.
184 base::RunLoop().RunUntilIdle();
185 blob_storage_context_
= blob_storage_context
->context();
187 quota_manager_proxy_
= new MockQuotaManagerProxy(
188 nullptr, base::MessageLoopProxy::current().get());
190 url_request_job_factory_
.reset(new net::URLRequestJobFactoryImpl
);
191 url_request_job_factory_
->SetProtocolHandler(
192 "blob", CreateMockBlobProtocolHandler(blob_storage_context
->context()));
194 net::URLRequestContext
* url_request_context
=
195 browser_context_
.GetRequestContext()->GetURLRequestContext();
197 url_request_context
->set_job_factory(url_request_job_factory_
.get());
199 CreateRequests(blob_storage_context
);
202 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
203 base::FilePath path
= MemoryOnly() ? base::FilePath() : temp_dir_
.path();
205 cache_
= make_scoped_refptr(new TestServiceWorkerCache(
206 GURL("http://example.com"), path
, url_request_context
,
207 quota_manager_proxy_
, blob_storage_context
->context()->AsWeakPtr()));
210 void TearDown() override
{
211 quota_manager_proxy_
->SimulateQuotaManagerDestroyed();
212 base::RunLoop().RunUntilIdle();
215 void CreateRequests(ChromeBlobStorageContext
* blob_storage_context
) {
216 ServiceWorkerHeaderMap headers
;
217 headers
.insert(std::make_pair("a", "a"));
218 headers
.insert(std::make_pair("b", "b"));
220 ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET",
221 headers
, Referrer(), false);
223 ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
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());
241 ServiceWorkerResponse(GURL("http://example.com/body.html"),
244 blink::WebServiceWorkerResponseTypeDefault
,
246 blob_handle_
->uuid(),
247 expected_blob_data_
.size(),
251 ServiceWorkerResponse(GURL("http://example.com/no_body.html"),
254 blink::WebServiceWorkerResponseTypeDefault
,
261 scoped_ptr
<ServiceWorkerFetchRequest
> CopyFetchRequest(
262 const ServiceWorkerFetchRequest
& request
) {
263 return make_scoped_ptr(new ServiceWorkerFetchRequest(request
.url
,
270 scoped_ptr
<ServiceWorkerResponse
> CopyFetchResponse(
271 const ServiceWorkerResponse
& response
) {
272 scoped_ptr
<ServiceWorkerResponse
> sw_response(
273 new ServiceWorkerResponse(response
.url
,
274 response
.status_code
,
275 response
.status_text
,
276 response
.response_type
,
280 response
.stream_url
));
281 return sw_response
.Pass();
284 bool Put(const ServiceWorkerFetchRequest
& request
,
285 const ServiceWorkerResponse
& response
) {
286 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
288 cache_
->Put(CopyFetchRequest(request
),
289 CopyFetchResponse(response
),
290 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback
,
291 base::Unretained(this),
292 base::Unretained(loop
.get())));
293 // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
294 // once the cache uses a passed in MessageLoopProxy instead of the CACHE
298 return callback_error_
== ServiceWorkerCache::ErrorTypeOK
;
301 bool Match(const ServiceWorkerFetchRequest
& request
) {
302 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
304 cache_
->Match(CopyFetchRequest(request
),
305 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback
,
306 base::Unretained(this),
307 base::Unretained(loop
.get())));
310 return callback_error_
== ServiceWorkerCache::ErrorTypeOK
;
313 bool Delete(const ServiceWorkerFetchRequest
& request
) {
314 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
316 cache_
->Delete(CopyFetchRequest(request
),
317 base::Bind(&ServiceWorkerCacheTest::ErrorTypeCallback
,
318 base::Unretained(this),
319 base::Unretained(loop
.get())));
322 return callback_error_
== ServiceWorkerCache::ErrorTypeOK
;
326 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
328 cache_
->Keys(base::Bind(&ServiceWorkerCacheTest::RequestsCallback
,
329 base::Unretained(this),
330 base::Unretained(loop
.get())));
333 return callback_error_
== ServiceWorkerCache::ErrorTypeOK
;
337 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
339 cache_
->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback
,
340 base::Unretained(this),
341 base::Unretained(loop
.get())));
343 return callback_closed_
;
346 void RequestsCallback(base::RunLoop
* run_loop
,
347 ServiceWorkerCache::ErrorType error
,
348 scoped_ptr
<ServiceWorkerCache::Requests
> requests
) {
349 callback_error_
= error
;
350 callback_strings_
.clear();
352 for (size_t i
= 0u; i
< requests
->size(); ++i
)
353 callback_strings_
.push_back(requests
->at(i
).url
.spec());
359 void ErrorTypeCallback(base::RunLoop
* run_loop
,
360 ServiceWorkerCache::ErrorType error
) {
361 callback_error_
= error
;
366 void ResponseAndErrorCallback(
367 base::RunLoop
* run_loop
,
368 ServiceWorkerCache::ErrorType error
,
369 scoped_ptr
<ServiceWorkerResponse
> response
,
370 scoped_ptr
<storage::BlobDataHandle
> body_handle
) {
371 callback_error_
= error
;
372 callback_response_
= response
.Pass();
373 callback_response_data_
.reset();
374 if (error
== ServiceWorkerCache::ErrorTypeOK
&&
375 !callback_response_
->blob_uuid
.empty()) {
376 callback_response_data_
= body_handle
.Pass();
383 void CloseCallback(base::RunLoop
* run_loop
) {
384 EXPECT_FALSE(callback_closed_
);
385 callback_closed_
= true;
390 void CopyBody(storage::BlobDataHandle
* blob_handle
, std::string
* output
) {
391 scoped_ptr
<storage::BlobDataSnapshot
> data
= blob_handle
->CreateSnapshot();
392 const auto& items
= data
->items();
393 for (const auto& item
: items
) {
394 output
->append(item
->bytes(), item
->length());
398 bool VerifyKeys(const std::vector
<std::string
>& expected_keys
) {
399 if (expected_keys
.size() != callback_strings_
.size())
402 std::set
<std::string
> found_set
;
403 for (int i
= 0, max
= callback_strings_
.size(); i
< max
; ++i
)
404 found_set
.insert(callback_strings_
[i
]);
406 for (int i
= 0, max
= expected_keys
.size(); i
< max
; ++i
) {
407 if (found_set
.find(expected_keys
[i
]) == found_set
.end())
413 bool TestResponseType(blink::WebServiceWorkerResponseType response_type
) {
414 body_response_
.response_type
= response_type
;
415 EXPECT_TRUE(Put(body_request_
, body_response_
));
416 EXPECT_TRUE(Match(body_request_
));
417 EXPECT_TRUE(Delete(body_request_
));
418 return response_type
== callback_response_
->response_type
;
421 void VerifyAllOpsFail() {
422 EXPECT_FALSE(Put(no_body_request_
, no_body_response_
));
423 EXPECT_FALSE(Match(no_body_request_
));
424 EXPECT_FALSE(Delete(body_request_
));
425 EXPECT_FALSE(Keys());
428 virtual bool MemoryOnly() { return false; }
431 TestBrowserContext browser_context_
;
432 TestBrowserThreadBundle browser_thread_bundle_
;
433 scoped_ptr
<net::URLRequestJobFactoryImpl
> url_request_job_factory_
;
434 scoped_refptr
<MockQuotaManagerProxy
> quota_manager_proxy_
;
435 storage::BlobStorageContext
* blob_storage_context_
;
437 base::ScopedTempDir temp_dir_
;
438 scoped_refptr
<TestServiceWorkerCache
> cache_
;
440 ServiceWorkerFetchRequest body_request_
;
441 ServiceWorkerResponse body_response_
;
442 ServiceWorkerFetchRequest no_body_request_
;
443 ServiceWorkerResponse no_body_response_
;
444 scoped_ptr
<storage::BlobDataHandle
> blob_handle_
;
445 std::string expected_blob_data_
;
447 ServiceWorkerCache::ErrorType callback_error_
;
448 scoped_ptr
<ServiceWorkerResponse
> callback_response_
;
449 scoped_ptr
<storage::BlobDataHandle
> callback_response_data_
;
450 std::vector
<std::string
> callback_strings_
;
451 bool callback_closed_
;
454 class ServiceWorkerCacheTestP
: public ServiceWorkerCacheTest
,
455 public testing::WithParamInterface
<bool> {
456 bool MemoryOnly() override
{ return !GetParam(); }
459 class ServiceWorkerCacheMemoryOnlyTest
460 : public ServiceWorkerCacheTest
,
461 public testing::WithParamInterface
<bool> {
462 bool MemoryOnly() override
{ return true; }
465 TEST_P(ServiceWorkerCacheTestP
, PutNoBody
) {
466 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
467 EXPECT_TRUE(callback_response_
);
468 EXPECT_STREQ(no_body_response_
.url
.spec().c_str(),
469 callback_response_
->url
.spec().c_str());
470 EXPECT_FALSE(callback_response_data_
);
471 EXPECT_STREQ("", callback_response_
->blob_uuid
.c_str());
472 EXPECT_EQ(0u, callback_response_
->blob_size
);
475 TEST_P(ServiceWorkerCacheTestP
, PutBody
) {
476 EXPECT_TRUE(Put(body_request_
, body_response_
));
477 EXPECT_TRUE(callback_response_
);
478 EXPECT_STREQ(body_response_
.url
.spec().c_str(),
479 callback_response_
->url
.spec().c_str());
480 EXPECT_TRUE(callback_response_data_
);
481 EXPECT_STRNE("", callback_response_
->blob_uuid
.c_str());
482 EXPECT_EQ(expected_blob_data_
.size(), callback_response_
->blob_size
);
484 std::string response_body
;
485 CopyBody(callback_response_data_
.get(), &response_body
);
486 EXPECT_STREQ(expected_blob_data_
.c_str(), response_body
.c_str());
489 TEST_P(ServiceWorkerCacheTestP
, ResponseURLDiffersFromRequestURL
) {
490 no_body_response_
.url
= GURL("http://example.com/foobar");
491 EXPECT_STRNE("http://example.com/foobar",
492 no_body_request_
.url
.spec().c_str());
493 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
494 EXPECT_TRUE(Match(no_body_request_
));
495 EXPECT_STREQ("http://example.com/foobar",
496 callback_response_
->url
.spec().c_str());
499 TEST_P(ServiceWorkerCacheTestP
, ResponseURLEmpty
) {
500 no_body_response_
.url
= GURL();
501 EXPECT_STRNE("", no_body_request_
.url
.spec().c_str());
502 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
503 EXPECT_TRUE(Match(no_body_request_
));
504 EXPECT_STREQ("", callback_response_
->url
.spec().c_str());
507 TEST_F(ServiceWorkerCacheTest
, PutBodyDropBlobRef
) {
508 scoped_ptr
<base::RunLoop
> loop(new base::RunLoop());
509 cache_
->Put(CopyFetchRequest(body_request_
),
510 CopyFetchResponse(body_response_
),
511 base::Bind(&ServiceWorkerCacheTestP::ResponseAndErrorCallback
,
512 base::Unretained(this),
513 base::Unretained(loop
.get())));
514 // The handle should be held by the cache now so the deref here should be
516 blob_handle_
.reset();
519 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK
, callback_error_
);
522 TEST_P(ServiceWorkerCacheTestP
, PutReplace
) {
523 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
524 EXPECT_TRUE(Match(body_request_
));
525 EXPECT_FALSE(callback_response_data_
);
527 EXPECT_TRUE(Put(body_request_
, body_response_
));
528 EXPECT_TRUE(Match(body_request_
));
529 EXPECT_TRUE(callback_response_data_
);
531 EXPECT_TRUE(Put(body_request_
, no_body_response_
));
532 EXPECT_TRUE(Match(body_request_
));
533 EXPECT_FALSE(callback_response_data_
);
536 TEST_P(ServiceWorkerCacheTestP
, MatchNoBody
) {
537 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
538 EXPECT_TRUE(Match(no_body_request_
));
539 EXPECT_EQ(200, callback_response_
->status_code
);
540 EXPECT_STREQ("OK", callback_response_
->status_text
.c_str());
541 EXPECT_STREQ("http://example.com/no_body.html",
542 callback_response_
->url
.spec().c_str());
543 EXPECT_STREQ("", callback_response_
->blob_uuid
.c_str());
544 EXPECT_EQ(0u, callback_response_
->blob_size
);
547 TEST_P(ServiceWorkerCacheTestP
, MatchBody
) {
548 EXPECT_TRUE(Put(body_request_
, body_response_
));
549 EXPECT_TRUE(Match(body_request_
));
550 EXPECT_EQ(200, callback_response_
->status_code
);
551 EXPECT_STREQ("OK", callback_response_
->status_text
.c_str());
552 EXPECT_STREQ("http://example.com/body.html",
553 callback_response_
->url
.spec().c_str());
554 EXPECT_STRNE("", callback_response_
->blob_uuid
.c_str());
555 EXPECT_EQ(expected_blob_data_
.size(), callback_response_
->blob_size
);
557 std::string response_body
;
558 CopyBody(callback_response_data_
.get(), &response_body
);
559 EXPECT_STREQ(expected_blob_data_
.c_str(), response_body
.c_str());
562 TEST_P(ServiceWorkerCacheTestP
, Vary
) {
563 body_request_
.headers
["vary_foo"] = "foo";
564 body_response_
.headers
["vary"] = "vary_foo";
565 EXPECT_TRUE(Put(body_request_
, body_response_
));
566 EXPECT_TRUE(Match(body_request_
));
568 body_request_
.headers
["vary_foo"] = "bar";
569 EXPECT_FALSE(Match(body_request_
));
571 body_request_
.headers
.erase("vary_foo");
572 EXPECT_FALSE(Match(body_request_
));
575 TEST_P(ServiceWorkerCacheTestP
, EmptyVary
) {
576 body_response_
.headers
["vary"] = "";
577 EXPECT_TRUE(Put(body_request_
, body_response_
));
578 EXPECT_TRUE(Match(body_request_
));
580 body_request_
.headers
["zoo"] = "zoo";
581 EXPECT_TRUE(Match(body_request_
));
584 TEST_P(ServiceWorkerCacheTestP
, NoVaryButDiffHeaders
) {
585 EXPECT_TRUE(Put(body_request_
, body_response_
));
586 EXPECT_TRUE(Match(body_request_
));
588 body_request_
.headers
["zoo"] = "zoo";
589 EXPECT_TRUE(Match(body_request_
));
592 TEST_P(ServiceWorkerCacheTestP
, VaryMultiple
) {
593 body_request_
.headers
["vary_foo"] = "foo";
594 body_request_
.headers
["vary_bar"] = "bar";
595 body_response_
.headers
["vary"] = " vary_foo , vary_bar";
596 EXPECT_TRUE(Put(body_request_
, body_response_
));
597 EXPECT_TRUE(Match(body_request_
));
599 body_request_
.headers
["vary_bar"] = "foo";
600 EXPECT_FALSE(Match(body_request_
));
602 body_request_
.headers
.erase("vary_bar");
603 EXPECT_FALSE(Match(body_request_
));
606 TEST_P(ServiceWorkerCacheTestP
, VaryNewHeader
) {
607 body_request_
.headers
["vary_foo"] = "foo";
608 body_response_
.headers
["vary"] = " vary_foo, vary_bar";
609 EXPECT_TRUE(Put(body_request_
, body_response_
));
610 EXPECT_TRUE(Match(body_request_
));
612 body_request_
.headers
["vary_bar"] = "bar";
613 EXPECT_FALSE(Match(body_request_
));
616 TEST_P(ServiceWorkerCacheTestP
, VaryStar
) {
617 body_response_
.headers
["vary"] = "*";
618 EXPECT_TRUE(Put(body_request_
, body_response_
));
619 EXPECT_FALSE(Match(body_request_
));
622 TEST_P(ServiceWorkerCacheTestP
, EmptyKeys
) {
624 EXPECT_EQ(0u, callback_strings_
.size());
627 TEST_P(ServiceWorkerCacheTestP
, TwoKeys
) {
628 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
629 EXPECT_TRUE(Put(body_request_
, body_response_
));
631 EXPECT_EQ(2u, callback_strings_
.size());
632 std::vector
<std::string
> expected_keys
;
633 expected_keys
.push_back(no_body_request_
.url
.spec());
634 expected_keys
.push_back(body_request_
.url
.spec());
635 EXPECT_TRUE(VerifyKeys(expected_keys
));
638 TEST_P(ServiceWorkerCacheTestP
, TwoKeysThenOne
) {
639 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
640 EXPECT_TRUE(Put(body_request_
, body_response_
));
642 EXPECT_EQ(2u, callback_strings_
.size());
643 std::vector
<std::string
> expected_keys
;
644 expected_keys
.push_back(no_body_request_
.url
.spec());
645 expected_keys
.push_back(body_request_
.url
.spec());
646 EXPECT_TRUE(VerifyKeys(expected_keys
));
648 EXPECT_TRUE(Delete(body_request_
));
650 EXPECT_EQ(1u, callback_strings_
.size());
651 std::vector
<std::string
> expected_key
;
652 expected_key
.push_back(no_body_request_
.url
.spec());
653 EXPECT_TRUE(VerifyKeys(expected_key
));
656 TEST_P(ServiceWorkerCacheTestP
, DeleteNoBody
) {
657 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
658 EXPECT_TRUE(Match(no_body_request_
));
659 EXPECT_TRUE(Delete(no_body_request_
));
660 EXPECT_FALSE(Match(no_body_request_
));
661 EXPECT_FALSE(Delete(no_body_request_
));
662 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
663 EXPECT_TRUE(Match(no_body_request_
));
664 EXPECT_TRUE(Delete(no_body_request_
));
667 TEST_P(ServiceWorkerCacheTestP
, DeleteBody
) {
668 EXPECT_TRUE(Put(body_request_
, body_response_
));
669 EXPECT_TRUE(Match(body_request_
));
670 EXPECT_TRUE(Delete(body_request_
));
671 EXPECT_FALSE(Match(body_request_
));
672 EXPECT_FALSE(Delete(body_request_
));
673 EXPECT_TRUE(Put(body_request_
, body_response_
));
674 EXPECT_TRUE(Match(body_request_
));
675 EXPECT_TRUE(Delete(body_request_
));
678 TEST_P(ServiceWorkerCacheTestP
, QuickStressNoBody
) {
679 for (int i
= 0; i
< 100; ++i
) {
680 EXPECT_FALSE(Match(no_body_request_
));
681 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
682 EXPECT_TRUE(Match(no_body_request_
));
683 EXPECT_TRUE(Delete(no_body_request_
));
687 TEST_P(ServiceWorkerCacheTestP
, QuickStressBody
) {
688 for (int i
= 0; i
< 100; ++i
) {
689 ASSERT_FALSE(Match(body_request_
));
690 ASSERT_TRUE(Put(body_request_
, body_response_
));
691 ASSERT_TRUE(Match(body_request_
));
692 ASSERT_TRUE(Delete(body_request_
));
696 TEST_P(ServiceWorkerCacheTestP
, PutResponseType
) {
697 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeBasic
));
698 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeCORS
));
699 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeDefault
));
700 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeError
));
701 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeOpaque
));
704 TEST_F(ServiceWorkerCacheTest
, CaselessServiceWorkerResponseHeaders
) {
705 // ServiceWorkerCache depends on ServiceWorkerResponse having caseless
706 // headers so that it can quickly lookup vary headers.
707 ServiceWorkerResponse
response(GURL("http://www.example.com"),
710 blink::WebServiceWorkerResponseTypeDefault
,
711 ServiceWorkerHeaderMap(),
715 response
.headers
["content-type"] = "foo";
716 response
.headers
["Content-Type"] = "bar";
717 EXPECT_EQ("bar", response
.headers
["content-type"]);
720 TEST_F(ServiceWorkerCacheTest
, CaselessServiceWorkerFetchRequestHeaders
) {
721 // ServiceWorkerCache depends on ServiceWorkerFetchRequest having caseless
722 // headers so that it can quickly lookup vary headers.
723 ServiceWorkerFetchRequest
request(GURL("http://www.example.com"),
725 ServiceWorkerHeaderMap(),
728 request
.headers
["content-type"] = "foo";
729 request
.headers
["Content-Type"] = "bar";
730 EXPECT_EQ("bar", request
.headers
["content-type"]);
733 TEST_P(ServiceWorkerCacheTestP
, QuotaManagerModified
) {
734 EXPECT_EQ(0, quota_manager_proxy_
->notify_storage_modified_count());
736 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
737 EXPECT_EQ(1, quota_manager_proxy_
->notify_storage_modified_count());
738 EXPECT_LT(0, quota_manager_proxy_
->last_notified_delta());
739 int64 sum_delta
= quota_manager_proxy_
->last_notified_delta();
741 EXPECT_TRUE(Put(body_request_
, body_response_
));
742 EXPECT_EQ(2, quota_manager_proxy_
->notify_storage_modified_count());
743 EXPECT_LT(sum_delta
, quota_manager_proxy_
->last_notified_delta());
744 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
746 EXPECT_TRUE(Delete(body_request_
));
747 EXPECT_EQ(3, quota_manager_proxy_
->notify_storage_modified_count());
748 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
750 EXPECT_TRUE(Delete(no_body_request_
));
751 EXPECT_EQ(4, quota_manager_proxy_
->notify_storage_modified_count());
752 sum_delta
+= quota_manager_proxy_
->last_notified_delta();
754 EXPECT_EQ(0, sum_delta
);
757 TEST_F(ServiceWorkerCacheMemoryOnlyTest
, MemoryBackedSize
) {
758 EXPECT_EQ(0, cache_
->MemoryBackedSize());
759 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
760 EXPECT_LT(0, cache_
->MemoryBackedSize());
761 int64 no_body_size
= cache_
->MemoryBackedSize();
763 EXPECT_TRUE(Delete(no_body_request_
));
764 EXPECT_EQ(0, cache_
->MemoryBackedSize());
766 EXPECT_TRUE(Put(body_request_
, body_response_
));
767 EXPECT_LT(no_body_size
, cache_
->MemoryBackedSize());
769 EXPECT_TRUE(Delete(body_request_
));
770 EXPECT_EQ(0, cache_
->MemoryBackedSize());
773 TEST_F(ServiceWorkerCacheTest
, MemoryBackedSizePersistent
) {
774 EXPECT_EQ(0, cache_
->MemoryBackedSize());
775 EXPECT_TRUE(Put(no_body_request_
, no_body_response_
));
776 EXPECT_EQ(0, cache_
->MemoryBackedSize());
779 TEST_P(ServiceWorkerCacheTestP
, OpsFailOnClosedBackendNeverCreated
) {
780 cache_
->set_delay_backend_creation(
781 true); // Will hang the test if a backend is created.
782 EXPECT_TRUE(Close());
786 TEST_P(ServiceWorkerCacheTestP
, OpsFailOnClosedBackend
) {
787 // Create the backend and put something in it.
788 EXPECT_TRUE(Put(body_request_
, body_response_
));
789 EXPECT_TRUE(Close());
793 TEST_P(ServiceWorkerCacheTestP
, VerifySerialScheduling
) {
794 // Start two operations, the first one is delayed but the second isn't. The
795 // second should wait for the first.
796 EXPECT_TRUE(Keys()); // Opens the backend.
797 DelayableBackend
* delayable_backend
= cache_
->UseDelayableBackend();
798 delayable_backend
->set_delay_open(true);
800 scoped_ptr
<ServiceWorkerResponse
> response1
=
801 CopyFetchResponse(body_response_
);
802 response1
->status_code
= 1;
804 scoped_ptr
<base::RunLoop
> close_loop1(new base::RunLoop());
805 cache_
->Put(CopyFetchRequest(body_request_
), response1
.Pass(),
806 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback
,
807 base::Unretained(this), close_loop1
.get()));
809 // Blocks on opening the cache entry.
810 base::RunLoop().RunUntilIdle();
812 delayable_backend
->set_delay_open(false);
813 scoped_ptr
<ServiceWorkerResponse
> response2
=
814 CopyFetchResponse(body_response_
);
815 response2
->status_code
= 2;
816 scoped_ptr
<base::RunLoop
> close_loop2(new base::RunLoop());
817 cache_
->Put(CopyFetchRequest(body_request_
), response2
.Pass(),
818 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback
,
819 base::Unretained(this), close_loop2
.get()));
821 // The second put operation should wait for the first to complete.
822 base::RunLoop().RunUntilIdle();
823 EXPECT_FALSE(callback_response_
);
825 delayable_backend
->OpenEntryContinue();
827 EXPECT_EQ(1, callback_response_
->status_code
);
829 EXPECT_EQ(2, callback_response_
->status_code
);
832 INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheTest
,
833 ServiceWorkerCacheTestP
,
834 ::testing::Values(false, true));
836 } // namespace content