1 // Copyright 2013 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.
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/logging.h"
9 #include "base/run_loop.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_disk_cache.h"
14 #include "content/browser/service_worker/service_worker_registration.h"
15 #include "content/browser/service_worker/service_worker_storage.h"
16 #include "content/browser/service_worker/service_worker_utils.h"
17 #include "content/browser/service_worker/service_worker_version.h"
18 #include "content/common/service_worker/service_worker_status_code.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/test_completion_callback.h"
23 #include "net/http/http_response_headers.h"
24 #include "testing/gtest/include/gtest/gtest.h"
27 using net::TestCompletionCallback
;
28 using net::WrappedIOBuffer
;
34 typedef ServiceWorkerDatabase::RegistrationData RegistrationData
;
35 typedef ServiceWorkerDatabase::ResourceRecord ResourceRecord
;
37 void StatusCallback(bool* was_called
,
38 ServiceWorkerStatusCode
* result
,
39 ServiceWorkerStatusCode status
) {
44 ServiceWorkerStorage::StatusCallback
MakeStatusCallback(
46 ServiceWorkerStatusCode
* result
) {
47 return base::Bind(&StatusCallback
, was_called
, result
);
52 ServiceWorkerStatusCode
* result
,
53 scoped_refptr
<ServiceWorkerRegistration
>* found
,
54 ServiceWorkerStatusCode status
,
55 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
58 *found
= registration
;
61 ServiceWorkerStorage::FindRegistrationCallback
MakeFindCallback(
63 ServiceWorkerStatusCode
* result
,
64 scoped_refptr
<ServiceWorkerRegistration
>* found
) {
65 return base::Bind(&FindCallback
, was_called
, result
, found
);
70 std::vector
<ServiceWorkerRegistrationInfo
>* all_out
,
71 const std::vector
<ServiceWorkerRegistrationInfo
>& all
) {
76 ServiceWorkerStorage::GetAllRegistrationInfosCallback
MakeGetAllCallback(
78 std::vector
<ServiceWorkerRegistrationInfo
>* all
) {
79 return base::Bind(&GetAllCallback
, was_called
, all
);
82 void OnCompareComplete(
83 ServiceWorkerStatusCode
* status_out
, bool* are_equal_out
,
84 ServiceWorkerStatusCode status
, bool are_equal
) {
86 *are_equal_out
= are_equal
;
90 ServiceWorkerStorage
* storage
, int64 id
,
91 const std::string
& headers
,
92 IOBuffer
* body
, int length
) {
93 scoped_ptr
<ServiceWorkerResponseWriter
> writer
=
94 storage
->CreateResponseWriter(id
);
96 scoped_ptr
<net::HttpResponseInfo
> info(new net::HttpResponseInfo
);
97 info
->request_time
= base::Time::Now();
98 info
->response_time
= base::Time::Now();
99 info
->was_cached
= false;
100 info
->headers
= new net::HttpResponseHeaders(headers
);
101 scoped_refptr
<HttpResponseInfoIOBuffer
> info_buffer
=
102 new HttpResponseInfoIOBuffer(info
.release());
104 TestCompletionCallback cb
;
105 writer
->WriteInfo(info_buffer
.get(), cb
.callback());
106 int rv
= cb
.WaitForResult();
110 TestCompletionCallback cb
;
111 writer
->WriteData(body
, length
, cb
.callback());
112 int rv
= cb
.WaitForResult();
113 EXPECT_EQ(length
, rv
);
117 void WriteStringResponse(
118 ServiceWorkerStorage
* storage
, int64 id
,
119 const std::string
& headers
,
120 const std::string
& body
) {
121 scoped_refptr
<IOBuffer
> body_buffer(new WrappedIOBuffer(body
.data()));
122 WriteResponse(storage
, id
, headers
, body_buffer
.get(), body
.length());
125 void WriteBasicResponse(ServiceWorkerStorage
* storage
, int64 id
) {
126 scoped_ptr
<ServiceWorkerResponseWriter
> writer
=
127 storage
->CreateResponseWriter(id
);
129 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\0Content-Length: 5\0\0";
130 const char kHttpBody
[] = "Hello";
131 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
132 WriteStringResponse(storage
, id
, headers
, std::string(kHttpBody
));
135 bool VerifyBasicResponse(ServiceWorkerStorage
* storage
, int64 id
,
136 bool expected_positive_result
) {
137 const std::string
kExpectedHttpBody("Hello");
138 scoped_ptr
<ServiceWorkerResponseReader
> reader
=
139 storage
->CreateResponseReader(id
);
140 scoped_refptr
<HttpResponseInfoIOBuffer
> info_buffer
=
141 new HttpResponseInfoIOBuffer();
143 TestCompletionCallback cb
;
144 reader
->ReadInfo(info_buffer
.get(), cb
.callback());
145 int rv
= cb
.WaitForResult();
146 if (expected_positive_result
)
152 std::string received_body
;
154 const int kBigEnough
= 512;
155 scoped_refptr
<net::IOBuffer
> buffer
= new IOBuffer(kBigEnough
);
156 TestCompletionCallback cb
;
157 reader
->ReadData(buffer
.get(), kBigEnough
, cb
.callback());
158 int rv
= cb
.WaitForResult();
159 EXPECT_EQ(static_cast<int>(kExpectedHttpBody
.size()), rv
);
162 received_body
.assign(buffer
->data(), rv
);
166 std::string("HONKYDORY") ==
167 info_buffer
->http_info
->headers
->GetStatusText();
168 bool data_match
= kExpectedHttpBody
== received_body
;
170 EXPECT_TRUE(status_match
);
171 EXPECT_TRUE(data_match
);
172 return status_match
&& data_match
;
175 void WriteResponseOfSize(ServiceWorkerStorage
* storage
, int64 id
,
176 char val
, int size
) {
177 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\00";
178 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
179 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(size
);
180 memset(buffer
->data(), val
, size
);
181 WriteResponse(storage
, id
, headers
, buffer
.get(), size
);
186 class ServiceWorkerStorageTest
: public testing::Test
{
188 ServiceWorkerStorageTest()
189 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
) {
192 virtual void SetUp() override
{
193 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager(
194 new MockServiceWorkerDatabaseTaskManager(
195 base::ThreadTaskRunnerHandle::Get()));
197 new ServiceWorkerContextCore(GetUserDataDirectory(),
198 base::ThreadTaskRunnerHandle::Get(),
199 database_task_manager
.Pass(),
200 base::ThreadTaskRunnerHandle::Get(),
205 context_ptr_
= context_
->AsWeakPtr();
208 virtual void TearDown() override
{
212 virtual base::FilePath
GetUserDataDirectory() { return base::FilePath(); }
214 ServiceWorkerStorage
* storage() { return context_
->storage(); }
216 // A static class method for friendliness.
217 static void VerifyPurgeableListStatusCallback(
218 ServiceWorkerDatabase
* database
,
219 std::set
<int64
> *purgeable_ids
,
221 ServiceWorkerStatusCode
* result
,
222 ServiceWorkerStatusCode status
) {
225 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
226 database
->GetPurgeableResourceIds(purgeable_ids
));
230 ServiceWorkerStatusCode
StoreRegistration(
231 scoped_refptr
<ServiceWorkerRegistration
> registration
,
232 scoped_refptr
<ServiceWorkerVersion
> version
) {
233 bool was_called
= false;
234 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
235 storage()->StoreRegistration(registration
.get(),
237 MakeStatusCallback(&was_called
, &result
));
238 EXPECT_FALSE(was_called
); // always async
239 base::RunLoop().RunUntilIdle();
240 EXPECT_TRUE(was_called
);
244 ServiceWorkerStatusCode
DeleteRegistration(
245 int64 registration_id
,
246 const GURL
& origin
) {
247 bool was_called
= false;
248 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
249 storage()->DeleteRegistration(
250 registration_id
, origin
, MakeStatusCallback(&was_called
, &result
));
251 EXPECT_FALSE(was_called
); // always async
252 base::RunLoop().RunUntilIdle();
253 EXPECT_TRUE(was_called
);
257 void GetAllRegistrations(
258 std::vector
<ServiceWorkerRegistrationInfo
>* registrations
) {
259 bool was_called
= false;
260 storage()->GetAllRegistrations(
261 MakeGetAllCallback(&was_called
, registrations
));
262 EXPECT_FALSE(was_called
); // always async
263 base::RunLoop().RunUntilIdle();
264 EXPECT_TRUE(was_called
);
267 ServiceWorkerStatusCode
UpdateToActiveState(
268 scoped_refptr
<ServiceWorkerRegistration
> registration
) {
269 bool was_called
= false;
270 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
271 storage()->UpdateToActiveState(registration
.get(),
272 MakeStatusCallback(&was_called
, &result
));
273 EXPECT_FALSE(was_called
); // always async
274 base::RunLoop().RunUntilIdle();
275 EXPECT_TRUE(was_called
);
279 void UpdateLastUpdateCheckTime(ServiceWorkerRegistration
* registration
) {
280 storage()->UpdateLastUpdateCheckTime(registration
);
281 base::RunLoop().RunUntilIdle();
284 ServiceWorkerStatusCode
FindRegistrationForDocument(
285 const GURL
& document_url
,
286 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
287 bool was_called
= false;
288 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
289 storage()->FindRegistrationForDocument(
290 document_url
, MakeFindCallback(&was_called
, &result
, registration
));
291 base::RunLoop().RunUntilIdle();
292 EXPECT_TRUE(was_called
);
296 ServiceWorkerStatusCode
FindRegistrationForPattern(
298 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
299 bool was_called
= false;
300 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
301 storage()->FindRegistrationForPattern(
302 scope
, MakeFindCallback(&was_called
, &result
, registration
));
303 EXPECT_FALSE(was_called
); // always async
304 base::RunLoop().RunUntilIdle();
305 EXPECT_TRUE(was_called
);
309 ServiceWorkerStatusCode
FindRegistrationForId(
310 int64 registration_id
,
312 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
313 bool was_called
= false;
314 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
315 storage()->FindRegistrationForId(
316 registration_id
, origin
,
317 MakeFindCallback(&was_called
, &result
, registration
));
318 base::RunLoop().RunUntilIdle();
319 EXPECT_TRUE(was_called
);
323 scoped_ptr
<ServiceWorkerContextCore
> context_
;
324 base::WeakPtr
<ServiceWorkerContextCore
> context_ptr_
;
325 TestBrowserThreadBundle browser_thread_bundle_
;
328 TEST_F(ServiceWorkerStorageTest
, StoreFindUpdateDeleteRegistration
) {
329 const GURL
kScope("http://www.test.not/scope/");
330 const GURL
kScript("http://www.test.not/script.js");
331 const GURL
kDocumentUrl("http://www.test.not/scope/document.html");
332 const int64 kRegistrationId
= 0;
333 const int64 kVersionId
= 0;
334 const base::Time kToday
= base::Time::Now();
335 const base::Time kYesterday
= kToday
- base::TimeDelta::FromDays(1);
337 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
339 // We shouldn't find anything without having stored anything.
340 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
341 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
342 EXPECT_FALSE(found_registration
.get());
344 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
345 FindRegistrationForPattern(kScope
, &found_registration
));
346 EXPECT_FALSE(found_registration
.get());
348 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
349 FindRegistrationForId(
350 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
351 EXPECT_FALSE(found_registration
.get());
354 scoped_refptr
<ServiceWorkerRegistration
> live_registration
=
355 new ServiceWorkerRegistration(
356 kScope
, kRegistrationId
, context_ptr_
);
357 scoped_refptr
<ServiceWorkerVersion
> live_version
=
358 new ServiceWorkerVersion(
359 live_registration
.get(), kScript
, kVersionId
, context_ptr_
);
360 live_version
->SetStatus(ServiceWorkerVersion::INSTALLED
);
361 live_registration
->SetWaitingVersion(live_version
.get());
362 live_registration
->set_last_update_check(kYesterday
);
363 EXPECT_EQ(SERVICE_WORKER_OK
,
364 StoreRegistration(live_registration
, live_version
));
366 // Now we should find it and get the live ptr back immediately.
367 EXPECT_EQ(SERVICE_WORKER_OK
,
368 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
369 EXPECT_EQ(live_registration
, found_registration
);
370 found_registration
= NULL
;
372 // But FindRegistrationForPattern is always async.
373 EXPECT_EQ(SERVICE_WORKER_OK
,
374 FindRegistrationForPattern(kScope
, &found_registration
));
375 EXPECT_EQ(live_registration
, found_registration
);
376 found_registration
= NULL
;
378 // Can be found by id too.
379 EXPECT_EQ(SERVICE_WORKER_OK
,
380 FindRegistrationForId(
381 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
382 ASSERT_TRUE(found_registration
.get());
383 EXPECT_EQ(kRegistrationId
, found_registration
->id());
384 EXPECT_EQ(live_registration
, found_registration
);
385 found_registration
= NULL
;
387 // Drop the live registration, but keep the version live.
388 live_registration
= NULL
;
390 // Now FindRegistrationForDocument should be async.
391 EXPECT_EQ(SERVICE_WORKER_OK
,
392 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
393 ASSERT_TRUE(found_registration
.get());
394 EXPECT_EQ(kRegistrationId
, found_registration
->id());
395 EXPECT_TRUE(found_registration
->HasOneRef());
396 EXPECT_EQ(live_version
.get(), found_registration
->waiting_version());
397 found_registration
= NULL
;
399 // Drop the live version too.
402 // And FindRegistrationForPattern is always async.
403 EXPECT_EQ(SERVICE_WORKER_OK
,
404 FindRegistrationForPattern(kScope
, &found_registration
));
405 ASSERT_TRUE(found_registration
.get());
406 EXPECT_EQ(kRegistrationId
, found_registration
->id());
407 EXPECT_TRUE(found_registration
->HasOneRef());
408 EXPECT_FALSE(found_registration
->active_version());
409 ASSERT_TRUE(found_registration
->waiting_version());
410 EXPECT_EQ(kYesterday
, found_registration
->last_update_check());
411 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
,
412 found_registration
->waiting_version()->status());
414 // Update to active and update the last check time.
415 scoped_refptr
<ServiceWorkerVersion
> temp_version
=
416 found_registration
->waiting_version();
417 temp_version
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
418 found_registration
->SetActiveVersion(temp_version
.get());
420 EXPECT_EQ(SERVICE_WORKER_OK
, UpdateToActiveState(found_registration
));
421 found_registration
->set_last_update_check(kToday
);
422 UpdateLastUpdateCheckTime(found_registration
.get());
424 found_registration
= NULL
;
426 // Trying to update a unstored registration to active should fail.
427 scoped_refptr
<ServiceWorkerRegistration
> unstored_registration
=
428 new ServiceWorkerRegistration(
429 kScope
, kRegistrationId
+ 1, context_ptr_
);
430 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
431 UpdateToActiveState(unstored_registration
));
432 unstored_registration
= NULL
;
434 // The Find methods should return a registration with an active version
435 // and the expected update time.
436 EXPECT_EQ(SERVICE_WORKER_OK
,
437 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
438 ASSERT_TRUE(found_registration
.get());
439 EXPECT_EQ(kRegistrationId
, found_registration
->id());
440 EXPECT_TRUE(found_registration
->HasOneRef());
441 EXPECT_FALSE(found_registration
->waiting_version());
442 ASSERT_TRUE(found_registration
->active_version());
443 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
,
444 found_registration
->active_version()->status());
445 EXPECT_EQ(kToday
, found_registration
->last_update_check());
447 // Delete from storage but with a instance still live.
448 EXPECT_TRUE(context_
->GetLiveVersion(kRegistrationId
));
449 EXPECT_EQ(SERVICE_WORKER_OK
,
450 DeleteRegistration(kRegistrationId
, kScope
.GetOrigin()));
451 EXPECT_TRUE(context_
->GetLiveVersion(kRegistrationId
));
453 // Should no longer be found.
454 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
455 FindRegistrationForId(
456 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
457 EXPECT_FALSE(found_registration
.get());
459 // Deleting an unstored registration should succeed.
460 EXPECT_EQ(SERVICE_WORKER_OK
,
461 DeleteRegistration(kRegistrationId
+ 1, kScope
.GetOrigin()));
464 TEST_F(ServiceWorkerStorageTest
, InstallingRegistrationsAreFindable
) {
465 const GURL
kScope("http://www.test.not/scope/");
466 const GURL
kScript("http://www.test.not/script.js");
467 const GURL
kDocumentUrl("http://www.test.not/scope/document.html");
468 const int64 kRegistrationId
= 0;
469 const int64 kVersionId
= 0;
471 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
473 // Create an unstored registration.
474 scoped_refptr
<ServiceWorkerRegistration
> live_registration
=
475 new ServiceWorkerRegistration(
476 kScope
, kRegistrationId
, context_ptr_
);
477 scoped_refptr
<ServiceWorkerVersion
> live_version
=
478 new ServiceWorkerVersion(
479 live_registration
.get(), kScript
, kVersionId
, context_ptr_
);
480 live_version
->SetStatus(ServiceWorkerVersion::INSTALLING
);
481 live_registration
->SetWaitingVersion(live_version
.get());
483 // Should not be findable, including by GetAllRegistrations.
484 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
485 FindRegistrationForId(
486 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
487 EXPECT_FALSE(found_registration
.get());
489 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
490 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
491 EXPECT_FALSE(found_registration
.get());
493 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
494 FindRegistrationForPattern(kScope
, &found_registration
));
495 EXPECT_FALSE(found_registration
.get());
497 std::vector
<ServiceWorkerRegistrationInfo
> all_registrations
;
498 GetAllRegistrations(&all_registrations
);
499 EXPECT_TRUE(all_registrations
.empty());
501 // Notify storage of it being installed.
502 storage()->NotifyInstallingRegistration(live_registration
.get());
504 // Now should be findable.
505 EXPECT_EQ(SERVICE_WORKER_OK
,
506 FindRegistrationForId(
507 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
508 EXPECT_EQ(live_registration
, found_registration
);
509 found_registration
= NULL
;
511 EXPECT_EQ(SERVICE_WORKER_OK
,
512 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
513 EXPECT_EQ(live_registration
, found_registration
);
514 found_registration
= NULL
;
516 EXPECT_EQ(SERVICE_WORKER_OK
,
517 FindRegistrationForPattern(kScope
, &found_registration
));
518 EXPECT_EQ(live_registration
, found_registration
);
519 found_registration
= NULL
;
521 GetAllRegistrations(&all_registrations
);
522 EXPECT_EQ(1u, all_registrations
.size());
523 all_registrations
.clear();
525 // Notify storage of installation no longer happening.
526 storage()->NotifyDoneInstallingRegistration(
527 live_registration
.get(), NULL
, SERVICE_WORKER_OK
);
529 // Once again, should not be findable.
530 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
531 FindRegistrationForId(
532 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
533 EXPECT_FALSE(found_registration
.get());
535 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
536 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
537 EXPECT_FALSE(found_registration
.get());
539 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
540 FindRegistrationForPattern(kScope
, &found_registration
));
541 EXPECT_FALSE(found_registration
.get());
543 GetAllRegistrations(&all_registrations
);
544 EXPECT_TRUE(all_registrations
.empty());
547 class ServiceWorkerResourceStorageTest
: public ServiceWorkerStorageTest
{
549 virtual void SetUp() override
{
550 ServiceWorkerStorageTest::SetUp();
552 storage()->LazyInitialize(base::Bind(&base::DoNothing
));
553 base::RunLoop().RunUntilIdle();
554 scope_
= GURL("http://www.test.not/scope/");
555 script_
= GURL("http://www.test.not/script.js");
556 import_
= GURL("http://www.test.not/import.js");
557 document_url_
= GURL("http://www.test.not/scope/document.html");
558 registration_id_
= storage()->NewRegistrationId();
559 version_id_
= storage()->NewVersionId();
560 resource_id1_
= storage()->NewResourceId();
561 resource_id2_
= storage()->NewResourceId();
562 resource_id1_size_
= 239193;
563 resource_id2_size_
= 59923;
565 // Cons up a new registration+version with two script resources.
566 RegistrationData data
;
567 data
.registration_id
= registration_id_
;
569 data
.script
= script_
;
570 data
.version_id
= version_id_
;
571 data
.is_active
= false;
572 std::vector
<ResourceRecord
> resources
;
574 ResourceRecord(resource_id1_
, script_
, resource_id1_size_
));
576 ResourceRecord(resource_id2_
, import_
, resource_id2_size_
));
577 registration_
= storage()->GetOrCreateRegistration(data
, resources
);
578 registration_
->waiting_version()->SetStatus(ServiceWorkerVersion::NEW
);
580 // Add the resources ids to the uncommitted list.
581 storage()->StoreUncommittedResponseId(resource_id1_
);
582 storage()->StoreUncommittedResponseId(resource_id2_
);
583 base::RunLoop().RunUntilIdle();
584 std::set
<int64
> verify_ids
;
585 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
586 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
587 EXPECT_EQ(2u, verify_ids
.size());
589 // And dump something in the disk cache for them.
590 WriteBasicResponse(storage(), resource_id1_
);
591 WriteBasicResponse(storage(), resource_id2_
);
592 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
593 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
595 // Storing the registration/version should take the resources ids out
596 // of the uncommitted list.
599 StoreRegistration(registration_
, registration_
->waiting_version()));
601 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
602 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
603 EXPECT_TRUE(verify_ids
.empty());
611 int64 registration_id_
;
614 uint64 resource_id1_size_
;
616 uint64 resource_id2_size_
;
617 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
620 class ServiceWorkerResourceStorageDiskTest
621 : public ServiceWorkerResourceStorageTest
{
623 virtual void SetUp() override
{
624 ASSERT_TRUE(user_data_directory_
.CreateUniqueTempDir());
625 ServiceWorkerResourceStorageTest::SetUp();
628 base::FilePath
GetUserDataDirectory() override
{
629 return user_data_directory_
.path();
633 base::ScopedTempDir user_data_directory_
;
636 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_NoLiveVersion
) {
637 bool was_called
= false;
638 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
639 std::set
<int64
> verify_ids
;
641 registration_
->SetWaitingVersion(NULL
);
642 registration_
= NULL
;
644 // Deleting the registration should result in the resources being added to the
645 // purgeable list and then doomed in the disk cache and removed from that
647 storage()->DeleteRegistration(
650 base::Bind(&VerifyPurgeableListStatusCallback
,
651 base::Unretained(storage()->database_
.get()),
655 base::RunLoop().RunUntilIdle();
656 ASSERT_TRUE(was_called
);
657 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
658 EXPECT_EQ(2u, verify_ids
.size());
660 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
661 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
662 EXPECT_TRUE(verify_ids
.empty());
664 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
665 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
668 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_WaitingVersion
) {
669 bool was_called
= false;
670 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
671 std::set
<int64
> verify_ids
;
673 // Deleting the registration should result in the resources being added to the
674 // purgeable list and then doomed in the disk cache and removed from that
676 storage()->DeleteRegistration(
679 base::Bind(&VerifyPurgeableListStatusCallback
,
680 base::Unretained(storage()->database_
.get()),
684 base::RunLoop().RunUntilIdle();
685 ASSERT_TRUE(was_called
);
686 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
687 EXPECT_EQ(2u, verify_ids
.size());
689 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
690 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
691 EXPECT_EQ(2u, verify_ids
.size());
693 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, false));
694 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, false));
696 // Doom the version, now it happens.
697 registration_
->waiting_version()->Doom();
698 base::RunLoop().RunUntilIdle();
699 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
700 EXPECT_EQ(2u, verify_ids
.size());
702 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
703 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
704 EXPECT_TRUE(verify_ids
.empty());
706 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
707 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
710 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_ActiveVersion
) {
711 // Promote the worker to active and add a controllee.
712 registration_
->SetActiveVersion(registration_
->waiting_version());
713 storage()->UpdateToActiveState(
714 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
715 scoped_ptr
<ServiceWorkerProviderHost
> host(
716 new ServiceWorkerProviderHost(33 /* dummy render process id */,
717 1 /* dummy provider_id */,
718 context_
->AsWeakPtr(),
720 registration_
->active_version()->AddControllee(host
.get());
722 bool was_called
= false;
723 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
724 std::set
<int64
> verify_ids
;
726 // Deleting the registration should move the resources to the purgeable list
727 // but keep them available.
728 storage()->DeleteRegistration(
731 base::Bind(&VerifyPurgeableListStatusCallback
,
732 base::Unretained(storage()->database_
.get()),
736 registration_
->active_version()->Doom();
737 base::RunLoop().RunUntilIdle();
738 ASSERT_TRUE(was_called
);
739 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
740 EXPECT_EQ(2u, verify_ids
.size());
742 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
743 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
744 EXPECT_EQ(2u, verify_ids
.size());
746 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
747 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
749 // Removing the controllee should cause the resources to be deleted.
750 registration_
->active_version()->RemoveControllee(host
.get());
751 base::RunLoop().RunUntilIdle();
753 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
754 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
755 EXPECT_TRUE(verify_ids
.empty());
757 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
758 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
761 TEST_F(ServiceWorkerResourceStorageDiskTest
, CleanupOnRestart
) {
762 // Promote the worker to active and add a controllee.
763 registration_
->SetActiveVersion(registration_
->waiting_version());
764 registration_
->SetWaitingVersion(NULL
);
765 storage()->UpdateToActiveState(
766 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
767 scoped_ptr
<ServiceWorkerProviderHost
> host(
768 new ServiceWorkerProviderHost(33 /* dummy render process id */,
769 1 /* dummy provider_id */,
770 context_
->AsWeakPtr(),
772 registration_
->active_version()->AddControllee(host
.get());
774 bool was_called
= false;
775 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
776 std::set
<int64
> verify_ids
;
778 // Deleting the registration should move the resources to the purgeable list
779 // but keep them available.
780 storage()->DeleteRegistration(
783 base::Bind(&VerifyPurgeableListStatusCallback
,
784 base::Unretained(storage()->database_
.get()),
788 base::RunLoop().RunUntilIdle();
789 ASSERT_TRUE(was_called
);
790 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
791 EXPECT_EQ(2u, verify_ids
.size());
793 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
794 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
795 EXPECT_EQ(2u, verify_ids
.size());
797 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
798 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
800 // Also add an uncommitted resource.
801 int64 kStaleUncommittedResourceId
= storage()->NewResourceId();
802 storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId
);
803 base::RunLoop().RunUntilIdle();
805 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
806 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
807 EXPECT_EQ(1u, verify_ids
.size());
808 WriteBasicResponse(storage(), kStaleUncommittedResourceId
);
810 VerifyBasicResponse(storage(), kStaleUncommittedResourceId
, true));
812 // Simulate browser shutdown. The purgeable and uncommitted resources are now
815 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager(
816 new MockServiceWorkerDatabaseTaskManager(
817 base::ThreadTaskRunnerHandle::Get()));
819 new ServiceWorkerContextCore(GetUserDataDirectory(),
820 base::ThreadTaskRunnerHandle::Get(),
821 database_task_manager
.Pass(),
822 base::ThreadTaskRunnerHandle::Get(),
827 storage()->LazyInitialize(base::Bind(&base::DoNothing
));
828 base::RunLoop().RunUntilIdle();
830 // Store a new uncommitted resource. This triggers stale resource cleanup.
831 int64 kNewResourceId
= storage()->NewResourceId();
832 WriteBasicResponse(storage(), kNewResourceId
);
833 storage()->StoreUncommittedResponseId(kNewResourceId
);
834 base::RunLoop().RunUntilIdle();
836 // The stale resources should be purged, but the new resource should persist.
838 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
839 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
840 ASSERT_EQ(1u, verify_ids
.size());
841 EXPECT_EQ(kNewResourceId
, *verify_ids
.begin());
843 // Purging resources needs interactions with SimpleCache's worker thread,
844 // so single RunUntilIdle() call may not be sufficient.
845 while (storage()->is_purge_pending_
)
846 base::RunLoop().RunUntilIdle();
849 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
850 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
851 EXPECT_TRUE(verify_ids
.empty());
852 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
853 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
855 VerifyBasicResponse(storage(), kStaleUncommittedResourceId
, false));
856 EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId
, true));
859 TEST_F(ServiceWorkerResourceStorageTest
, UpdateRegistration
) {
860 // Promote the worker to active worker and add a controllee.
861 registration_
->SetActiveVersion(registration_
->waiting_version());
862 storage()->UpdateToActiveState(
863 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
864 scoped_ptr
<ServiceWorkerProviderHost
> host(
865 new ServiceWorkerProviderHost(33 /* dummy render process id */,
866 1 /* dummy provider_id */,
867 context_
->AsWeakPtr(),
869 registration_
->active_version()->AddControllee(host
.get());
871 bool was_called
= false;
872 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
873 std::set
<int64
> verify_ids
;
875 // Make an updated registration.
876 scoped_refptr
<ServiceWorkerVersion
> live_version
= new ServiceWorkerVersion(
877 registration_
.get(), script_
, storage()->NewVersionId(), context_ptr_
);
878 live_version
->SetStatus(ServiceWorkerVersion::NEW
);
879 registration_
->SetWaitingVersion(live_version
.get());
881 // Writing the registration should move the old version's resources to the
882 // purgeable list but keep them available.
883 storage()->StoreRegistration(
885 registration_
->waiting_version(),
886 base::Bind(&VerifyPurgeableListStatusCallback
,
887 base::Unretained(storage()->database_
.get()),
891 registration_
->active_version()->Doom();
892 base::RunLoop().RunUntilIdle();
893 ASSERT_TRUE(was_called
);
894 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
895 EXPECT_EQ(2u, verify_ids
.size());
897 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
898 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
899 EXPECT_EQ(2u, verify_ids
.size());
901 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, false));
902 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, false));
904 // Removing the controllee should cause the old version's resources to be
906 registration_
->active_version()->RemoveControllee(host
.get());
907 base::RunLoop().RunUntilIdle();
909 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
910 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
911 EXPECT_TRUE(verify_ids
.empty());
913 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
914 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
917 TEST_F(ServiceWorkerStorageTest
, FindRegistration_LongestScopeMatch
) {
918 const GURL
kDocumentUrl("http://www.example.com/scope/foo");
919 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
921 // Registration for "/scope/".
922 const GURL
kScope1("http://www.example.com/scope/");
923 const GURL
kScript1("http://www.example.com/script1.js");
924 const int64 kRegistrationId1
= 1;
925 const int64 kVersionId1
= 1;
926 scoped_refptr
<ServiceWorkerRegistration
> live_registration1
=
927 new ServiceWorkerRegistration(
928 kScope1
, kRegistrationId1
, context_ptr_
);
929 scoped_refptr
<ServiceWorkerVersion
> live_version1
=
930 new ServiceWorkerVersion(
931 live_registration1
.get(), kScript1
, kVersionId1
, context_ptr_
);
932 live_version1
->SetStatus(ServiceWorkerVersion::INSTALLED
);
933 live_registration1
->SetWaitingVersion(live_version1
.get());
935 // Registration for "/scope/foo".
936 const GURL
kScope2("http://www.example.com/scope/foo");
937 const GURL
kScript2("http://www.example.com/script2.js");
938 const int64 kRegistrationId2
= 2;
939 const int64 kVersionId2
= 2;
940 scoped_refptr
<ServiceWorkerRegistration
> live_registration2
=
941 new ServiceWorkerRegistration(
942 kScope2
, kRegistrationId2
, context_ptr_
);
943 scoped_refptr
<ServiceWorkerVersion
> live_version2
=
944 new ServiceWorkerVersion(
945 live_registration2
.get(), kScript2
, kVersionId2
, context_ptr_
);
946 live_version2
->SetStatus(ServiceWorkerVersion::INSTALLED
);
947 live_registration2
->SetWaitingVersion(live_version2
.get());
949 // Registration for "/scope/foobar".
950 const GURL
kScope3("http://www.example.com/scope/foobar");
951 const GURL
kScript3("http://www.example.com/script3.js");
952 const int64 kRegistrationId3
= 3;
953 const int64 kVersionId3
= 3;
954 scoped_refptr
<ServiceWorkerRegistration
> live_registration3
=
955 new ServiceWorkerRegistration(
956 kScope3
, kRegistrationId3
, context_ptr_
);
957 scoped_refptr
<ServiceWorkerVersion
> live_version3
=
958 new ServiceWorkerVersion(
959 live_registration3
.get(), kScript3
, kVersionId3
, context_ptr_
);
960 live_version3
->SetStatus(ServiceWorkerVersion::INSTALLED
);
961 live_registration3
->SetWaitingVersion(live_version3
.get());
963 // Notify storage of they being installed.
964 storage()->NotifyInstallingRegistration(live_registration1
.get());
965 storage()->NotifyInstallingRegistration(live_registration2
.get());
966 storage()->NotifyInstallingRegistration(live_registration3
.get());
968 // Find a registration among installing ones.
969 EXPECT_EQ(SERVICE_WORKER_OK
,
970 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
971 EXPECT_EQ(live_registration2
, found_registration
);
972 found_registration
= NULL
;
974 // Store registrations.
975 EXPECT_EQ(SERVICE_WORKER_OK
,
976 StoreRegistration(live_registration1
, live_version1
));
977 EXPECT_EQ(SERVICE_WORKER_OK
,
978 StoreRegistration(live_registration2
, live_version2
));
979 EXPECT_EQ(SERVICE_WORKER_OK
,
980 StoreRegistration(live_registration3
, live_version3
));
982 // Notify storage of installations no longer happening.
983 storage()->NotifyDoneInstallingRegistration(
984 live_registration1
.get(), NULL
, SERVICE_WORKER_OK
);
985 storage()->NotifyDoneInstallingRegistration(
986 live_registration2
.get(), NULL
, SERVICE_WORKER_OK
);
987 storage()->NotifyDoneInstallingRegistration(
988 live_registration3
.get(), NULL
, SERVICE_WORKER_OK
);
990 // Find a registration among installed ones.
991 EXPECT_EQ(SERVICE_WORKER_OK
,
992 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
993 EXPECT_EQ(live_registration2
, found_registration
);
996 TEST_F(ServiceWorkerStorageTest
, CompareResources
) {
997 // Compare two small responses containing the same data.
998 WriteBasicResponse(storage(), 1);
999 WriteBasicResponse(storage(), 2);
1000 ServiceWorkerStatusCode status
= static_cast<ServiceWorkerStatusCode
>(-1);
1001 bool are_equal
= false;
1002 storage()->CompareScriptResources(
1004 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1005 base::RunLoop().RunUntilIdle();
1006 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1007 EXPECT_TRUE(are_equal
);
1009 // Compare two small responses with different data.
1010 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\0\0";
1011 const char kHttpBody
[] = "Goodbye";
1012 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
1013 WriteStringResponse(storage(), 3, headers
, std::string(kHttpBody
));
1014 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1016 storage()->CompareScriptResources(
1018 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1019 base::RunLoop().RunUntilIdle();
1020 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1021 EXPECT_FALSE(are_equal
);
1023 // Compare two large responses with the same data.
1024 const int k32K
= 32 * 1024;
1025 WriteResponseOfSize(storage(), 4, 'a', k32K
);
1026 WriteResponseOfSize(storage(), 5, 'a', k32K
);
1027 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1029 storage()->CompareScriptResources(
1031 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1032 base::RunLoop().RunUntilIdle();
1033 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1034 EXPECT_TRUE(are_equal
);
1036 // Compare a large and small response.
1037 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1039 storage()->CompareScriptResources(
1041 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1042 base::RunLoop().RunUntilIdle();
1043 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1044 EXPECT_FALSE(are_equal
);
1046 // Compare two large responses with different data.
1047 WriteResponseOfSize(storage(), 6, 'b', k32K
);
1048 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1050 storage()->CompareScriptResources(
1052 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1053 base::RunLoop().RunUntilIdle();
1054 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1055 EXPECT_FALSE(are_equal
);
1058 } // namespace content