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 OnIOComplete(int* rv_out
, int rv
) {
86 void OnCompareComplete(
87 ServiceWorkerStatusCode
* status_out
, bool* are_equal_out
,
88 ServiceWorkerStatusCode status
, bool are_equal
) {
90 *are_equal_out
= are_equal
;
94 ServiceWorkerStorage
* storage
, int64 id
,
95 const std::string
& headers
,
96 IOBuffer
* body
, int length
) {
97 scoped_ptr
<ServiceWorkerResponseWriter
> writer
=
98 storage
->CreateResponseWriter(id
);
100 scoped_ptr
<net::HttpResponseInfo
> info(new net::HttpResponseInfo
);
101 info
->request_time
= base::Time::Now();
102 info
->response_time
= base::Time::Now();
103 info
->was_cached
= false;
104 info
->headers
= new net::HttpResponseHeaders(headers
);
105 scoped_refptr
<HttpResponseInfoIOBuffer
> info_buffer
=
106 new HttpResponseInfoIOBuffer(info
.release());
109 writer
->WriteInfo(info_buffer
.get(), base::Bind(&OnIOComplete
, &rv
));
110 base::RunLoop().RunUntilIdle();
114 writer
->WriteData(body
, length
, base::Bind(&OnIOComplete
, &rv
));
115 base::RunLoop().RunUntilIdle();
116 EXPECT_EQ(length
, rv
);
119 void WriteStringResponse(
120 ServiceWorkerStorage
* storage
, int64 id
,
121 const std::string
& headers
,
122 const std::string
& body
) {
123 scoped_refptr
<IOBuffer
> body_buffer(new WrappedIOBuffer(body
.data()));
124 WriteResponse(storage
, id
, headers
, body_buffer
.get(), body
.length());
127 void WriteBasicResponse(ServiceWorkerStorage
* storage
, int64 id
) {
128 scoped_ptr
<ServiceWorkerResponseWriter
> writer
=
129 storage
->CreateResponseWriter(id
);
131 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\0Content-Length: 5\0\0";
132 const char kHttpBody
[] = "Hello";
133 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
134 WriteStringResponse(storage
, id
, headers
, std::string(kHttpBody
));
137 bool VerifyBasicResponse(ServiceWorkerStorage
* storage
, int64 id
,
138 bool expected_positive_result
) {
139 const std::string
kExpectedHttpBody("Hello");
140 scoped_ptr
<ServiceWorkerResponseReader
> reader
=
141 storage
->CreateResponseReader(id
);
142 scoped_refptr
<HttpResponseInfoIOBuffer
> info_buffer
=
143 new HttpResponseInfoIOBuffer();
145 TestCompletionCallback cb
;
146 reader
->ReadInfo(info_buffer
.get(), cb
.callback());
147 int rv
= cb
.WaitForResult();
148 if (expected_positive_result
)
154 std::string received_body
;
156 const int kBigEnough
= 512;
157 scoped_refptr
<net::IOBuffer
> buffer
= new IOBuffer(kBigEnough
);
158 TestCompletionCallback cb
;
159 reader
->ReadData(buffer
.get(), kBigEnough
, cb
.callback());
160 int rv
= cb
.WaitForResult();
161 EXPECT_EQ(static_cast<int>(kExpectedHttpBody
.size()), rv
);
164 received_body
.assign(buffer
->data(), rv
);
168 std::string("HONKYDORY") ==
169 info_buffer
->http_info
->headers
->GetStatusText();
170 bool data_match
= kExpectedHttpBody
== received_body
;
172 EXPECT_TRUE(status_match
);
173 EXPECT_TRUE(data_match
);
174 return status_match
&& data_match
;
177 void WriteResponseOfSize(ServiceWorkerStorage
* storage
, int64 id
,
178 char val
, int size
) {
179 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\00";
180 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
181 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(size
);
182 memset(buffer
->data(), val
, size
);
183 WriteResponse(storage
, id
, headers
, buffer
.get(), size
);
188 class ServiceWorkerStorageTest
: public testing::Test
{
190 ServiceWorkerStorageTest()
191 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
) {
194 virtual void SetUp() OVERRIDE
{
196 new ServiceWorkerContextCore(GetUserDataDirectory(),
197 base::ThreadTaskRunnerHandle::Get(),
198 base::ThreadTaskRunnerHandle::Get(),
199 base::ThreadTaskRunnerHandle::Get(),
203 context_ptr_
= context_
->AsWeakPtr();
206 virtual void TearDown() OVERRIDE
{
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 int64 kRegistrationId
= 0;
331 const int64 kVersionId
= 0;
332 const base::Time kToday
= base::Time::Now();
333 const base::Time kYesterday
= kToday
- base::TimeDelta::FromDays(1);
335 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
337 // We shouldn't find anything without having stored anything.
338 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
339 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
340 EXPECT_FALSE(found_registration
.get());
342 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
343 FindRegistrationForPattern(kScope
, &found_registration
));
344 EXPECT_FALSE(found_registration
.get());
346 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
347 FindRegistrationForId(
348 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
349 EXPECT_FALSE(found_registration
.get());
352 scoped_refptr
<ServiceWorkerRegistration
> live_registration
=
353 new ServiceWorkerRegistration(
354 kScope
, kRegistrationId
, context_ptr_
);
355 scoped_refptr
<ServiceWorkerVersion
> live_version
=
356 new ServiceWorkerVersion(
357 live_registration
.get(), kScript
, kVersionId
, context_ptr_
);
358 live_version
->SetStatus(ServiceWorkerVersion::INSTALLED
);
359 live_registration
->SetWaitingVersion(live_version
.get());
360 live_registration
->set_last_update_check(kYesterday
);
361 EXPECT_EQ(SERVICE_WORKER_OK
,
362 StoreRegistration(live_registration
, live_version
));
364 // Now we should find it and get the live ptr back immediately.
365 EXPECT_EQ(SERVICE_WORKER_OK
,
366 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
367 EXPECT_EQ(live_registration
, found_registration
);
368 found_registration
= NULL
;
370 // But FindRegistrationForPattern is always async.
371 EXPECT_EQ(SERVICE_WORKER_OK
,
372 FindRegistrationForPattern(kScope
, &found_registration
));
373 EXPECT_EQ(live_registration
, found_registration
);
374 found_registration
= NULL
;
376 // Can be found by id too.
377 EXPECT_EQ(SERVICE_WORKER_OK
,
378 FindRegistrationForId(
379 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
380 ASSERT_TRUE(found_registration
.get());
381 EXPECT_EQ(kRegistrationId
, found_registration
->id());
382 EXPECT_EQ(live_registration
, found_registration
);
383 found_registration
= NULL
;
385 // Drop the live registration, but keep the version live.
386 live_registration
= NULL
;
388 // Now FindRegistrationForDocument should be async.
389 EXPECT_EQ(SERVICE_WORKER_OK
,
390 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
391 ASSERT_TRUE(found_registration
.get());
392 EXPECT_EQ(kRegistrationId
, found_registration
->id());
393 EXPECT_TRUE(found_registration
->HasOneRef());
394 EXPECT_EQ(live_version
.get(), found_registration
->waiting_version());
395 found_registration
= NULL
;
397 // Drop the live version too.
400 // And FindRegistrationForPattern is always async.
401 EXPECT_EQ(SERVICE_WORKER_OK
,
402 FindRegistrationForPattern(kScope
, &found_registration
));
403 ASSERT_TRUE(found_registration
.get());
404 EXPECT_EQ(kRegistrationId
, found_registration
->id());
405 EXPECT_TRUE(found_registration
->HasOneRef());
406 EXPECT_FALSE(found_registration
->active_version());
407 ASSERT_TRUE(found_registration
->waiting_version());
408 EXPECT_EQ(kYesterday
, found_registration
->last_update_check());
409 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
,
410 found_registration
->waiting_version()->status());
412 // Update to active and update the last check time.
413 scoped_refptr
<ServiceWorkerVersion
> temp_version
=
414 found_registration
->waiting_version();
415 temp_version
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
416 found_registration
->SetActiveVersion(temp_version
.get());
418 EXPECT_EQ(SERVICE_WORKER_OK
, UpdateToActiveState(found_registration
));
419 found_registration
->set_last_update_check(kToday
);
420 UpdateLastUpdateCheckTime(found_registration
.get());
422 found_registration
= NULL
;
424 // Trying to update a unstored registration to active should fail.
425 scoped_refptr
<ServiceWorkerRegistration
> unstored_registration
=
426 new ServiceWorkerRegistration(
427 kScope
, kRegistrationId
+ 1, context_ptr_
);
428 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
429 UpdateToActiveState(unstored_registration
));
430 unstored_registration
= NULL
;
432 // The Find methods should return a registration with an active version
433 // and the expected update time.
434 EXPECT_EQ(SERVICE_WORKER_OK
,
435 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
436 ASSERT_TRUE(found_registration
.get());
437 EXPECT_EQ(kRegistrationId
, found_registration
->id());
438 EXPECT_TRUE(found_registration
->HasOneRef());
439 EXPECT_FALSE(found_registration
->waiting_version());
440 ASSERT_TRUE(found_registration
->active_version());
441 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
,
442 found_registration
->active_version()->status());
443 EXPECT_EQ(kToday
, found_registration
->last_update_check());
445 // Delete from storage but with a instance still live.
446 EXPECT_TRUE(context_
->GetLiveVersion(kRegistrationId
));
447 EXPECT_EQ(SERVICE_WORKER_OK
,
448 DeleteRegistration(kRegistrationId
, kScope
.GetOrigin()));
449 EXPECT_TRUE(context_
->GetLiveVersion(kRegistrationId
));
451 // Should no longer be found.
452 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
453 FindRegistrationForId(
454 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
455 EXPECT_FALSE(found_registration
.get());
457 // Deleting an unstored registration should succeed.
458 EXPECT_EQ(SERVICE_WORKER_OK
,
459 DeleteRegistration(kRegistrationId
+ 1, kScope
.GetOrigin()));
462 TEST_F(ServiceWorkerStorageTest
, InstallingRegistrationsAreFindable
) {
463 const GURL
kScope("http://www.test.not/scope/");
464 const GURL
kScript("http://www.test.not/script.js");
465 const GURL
kDocumentUrl("http://www.test.not/scope/document.html");
466 const int64 kRegistrationId
= 0;
467 const int64 kVersionId
= 0;
469 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
471 // Create an unstored registration.
472 scoped_refptr
<ServiceWorkerRegistration
> live_registration
=
473 new ServiceWorkerRegistration(
474 kScope
, kRegistrationId
, context_ptr_
);
475 scoped_refptr
<ServiceWorkerVersion
> live_version
=
476 new ServiceWorkerVersion(
477 live_registration
.get(), kScript
, kVersionId
, context_ptr_
);
478 live_version
->SetStatus(ServiceWorkerVersion::INSTALLING
);
479 live_registration
->SetWaitingVersion(live_version
.get());
481 // Should not be findable, including by GetAllRegistrations.
482 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
483 FindRegistrationForId(
484 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
485 EXPECT_FALSE(found_registration
.get());
487 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
488 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
489 EXPECT_FALSE(found_registration
.get());
491 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
492 FindRegistrationForPattern(kScope
, &found_registration
));
493 EXPECT_FALSE(found_registration
.get());
495 std::vector
<ServiceWorkerRegistrationInfo
> all_registrations
;
496 GetAllRegistrations(&all_registrations
);
497 EXPECT_TRUE(all_registrations
.empty());
499 // Notify storage of it being installed.
500 storage()->NotifyInstallingRegistration(live_registration
.get());
502 // Now should be findable.
503 EXPECT_EQ(SERVICE_WORKER_OK
,
504 FindRegistrationForId(
505 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
506 EXPECT_EQ(live_registration
, found_registration
);
507 found_registration
= NULL
;
509 EXPECT_EQ(SERVICE_WORKER_OK
,
510 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
511 EXPECT_EQ(live_registration
, found_registration
);
512 found_registration
= NULL
;
514 EXPECT_EQ(SERVICE_WORKER_OK
,
515 FindRegistrationForPattern(kScope
, &found_registration
));
516 EXPECT_EQ(live_registration
, found_registration
);
517 found_registration
= NULL
;
519 GetAllRegistrations(&all_registrations
);
520 EXPECT_EQ(1u, all_registrations
.size());
521 all_registrations
.clear();
523 // Notify storage of installation no longer happening.
524 storage()->NotifyDoneInstallingRegistration(
525 live_registration
.get(), NULL
, SERVICE_WORKER_OK
);
527 // Once again, should not be findable.
528 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
529 FindRegistrationForId(
530 kRegistrationId
, kScope
.GetOrigin(), &found_registration
));
531 EXPECT_FALSE(found_registration
.get());
533 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
534 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
535 EXPECT_FALSE(found_registration
.get());
537 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
,
538 FindRegistrationForPattern(kScope
, &found_registration
));
539 EXPECT_FALSE(found_registration
.get());
541 GetAllRegistrations(&all_registrations
);
542 EXPECT_TRUE(all_registrations
.empty());
545 class ServiceWorkerResourceStorageTest
: public ServiceWorkerStorageTest
{
547 virtual void SetUp() OVERRIDE
{
548 ServiceWorkerStorageTest::SetUp();
550 storage()->LazyInitialize(base::Bind(&base::DoNothing
));
551 base::RunLoop().RunUntilIdle();
552 scope_
= GURL("http://www.test.not/scope/");
553 script_
= GURL("http://www.test.not/script.js");
554 import_
= GURL("http://www.test.not/import.js");
555 document_url_
= GURL("http://www.test.not/scope/document.html");
556 registration_id_
= storage()->NewRegistrationId();
557 version_id_
= storage()->NewVersionId();
558 resource_id1_
= storage()->NewResourceId();
559 resource_id2_
= storage()->NewResourceId();
561 // Cons up a new registration+version with two script resources.
562 RegistrationData data
;
563 data
.registration_id
= registration_id_
;
565 data
.script
= script_
;
566 data
.version_id
= version_id_
;
567 data
.is_active
= false;
568 std::vector
<ResourceRecord
> resources
;
569 resources
.push_back(ResourceRecord(resource_id1_
, script_
));
570 resources
.push_back(ResourceRecord(resource_id2_
, import_
));
571 registration_
= storage()->GetOrCreateRegistration(data
, resources
);
572 registration_
->waiting_version()->SetStatus(ServiceWorkerVersion::NEW
);
574 // Add the resources ids to the uncommitted list.
575 storage()->StoreUncommittedResponseId(resource_id1_
);
576 storage()->StoreUncommittedResponseId(resource_id2_
);
577 base::RunLoop().RunUntilIdle();
578 std::set
<int64
> verify_ids
;
579 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
580 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
581 EXPECT_EQ(2u, verify_ids
.size());
583 // And dump something in the disk cache for them.
584 WriteBasicResponse(storage(), resource_id1_
);
585 WriteBasicResponse(storage(), resource_id2_
);
586 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
587 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
589 // Storing the registration/version should take the resources ids out
590 // of the uncommitted list.
593 StoreRegistration(registration_
, registration_
->waiting_version()));
595 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
596 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
597 EXPECT_TRUE(verify_ids
.empty());
605 int64 registration_id_
;
609 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
612 class ServiceWorkerResourceStorageDiskTest
613 : public ServiceWorkerResourceStorageTest
{
615 virtual void SetUp() OVERRIDE
{
616 ASSERT_TRUE(user_data_directory_
.CreateUniqueTempDir());
617 ServiceWorkerResourceStorageTest::SetUp();
620 virtual base::FilePath
GetUserDataDirectory() OVERRIDE
{
621 return user_data_directory_
.path();
625 base::ScopedTempDir user_data_directory_
;
628 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_NoLiveVersion
) {
629 bool was_called
= false;
630 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
631 std::set
<int64
> verify_ids
;
633 registration_
->SetWaitingVersion(NULL
);
634 registration_
= NULL
;
636 // Deleting the registration should result in the resources being added to the
637 // purgeable list and then doomed in the disk cache and removed from that
639 storage()->DeleteRegistration(
642 base::Bind(&VerifyPurgeableListStatusCallback
,
643 base::Unretained(storage()->database_
.get()),
647 base::RunLoop().RunUntilIdle();
648 ASSERT_TRUE(was_called
);
649 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
650 EXPECT_EQ(2u, verify_ids
.size());
652 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
653 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
654 EXPECT_TRUE(verify_ids
.empty());
656 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
657 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
660 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_WaitingVersion
) {
661 bool was_called
= false;
662 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
663 std::set
<int64
> verify_ids
;
665 // Deleting the registration should result in the resources being added to the
666 // purgeable list and then doomed in the disk cache and removed from that
668 storage()->DeleteRegistration(
671 base::Bind(&VerifyPurgeableListStatusCallback
,
672 base::Unretained(storage()->database_
.get()),
676 base::RunLoop().RunUntilIdle();
677 ASSERT_TRUE(was_called
);
678 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
679 EXPECT_EQ(2u, verify_ids
.size());
681 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
682 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
683 EXPECT_EQ(2u, verify_ids
.size());
685 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, false));
686 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, false));
688 // Doom the version, now it happens.
689 registration_
->waiting_version()->Doom();
690 base::RunLoop().RunUntilIdle();
691 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
692 EXPECT_EQ(2u, verify_ids
.size());
694 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
695 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
696 EXPECT_TRUE(verify_ids
.empty());
698 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
699 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
702 TEST_F(ServiceWorkerResourceStorageTest
, DeleteRegistration_ActiveVersion
) {
703 // Promote the worker to active and add a controllee.
704 registration_
->SetActiveVersion(registration_
->waiting_version());
705 storage()->UpdateToActiveState(
706 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
707 scoped_ptr
<ServiceWorkerProviderHost
> host(
708 new ServiceWorkerProviderHost(33 /* dummy render process id */,
709 1 /* dummy provider_id */,
710 context_
->AsWeakPtr(),
712 registration_
->active_version()->AddControllee(host
.get());
714 bool was_called
= false;
715 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
716 std::set
<int64
> verify_ids
;
718 // Deleting the registration should move the resources to the purgeable list
719 // but keep them available.
720 storage()->DeleteRegistration(
723 base::Bind(&VerifyPurgeableListStatusCallback
,
724 base::Unretained(storage()->database_
.get()),
728 registration_
->active_version()->Doom();
729 base::RunLoop().RunUntilIdle();
730 ASSERT_TRUE(was_called
);
731 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
732 EXPECT_EQ(2u, verify_ids
.size());
734 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
735 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
736 EXPECT_EQ(2u, verify_ids
.size());
738 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
739 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
741 // Removing the controllee should cause the resources to be deleted.
742 registration_
->active_version()->RemoveControllee(host
.get());
743 base::RunLoop().RunUntilIdle();
745 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
746 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
747 EXPECT_TRUE(verify_ids
.empty());
749 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
750 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
753 // Android has flaky IO error: http://crbug.com/387045
754 #if defined(OS_ANDROID)
755 #define MAYBE_CleanupOnRestart DISABLED_CleanupOnRestart
757 #define MAYBE_CleanupOnRestart CleanupOnRestart
759 TEST_F(ServiceWorkerResourceStorageDiskTest
, MAYBE_CleanupOnRestart
) {
760 // Promote the worker to active and add a controllee.
761 registration_
->SetActiveVersion(registration_
->waiting_version());
762 registration_
->SetWaitingVersion(NULL
);
763 storage()->UpdateToActiveState(
764 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
765 scoped_ptr
<ServiceWorkerProviderHost
> host(
766 new ServiceWorkerProviderHost(33 /* dummy render process id */,
767 1 /* dummy provider_id */,
768 context_
->AsWeakPtr(),
770 registration_
->active_version()->AddControllee(host
.get());
772 bool was_called
= false;
773 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
774 std::set
<int64
> verify_ids
;
776 // Deleting the registration should move the resources to the purgeable list
777 // but keep them available.
778 storage()->DeleteRegistration(
781 base::Bind(&VerifyPurgeableListStatusCallback
,
782 base::Unretained(storage()->database_
.get()),
786 base::RunLoop().RunUntilIdle();
787 ASSERT_TRUE(was_called
);
788 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
789 EXPECT_EQ(2u, verify_ids
.size());
791 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
792 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
793 EXPECT_EQ(2u, verify_ids
.size());
795 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, true));
796 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, true));
798 // Also add an uncommitted resource.
799 int64 kStaleUncommittedResourceId
= storage()->NewResourceId();
800 storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId
);
801 base::RunLoop().RunUntilIdle();
803 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
804 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
805 EXPECT_EQ(1u, verify_ids
.size());
806 WriteBasicResponse(storage(), kStaleUncommittedResourceId
);
808 VerifyBasicResponse(storage(), kStaleUncommittedResourceId
, true));
810 // Simulate browser shutdown. The purgeable and uncommitted resources are now
814 new ServiceWorkerContextCore(GetUserDataDirectory(),
815 base::ThreadTaskRunnerHandle::Get(),
816 base::ThreadTaskRunnerHandle::Get(),
817 base::ThreadTaskRunnerHandle::Get(),
821 storage()->LazyInitialize(base::Bind(&base::DoNothing
));
822 base::RunLoop().RunUntilIdle();
824 // Store a new uncommitted resource. This triggers stale resource cleanup.
825 int64 kNewResourceId
= storage()->NewResourceId();
826 WriteBasicResponse(storage(), kNewResourceId
);
827 storage()->StoreUncommittedResponseId(kNewResourceId
);
828 base::RunLoop().RunUntilIdle();
830 // The stale resources should be purged, but the new resource should persist.
832 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
833 storage()->database_
->GetUncommittedResourceIds(&verify_ids
));
834 ASSERT_EQ(1u, verify_ids
.size());
835 EXPECT_EQ(kNewResourceId
, *verify_ids
.begin());
838 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
839 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
840 EXPECT_TRUE(verify_ids
.empty());
841 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
842 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
844 VerifyBasicResponse(storage(), kStaleUncommittedResourceId
, false));
845 EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId
, true));
848 TEST_F(ServiceWorkerResourceStorageTest
, UpdateRegistration
) {
849 // Promote the worker to active worker and add a controllee.
850 registration_
->SetActiveVersion(registration_
->waiting_version());
851 storage()->UpdateToActiveState(
852 registration_
.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
853 scoped_ptr
<ServiceWorkerProviderHost
> host(
854 new ServiceWorkerProviderHost(33 /* dummy render process id */,
855 1 /* dummy provider_id */,
856 context_
->AsWeakPtr(),
858 registration_
->active_version()->AddControllee(host
.get());
860 bool was_called
= false;
861 ServiceWorkerStatusCode result
= SERVICE_WORKER_ERROR_FAILED
;
862 std::set
<int64
> verify_ids
;
864 // Make an updated registration.
865 scoped_refptr
<ServiceWorkerVersion
> live_version
= new ServiceWorkerVersion(
866 registration_
.get(), script_
, storage()->NewVersionId(), context_ptr_
);
867 live_version
->SetStatus(ServiceWorkerVersion::NEW
);
868 registration_
->SetWaitingVersion(live_version
.get());
870 // Writing the registration should move the old version's resources to the
871 // purgeable list but keep them available.
872 storage()->StoreRegistration(
874 registration_
->waiting_version(),
875 base::Bind(&VerifyPurgeableListStatusCallback
,
876 base::Unretained(storage()->database_
.get()),
880 registration_
->active_version()->Doom();
881 base::RunLoop().RunUntilIdle();
882 ASSERT_TRUE(was_called
);
883 EXPECT_EQ(SERVICE_WORKER_OK
, result
);
884 EXPECT_EQ(2u, verify_ids
.size());
886 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
887 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
888 EXPECT_EQ(2u, verify_ids
.size());
890 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_
, false));
891 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_
, false));
893 // Removing the controllee should cause the old version's resources to be
895 registration_
->active_version()->RemoveControllee(host
.get());
896 base::RunLoop().RunUntilIdle();
898 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK
,
899 storage()->database_
->GetPurgeableResourceIds(&verify_ids
));
900 EXPECT_TRUE(verify_ids
.empty());
902 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_
, false));
903 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_
, false));
906 TEST_F(ServiceWorkerStorageTest
, FindRegistration_LongestScopeMatch
) {
907 const GURL
kDocumentUrl("http://www.example.com/scope/foo");
908 scoped_refptr
<ServiceWorkerRegistration
> found_registration
;
910 // Registration for "/scope/".
911 const GURL
kScope1("http://www.example.com/scope/");
912 const GURL
kScript1("http://www.example.com/script1.js");
913 const int64 kRegistrationId1
= 1;
914 const int64 kVersionId1
= 1;
915 scoped_refptr
<ServiceWorkerRegistration
> live_registration1
=
916 new ServiceWorkerRegistration(
917 kScope1
, kRegistrationId1
, context_ptr_
);
918 scoped_refptr
<ServiceWorkerVersion
> live_version1
=
919 new ServiceWorkerVersion(
920 live_registration1
.get(), kScript1
, kVersionId1
, context_ptr_
);
921 live_version1
->SetStatus(ServiceWorkerVersion::INSTALLED
);
922 live_registration1
->SetWaitingVersion(live_version1
.get());
924 // Registration for "/scope/foo".
925 const GURL
kScope2("http://www.example.com/scope/foo");
926 const GURL
kScript2("http://www.example.com/script2.js");
927 const int64 kRegistrationId2
= 2;
928 const int64 kVersionId2
= 2;
929 scoped_refptr
<ServiceWorkerRegistration
> live_registration2
=
930 new ServiceWorkerRegistration(
931 kScope2
, kRegistrationId2
, context_ptr_
);
932 scoped_refptr
<ServiceWorkerVersion
> live_version2
=
933 new ServiceWorkerVersion(
934 live_registration2
.get(), kScript2
, kVersionId2
, context_ptr_
);
935 live_version2
->SetStatus(ServiceWorkerVersion::INSTALLED
);
936 live_registration2
->SetWaitingVersion(live_version2
.get());
938 // Registration for "/scope/foobar".
939 const GURL
kScope3("http://www.example.com/scope/foobar");
940 const GURL
kScript3("http://www.example.com/script3.js");
941 const int64 kRegistrationId3
= 3;
942 const int64 kVersionId3
= 3;
943 scoped_refptr
<ServiceWorkerRegistration
> live_registration3
=
944 new ServiceWorkerRegistration(
945 kScope3
, kRegistrationId3
, context_ptr_
);
946 scoped_refptr
<ServiceWorkerVersion
> live_version3
=
947 new ServiceWorkerVersion(
948 live_registration3
.get(), kScript3
, kVersionId3
, context_ptr_
);
949 live_version3
->SetStatus(ServiceWorkerVersion::INSTALLED
);
950 live_registration3
->SetWaitingVersion(live_version3
.get());
952 // Notify storage of they being installed.
953 storage()->NotifyInstallingRegistration(live_registration1
.get());
954 storage()->NotifyInstallingRegistration(live_registration2
.get());
955 storage()->NotifyInstallingRegistration(live_registration3
.get());
957 // Find a registration among installing ones.
958 EXPECT_EQ(SERVICE_WORKER_OK
,
959 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
960 EXPECT_EQ(live_registration2
, found_registration
);
961 found_registration
= NULL
;
963 // Store registrations.
964 EXPECT_EQ(SERVICE_WORKER_OK
,
965 StoreRegistration(live_registration1
, live_version1
));
966 EXPECT_EQ(SERVICE_WORKER_OK
,
967 StoreRegistration(live_registration2
, live_version2
));
968 EXPECT_EQ(SERVICE_WORKER_OK
,
969 StoreRegistration(live_registration3
, live_version3
));
971 // Notify storage of installations no longer happening.
972 storage()->NotifyDoneInstallingRegistration(
973 live_registration1
.get(), NULL
, SERVICE_WORKER_OK
);
974 storage()->NotifyDoneInstallingRegistration(
975 live_registration2
.get(), NULL
, SERVICE_WORKER_OK
);
976 storage()->NotifyDoneInstallingRegistration(
977 live_registration3
.get(), NULL
, SERVICE_WORKER_OK
);
979 // Find a registration among installed ones.
980 EXPECT_EQ(SERVICE_WORKER_OK
,
981 FindRegistrationForDocument(kDocumentUrl
, &found_registration
));
982 EXPECT_EQ(live_registration2
, found_registration
);
985 TEST_F(ServiceWorkerStorageTest
, CompareResources
) {
986 // Compare two small responses containing the same data.
987 WriteBasicResponse(storage(), 1);
988 WriteBasicResponse(storage(), 2);
989 ServiceWorkerStatusCode status
= static_cast<ServiceWorkerStatusCode
>(-1);
990 bool are_equal
= false;
991 storage()->CompareScriptResources(
993 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
994 base::RunLoop().RunUntilIdle();
995 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
996 EXPECT_TRUE(are_equal
);
998 // Compare two small responses with different data.
999 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\0\0";
1000 const char kHttpBody
[] = "Goodbye";
1001 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
1002 WriteStringResponse(storage(), 3, headers
, std::string(kHttpBody
));
1003 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1005 storage()->CompareScriptResources(
1007 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1008 base::RunLoop().RunUntilIdle();
1009 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1010 EXPECT_FALSE(are_equal
);
1012 // Compare two large responses with the same data.
1013 const int k32K
= 32 * 1024;
1014 WriteResponseOfSize(storage(), 4, 'a', k32K
);
1015 WriteResponseOfSize(storage(), 5, 'a', k32K
);
1016 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1018 storage()->CompareScriptResources(
1020 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1021 base::RunLoop().RunUntilIdle();
1022 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1023 EXPECT_TRUE(are_equal
);
1025 // Compare a large and small response.
1026 status
= static_cast<ServiceWorkerStatusCode
>(-1);
1028 storage()->CompareScriptResources(
1030 base::Bind(&OnCompareComplete
, &status
, &are_equal
));
1031 base::RunLoop().RunUntilIdle();
1032 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
1033 EXPECT_FALSE(are_equal
);
1035 // Compare two large responses with different data.
1036 WriteResponseOfSize(storage(), 6, 'b', k32K
);
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
);
1047 } // namespace content