cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_storage_unittest.cc
blob43ff928136ca161eb2f2ce427ef46ef22951a18e
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.
5 #include <string>
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"
26 using net::IOBuffer;
27 using net::TestCompletionCallback;
28 using net::WrappedIOBuffer;
30 namespace content {
32 namespace {
34 typedef ServiceWorkerDatabase::RegistrationData RegistrationData;
35 typedef ServiceWorkerDatabase::ResourceRecord ResourceRecord;
37 void StatusCallback(bool* was_called,
38 ServiceWorkerStatusCode* result,
39 ServiceWorkerStatusCode status) {
40 *was_called = true;
41 *result = status;
44 ServiceWorkerStorage::StatusCallback MakeStatusCallback(
45 bool* was_called,
46 ServiceWorkerStatusCode* result) {
47 return base::Bind(&StatusCallback, was_called, result);
50 void FindCallback(
51 bool* was_called,
52 ServiceWorkerStatusCode* result,
53 scoped_refptr<ServiceWorkerRegistration>* found,
54 ServiceWorkerStatusCode status,
55 const scoped_refptr<ServiceWorkerRegistration>& registration) {
56 *was_called = true;
57 *result = status;
58 *found = registration;
61 ServiceWorkerStorage::FindRegistrationCallback MakeFindCallback(
62 bool* was_called,
63 ServiceWorkerStatusCode* result,
64 scoped_refptr<ServiceWorkerRegistration>* found) {
65 return base::Bind(&FindCallback, was_called, result, found);
68 void GetAllCallback(
69 bool* was_called,
70 std::vector<ServiceWorkerRegistrationInfo>* all_out,
71 const std::vector<ServiceWorkerRegistrationInfo>& all) {
72 *was_called = true;
73 *all_out = all;
76 ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback(
77 bool* was_called,
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) {
85 *status_out = status;
86 *are_equal_out = are_equal;
89 void WriteResponse(
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();
107 EXPECT_LT(0, rv);
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)
147 EXPECT_LT(0, rv);
148 if (rv <= 0)
149 return false;
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);
160 if (rv <= 0)
161 return false;
162 received_body.assign(buffer->data(), rv);
165 bool status_match =
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);
184 } // namespace
186 class ServiceWorkerStorageTest : public testing::Test {
187 public:
188 ServiceWorkerStorageTest()
189 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {
192 virtual void SetUp() override {
193 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
194 new MockServiceWorkerDatabaseTaskManager(
195 base::ThreadTaskRunnerHandle::Get()));
196 context_.reset(
197 new ServiceWorkerContextCore(GetUserDataDirectory(),
198 base::ThreadTaskRunnerHandle::Get(),
199 database_task_manager.Pass(),
200 base::ThreadTaskRunnerHandle::Get(),
201 NULL,
202 NULL,
203 NULL,
204 NULL));
205 context_ptr_ = context_->AsWeakPtr();
208 virtual void TearDown() override {
209 context_.reset();
212 virtual base::FilePath GetUserDataDirectory() { return base::FilePath(); }
214 ServiceWorkerStorage* storage() { return context_->storage(); }
216 // A static class method for friendliness.
217 static void VerifyPurgeableListStatusCallback(
218 ServiceWorkerDatabase* database,
219 std::set<int64> *purgeable_ids,
220 bool* was_called,
221 ServiceWorkerStatusCode* result,
222 ServiceWorkerStatusCode status) {
223 *was_called = true;
224 *result = status;
225 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
226 database->GetPurgeableResourceIds(purgeable_ids));
229 protected:
230 ServiceWorkerStatusCode StoreRegistration(
231 scoped_refptr<ServiceWorkerRegistration> registration,
232 scoped_refptr<ServiceWorkerVersion> version) {
233 bool was_called = false;
234 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
235 storage()->StoreRegistration(registration.get(),
236 version.get(),
237 MakeStatusCallback(&was_called, &result));
238 EXPECT_FALSE(was_called); // always async
239 base::RunLoop().RunUntilIdle();
240 EXPECT_TRUE(was_called);
241 return result;
244 ServiceWorkerStatusCode DeleteRegistration(
245 int64 registration_id,
246 const GURL& origin) {
247 bool was_called = false;
248 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
249 storage()->DeleteRegistration(
250 registration_id, origin, MakeStatusCallback(&was_called, &result));
251 EXPECT_FALSE(was_called); // always async
252 base::RunLoop().RunUntilIdle();
253 EXPECT_TRUE(was_called);
254 return result;
257 void GetAllRegistrations(
258 std::vector<ServiceWorkerRegistrationInfo>* registrations) {
259 bool was_called = false;
260 storage()->GetAllRegistrations(
261 MakeGetAllCallback(&was_called, registrations));
262 EXPECT_FALSE(was_called); // always async
263 base::RunLoop().RunUntilIdle();
264 EXPECT_TRUE(was_called);
267 ServiceWorkerStatusCode UpdateToActiveState(
268 scoped_refptr<ServiceWorkerRegistration> registration) {
269 bool was_called = false;
270 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
271 storage()->UpdateToActiveState(registration.get(),
272 MakeStatusCallback(&was_called, &result));
273 EXPECT_FALSE(was_called); // always async
274 base::RunLoop().RunUntilIdle();
275 EXPECT_TRUE(was_called);
276 return result;
279 void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration) {
280 storage()->UpdateLastUpdateCheckTime(registration);
281 base::RunLoop().RunUntilIdle();
284 ServiceWorkerStatusCode FindRegistrationForDocument(
285 const GURL& document_url,
286 scoped_refptr<ServiceWorkerRegistration>* registration) {
287 bool was_called = false;
288 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
289 storage()->FindRegistrationForDocument(
290 document_url, MakeFindCallback(&was_called, &result, registration));
291 base::RunLoop().RunUntilIdle();
292 EXPECT_TRUE(was_called);
293 return result;
296 ServiceWorkerStatusCode FindRegistrationForPattern(
297 const GURL& scope,
298 scoped_refptr<ServiceWorkerRegistration>* registration) {
299 bool was_called = false;
300 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
301 storage()->FindRegistrationForPattern(
302 scope, MakeFindCallback(&was_called, &result, registration));
303 EXPECT_FALSE(was_called); // always async
304 base::RunLoop().RunUntilIdle();
305 EXPECT_TRUE(was_called);
306 return result;
309 ServiceWorkerStatusCode FindRegistrationForId(
310 int64 registration_id,
311 const GURL& origin,
312 scoped_refptr<ServiceWorkerRegistration>* registration) {
313 bool was_called = false;
314 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
315 storage()->FindRegistrationForId(
316 registration_id, origin,
317 MakeFindCallback(&was_called, &result, registration));
318 base::RunLoop().RunUntilIdle();
319 EXPECT_TRUE(was_called);
320 return result;
323 scoped_ptr<ServiceWorkerContextCore> context_;
324 base::WeakPtr<ServiceWorkerContextCore> context_ptr_;
325 TestBrowserThreadBundle browser_thread_bundle_;
328 TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
329 const GURL kScope("http://www.test.not/scope/");
330 const GURL kScript("http://www.test.not/script.js");
331 const GURL kDocumentUrl("http://www.test.not/scope/document.html");
332 const int64 kRegistrationId = 0;
333 const int64 kVersionId = 0;
334 const base::Time kToday = base::Time::Now();
335 const base::Time kYesterday = kToday - base::TimeDelta::FromDays(1);
337 scoped_refptr<ServiceWorkerRegistration> found_registration;
339 // We shouldn't find anything without having stored anything.
340 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
341 FindRegistrationForDocument(kDocumentUrl, &found_registration));
342 EXPECT_FALSE(found_registration.get());
344 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
345 FindRegistrationForPattern(kScope, &found_registration));
346 EXPECT_FALSE(found_registration.get());
348 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
349 FindRegistrationForId(
350 kRegistrationId, kScope.GetOrigin(), &found_registration));
351 EXPECT_FALSE(found_registration.get());
353 // Store something.
354 scoped_refptr<ServiceWorkerRegistration> live_registration =
355 new ServiceWorkerRegistration(
356 kScope, kRegistrationId, context_ptr_);
357 scoped_refptr<ServiceWorkerVersion> live_version =
358 new ServiceWorkerVersion(
359 live_registration.get(), kScript, kVersionId, context_ptr_);
360 live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
361 live_registration->SetWaitingVersion(live_version.get());
362 live_registration->set_last_update_check(kYesterday);
363 EXPECT_EQ(SERVICE_WORKER_OK,
364 StoreRegistration(live_registration, live_version));
366 // Now we should find it and get the live ptr back immediately.
367 EXPECT_EQ(SERVICE_WORKER_OK,
368 FindRegistrationForDocument(kDocumentUrl, &found_registration));
369 EXPECT_EQ(live_registration, found_registration);
370 found_registration = NULL;
372 // But FindRegistrationForPattern is always async.
373 EXPECT_EQ(SERVICE_WORKER_OK,
374 FindRegistrationForPattern(kScope, &found_registration));
375 EXPECT_EQ(live_registration, found_registration);
376 found_registration = NULL;
378 // Can be found by id too.
379 EXPECT_EQ(SERVICE_WORKER_OK,
380 FindRegistrationForId(
381 kRegistrationId, kScope.GetOrigin(), &found_registration));
382 ASSERT_TRUE(found_registration.get());
383 EXPECT_EQ(kRegistrationId, found_registration->id());
384 EXPECT_EQ(live_registration, found_registration);
385 found_registration = NULL;
387 // Drop the live registration, but keep the version live.
388 live_registration = NULL;
390 // Now FindRegistrationForDocument should be async.
391 EXPECT_EQ(SERVICE_WORKER_OK,
392 FindRegistrationForDocument(kDocumentUrl, &found_registration));
393 ASSERT_TRUE(found_registration.get());
394 EXPECT_EQ(kRegistrationId, found_registration->id());
395 EXPECT_TRUE(found_registration->HasOneRef());
396 EXPECT_EQ(live_version.get(), found_registration->waiting_version());
397 found_registration = NULL;
399 // Drop the live version too.
400 live_version = NULL;
402 // And FindRegistrationForPattern is always async.
403 EXPECT_EQ(SERVICE_WORKER_OK,
404 FindRegistrationForPattern(kScope, &found_registration));
405 ASSERT_TRUE(found_registration.get());
406 EXPECT_EQ(kRegistrationId, found_registration->id());
407 EXPECT_TRUE(found_registration->HasOneRef());
408 EXPECT_FALSE(found_registration->active_version());
409 ASSERT_TRUE(found_registration->waiting_version());
410 EXPECT_EQ(kYesterday, found_registration->last_update_check());
411 EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
412 found_registration->waiting_version()->status());
414 // Update to active and update the last check time.
415 scoped_refptr<ServiceWorkerVersion> temp_version =
416 found_registration->waiting_version();
417 temp_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
418 found_registration->SetActiveVersion(temp_version.get());
419 temp_version = NULL;
420 EXPECT_EQ(SERVICE_WORKER_OK, UpdateToActiveState(found_registration));
421 found_registration->set_last_update_check(kToday);
422 UpdateLastUpdateCheckTime(found_registration.get());
424 found_registration = NULL;
426 // Trying to update a unstored registration to active should fail.
427 scoped_refptr<ServiceWorkerRegistration> unstored_registration =
428 new ServiceWorkerRegistration(
429 kScope, kRegistrationId + 1, context_ptr_);
430 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
431 UpdateToActiveState(unstored_registration));
432 unstored_registration = NULL;
434 // The Find methods should return a registration with an active version
435 // and the expected update time.
436 EXPECT_EQ(SERVICE_WORKER_OK,
437 FindRegistrationForDocument(kDocumentUrl, &found_registration));
438 ASSERT_TRUE(found_registration.get());
439 EXPECT_EQ(kRegistrationId, found_registration->id());
440 EXPECT_TRUE(found_registration->HasOneRef());
441 EXPECT_FALSE(found_registration->waiting_version());
442 ASSERT_TRUE(found_registration->active_version());
443 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
444 found_registration->active_version()->status());
445 EXPECT_EQ(kToday, found_registration->last_update_check());
447 // Delete from storage but with a instance still live.
448 EXPECT_TRUE(context_->GetLiveVersion(kRegistrationId));
449 EXPECT_EQ(SERVICE_WORKER_OK,
450 DeleteRegistration(kRegistrationId, kScope.GetOrigin()));
451 EXPECT_TRUE(context_->GetLiveVersion(kRegistrationId));
453 // Should no longer be found.
454 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
455 FindRegistrationForId(
456 kRegistrationId, kScope.GetOrigin(), &found_registration));
457 EXPECT_FALSE(found_registration.get());
459 // Deleting an unstored registration should succeed.
460 EXPECT_EQ(SERVICE_WORKER_OK,
461 DeleteRegistration(kRegistrationId + 1, kScope.GetOrigin()));
464 TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
465 const GURL kScope("http://www.test.not/scope/");
466 const GURL kScript("http://www.test.not/script.js");
467 const GURL kDocumentUrl("http://www.test.not/scope/document.html");
468 const int64 kRegistrationId = 0;
469 const int64 kVersionId = 0;
471 scoped_refptr<ServiceWorkerRegistration> found_registration;
473 // Create an unstored registration.
474 scoped_refptr<ServiceWorkerRegistration> live_registration =
475 new ServiceWorkerRegistration(
476 kScope, kRegistrationId, context_ptr_);
477 scoped_refptr<ServiceWorkerVersion> live_version =
478 new ServiceWorkerVersion(
479 live_registration.get(), kScript, kVersionId, context_ptr_);
480 live_version->SetStatus(ServiceWorkerVersion::INSTALLING);
481 live_registration->SetWaitingVersion(live_version.get());
483 // Should not be findable, including by GetAllRegistrations.
484 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
485 FindRegistrationForId(
486 kRegistrationId, kScope.GetOrigin(), &found_registration));
487 EXPECT_FALSE(found_registration.get());
489 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
490 FindRegistrationForDocument(kDocumentUrl, &found_registration));
491 EXPECT_FALSE(found_registration.get());
493 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
494 FindRegistrationForPattern(kScope, &found_registration));
495 EXPECT_FALSE(found_registration.get());
497 std::vector<ServiceWorkerRegistrationInfo> all_registrations;
498 GetAllRegistrations(&all_registrations);
499 EXPECT_TRUE(all_registrations.empty());
501 // Notify storage of it being installed.
502 storage()->NotifyInstallingRegistration(live_registration.get());
504 // Now should be findable.
505 EXPECT_EQ(SERVICE_WORKER_OK,
506 FindRegistrationForId(
507 kRegistrationId, kScope.GetOrigin(), &found_registration));
508 EXPECT_EQ(live_registration, found_registration);
509 found_registration = NULL;
511 EXPECT_EQ(SERVICE_WORKER_OK,
512 FindRegistrationForDocument(kDocumentUrl, &found_registration));
513 EXPECT_EQ(live_registration, found_registration);
514 found_registration = NULL;
516 EXPECT_EQ(SERVICE_WORKER_OK,
517 FindRegistrationForPattern(kScope, &found_registration));
518 EXPECT_EQ(live_registration, found_registration);
519 found_registration = NULL;
521 GetAllRegistrations(&all_registrations);
522 EXPECT_EQ(1u, all_registrations.size());
523 all_registrations.clear();
525 // Notify storage of installation no longer happening.
526 storage()->NotifyDoneInstallingRegistration(
527 live_registration.get(), NULL, SERVICE_WORKER_OK);
529 // Once again, should not be findable.
530 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
531 FindRegistrationForId(
532 kRegistrationId, kScope.GetOrigin(), &found_registration));
533 EXPECT_FALSE(found_registration.get());
535 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
536 FindRegistrationForDocument(kDocumentUrl, &found_registration));
537 EXPECT_FALSE(found_registration.get());
539 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
540 FindRegistrationForPattern(kScope, &found_registration));
541 EXPECT_FALSE(found_registration.get());
543 GetAllRegistrations(&all_registrations);
544 EXPECT_TRUE(all_registrations.empty());
547 class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
548 public:
549 virtual void SetUp() override {
550 ServiceWorkerStorageTest::SetUp();
552 storage()->LazyInitialize(base::Bind(&base::DoNothing));
553 base::RunLoop().RunUntilIdle();
554 scope_ = GURL("http://www.test.not/scope/");
555 script_ = GURL("http://www.test.not/script.js");
556 import_ = GURL("http://www.test.not/import.js");
557 document_url_ = GURL("http://www.test.not/scope/document.html");
558 registration_id_ = storage()->NewRegistrationId();
559 version_id_ = storage()->NewVersionId();
560 resource_id1_ = storage()->NewResourceId();
561 resource_id2_ = storage()->NewResourceId();
562 resource_id1_size_ = 239193;
563 resource_id2_size_ = 59923;
565 // Cons up a new registration+version with two script resources.
566 RegistrationData data;
567 data.registration_id = registration_id_;
568 data.scope = scope_;
569 data.script = script_;
570 data.version_id = version_id_;
571 data.is_active = false;
572 std::vector<ResourceRecord> resources;
573 resources.push_back(
574 ResourceRecord(resource_id1_, script_, resource_id1_size_));
575 resources.push_back(
576 ResourceRecord(resource_id2_, import_, resource_id2_size_));
577 registration_ = storage()->GetOrCreateRegistration(data, resources);
578 registration_->waiting_version()->SetStatus(ServiceWorkerVersion::NEW);
580 // Add the resources ids to the uncommitted list.
581 storage()->StoreUncommittedResponseId(resource_id1_);
582 storage()->StoreUncommittedResponseId(resource_id2_);
583 base::RunLoop().RunUntilIdle();
584 std::set<int64> verify_ids;
585 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
586 storage()->database_->GetUncommittedResourceIds(&verify_ids));
587 EXPECT_EQ(2u, verify_ids.size());
589 // And dump something in the disk cache for them.
590 WriteBasicResponse(storage(), resource_id1_);
591 WriteBasicResponse(storage(), resource_id2_);
592 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
593 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
595 // Storing the registration/version should take the resources ids out
596 // of the uncommitted list.
597 EXPECT_EQ(
598 SERVICE_WORKER_OK,
599 StoreRegistration(registration_, registration_->waiting_version()));
600 verify_ids.clear();
601 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
602 storage()->database_->GetUncommittedResourceIds(&verify_ids));
603 EXPECT_TRUE(verify_ids.empty());
606 protected:
607 GURL scope_;
608 GURL script_;
609 GURL import_;
610 GURL document_url_;
611 int64 registration_id_;
612 int64 version_id_;
613 int64 resource_id1_;
614 uint64 resource_id1_size_;
615 int64 resource_id2_;
616 uint64 resource_id2_size_;
617 scoped_refptr<ServiceWorkerRegistration> registration_;
620 class ServiceWorkerResourceStorageDiskTest
621 : public ServiceWorkerResourceStorageTest {
622 public:
623 virtual void SetUp() override {
624 ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir());
625 ServiceWorkerResourceStorageTest::SetUp();
628 base::FilePath GetUserDataDirectory() override {
629 return user_data_directory_.path();
632 protected:
633 base::ScopedTempDir user_data_directory_;
636 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_NoLiveVersion) {
637 bool was_called = false;
638 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
639 std::set<int64> verify_ids;
641 registration_->SetWaitingVersion(NULL);
642 registration_ = NULL;
644 // Deleting the registration should result in the resources being added to the
645 // purgeable list and then doomed in the disk cache and removed from that
646 // list.
647 storage()->DeleteRegistration(
648 registration_id_,
649 scope_.GetOrigin(),
650 base::Bind(&VerifyPurgeableListStatusCallback,
651 base::Unretained(storage()->database_.get()),
652 &verify_ids,
653 &was_called,
654 &result));
655 base::RunLoop().RunUntilIdle();
656 ASSERT_TRUE(was_called);
657 EXPECT_EQ(SERVICE_WORKER_OK, result);
658 EXPECT_EQ(2u, verify_ids.size());
659 verify_ids.clear();
660 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
661 storage()->database_->GetPurgeableResourceIds(&verify_ids));
662 EXPECT_TRUE(verify_ids.empty());
664 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
665 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
668 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_WaitingVersion) {
669 bool was_called = false;
670 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
671 std::set<int64> verify_ids;
673 // Deleting the registration should result in the resources being added to the
674 // purgeable list and then doomed in the disk cache and removed from that
675 // list.
676 storage()->DeleteRegistration(
677 registration_->id(),
678 scope_.GetOrigin(),
679 base::Bind(&VerifyPurgeableListStatusCallback,
680 base::Unretained(storage()->database_.get()),
681 &verify_ids,
682 &was_called,
683 &result));
684 base::RunLoop().RunUntilIdle();
685 ASSERT_TRUE(was_called);
686 EXPECT_EQ(SERVICE_WORKER_OK, result);
687 EXPECT_EQ(2u, verify_ids.size());
688 verify_ids.clear();
689 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
690 storage()->database_->GetPurgeableResourceIds(&verify_ids));
691 EXPECT_EQ(2u, verify_ids.size());
693 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
694 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
696 // Doom the version, now it happens.
697 registration_->waiting_version()->Doom();
698 base::RunLoop().RunUntilIdle();
699 EXPECT_EQ(SERVICE_WORKER_OK, result);
700 EXPECT_EQ(2u, verify_ids.size());
701 verify_ids.clear();
702 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
703 storage()->database_->GetPurgeableResourceIds(&verify_ids));
704 EXPECT_TRUE(verify_ids.empty());
706 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
707 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
710 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) {
711 // Promote the worker to active and add a controllee.
712 registration_->SetActiveVersion(registration_->waiting_version());
713 storage()->UpdateToActiveState(
714 registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
715 scoped_ptr<ServiceWorkerProviderHost> host(
716 new ServiceWorkerProviderHost(33 /* dummy render process id */,
717 1 /* dummy provider_id */,
718 context_->AsWeakPtr(),
719 NULL));
720 registration_->active_version()->AddControllee(host.get());
722 bool was_called = false;
723 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
724 std::set<int64> verify_ids;
726 // Deleting the registration should move the resources to the purgeable list
727 // but keep them available.
728 storage()->DeleteRegistration(
729 registration_->id(),
730 scope_.GetOrigin(),
731 base::Bind(&VerifyPurgeableListStatusCallback,
732 base::Unretained(storage()->database_.get()),
733 &verify_ids,
734 &was_called,
735 &result));
736 registration_->active_version()->Doom();
737 base::RunLoop().RunUntilIdle();
738 ASSERT_TRUE(was_called);
739 EXPECT_EQ(SERVICE_WORKER_OK, result);
740 EXPECT_EQ(2u, verify_ids.size());
741 verify_ids.clear();
742 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
743 storage()->database_->GetPurgeableResourceIds(&verify_ids));
744 EXPECT_EQ(2u, verify_ids.size());
746 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
747 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
749 // Removing the controllee should cause the resources to be deleted.
750 registration_->active_version()->RemoveControllee(host.get());
751 base::RunLoop().RunUntilIdle();
752 verify_ids.clear();
753 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
754 storage()->database_->GetPurgeableResourceIds(&verify_ids));
755 EXPECT_TRUE(verify_ids.empty());
757 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
758 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
761 TEST_F(ServiceWorkerResourceStorageDiskTest, CleanupOnRestart) {
762 // Promote the worker to active and add a controllee.
763 registration_->SetActiveVersion(registration_->waiting_version());
764 registration_->SetWaitingVersion(NULL);
765 storage()->UpdateToActiveState(
766 registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
767 scoped_ptr<ServiceWorkerProviderHost> host(
768 new ServiceWorkerProviderHost(33 /* dummy render process id */,
769 1 /* dummy provider_id */,
770 context_->AsWeakPtr(),
771 NULL));
772 registration_->active_version()->AddControllee(host.get());
774 bool was_called = false;
775 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
776 std::set<int64> verify_ids;
778 // Deleting the registration should move the resources to the purgeable list
779 // but keep them available.
780 storage()->DeleteRegistration(
781 registration_->id(),
782 scope_.GetOrigin(),
783 base::Bind(&VerifyPurgeableListStatusCallback,
784 base::Unretained(storage()->database_.get()),
785 &verify_ids,
786 &was_called,
787 &result));
788 base::RunLoop().RunUntilIdle();
789 ASSERT_TRUE(was_called);
790 EXPECT_EQ(SERVICE_WORKER_OK, result);
791 EXPECT_EQ(2u, verify_ids.size());
792 verify_ids.clear();
793 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
794 storage()->database_->GetPurgeableResourceIds(&verify_ids));
795 EXPECT_EQ(2u, verify_ids.size());
797 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
798 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
800 // Also add an uncommitted resource.
801 int64 kStaleUncommittedResourceId = storage()->NewResourceId();
802 storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId);
803 base::RunLoop().RunUntilIdle();
804 verify_ids.clear();
805 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
806 storage()->database_->GetUncommittedResourceIds(&verify_ids));
807 EXPECT_EQ(1u, verify_ids.size());
808 WriteBasicResponse(storage(), kStaleUncommittedResourceId);
809 EXPECT_TRUE(
810 VerifyBasicResponse(storage(), kStaleUncommittedResourceId, true));
812 // Simulate browser shutdown. The purgeable and uncommitted resources are now
813 // stale.
814 context_.reset();
815 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
816 new MockServiceWorkerDatabaseTaskManager(
817 base::ThreadTaskRunnerHandle::Get()));
818 context_.reset(
819 new ServiceWorkerContextCore(GetUserDataDirectory(),
820 base::ThreadTaskRunnerHandle::Get(),
821 database_task_manager.Pass(),
822 base::ThreadTaskRunnerHandle::Get(),
823 NULL,
824 NULL,
825 NULL,
826 NULL));
827 storage()->LazyInitialize(base::Bind(&base::DoNothing));
828 base::RunLoop().RunUntilIdle();
830 // Store a new uncommitted resource. This triggers stale resource cleanup.
831 int64 kNewResourceId = storage()->NewResourceId();
832 WriteBasicResponse(storage(), kNewResourceId);
833 storage()->StoreUncommittedResponseId(kNewResourceId);
834 base::RunLoop().RunUntilIdle();
836 // The stale resources should be purged, but the new resource should persist.
837 verify_ids.clear();
838 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
839 storage()->database_->GetUncommittedResourceIds(&verify_ids));
840 ASSERT_EQ(1u, verify_ids.size());
841 EXPECT_EQ(kNewResourceId, *verify_ids.begin());
843 // Purging resources needs interactions with SimpleCache's worker thread,
844 // so single RunUntilIdle() call may not be sufficient.
845 while (storage()->is_purge_pending_)
846 base::RunLoop().RunUntilIdle();
848 verify_ids.clear();
849 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
850 storage()->database_->GetPurgeableResourceIds(&verify_ids));
851 EXPECT_TRUE(verify_ids.empty());
852 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
853 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
854 EXPECT_FALSE(
855 VerifyBasicResponse(storage(), kStaleUncommittedResourceId, false));
856 EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId, true));
859 TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
860 // Promote the worker to active worker and add a controllee.
861 registration_->SetActiveVersion(registration_->waiting_version());
862 storage()->UpdateToActiveState(
863 registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
864 scoped_ptr<ServiceWorkerProviderHost> host(
865 new ServiceWorkerProviderHost(33 /* dummy render process id */,
866 1 /* dummy provider_id */,
867 context_->AsWeakPtr(),
868 NULL));
869 registration_->active_version()->AddControllee(host.get());
871 bool was_called = false;
872 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
873 std::set<int64> verify_ids;
875 // Make an updated registration.
876 scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
877 registration_.get(), script_, storage()->NewVersionId(), context_ptr_);
878 live_version->SetStatus(ServiceWorkerVersion::NEW);
879 registration_->SetWaitingVersion(live_version.get());
881 // Writing the registration should move the old version's resources to the
882 // purgeable list but keep them available.
883 storage()->StoreRegistration(
884 registration_.get(),
885 registration_->waiting_version(),
886 base::Bind(&VerifyPurgeableListStatusCallback,
887 base::Unretained(storage()->database_.get()),
888 &verify_ids,
889 &was_called,
890 &result));
891 registration_->active_version()->Doom();
892 base::RunLoop().RunUntilIdle();
893 ASSERT_TRUE(was_called);
894 EXPECT_EQ(SERVICE_WORKER_OK, result);
895 EXPECT_EQ(2u, verify_ids.size());
896 verify_ids.clear();
897 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
898 storage()->database_->GetPurgeableResourceIds(&verify_ids));
899 EXPECT_EQ(2u, verify_ids.size());
901 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
902 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
904 // Removing the controllee should cause the old version's resources to be
905 // deleted.
906 registration_->active_version()->RemoveControllee(host.get());
907 base::RunLoop().RunUntilIdle();
908 verify_ids.clear();
909 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
910 storage()->database_->GetPurgeableResourceIds(&verify_ids));
911 EXPECT_TRUE(verify_ids.empty());
913 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
914 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
917 TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
918 const GURL kDocumentUrl("http://www.example.com/scope/foo");
919 scoped_refptr<ServiceWorkerRegistration> found_registration;
921 // Registration for "/scope/".
922 const GURL kScope1("http://www.example.com/scope/");
923 const GURL kScript1("http://www.example.com/script1.js");
924 const int64 kRegistrationId1 = 1;
925 const int64 kVersionId1 = 1;
926 scoped_refptr<ServiceWorkerRegistration> live_registration1 =
927 new ServiceWorkerRegistration(
928 kScope1, kRegistrationId1, context_ptr_);
929 scoped_refptr<ServiceWorkerVersion> live_version1 =
930 new ServiceWorkerVersion(
931 live_registration1.get(), kScript1, kVersionId1, context_ptr_);
932 live_version1->SetStatus(ServiceWorkerVersion::INSTALLED);
933 live_registration1->SetWaitingVersion(live_version1.get());
935 // Registration for "/scope/foo".
936 const GURL kScope2("http://www.example.com/scope/foo");
937 const GURL kScript2("http://www.example.com/script2.js");
938 const int64 kRegistrationId2 = 2;
939 const int64 kVersionId2 = 2;
940 scoped_refptr<ServiceWorkerRegistration> live_registration2 =
941 new ServiceWorkerRegistration(
942 kScope2, kRegistrationId2, context_ptr_);
943 scoped_refptr<ServiceWorkerVersion> live_version2 =
944 new ServiceWorkerVersion(
945 live_registration2.get(), kScript2, kVersionId2, context_ptr_);
946 live_version2->SetStatus(ServiceWorkerVersion::INSTALLED);
947 live_registration2->SetWaitingVersion(live_version2.get());
949 // Registration for "/scope/foobar".
950 const GURL kScope3("http://www.example.com/scope/foobar");
951 const GURL kScript3("http://www.example.com/script3.js");
952 const int64 kRegistrationId3 = 3;
953 const int64 kVersionId3 = 3;
954 scoped_refptr<ServiceWorkerRegistration> live_registration3 =
955 new ServiceWorkerRegistration(
956 kScope3, kRegistrationId3, context_ptr_);
957 scoped_refptr<ServiceWorkerVersion> live_version3 =
958 new ServiceWorkerVersion(
959 live_registration3.get(), kScript3, kVersionId3, context_ptr_);
960 live_version3->SetStatus(ServiceWorkerVersion::INSTALLED);
961 live_registration3->SetWaitingVersion(live_version3.get());
963 // Notify storage of they being installed.
964 storage()->NotifyInstallingRegistration(live_registration1.get());
965 storage()->NotifyInstallingRegistration(live_registration2.get());
966 storage()->NotifyInstallingRegistration(live_registration3.get());
968 // Find a registration among installing ones.
969 EXPECT_EQ(SERVICE_WORKER_OK,
970 FindRegistrationForDocument(kDocumentUrl, &found_registration));
971 EXPECT_EQ(live_registration2, found_registration);
972 found_registration = NULL;
974 // Store registrations.
975 EXPECT_EQ(SERVICE_WORKER_OK,
976 StoreRegistration(live_registration1, live_version1));
977 EXPECT_EQ(SERVICE_WORKER_OK,
978 StoreRegistration(live_registration2, live_version2));
979 EXPECT_EQ(SERVICE_WORKER_OK,
980 StoreRegistration(live_registration3, live_version3));
982 // Notify storage of installations no longer happening.
983 storage()->NotifyDoneInstallingRegistration(
984 live_registration1.get(), NULL, SERVICE_WORKER_OK);
985 storage()->NotifyDoneInstallingRegistration(
986 live_registration2.get(), NULL, SERVICE_WORKER_OK);
987 storage()->NotifyDoneInstallingRegistration(
988 live_registration3.get(), NULL, SERVICE_WORKER_OK);
990 // Find a registration among installed ones.
991 EXPECT_EQ(SERVICE_WORKER_OK,
992 FindRegistrationForDocument(kDocumentUrl, &found_registration));
993 EXPECT_EQ(live_registration2, found_registration);
996 TEST_F(ServiceWorkerStorageTest, CompareResources) {
997 // Compare two small responses containing the same data.
998 WriteBasicResponse(storage(), 1);
999 WriteBasicResponse(storage(), 2);
1000 ServiceWorkerStatusCode status = static_cast<ServiceWorkerStatusCode>(-1);
1001 bool are_equal = false;
1002 storage()->CompareScriptResources(
1003 1, 2,
1004 base::Bind(&OnCompareComplete, &status, &are_equal));
1005 base::RunLoop().RunUntilIdle();
1006 EXPECT_EQ(SERVICE_WORKER_OK, status);
1007 EXPECT_TRUE(are_equal);
1009 // Compare two small responses with different data.
1010 const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0";
1011 const char kHttpBody[] = "Goodbye";
1012 std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
1013 WriteStringResponse(storage(), 3, headers, std::string(kHttpBody));
1014 status = static_cast<ServiceWorkerStatusCode>(-1);
1015 are_equal = true;
1016 storage()->CompareScriptResources(
1017 1, 3,
1018 base::Bind(&OnCompareComplete, &status, &are_equal));
1019 base::RunLoop().RunUntilIdle();
1020 EXPECT_EQ(SERVICE_WORKER_OK, status);
1021 EXPECT_FALSE(are_equal);
1023 // Compare two large responses with the same data.
1024 const int k32K = 32 * 1024;
1025 WriteResponseOfSize(storage(), 4, 'a', k32K);
1026 WriteResponseOfSize(storage(), 5, 'a', k32K);
1027 status = static_cast<ServiceWorkerStatusCode>(-1);
1028 are_equal = false;
1029 storage()->CompareScriptResources(
1030 4, 5,
1031 base::Bind(&OnCompareComplete, &status, &are_equal));
1032 base::RunLoop().RunUntilIdle();
1033 EXPECT_EQ(SERVICE_WORKER_OK, status);
1034 EXPECT_TRUE(are_equal);
1036 // Compare a large and small response.
1037 status = static_cast<ServiceWorkerStatusCode>(-1);
1038 are_equal = true;
1039 storage()->CompareScriptResources(
1040 1, 5,
1041 base::Bind(&OnCompareComplete, &status, &are_equal));
1042 base::RunLoop().RunUntilIdle();
1043 EXPECT_EQ(SERVICE_WORKER_OK, status);
1044 EXPECT_FALSE(are_equal);
1046 // Compare two large responses with different data.
1047 WriteResponseOfSize(storage(), 6, 'b', k32K);
1048 status = static_cast<ServiceWorkerStatusCode>(-1);
1049 are_equal = true;
1050 storage()->CompareScriptResources(
1051 5, 6,
1052 base::Bind(&OnCompareComplete, &status, &are_equal));
1053 base::RunLoop().RunUntilIdle();
1054 EXPECT_EQ(SERVICE_WORKER_OK, status);
1055 EXPECT_FALSE(are_equal);
1058 } // namespace content