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 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 void TearDown() override
{ context_
.reset(); }
210 virtual base::FilePath
GetUserDataDirectory() { return base::FilePath(); }
212 ServiceWorkerStorage
* storage() { return context_
->storage(); }
214 // A static class method for friendliness.
215 static void VerifyPurgeableListStatusCallback(
216 ServiceWorkerDatabase
* database
,
217 std::set
<int64
> *purgeable_ids
,
219 ServiceWorkerStatusCode
* result
,
220 ServiceWorkerStatusCode status
) {
223 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
224 database
->GetPurgeableResourceIds(purgeable_ids
));
228 ServiceWorkerStatusCode
StoreRegistration(
229 scoped_refptr
<ServiceWorkerRegistration
> registration
,
230 scoped_refptr
<ServiceWorkerVersion
> version
) {
231 bool was_called
= false;
232 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
233 storage()->StoreRegistration(registration
.get(),
235 MakeStatusCallback(&was_called
, &result
));
236 EXPECT_FALSE(was_called
); // always async
237 base::RunLoop().RunUntilIdle();
238 EXPECT_TRUE(was_called
);
242 ServiceWorkerStatusCode
DeleteRegistration(
243 int64 registration_id
,
244 const GURL
& origin
) {
245 bool was_called
= false;
246 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
247 storage()->DeleteRegistration(
248 registration_id
, origin
, MakeStatusCallback(&was_called
, &result
));
249 EXPECT_FALSE(was_called
); // always async
250 base::RunLoop().RunUntilIdle();
251 EXPECT_TRUE(was_called
);
255 void GetAllRegistrations(
256 std::vector
<ServiceWorkerRegistrationInfo
>* registrations
) {
257 bool was_called
= false;
258 storage()->GetAllRegistrations(
259 MakeGetAllCallback(&was_called
, registrations
));
260 EXPECT_FALSE(was_called
); // always async
261 base::RunLoop().RunUntilIdle();
262 EXPECT_TRUE(was_called
);
265 ServiceWorkerStatusCode
UpdateToActiveState(
266 scoped_refptr
<ServiceWorkerRegistration
> registration
) {
267 bool was_called
= false;
268 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
269 storage()->UpdateToActiveState(registration
.get(),
270 MakeStatusCallback(&was_called
, &result
));
271 EXPECT_FALSE(was_called
); // always async
272 base::RunLoop().RunUntilIdle();
273 EXPECT_TRUE(was_called
);
277 void UpdateLastUpdateCheckTime(ServiceWorkerRegistration
* registration
) {
278 storage()->UpdateLastUpdateCheckTime(registration
);
279 base::RunLoop().RunUntilIdle();
282 ServiceWorkerStatusCode
FindRegistrationForDocument(
283 const GURL
& document_url
,
284 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
285 bool was_called
= false;
286 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
287 storage()->FindRegistrationForDocument(
288 document_url
, MakeFindCallback(&was_called
, &result
, registration
));
289 base::RunLoop().RunUntilIdle();
290 EXPECT_TRUE(was_called
);
294 ServiceWorkerStatusCode
FindRegistrationForPattern(
296 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
297 bool was_called
= false;
298 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
299 storage()->FindRegistrationForPattern(
300 scope
, MakeFindCallback(&was_called
, &result
, registration
));
301 EXPECT_FALSE(was_called
); // always async
302 base::RunLoop().RunUntilIdle();
303 EXPECT_TRUE(was_called
);
307 ServiceWorkerStatusCode
FindRegistrationForId(
308 int64 registration_id
,
310 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
311 bool was_called
= false;
312 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
313 storage()->FindRegistrationForId(
314 registration_id
, origin
,
315 MakeFindCallback(&was_called
, &result
, registration
));
316 base::RunLoop().RunUntilIdle();
317 EXPECT_TRUE(was_called
);
321 scoped_ptr
<ServiceWorkerContextCore
> context_
;
322 base::WeakPtr
<ServiceWorkerContextCore
> context_ptr_
;
323 TestBrowserThreadBundle browser_thread_bundle_
;
326 TEST_F(ServiceWorkerStorageTest
, StoreFindUpdateDeleteRegistration
) {
327 const GURL
kScope("http://www.test.not/scope/");
328 const GURL
kScript("http://www.test.not/script.js");
329 const GURL
kDocumentUrl("http://www.test.not/scope/document.html");
330 const GURL
kResource1("http://www.test.not/scope/resource1.js");
331 const int64 kResource1Size
= 1591234;
332 const GURL
kResource2("http://www.test.not/scope/resource2.js");
333 const int64 kResource2Size
= 51;
334 const int64 kRegistrationId
= 0;
335 const int64 kVersionId
= 0;
336 const base::Time kToday
= base::Time::Now();
337 const base::Time kYesterday
= kToday
- base::TimeDelta::FromDays(1);
339 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
341 // We shouldn't find anything without having stored anything.
342 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
343 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
344 EXPECT_FALSE(found_registration
.get());
346 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
347 FindRegistrationForPattern(kScope
, &found_registration
));
348 EXPECT_FALSE(found_registration
.get());
350 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
351 FindRegistrationForId(
352 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
353 EXPECT_FALSE(found_registration
.get());
355 std::vector
<ServiceWorkerDatabase::ResourceRecord
> resources
;
357 ServiceWorkerDatabase::ResourceRecord(1, kResource1
, kResource1Size
));
359 ServiceWorkerDatabase::ResourceRecord(2, kResource2
, kResource2Size
));
362 scoped_refptr
<ServiceWorkerRegistration
> live_registration
=
363 new ServiceWorkerRegistration(
364 kScope
, kRegistrationId
, context_ptr_
);
365 scoped_refptr
<ServiceWorkerVersion
> live_version
=
366 new ServiceWorkerVersion(
367 live_registration
.get(), kScript
, kVersionId
, context_ptr_
);
368 live_version
->SetStatus(ServiceWorkerVersion::INSTALLED
);
369 live_version
->script_cache_map()->SetResources(resources
);
370 live_registration
->SetWaitingVersion(live_version
.get());
371 live_registration
->set_last_update_check(kYesterday
);
372 EXPECT_EQ(SERVICE_WORKER_OK
,
373 StoreRegistration(live_registration
, live_version
));
375 // Now we should find it and get the live ptr back immediately.
376 EXPECT_EQ(SERVICE_WORKER_OK
,
377 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
378 EXPECT_EQ(live_registration
, found_registration
);
379 EXPECT_EQ(kResource1Size
+ kResource2Size
,
380 live_registration
->resources_total_size_bytes());
381 EXPECT_EQ(kResource1Size
+ kResource2Size
,
382 found_registration
->resources_total_size_bytes());
383 found_registration
= NULL
;
385 // But FindRegistrationForPattern is always async.
386 EXPECT_EQ(SERVICE_WORKER_OK
,
387 FindRegistrationForPattern(kScope
, &found_registration
));
388 EXPECT_EQ(live_registration
, found_registration
);
389 found_registration
= NULL
;
391 // Can be found by id too.
392 EXPECT_EQ(SERVICE_WORKER_OK
,
393 FindRegistrationForId(
394 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
395 ASSERT_TRUE(found_registration
.get());
396 EXPECT_EQ(kRegistrationId
, found_registration
->id());
397 EXPECT_EQ(live_registration
, found_registration
);
398 found_registration
= NULL
;
400 // Drop the live registration, but keep the version live.
401 live_registration
= NULL
;
403 // Now FindRegistrationForDocument should be async.
404 EXPECT_EQ(SERVICE_WORKER_OK
,
405 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
406 ASSERT_TRUE(found_registration
.get());
407 EXPECT_EQ(kRegistrationId
, found_registration
->id());
408 EXPECT_TRUE(found_registration
->HasOneRef());
410 // Check that sizes are populated correctly
411 EXPECT_EQ(live_version
.get(), found_registration
->waiting_version());
412 EXPECT_EQ(kResource1Size
+ kResource2Size
,
413 found_registration
->resources_total_size_bytes());
414 std::vector
<ServiceWorkerRegistrationInfo
> all_registrations
;
415 GetAllRegistrations(&all_registrations
);
416 EXPECT_EQ(1u, all_registrations
.size());
417 ServiceWorkerRegistrationInfo info
= all_registrations
[0];
418 EXPECT_EQ(kResource1Size
+ kResource2Size
, info
.stored_version_size_bytes
);
419 all_registrations
.clear();
421 found_registration
= NULL
;
423 // Drop the live version too.
426 // And FindRegistrationForPattern is always async.
427 EXPECT_EQ(SERVICE_WORKER_OK
,
428 FindRegistrationForPattern(kScope
, &found_registration
));
429 ASSERT_TRUE(found_registration
.get());
430 EXPECT_EQ(kRegistrationId
, found_registration
->id());
431 EXPECT_TRUE(found_registration
->HasOneRef());
432 EXPECT_FALSE(found_registration
->active_version());
433 ASSERT_TRUE(found_registration
->waiting_version());
434 EXPECT_EQ(kYesterday
, found_registration
->last_update_check());
435 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
,
436 found_registration
->waiting_version()->status());
438 // Update to active and update the last check time.
439 scoped_refptr
<ServiceWorkerVersion
> temp_version
=
440 found_registration
->waiting_version();
441 temp_version
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
442 found_registration
->SetActiveVersion(temp_version
.get());
444 EXPECT_EQ(SERVICE_WORKER_OK
, UpdateToActiveState(found_registration
));
445 found_registration
->set_last_update_check(kToday
);
446 UpdateLastUpdateCheckTime(found_registration
.get());
448 found_registration
= NULL
;
450 // Trying to update a unstored registration to active should fail.
451 scoped_refptr
<ServiceWorkerRegistration
> unstored_registration
=
452 new ServiceWorkerRegistration(
453 kScope
, kRegistrationId
+ 1, context_ptr_
);
454 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
455 UpdateToActiveState(unstored_registration
));
456 unstored_registration
= NULL
;
458 // The Find methods should return a registration with an active version
459 // and the expected update time.
460 EXPECT_EQ(SERVICE_WORKER_OK
,
461 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
462 ASSERT_TRUE(found_registration
.get());
463 EXPECT_EQ(kRegistrationId
, found_registration
->id());
464 EXPECT_TRUE(found_registration
->HasOneRef());
465 EXPECT_FALSE(found_registration
->waiting_version());
466 ASSERT_TRUE(found_registration
->active_version());
467 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
,
468 found_registration
->active_version()->status());
469 EXPECT_EQ(kToday
, found_registration
->last_update_check());
471 // Delete from storage but with a instance still live.
472 EXPECT_TRUE(context_
->GetLiveVersion(kRegistrationId
));
473 EXPECT_EQ(SERVICE_WORKER_OK
,
474 DeleteRegistration(kRegistrationId
, kScope
.GetOrigin()));
475 EXPECT_TRUE(context_
->GetLiveVersion(kRegistrationId
));
477 // Should no longer be found.
478 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
479 FindRegistrationForId(
480 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
481 EXPECT_FALSE(found_registration
.get());
483 // Deleting an unstored registration should succeed.
484 EXPECT_EQ(SERVICE_WORKER_OK
,
485 DeleteRegistration(kRegistrationId
+ 1, kScope
.GetOrigin()));
488 TEST_F(ServiceWorkerStorageTest
, InstallingRegistrationsAreFindable
) {
489 const GURL
kScope("http://www.test.not/scope/");
490 const GURL
kScript("http://www.test.not/script.js");
491 const GURL
kDocumentUrl("http://www.test.not/scope/document.html");
492 const int64 kRegistrationId
= 0;
493 const int64 kVersionId
= 0;
495 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
497 // Create an unstored registration.
498 scoped_refptr
<ServiceWorkerRegistration
> live_registration
=
499 new ServiceWorkerRegistration(
500 kScope
, kRegistrationId
, context_ptr_
);
501 scoped_refptr
<ServiceWorkerVersion
> live_version
=
502 new ServiceWorkerVersion(
503 live_registration
.get(), kScript
, kVersionId
, context_ptr_
);
504 live_version
->SetStatus(ServiceWorkerVersion::INSTALLING
);
505 live_registration
->SetWaitingVersion(live_version
.get());
507 // Should not be findable, including by GetAllRegistrations.
508 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
509 FindRegistrationForId(
510 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
511 EXPECT_FALSE(found_registration
.get());
513 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
514 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
515 EXPECT_FALSE(found_registration
.get());
517 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
518 FindRegistrationForPattern(kScope
, &found_registration
));
519 EXPECT_FALSE(found_registration
.get());
521 std::vector
<ServiceWorkerRegistrationInfo
> all_registrations
;
522 GetAllRegistrations(&all_registrations
);
523 EXPECT_TRUE(all_registrations
.empty());
525 // Notify storage of it being installed.
526 storage()->NotifyInstallingRegistration(live_registration
.get());
528 // Now should be findable.
529 EXPECT_EQ(SERVICE_WORKER_OK
,
530 FindRegistrationForId(
531 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
532 EXPECT_EQ(live_registration
, found_registration
);
533 found_registration
= NULL
;
535 EXPECT_EQ(SERVICE_WORKER_OK
,
536 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
537 EXPECT_EQ(live_registration
, found_registration
);
538 found_registration
= NULL
;
540 EXPECT_EQ(SERVICE_WORKER_OK
,
541 FindRegistrationForPattern(kScope
, &found_registration
));
542 EXPECT_EQ(live_registration
, found_registration
);
543 found_registration
= NULL
;
545 GetAllRegistrations(&all_registrations
);
546 EXPECT_EQ(1u, all_registrations
.size());
547 all_registrations
.clear();
549 // Notify storage of installation no longer happening.
550 storage()->NotifyDoneInstallingRegistration(
551 live_registration
.get(), NULL
, SERVICE_WORKER_OK
);
553 // Once again, should not be findable.
554 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
555 FindRegistrationForId(
556 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
557 EXPECT_FALSE(found_registration
.get());
559 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
560 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
561 EXPECT_FALSE(found_registration
.get());
563 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
564 FindRegistrationForPattern(kScope
, &found_registration
));
565 EXPECT_FALSE(found_registration
.get());
567 GetAllRegistrations(&all_registrations
);
568 EXPECT_TRUE(all_registrations
.empty());
571 class ServiceWorkerResourceStorageTest
: public ServiceWorkerStorageTest
{
573 void SetUp() override
{
574 ServiceWorkerStorageTest::SetUp();
576 storage()->LazyInitialize(base::Bind(&base::DoNothing
));
577 base::RunLoop().RunUntilIdle();
578 scope_
= GURL("http://www.test.not/scope/");
579 script_
= GURL("http://www.test.not/script.js");
580 import_
= GURL("http://www.test.not/import.js");
581 document_url_
= GURL("http://www.test.not/scope/document.html");
582 registration_id_
= storage()->NewRegistrationId();
583 version_id_
= storage()->NewVersionId();
584 resource_id1_
= storage()->NewResourceId();
585 resource_id2_
= storage()->NewResourceId();
586 resource_id1_size_
= 239193;
587 resource_id2_size_
= 59923;
589 // Cons up a new registration+version with two script resources.
590 RegistrationData data
;
591 data
.registration_id
= registration_id_
;
593 data
.script
= script_
;
594 data
.version_id
= version_id_
;
595 data
.is_active
= false;
596 std::vector
<ResourceRecord
> resources
;
598 ResourceRecord(resource_id1_
, script_
, resource_id1_size_
));
600 ResourceRecord(resource_id2_
, import_
, resource_id2_size_
));
601 registration_
= storage()->GetOrCreateRegistration(data
, resources
);
602 registration_
->waiting_version()->SetStatus(ServiceWorkerVersion::NEW
);
604 // Add the resources ids to the uncommitted list.
605 storage()->StoreUncommittedResponseId(resource_id1_
);
606 storage()->StoreUncommittedResponseId(resource_id2_
);
607 base::RunLoop().RunUntilIdle();
608 std::set
<int64
> verify_ids
;
609 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
610 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
611 EXPECT_EQ(2u, verify_ids
.size());
613 // And dump something in the disk cache for them.
614 WriteBasicResponse(storage(), resource_id1_
);
615 WriteBasicResponse(storage(), resource_id2_
);
616 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
617 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
619 // Storing the registration/version should take the resources ids out
620 // of the uncommitted list.
623 StoreRegistration(registration_
, registration_
->waiting_version()));
625 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
626 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
627 EXPECT_TRUE(verify_ids
.empty());
635 int64 registration_id_
;
638 uint64 resource_id1_size_
;
640 uint64 resource_id2_size_
;
641 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
644 class ServiceWorkerResourceStorageDiskTest
645 : public ServiceWorkerResourceStorageTest
{
647 void SetUp() override
{
648 ASSERT_TRUE(user_data_directory_
.CreateUniqueTempDir());
649 ServiceWorkerResourceStorageTest::SetUp();
652 base::FilePath
GetUserDataDirectory() override
{
653 return user_data_directory_
.path();
657 base::ScopedTempDir user_data_directory_
;
660 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_NoLiveVersion
) {
661 bool was_called
= false;
662 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
663 std::set
<int64
> verify_ids
;
665 registration_
->SetWaitingVersion(NULL
);
666 registration_
= NULL
;
668 // Deleting the registration should result in the resources being added to the
669 // purgeable list and then doomed in the disk cache and removed from that
671 storage()->DeleteRegistration(
674 base::Bind(&VerifyPurgeableListStatusCallback
,
675 base::Unretained(storage()->database_
.get()),
679 base::RunLoop().RunUntilIdle();
680 ASSERT_TRUE(was_called
);
681 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
682 EXPECT_EQ(2u, verify_ids
.size());
684 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
685 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
686 EXPECT_TRUE(verify_ids
.empty());
688 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
689 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
692 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_WaitingVersion
) {
693 bool was_called
= false;
694 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
695 std::set
<int64
> verify_ids
;
697 // Deleting the registration should result in the resources being added to the
698 // purgeable list and then doomed in the disk cache and removed from that
700 storage()->DeleteRegistration(
703 base::Bind(&VerifyPurgeableListStatusCallback
,
704 base::Unretained(storage()->database_
.get()),
708 base::RunLoop().RunUntilIdle();
709 ASSERT_TRUE(was_called
);
710 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
711 EXPECT_EQ(2u, verify_ids
.size());
713 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
714 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
715 EXPECT_EQ(2u, verify_ids
.size());
717 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, false));
718 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, false));
720 // Doom the version, now it happens.
721 registration_
->waiting_version()->Doom();
722 base::RunLoop().RunUntilIdle();
723 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
724 EXPECT_EQ(2u, verify_ids
.size());
726 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
727 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
728 EXPECT_TRUE(verify_ids
.empty());
730 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
731 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
734 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_ActiveVersion
) {
735 // Promote the worker to active and add a controllee.
736 registration_
->SetActiveVersion(registration_
->waiting_version());
737 storage()->UpdateToActiveState(
738 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
739 scoped_ptr
<ServiceWorkerProviderHost
> host(
740 new ServiceWorkerProviderHost(33 /* dummy render process id */,
741 1 /* dummy provider_id */,
742 context_
->AsWeakPtr(),
744 registration_
->active_version()->AddControllee(host
.get());
746 bool was_called
= false;
747 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
748 std::set
<int64
> verify_ids
;
750 // Deleting the registration should move the resources to the purgeable list
751 // but keep them available.
752 storage()->DeleteRegistration(
755 base::Bind(&VerifyPurgeableListStatusCallback
,
756 base::Unretained(storage()->database_
.get()),
760 registration_
->active_version()->Doom();
761 base::RunLoop().RunUntilIdle();
762 ASSERT_TRUE(was_called
);
763 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
764 EXPECT_EQ(2u, verify_ids
.size());
766 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
767 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
768 EXPECT_EQ(2u, verify_ids
.size());
770 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
771 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
773 // Removing the controllee should cause the resources to be deleted.
774 registration_
->active_version()->RemoveControllee(host
.get());
775 base::RunLoop().RunUntilIdle();
777 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
778 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
779 EXPECT_TRUE(verify_ids
.empty());
781 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
782 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
785 TEST_F(ServiceWorkerResourceStorageDiskTest
, CleanupOnRestart
) {
786 // Promote the worker to active and add a controllee.
787 registration_
->SetActiveVersion(registration_
->waiting_version());
788 registration_
->SetWaitingVersion(NULL
);
789 storage()->UpdateToActiveState(
790 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
791 scoped_ptr
<ServiceWorkerProviderHost
> host(
792 new ServiceWorkerProviderHost(33 /* dummy render process id */,
793 1 /* dummy provider_id */,
794 context_
->AsWeakPtr(),
796 registration_
->active_version()->AddControllee(host
.get());
798 bool was_called
= false;
799 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
800 std::set
<int64
> verify_ids
;
802 // Deleting the registration should move the resources to the purgeable list
803 // but keep them available.
804 storage()->DeleteRegistration(
807 base::Bind(&VerifyPurgeableListStatusCallback
,
808 base::Unretained(storage()->database_
.get()),
812 base::RunLoop().RunUntilIdle();
813 ASSERT_TRUE(was_called
);
814 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
815 EXPECT_EQ(2u, verify_ids
.size());
817 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
818 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
819 EXPECT_EQ(2u, verify_ids
.size());
821 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
822 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
824 // Also add an uncommitted resource.
825 int64 kStaleUncommittedResourceId
= storage()->NewResourceId();
826 storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId
);
827 base::RunLoop().RunUntilIdle();
829 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
830 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
831 EXPECT_EQ(1u, verify_ids
.size());
832 WriteBasicResponse(storage(), kStaleUncommittedResourceId
);
834 VerifyBasicResponse(storage(), kStaleUncommittedResourceId
, true));
836 // Simulate browser shutdown. The purgeable and uncommitted resources are now
839 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager(
840 new MockServiceWorkerDatabaseTaskManager(
841 base::ThreadTaskRunnerHandle::Get()));
843 new ServiceWorkerContextCore(GetUserDataDirectory(),
844 base::ThreadTaskRunnerHandle::Get(),
845 database_task_manager
.Pass(),
846 base::ThreadTaskRunnerHandle::Get(),
851 storage()->LazyInitialize(base::Bind(&base::DoNothing
));
852 base::RunLoop().RunUntilIdle();
854 // Store a new uncommitted resource. This triggers stale resource cleanup.
855 int64 kNewResourceId
= storage()->NewResourceId();
856 WriteBasicResponse(storage(), kNewResourceId
);
857 storage()->StoreUncommittedResponseId(kNewResourceId
);
858 base::RunLoop().RunUntilIdle();
860 // The stale resources should be purged, but the new resource should persist.
862 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
863 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
864 ASSERT_EQ(1u, verify_ids
.size());
865 EXPECT_EQ(kNewResourceId
, *verify_ids
.begin());
867 // Purging resources needs interactions with SimpleCache's worker thread,
868 // so single RunUntilIdle() call may not be sufficient.
869 while (storage()->is_purge_pending_
)
870 base::RunLoop().RunUntilIdle();
873 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
874 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
875 EXPECT_TRUE(verify_ids
.empty());
876 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
877 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
879 VerifyBasicResponse(storage(), kStaleUncommittedResourceId
, false));
880 EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId
, true));
883 TEST_F(ServiceWorkerResourceStorageTest
, UpdateRegistration
) {
884 // Promote the worker to active worker and add a controllee.
885 registration_
->SetActiveVersion(registration_
->waiting_version());
886 storage()->UpdateToActiveState(
887 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
888 scoped_ptr
<ServiceWorkerProviderHost
> host(
889 new ServiceWorkerProviderHost(33 /* dummy render process id */,
890 1 /* dummy provider_id */,
891 context_
->AsWeakPtr(),
893 registration_
->active_version()->AddControllee(host
.get());
895 bool was_called
= false;
896 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
897 std::set
<int64
> verify_ids
;
899 // Make an updated registration.
900 scoped_refptr
<ServiceWorkerVersion
> live_version
= new ServiceWorkerVersion(
901 registration_
.get(), script_
, storage()->NewVersionId(), context_ptr_
);
902 live_version
->SetStatus(ServiceWorkerVersion::NEW
);
903 registration_
->SetWaitingVersion(live_version
.get());
905 // Writing the registration should move the old version's resources to the
906 // purgeable list but keep them available.
907 storage()->StoreRegistration(
909 registration_
->waiting_version(),
910 base::Bind(&VerifyPurgeableListStatusCallback
,
911 base::Unretained(storage()->database_
.get()),
915 registration_
->active_version()->Doom();
916 base::RunLoop().RunUntilIdle();
917 ASSERT_TRUE(was_called
);
918 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
919 EXPECT_EQ(2u, verify_ids
.size());
921 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
922 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
923 EXPECT_EQ(2u, verify_ids
.size());
925 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, false));
926 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, false));
928 // Removing the controllee should cause the old version's resources to be
930 registration_
->active_version()->RemoveControllee(host
.get());
931 base::RunLoop().RunUntilIdle();
933 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
934 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
935 EXPECT_TRUE(verify_ids
.empty());
937 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
938 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
941 TEST_F(ServiceWorkerStorageTest
, FindRegistration_LongestScopeMatch
) {
942 const GURL
kDocumentUrl("http://www.example.com/scope/foo");
943 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
945 // Registration for "/scope/".
946 const GURL
kScope1("http://www.example.com/scope/");
947 const GURL
kScript1("http://www.example.com/script1.js");
948 const int64 kRegistrationId1
= 1;
949 const int64 kVersionId1
= 1;
950 scoped_refptr
<ServiceWorkerRegistration
> live_registration1
=
951 new ServiceWorkerRegistration(
952 kScope1
, kRegistrationId1
, context_ptr_
);
953 scoped_refptr
<ServiceWorkerVersion
> live_version1
=
954 new ServiceWorkerVersion(
955 live_registration1
.get(), kScript1
, kVersionId1
, context_ptr_
);
956 live_version1
->SetStatus(ServiceWorkerVersion::INSTALLED
);
957 live_registration1
->SetWaitingVersion(live_version1
.get());
959 // Registration for "/scope/foo".
960 const GURL
kScope2("http://www.example.com/scope/foo");
961 const GURL
kScript2("http://www.example.com/script2.js");
962 const int64 kRegistrationId2
= 2;
963 const int64 kVersionId2
= 2;
964 scoped_refptr
<ServiceWorkerRegistration
> live_registration2
=
965 new ServiceWorkerRegistration(
966 kScope2
, kRegistrationId2
, context_ptr_
);
967 scoped_refptr
<ServiceWorkerVersion
> live_version2
=
968 new ServiceWorkerVersion(
969 live_registration2
.get(), kScript2
, kVersionId2
, context_ptr_
);
970 live_version2
->SetStatus(ServiceWorkerVersion::INSTALLED
);
971 live_registration2
->SetWaitingVersion(live_version2
.get());
973 // Registration for "/scope/foobar".
974 const GURL
kScope3("http://www.example.com/scope/foobar");
975 const GURL
kScript3("http://www.example.com/script3.js");
976 const int64 kRegistrationId3
= 3;
977 const int64 kVersionId3
= 3;
978 scoped_refptr
<ServiceWorkerRegistration
> live_registration3
=
979 new ServiceWorkerRegistration(
980 kScope3
, kRegistrationId3
, context_ptr_
);
981 scoped_refptr
<ServiceWorkerVersion
> live_version3
=
982 new ServiceWorkerVersion(
983 live_registration3
.get(), kScript3
, kVersionId3
, context_ptr_
);
984 live_version3
->SetStatus(ServiceWorkerVersion::INSTALLED
);
985 live_registration3
->SetWaitingVersion(live_version3
.get());
987 // Notify storage of they being installed.
988 storage()->NotifyInstallingRegistration(live_registration1
.get());
989 storage()->NotifyInstallingRegistration(live_registration2
.get());
990 storage()->NotifyInstallingRegistration(live_registration3
.get());
992 // Find a registration among installing ones.
993 EXPECT_EQ(SERVICE_WORKER_OK
,
994 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
995 EXPECT_EQ(live_registration2
, found_registration
);
996 found_registration
= NULL
;
998 // Store registrations.
999 EXPECT_EQ(SERVICE_WORKER_OK
,
1000 StoreRegistration(live_registration1
, live_version1
));
1001 EXPECT_EQ(SERVICE_WORKER_OK
,
1002 StoreRegistration(live_registration2
, live_version2
));
1003 EXPECT_EQ(SERVICE_WORKER_OK
,
1004 StoreRegistration(live_registration3
, live_version3
));
1006 // Notify storage of installations no longer happening.
1007 storage()->NotifyDoneInstallingRegistration(
1008 live_registration1
.get(), NULL
, SERVICE_WORKER_OK
);
1009 storage()->NotifyDoneInstallingRegistration(
1010 live_registration2
.get(), NULL
, SERVICE_WORKER_OK
);
1011 storage()->NotifyDoneInstallingRegistration(
1012 live_registration3
.get(), NULL
, SERVICE_WORKER_OK
);
1014 // Find a registration among installed ones.
1015 EXPECT_EQ(SERVICE_WORKER_OK
,
1016 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
1017 EXPECT_EQ(live_registration2
, found_registration
);
1020 TEST_F(ServiceWorkerStorageTest
, CompareResources
) {
1021 // Compare two small responses containing the same data.
1022 WriteBasicResponse(storage(), 1);
1023 WriteBasicResponse(storage(), 2);
1024 ServiceWorkerStatusCode status
= static_cast<ServiceWorkerStatusCode
>(-1);
1025 bool are_equal
= false;
1026 storage()->CompareScriptResources(
1028 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1029 base::RunLoop().RunUntilIdle();
1030 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1031 EXPECT_TRUE(are_equal
);
1033 // Compare two small responses with different data.
1034 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\0\0";
1035 const char kHttpBody
[] = "Goodbye";
1036 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
1037 WriteStringResponse(storage(), 3, headers
, std::string(kHttpBody
));
1038 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1040 storage()->CompareScriptResources(
1042 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1043 base::RunLoop().RunUntilIdle();
1044 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1045 EXPECT_FALSE(are_equal
);
1047 // Compare two large responses with the same data.
1048 const int k32K
= 32 * 1024;
1049 WriteResponseOfSize(storage(), 4, 'a', k32K
);
1050 WriteResponseOfSize(storage(), 5, 'a', k32K
);
1051 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1053 storage()->CompareScriptResources(
1055 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1056 base::RunLoop().RunUntilIdle();
1057 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1058 EXPECT_TRUE(are_equal
);
1060 // Compare a large and small response.
1061 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1063 storage()->CompareScriptResources(
1065 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1066 base::RunLoop().RunUntilIdle();
1067 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1068 EXPECT_FALSE(are_equal
);
1070 // Compare two large responses with different data.
1071 WriteResponseOfSize(storage(), 6, 'b', k32K
);
1072 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1074 storage()->CompareScriptResources(
1076 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1077 base::RunLoop().RunUntilIdle();
1078 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1079 EXPECT_FALSE(are_equal
);
1082 } // namespace content