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/message_loop/message_loop.h"
10 #include "base/run_loop.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, 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, 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, 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, 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, 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::MessageLoopProxy::current(),
198 base::MessageLoopProxy::current(),
199 base::MessageLoopProxy::current(),
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(
234 registration, version, MakeStatusCallback(&was_called, &result));
235 EXPECT_FALSE(was_called); // always async
236 base::RunLoop().RunUntilIdle();
237 EXPECT_TRUE(was_called);
241 ServiceWorkerStatusCode DeleteRegistration(
242 int64 registration_id,
243 const GURL& origin) {
244 bool was_called = false;
245 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
246 storage()->DeleteRegistration(
247 registration_id, origin, MakeStatusCallback(&was_called, &result));
248 EXPECT_FALSE(was_called); // always async
249 base::RunLoop().RunUntilIdle();
250 EXPECT_TRUE(was_called);
254 void GetAllRegistrations(
255 std::vector<ServiceWorkerRegistrationInfo>* registrations) {
256 bool was_called = false;
257 storage()->GetAllRegistrations(
258 MakeGetAllCallback(&was_called, registrations));
259 EXPECT_FALSE(was_called); // always async
260 base::RunLoop().RunUntilIdle();
261 EXPECT_TRUE(was_called);
264 ServiceWorkerStatusCode UpdateToActiveState(
265 scoped_refptr<ServiceWorkerRegistration> registration) {
266 bool was_called = false;
267 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
268 storage()->UpdateToActiveState(
269 registration, MakeStatusCallback(&was_called, &result));
270 EXPECT_FALSE(was_called); // always async
271 base::RunLoop().RunUntilIdle();
272 EXPECT_TRUE(was_called);
276 void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration) {
277 storage()->UpdateLastUpdateCheckTime(registration);
278 base::RunLoop().RunUntilIdle();
281 ServiceWorkerStatusCode FindRegistrationForDocument(
282 const GURL& document_url,
283 scoped_refptr<ServiceWorkerRegistration>* registration) {
284 bool was_called = false;
285 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
286 storage()->FindRegistrationForDocument(
287 document_url, MakeFindCallback(&was_called, &result, registration));
288 base::RunLoop().RunUntilIdle();
289 EXPECT_TRUE(was_called);
293 ServiceWorkerStatusCode FindRegistrationForPattern(
295 scoped_refptr<ServiceWorkerRegistration>* registration) {
296 bool was_called = false;
297 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
298 storage()->FindRegistrationForPattern(
299 scope, MakeFindCallback(&was_called, &result, registration));
300 EXPECT_FALSE(was_called); // always async
301 base::RunLoop().RunUntilIdle();
302 EXPECT_TRUE(was_called);
306 ServiceWorkerStatusCode FindRegistrationForId(
307 int64 registration_id,
309 scoped_refptr<ServiceWorkerRegistration>* registration) {
310 bool was_called = false;
311 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
312 storage()->FindRegistrationForId(
313 registration_id, origin,
314 MakeFindCallback(&was_called, &result, registration));
315 base::RunLoop().RunUntilIdle();
316 EXPECT_TRUE(was_called);
320 scoped_ptr<ServiceWorkerContextCore> context_;
321 base::WeakPtr<ServiceWorkerContextCore> context_ptr_;
322 TestBrowserThreadBundle browser_thread_bundle_;
325 TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
326 const GURL kScope("http://www.test.not/scope/");
327 const GURL kScript("http://www.test.not/script.js");
328 const GURL kDocumentUrl("http://www.test.not/scope/document.html");
329 const int64 kRegistrationId = 0;
330 const int64 kVersionId = 0;
331 const base::Time kToday = base::Time::Now();
332 const base::Time kYesterday = kToday - base::TimeDelta::FromDays(1);
334 scoped_refptr<ServiceWorkerRegistration> found_registration;
336 // We shouldn't find anything without having stored anything.
337 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
338 FindRegistrationForDocument(kDocumentUrl, &found_registration));
339 EXPECT_FALSE(found_registration);
341 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
342 FindRegistrationForPattern(kScope, &found_registration));
343 EXPECT_FALSE(found_registration);
345 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
346 FindRegistrationForId(
347 kRegistrationId, kScope.GetOrigin(), &found_registration));
348 EXPECT_FALSE(found_registration);
351 scoped_refptr<ServiceWorkerRegistration> live_registration =
352 new ServiceWorkerRegistration(
353 kScope, kScript, kRegistrationId, context_ptr_);
354 scoped_refptr<ServiceWorkerVersion> live_version =
355 new ServiceWorkerVersion(
356 live_registration, kVersionId, context_ptr_);
357 live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
358 live_registration->SetWaitingVersion(live_version);
359 live_registration->set_last_update_check(kYesterday);
360 EXPECT_EQ(SERVICE_WORKER_OK,
361 StoreRegistration(live_registration, live_version));
363 // Now we should find it and get the live ptr back immediately.
364 EXPECT_EQ(SERVICE_WORKER_OK,
365 FindRegistrationForDocument(kDocumentUrl, &found_registration));
366 EXPECT_EQ(live_registration, found_registration);
367 found_registration = NULL;
369 // But FindRegistrationForPattern is always async.
370 EXPECT_EQ(SERVICE_WORKER_OK,
371 FindRegistrationForPattern(kScope, &found_registration));
372 EXPECT_EQ(live_registration, found_registration);
373 found_registration = NULL;
375 // Can be found by id too.
376 EXPECT_EQ(SERVICE_WORKER_OK,
377 FindRegistrationForId(
378 kRegistrationId, kScope.GetOrigin(), &found_registration));
379 ASSERT_TRUE(found_registration);
380 EXPECT_EQ(kRegistrationId, found_registration->id());
381 EXPECT_EQ(live_registration, found_registration);
382 found_registration = NULL;
384 // Drop the live registration, but keep the version live.
385 live_registration = NULL;
387 // Now FindRegistrationForDocument should be async.
388 EXPECT_EQ(SERVICE_WORKER_OK,
389 FindRegistrationForDocument(kDocumentUrl, &found_registration));
390 ASSERT_TRUE(found_registration);
391 EXPECT_EQ(kRegistrationId, found_registration->id());
392 EXPECT_TRUE(found_registration->HasOneRef());
393 EXPECT_EQ(live_version, found_registration->waiting_version());
394 found_registration = NULL;
396 // Drop the live version too.
399 // And FindRegistrationForPattern is always async.
400 EXPECT_EQ(SERVICE_WORKER_OK,
401 FindRegistrationForPattern(kScope, &found_registration));
402 ASSERT_TRUE(found_registration);
403 EXPECT_EQ(kRegistrationId, found_registration->id());
404 EXPECT_TRUE(found_registration->HasOneRef());
405 EXPECT_FALSE(found_registration->active_version());
406 ASSERT_TRUE(found_registration->waiting_version());
407 EXPECT_EQ(kYesterday, found_registration->last_update_check());
408 EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
409 found_registration->waiting_version()->status());
411 // Update to active and update the last check time.
412 scoped_refptr<ServiceWorkerVersion> temp_version =
413 found_registration->waiting_version();
414 temp_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
415 found_registration->SetActiveVersion(temp_version);
417 EXPECT_EQ(SERVICE_WORKER_OK, UpdateToActiveState(found_registration));
418 found_registration->set_last_update_check(kToday);
419 UpdateLastUpdateCheckTime(found_registration);
421 found_registration = NULL;
423 // Trying to update a unstored registration to active should fail.
424 scoped_refptr<ServiceWorkerRegistration> unstored_registration =
425 new ServiceWorkerRegistration(
426 kScope, kScript, kRegistrationId + 1, context_ptr_);
427 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
428 UpdateToActiveState(unstored_registration));
429 unstored_registration = NULL;
431 // The Find methods should return a registration with an active version
432 // and the expected update time.
433 EXPECT_EQ(SERVICE_WORKER_OK,
434 FindRegistrationForDocument(kDocumentUrl, &found_registration));
435 ASSERT_TRUE(found_registration);
436 EXPECT_EQ(kRegistrationId, found_registration->id());
437 EXPECT_TRUE(found_registration->HasOneRef());
438 EXPECT_FALSE(found_registration->waiting_version());
439 ASSERT_TRUE(found_registration->active_version());
440 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
441 found_registration->active_version()->status());
442 EXPECT_EQ(kToday, found_registration->last_update_check());
444 // Delete from storage but with a instance still live.
445 EXPECT_TRUE(context_->GetLiveVersion(kRegistrationId));
446 EXPECT_EQ(SERVICE_WORKER_OK,
447 DeleteRegistration(kRegistrationId, kScope.GetOrigin()));
448 EXPECT_TRUE(context_->GetLiveVersion(kRegistrationId));
450 // Should no longer be found.
451 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
452 FindRegistrationForId(
453 kRegistrationId, kScope.GetOrigin(), &found_registration));
454 EXPECT_FALSE(found_registration);
456 // Deleting an unstored registration should succeed.
457 EXPECT_EQ(SERVICE_WORKER_OK,
458 DeleteRegistration(kRegistrationId + 1, kScope.GetOrigin()));
461 TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
462 const GURL kScope("http://www.test.not/scope/");
463 const GURL kScript("http://www.test.not/script.js");
464 const GURL kDocumentUrl("http://www.test.not/scope/document.html");
465 const int64 kRegistrationId = 0;
466 const int64 kVersionId = 0;
468 scoped_refptr<ServiceWorkerRegistration> found_registration;
470 // Create an unstored registration.
471 scoped_refptr<ServiceWorkerRegistration> live_registration =
472 new ServiceWorkerRegistration(
473 kScope, kScript, kRegistrationId, context_ptr_);
474 scoped_refptr<ServiceWorkerVersion> live_version =
475 new ServiceWorkerVersion(
476 live_registration, kVersionId, context_ptr_);
477 live_version->SetStatus(ServiceWorkerVersion::INSTALLING);
478 live_registration->SetWaitingVersion(live_version);
480 // Should not be findable, including by GetAllRegistrations.
481 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
482 FindRegistrationForId(
483 kRegistrationId, kScope.GetOrigin(), &found_registration));
484 EXPECT_FALSE(found_registration);
486 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
487 FindRegistrationForDocument(kDocumentUrl, &found_registration));
488 EXPECT_FALSE(found_registration);
490 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
491 FindRegistrationForPattern(kScope, &found_registration));
492 EXPECT_FALSE(found_registration);
494 std::vector<ServiceWorkerRegistrationInfo> all_registrations;
495 GetAllRegistrations(&all_registrations);
496 EXPECT_TRUE(all_registrations.empty());
498 // Notify storage of it being installed.
499 storage()->NotifyInstallingRegistration(live_registration);
501 // Now should be findable.
502 EXPECT_EQ(SERVICE_WORKER_OK,
503 FindRegistrationForId(
504 kRegistrationId, kScope.GetOrigin(), &found_registration));
505 EXPECT_EQ(live_registration, found_registration);
506 found_registration = NULL;
508 EXPECT_EQ(SERVICE_WORKER_OK,
509 FindRegistrationForDocument(kDocumentUrl, &found_registration));
510 EXPECT_EQ(live_registration, found_registration);
511 found_registration = NULL;
513 EXPECT_EQ(SERVICE_WORKER_OK,
514 FindRegistrationForPattern(kScope, &found_registration));
515 EXPECT_EQ(live_registration, found_registration);
516 found_registration = NULL;
518 GetAllRegistrations(&all_registrations);
519 EXPECT_EQ(1u, all_registrations.size());
520 all_registrations.clear();
522 // Notify storage of installation no longer happening.
523 storage()->NotifyDoneInstallingRegistration(
524 live_registration, NULL, SERVICE_WORKER_OK);
526 // Once again, should not be findable.
527 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
528 FindRegistrationForId(
529 kRegistrationId, kScope.GetOrigin(), &found_registration));
530 EXPECT_FALSE(found_registration);
532 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
533 FindRegistrationForDocument(kDocumentUrl, &found_registration));
534 EXPECT_FALSE(found_registration);
536 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
537 FindRegistrationForPattern(kScope, &found_registration));
538 EXPECT_FALSE(found_registration);
540 GetAllRegistrations(&all_registrations);
541 EXPECT_TRUE(all_registrations.empty());
544 class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
546 virtual void SetUp() OVERRIDE {
547 ServiceWorkerStorageTest::SetUp();
549 storage()->LazyInitialize(base::Bind(&base::DoNothing));
550 base::RunLoop().RunUntilIdle();
551 scope_ = GURL("http://www.test.not/scope/");
552 script_ = GURL("http://www.test.not/script.js");
553 import_ = GURL("http://www.test.not/import.js");
554 document_url_ = GURL("http://www.test.not/scope/document.html");
555 registration_id_ = storage()->NewRegistrationId();
556 version_id_ = storage()->NewVersionId();
557 resource_id1_ = storage()->NewResourceId();
558 resource_id2_ = storage()->NewResourceId();
560 // Cons up a new registration+version with two script resources.
561 RegistrationData data;
562 data.registration_id = registration_id_;
564 data.script = script_;
565 data.version_id = version_id_;
566 data.is_active = false;
567 std::vector<ResourceRecord> resources;
568 resources.push_back(ResourceRecord(resource_id1_, script_));
569 resources.push_back(ResourceRecord(resource_id2_, import_));
570 registration_ = storage()->GetOrCreateRegistration(data, resources);
571 registration_->waiting_version()->SetStatus(ServiceWorkerVersion::NEW);
573 // Add the resources ids to the uncommitted list.
574 storage()->StoreUncommittedResponseId(resource_id1_);
575 storage()->StoreUncommittedResponseId(resource_id2_);
576 base::RunLoop().RunUntilIdle();
577 std::set<int64> verify_ids;
578 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
579 storage()->database_->GetUncommittedResourceIds(&verify_ids));
580 EXPECT_EQ(2u, verify_ids.size());
582 // And dump something in the disk cache for them.
583 WriteBasicResponse(storage(), resource_id1_);
584 WriteBasicResponse(storage(), resource_id2_);
585 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
586 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
588 // Storing the registration/version should take the resources ids out
589 // of the uncommitted list.
592 StoreRegistration(registration_, registration_->waiting_version()));
594 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
595 storage()->database_->GetUncommittedResourceIds(&verify_ids));
596 EXPECT_TRUE(verify_ids.empty());
604 int64 registration_id_;
608 scoped_refptr<ServiceWorkerRegistration> registration_;
611 class ServiceWorkerResourceStorageDiskTest
612 : public ServiceWorkerResourceStorageTest {
614 virtual void SetUp() OVERRIDE {
615 ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir());
616 ServiceWorkerResourceStorageTest::SetUp();
619 virtual base::FilePath GetUserDataDirectory() OVERRIDE {
620 return user_data_directory_.path();
624 base::ScopedTempDir user_data_directory_;
627 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_NoLiveVersion) {
628 bool was_called = false;
629 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
630 std::set<int64> verify_ids;
632 registration_->SetWaitingVersion(NULL);
633 registration_ = NULL;
635 // Deleting the registration should result in the resources being added to the
636 // purgeable list and then doomed in the disk cache and removed from that
638 storage()->DeleteRegistration(
641 base::Bind(&VerifyPurgeableListStatusCallback,
642 base::Unretained(storage()->database_.get()),
646 base::RunLoop().RunUntilIdle();
647 ASSERT_TRUE(was_called);
648 EXPECT_EQ(SERVICE_WORKER_OK, result);
649 EXPECT_EQ(2u, verify_ids.size());
651 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
652 storage()->database_->GetPurgeableResourceIds(&verify_ids));
653 EXPECT_TRUE(verify_ids.empty());
655 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
656 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
659 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_WaitingVersion) {
660 bool was_called = false;
661 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
662 std::set<int64> verify_ids;
664 // Deleting the registration should result in the resources being added to the
665 // purgeable list and then doomed in the disk cache and removed from that
667 storage()->DeleteRegistration(
670 base::Bind(&VerifyPurgeableListStatusCallback,
671 base::Unretained(storage()->database_.get()),
675 base::RunLoop().RunUntilIdle();
676 ASSERT_TRUE(was_called);
677 EXPECT_EQ(SERVICE_WORKER_OK, result);
678 EXPECT_EQ(2u, verify_ids.size());
680 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
681 storage()->database_->GetPurgeableResourceIds(&verify_ids));
682 EXPECT_EQ(2u, verify_ids.size());
684 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
685 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
687 // Doom the version, now it happens.
688 registration_->waiting_version()->Doom();
689 base::RunLoop().RunUntilIdle();
690 EXPECT_EQ(SERVICE_WORKER_OK, result);
691 EXPECT_EQ(2u, verify_ids.size());
693 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
694 storage()->database_->GetPurgeableResourceIds(&verify_ids));
695 EXPECT_TRUE(verify_ids.empty());
697 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
698 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
701 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) {
702 // Promote the worker to active and add a controllee.
703 registration_->SetActiveVersion(registration_->waiting_version());
704 storage()->UpdateToActiveState(
705 registration_, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
706 scoped_ptr<ServiceWorkerProviderHost> host(
707 new ServiceWorkerProviderHost(33 /* dummy render process id */,
708 1 /* dummy provider_id */,
709 context_->AsWeakPtr(),
711 registration_->active_version()->AddControllee(host.get());
713 bool was_called = false;
714 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
715 std::set<int64> verify_ids;
717 // Deleting the registration should move the resources to the purgeable list
718 // but keep them available.
719 storage()->DeleteRegistration(
722 base::Bind(&VerifyPurgeableListStatusCallback,
723 base::Unretained(storage()->database_.get()),
727 registration_->active_version()->Doom();
728 base::RunLoop().RunUntilIdle();
729 ASSERT_TRUE(was_called);
730 EXPECT_EQ(SERVICE_WORKER_OK, result);
731 EXPECT_EQ(2u, verify_ids.size());
733 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
734 storage()->database_->GetPurgeableResourceIds(&verify_ids));
735 EXPECT_EQ(2u, verify_ids.size());
737 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
738 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
740 // Removing the controllee should cause the resources to be deleted.
741 registration_->active_version()->RemoveControllee(host.get());
742 base::RunLoop().RunUntilIdle();
744 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
745 storage()->database_->GetPurgeableResourceIds(&verify_ids));
746 EXPECT_TRUE(verify_ids.empty());
748 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
749 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
752 // Android has flaky IO error: http://crbug.com/387045
753 #if defined(OS_ANDROID)
754 #define MAYBE_CleanupOnRestart DISABLED_CleanupOnRestart
756 #define MAYBE_CleanupOnRestart CleanupOnRestart
758 TEST_F(ServiceWorkerResourceStorageDiskTest, MAYBE_CleanupOnRestart) {
759 // Promote the worker to active and add a controllee.
760 registration_->SetActiveVersion(registration_->waiting_version());
761 registration_->SetWaitingVersion(NULL);
762 storage()->UpdateToActiveState(
763 registration_, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
764 scoped_ptr<ServiceWorkerProviderHost> host(
765 new ServiceWorkerProviderHost(33 /* dummy render process id */,
766 1 /* dummy provider_id */,
767 context_->AsWeakPtr(),
769 registration_->active_version()->AddControllee(host.get());
771 bool was_called = false;
772 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
773 std::set<int64> verify_ids;
775 // Deleting the registration should move the resources to the purgeable list
776 // but keep them available.
777 storage()->DeleteRegistration(
780 base::Bind(&VerifyPurgeableListStatusCallback,
781 base::Unretained(storage()->database_.get()),
785 base::RunLoop().RunUntilIdle();
786 ASSERT_TRUE(was_called);
787 EXPECT_EQ(SERVICE_WORKER_OK, result);
788 EXPECT_EQ(2u, verify_ids.size());
790 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
791 storage()->database_->GetPurgeableResourceIds(&verify_ids));
792 EXPECT_EQ(2u, verify_ids.size());
794 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
795 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
797 // Also add an uncommitted resource.
798 int64 kStaleUncommittedResourceId = storage()->NewResourceId();
799 storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId);
800 base::RunLoop().RunUntilIdle();
802 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
803 storage()->database_->GetUncommittedResourceIds(&verify_ids));
804 EXPECT_EQ(1u, verify_ids.size());
805 WriteBasicResponse(storage(), kStaleUncommittedResourceId);
807 VerifyBasicResponse(storage(), kStaleUncommittedResourceId, true));
809 // Simulate browser shutdown. The purgeable and uncommitted resources are now
812 context_.reset(new ServiceWorkerContextCore(GetUserDataDirectory(),
813 base::MessageLoopProxy::current(),
814 base::MessageLoopProxy::current(),
815 base::MessageLoopProxy::current(),
819 storage()->LazyInitialize(base::Bind(&base::DoNothing));
820 base::RunLoop().RunUntilIdle();
822 // Store a new uncommitted resource. This triggers stale resource cleanup.
823 int64 kNewResourceId = storage()->NewResourceId();
824 WriteBasicResponse(storage(), kNewResourceId);
825 storage()->StoreUncommittedResponseId(kNewResourceId);
826 base::RunLoop().RunUntilIdle();
828 // The stale resources should be purged, but the new resource should persist.
830 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
831 storage()->database_->GetUncommittedResourceIds(&verify_ids));
832 ASSERT_EQ(1u, verify_ids.size());
833 EXPECT_EQ(kNewResourceId, *verify_ids.begin());
836 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
837 storage()->database_->GetPurgeableResourceIds(&verify_ids));
838 EXPECT_TRUE(verify_ids.empty());
839 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
840 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
842 VerifyBasicResponse(storage(), kStaleUncommittedResourceId, false));
843 EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId, true));
846 TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
847 // Promote the worker to active worker and add a controllee.
848 registration_->SetActiveVersion(registration_->waiting_version());
849 storage()->UpdateToActiveState(
850 registration_, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
851 scoped_ptr<ServiceWorkerProviderHost> host(
852 new ServiceWorkerProviderHost(33 /* dummy render process id */,
853 1 /* dummy provider_id */,
854 context_->AsWeakPtr(),
856 registration_->active_version()->AddControllee(host.get());
858 bool was_called = false;
859 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
860 std::set<int64> verify_ids;
862 // Make an updated registration.
863 scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
864 registration_, storage()->NewVersionId(), context_ptr_);
865 live_version->SetStatus(ServiceWorkerVersion::NEW);
866 registration_->SetWaitingVersion(live_version);
868 // Writing the registration should move the old version's resources to the
869 // purgeable list but keep them available.
870 storage()->StoreRegistration(
872 registration_->waiting_version(),
873 base::Bind(&VerifyPurgeableListStatusCallback,
874 base::Unretained(storage()->database_.get()),
878 registration_->active_version()->Doom();
879 base::RunLoop().RunUntilIdle();
880 ASSERT_TRUE(was_called);
881 EXPECT_EQ(SERVICE_WORKER_OK, result);
882 EXPECT_EQ(2u, verify_ids.size());
884 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
885 storage()->database_->GetPurgeableResourceIds(&verify_ids));
886 EXPECT_EQ(2u, verify_ids.size());
888 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
889 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
891 // Removing the controllee should cause the old version's resources to be
893 registration_->active_version()->RemoveControllee(host.get());
894 base::RunLoop().RunUntilIdle();
896 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
897 storage()->database_->GetPurgeableResourceIds(&verify_ids));
898 EXPECT_TRUE(verify_ids.empty());
900 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
901 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
904 TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
905 const GURL kDocumentUrl("http://www.example.com/scope/foo");
906 scoped_refptr<ServiceWorkerRegistration> found_registration;
908 // Registration for "/scope/".
909 const GURL kScope1("http://www.example.com/scope/");
910 const GURL kScript1("http://www.example.com/script1.js");
911 const int64 kRegistrationId1 = 1;
912 const int64 kVersionId1 = 1;
913 scoped_refptr<ServiceWorkerRegistration> live_registration1 =
914 new ServiceWorkerRegistration(
915 kScope1, kScript1, kRegistrationId1, context_ptr_);
916 scoped_refptr<ServiceWorkerVersion> live_version1 =
917 new ServiceWorkerVersion(
918 live_registration1, kVersionId1, context_ptr_);
919 live_version1->SetStatus(ServiceWorkerVersion::INSTALLED);
920 live_registration1->SetWaitingVersion(live_version1);
922 // Registration for "/scope/foo".
923 const GURL kScope2("http://www.example.com/scope/foo");
924 const GURL kScript2("http://www.example.com/script2.js");
925 const int64 kRegistrationId2 = 2;
926 const int64 kVersionId2 = 2;
927 scoped_refptr<ServiceWorkerRegistration> live_registration2 =
928 new ServiceWorkerRegistration(
929 kScope2, kScript2, kRegistrationId2, context_ptr_);
930 scoped_refptr<ServiceWorkerVersion> live_version2 =
931 new ServiceWorkerVersion(
932 live_registration2, kVersionId2, context_ptr_);
933 live_version2->SetStatus(ServiceWorkerVersion::INSTALLED);
934 live_registration2->SetWaitingVersion(live_version2);
936 // Registration for "/scope/foobar".
937 const GURL kScope3("http://www.example.com/scope/foobar");
938 const GURL kScript3("http://www.example.com/script3.js");
939 const int64 kRegistrationId3 = 3;
940 const int64 kVersionId3 = 3;
941 scoped_refptr<ServiceWorkerRegistration> live_registration3 =
942 new ServiceWorkerRegistration(
943 kScope3, kScript3, kRegistrationId3, context_ptr_);
944 scoped_refptr<ServiceWorkerVersion> live_version3 =
945 new ServiceWorkerVersion(
946 live_registration3, kVersionId3, context_ptr_);
947 live_version3->SetStatus(ServiceWorkerVersion::INSTALLED);
948 live_registration3->SetWaitingVersion(live_version3);
950 // Notify storage of they being installed.
951 storage()->NotifyInstallingRegistration(live_registration1);
952 storage()->NotifyInstallingRegistration(live_registration2);
953 storage()->NotifyInstallingRegistration(live_registration3);
955 // Find a registration among installing ones.
956 EXPECT_EQ(SERVICE_WORKER_OK,
957 FindRegistrationForDocument(kDocumentUrl, &found_registration));
958 EXPECT_EQ(live_registration2, found_registration);
959 found_registration = NULL;
961 // Store registrations.
962 EXPECT_EQ(SERVICE_WORKER_OK,
963 StoreRegistration(live_registration1, live_version1));
964 EXPECT_EQ(SERVICE_WORKER_OK,
965 StoreRegistration(live_registration2, live_version2));
966 EXPECT_EQ(SERVICE_WORKER_OK,
967 StoreRegistration(live_registration3, live_version3));
969 // Notify storage of installations no longer happening.
970 storage()->NotifyDoneInstallingRegistration(
971 live_registration1, NULL, SERVICE_WORKER_OK);
972 storage()->NotifyDoneInstallingRegistration(
973 live_registration2, NULL, SERVICE_WORKER_OK);
974 storage()->NotifyDoneInstallingRegistration(
975 live_registration3, NULL, SERVICE_WORKER_OK);
977 // Find a registration among installed ones.
978 EXPECT_EQ(SERVICE_WORKER_OK,
979 FindRegistrationForDocument(kDocumentUrl, &found_registration));
980 EXPECT_EQ(live_registration2, found_registration);
983 TEST_F(ServiceWorkerStorageTest, CompareResources) {
984 // Compare two small responses containing the same data.
985 WriteBasicResponse(storage(), 1);
986 WriteBasicResponse(storage(), 2);
987 ServiceWorkerStatusCode status = static_cast<ServiceWorkerStatusCode>(-1);
988 bool are_equal = false;
989 storage()->CompareScriptResources(
991 base::Bind(&OnCompareComplete, &status, &are_equal));
992 base::RunLoop().RunUntilIdle();
993 EXPECT_EQ(SERVICE_WORKER_OK, status);
994 EXPECT_TRUE(are_equal);
996 // Compare two small responses with different data.
997 const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0";
998 const char kHttpBody[] = "Goodbye";
999 std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
1000 WriteStringResponse(storage(), 3, headers, std::string(kHttpBody));
1001 status = static_cast<ServiceWorkerStatusCode>(-1);
1003 storage()->CompareScriptResources(
1005 base::Bind(&OnCompareComplete, &status, &are_equal));
1006 base::RunLoop().RunUntilIdle();
1007 EXPECT_EQ(SERVICE_WORKER_OK, status);
1008 EXPECT_FALSE(are_equal);
1010 // Compare two large responses with the same data.
1011 const int k32K = 32 * 1024;
1012 WriteResponseOfSize(storage(), 4, 'a', k32K);
1013 WriteResponseOfSize(storage(), 5, 'a', k32K);
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_TRUE(are_equal);
1023 // Compare a large and small response.
1024 status = static_cast<ServiceWorkerStatusCode>(-1);
1026 storage()->CompareScriptResources(
1028 base::Bind(&OnCompareComplete, &status, &are_equal));
1029 base::RunLoop().RunUntilIdle();
1030 EXPECT_EQ(SERVICE_WORKER_OK, status);
1031 EXPECT_FALSE(are_equal);
1033 // Compare two large responses with different data.
1034 WriteResponseOfSize(storage(), 6, 'b', k32K);
1035 status = static_cast<ServiceWorkerStatusCode>(-1);
1037 storage()->CompareScriptResources(
1039 base::Bind(&OnCompareComplete, &status, &are_equal));
1040 base::RunLoop().RunUntilIdle();
1041 EXPECT_EQ(SERVICE_WORKER_OK, status);
1042 EXPECT_FALSE(are_equal);
1045 } // namespace content