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. 4 5 #include <string> 6 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" 25 26 using net::IOBuffer; 27 using net::TestCompletionCallback; 28 using net::WrappedIOBuffer; 29 30 namespace content { 31 32 namespace { 33 34 typedef ServiceWorkerDatabase::RegistrationData RegistrationData; 35 typedef ServiceWorkerDatabase::ResourceRecord ResourceRecord; 36 37 void StatusCallback(bool* was_called, 38 ServiceWorkerStatusCode* result, 39 ServiceWorkerStatusCode status) { 40 *was_called = true; 41 *result = status; 42 } 43 44 ServiceWorkerStorage::StatusCallback MakeStatusCallback( 45 bool* was_called, 46 ServiceWorkerStatusCode* result) { 47 return base::Bind(&StatusCallback, was_called, result); 48 } 49 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; 59 } 60 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); 66 } 67 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; 74 } 75 76 ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback( 77 bool* was_called, 78 std::vector<ServiceWorkerRegistrationInfo>* all) { 79 return base::Bind(&GetAllCallback, was_called, all); 80 } 81 82 void OnIOComplete(int* rv_out, int rv) { 83 *rv_out = rv; 84 } 85 86 void OnCompareComplete( 87 ServiceWorkerStatusCode* status_out, bool* are_equal_out, 88 ServiceWorkerStatusCode status, bool are_equal) { 89 *status_out = status; 90 *are_equal_out = are_equal; 91 } 92 93 void WriteResponse( 94 ServiceWorkerStorage* storage, int64 id, 95 const std::string& headers, 96 IOBuffer* body, int length) { 97 scoped_ptr<ServiceWorkerResponseWriter> writer = 98 storage->CreateResponseWriter(id); 99 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()); 107 108 int rv = -1234; 109 writer->WriteInfo(info_buffer.get(), base::Bind(&OnIOComplete, &rv)); 110 base::RunLoop().RunUntilIdle(); 111 EXPECT_LT(0, rv); 112 113 rv = -1234; 114 writer->WriteData(body, length, base::Bind(&OnIOComplete, &rv)); 115 base::RunLoop().RunUntilIdle(); 116 EXPECT_EQ(length, rv); 117 } 118 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()); 125 } 126 127 void WriteBasicResponse(ServiceWorkerStorage* storage, int64 id) { 128 scoped_ptr<ServiceWorkerResponseWriter> writer = 129 storage->CreateResponseWriter(id); 130 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)); 135 } 136 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(); 144 { 145 TestCompletionCallback cb; 146 reader->ReadInfo(info_buffer.get(), cb.callback()); 147 int rv = cb.WaitForResult(); 148 if (expected_positive_result) 149 EXPECT_LT(0, rv); 150 if (rv <= 0) 151 return false; 152 } 153 154 std::string received_body; 155 { 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); 162 if (rv <= 0) 163 return false; 164 received_body.assign(buffer->data(), rv); 165 } 166 167 bool status_match = 168 std::string("HONKYDORY") == 169 info_buffer->http_info->headers->GetStatusText(); 170 bool data_match = kExpectedHttpBody == received_body; 171 172 EXPECT_TRUE(status_match); 173 EXPECT_TRUE(data_match); 174 return status_match && data_match; 175 } 176 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); 184 } 185 186 } // namespace 187 188 class ServiceWorkerStorageTest : public testing::Test { 189 public: 190 ServiceWorkerStorageTest() 191 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) { 192 } 193 194 virtual void SetUp() OVERRIDE { 195 context_.reset( 196 new ServiceWorkerContextCore(GetUserDataDirectory(), 197 base::ThreadTaskRunnerHandle::Get(), 198 base::ThreadTaskRunnerHandle::Get(), 199 base::ThreadTaskRunnerHandle::Get(), 200 NULL, 201 NULL, 202 NULL)); 203 context_ptr_ = context_->AsWeakPtr(); 204 } 205 206 virtual void TearDown() OVERRIDE { 207 context_.reset(); 208 } 209 210 virtual base::FilePath GetUserDataDirectory() { return base::FilePath(); } 211 212 ServiceWorkerStorage* storage() { return context_->storage(); } 213 214 // A static class method for friendliness. 215 static void VerifyPurgeableListStatusCallback( 216 ServiceWorkerDatabase* database, 217 std::set<int64> *purgeable_ids, 218 bool* was_called, 219 ServiceWorkerStatusCode* result, 220 ServiceWorkerStatusCode status) { 221 *was_called = true; 222 *result = status; 223 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 224 database->GetPurgeableResourceIds(purgeable_ids)); 225 } 226 227 protected: 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(), 234 version.get(), 235 MakeStatusCallback(&was_called, &result)); 236 EXPECT_FALSE(was_called); // always async 237 base::RunLoop().RunUntilIdle(); 238 EXPECT_TRUE(was_called); 239 return result; 240 } 241 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); 252 return result; 253 } 254 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); 263 } 264 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); 274 return result; 275 } 276 277 void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration) { 278 storage()->UpdateLastUpdateCheckTime(registration); 279 base::RunLoop().RunUntilIdle(); 280 } 281 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); 291 return result; 292 } 293 294 ServiceWorkerStatusCode FindRegistrationForPattern( 295 const GURL& scope, 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); 304 return result; 305 } 306 307 ServiceWorkerStatusCode FindRegistrationForId( 308 int64 registration_id, 309 const GURL& origin, 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); 318 return result; 319 } 320 321 scoped_ptr<ServiceWorkerContextCore> context_; 322 base::WeakPtr<ServiceWorkerContextCore> context_ptr_; 323 TestBrowserThreadBundle browser_thread_bundle_; 324 }; 325 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); 334 335 scoped_refptr<ServiceWorkerRegistration> found_registration; 336 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()); 341 342 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, 343 FindRegistrationForPattern(kScope, &found_registration)); 344 EXPECT_FALSE(found_registration.get()); 345 346 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, 347 FindRegistrationForId( 348 kRegistrationId, kScope.GetOrigin(), &found_registration)); 349 EXPECT_FALSE(found_registration.get()); 350 351 // Store something. 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)); 363 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; 369 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; 375 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; 384 385 // Drop the live registration, but keep the version live. 386 live_registration = NULL; 387 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; 396 397 // Drop the live version too. 398 live_version = NULL; 399 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()); 411 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()); 417 temp_version = NULL; 418 EXPECT_EQ(SERVICE_WORKER_OK, UpdateToActiveState(found_registration)); 419 found_registration->set_last_update_check(kToday); 420 UpdateLastUpdateCheckTime(found_registration.get()); 421 422 found_registration = NULL; 423 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; 431 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()); 444 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)); 450 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()); 456 457 // Deleting an unstored registration should succeed. 458 EXPECT_EQ(SERVICE_WORKER_OK, 459 DeleteRegistration(kRegistrationId + 1, kScope.GetOrigin())); 460 } 461 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; 468 469 scoped_refptr<ServiceWorkerRegistration> found_registration; 470 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()); 480 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()); 486 487 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, 488 FindRegistrationForDocument(kDocumentUrl, &found_registration)); 489 EXPECT_FALSE(found_registration.get()); 490 491 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, 492 FindRegistrationForPattern(kScope, &found_registration)); 493 EXPECT_FALSE(found_registration.get()); 494 495 std::vector<ServiceWorkerRegistrationInfo> all_registrations; 496 GetAllRegistrations(&all_registrations); 497 EXPECT_TRUE(all_registrations.empty()); 498 499 // Notify storage of it being installed. 500 storage()->NotifyInstallingRegistration(live_registration.get()); 501 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; 508 509 EXPECT_EQ(SERVICE_WORKER_OK, 510 FindRegistrationForDocument(kDocumentUrl, &found_registration)); 511 EXPECT_EQ(live_registration, found_registration); 512 found_registration = NULL; 513 514 EXPECT_EQ(SERVICE_WORKER_OK, 515 FindRegistrationForPattern(kScope, &found_registration)); 516 EXPECT_EQ(live_registration, found_registration); 517 found_registration = NULL; 518 519 GetAllRegistrations(&all_registrations); 520 EXPECT_EQ(1u, all_registrations.size()); 521 all_registrations.clear(); 522 523 // Notify storage of installation no longer happening. 524 storage()->NotifyDoneInstallingRegistration( 525 live_registration.get(), NULL, SERVICE_WORKER_OK); 526 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()); 532 533 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, 534 FindRegistrationForDocument(kDocumentUrl, &found_registration)); 535 EXPECT_FALSE(found_registration.get()); 536 537 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, 538 FindRegistrationForPattern(kScope, &found_registration)); 539 EXPECT_FALSE(found_registration.get()); 540 541 GetAllRegistrations(&all_registrations); 542 EXPECT_TRUE(all_registrations.empty()); 543 } 544 545 class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest { 546 public: 547 virtual void SetUp() OVERRIDE { 548 ServiceWorkerStorageTest::SetUp(); 549 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(); 560 561 // Cons up a new registration+version with two script resources. 562 RegistrationData data; 563 data.registration_id = registration_id_; 564 data.scope = scope_; 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); 573 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()); 582 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)); 588 589 // Storing the registration/version should take the resources ids out 590 // of the uncommitted list. 591 EXPECT_EQ( 592 SERVICE_WORKER_OK, 593 StoreRegistration(registration_, registration_->waiting_version())); 594 verify_ids.clear(); 595 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 596 storage()->database_->GetUncommittedResourceIds(&verify_ids)); 597 EXPECT_TRUE(verify_ids.empty()); 598 } 599 600 protected: 601 GURL scope_; 602 GURL script_; 603 GURL import_; 604 GURL document_url_; 605 int64 registration_id_; 606 int64 version_id_; 607 int64 resource_id1_; 608 int64 resource_id2_; 609 scoped_refptr<ServiceWorkerRegistration> registration_; 610 }; 611 612 class ServiceWorkerResourceStorageDiskTest 613 : public ServiceWorkerResourceStorageTest { 614 public: 615 virtual void SetUp() OVERRIDE { 616 ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir()); 617 ServiceWorkerResourceStorageTest::SetUp(); 618 } 619 620 virtual base::FilePath GetUserDataDirectory() OVERRIDE { 621 return user_data_directory_.path(); 622 } 623 624 protected: 625 base::ScopedTempDir user_data_directory_; 626 }; 627 628 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_NoLiveVersion) { 629 bool was_called = false; 630 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; 631 std::set<int64> verify_ids; 632 633 registration_->SetWaitingVersion(NULL); 634 registration_ = NULL; 635 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 638 // list. 639 storage()->DeleteRegistration( 640 registration_id_, 641 scope_.GetOrigin(), 642 base::Bind(&VerifyPurgeableListStatusCallback, 643 base::Unretained(storage()->database_.get()), 644 &verify_ids, 645 &was_called, 646 &result)); 647 base::RunLoop().RunUntilIdle(); 648 ASSERT_TRUE(was_called); 649 EXPECT_EQ(SERVICE_WORKER_OK, result); 650 EXPECT_EQ(2u, verify_ids.size()); 651 verify_ids.clear(); 652 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 653 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 654 EXPECT_TRUE(verify_ids.empty()); 655 656 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false)); 657 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false)); 658 } 659 660 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_WaitingVersion) { 661 bool was_called = false; 662 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; 663 std::set<int64> verify_ids; 664 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 667 // list. 668 storage()->DeleteRegistration( 669 registration_->id(), 670 scope_.GetOrigin(), 671 base::Bind(&VerifyPurgeableListStatusCallback, 672 base::Unretained(storage()->database_.get()), 673 &verify_ids, 674 &was_called, 675 &result)); 676 base::RunLoop().RunUntilIdle(); 677 ASSERT_TRUE(was_called); 678 EXPECT_EQ(SERVICE_WORKER_OK, result); 679 EXPECT_EQ(2u, verify_ids.size()); 680 verify_ids.clear(); 681 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 682 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 683 EXPECT_EQ(2u, verify_ids.size()); 684 685 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false)); 686 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false)); 687 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()); 693 verify_ids.clear(); 694 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 695 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 696 EXPECT_TRUE(verify_ids.empty()); 697 698 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false)); 699 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false)); 700 } 701 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(), 711 NULL)); 712 registration_->active_version()->AddControllee(host.get()); 713 714 bool was_called = false; 715 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; 716 std::set<int64> verify_ids; 717 718 // Deleting the registration should move the resources to the purgeable list 719 // but keep them available. 720 storage()->DeleteRegistration( 721 registration_->id(), 722 scope_.GetOrigin(), 723 base::Bind(&VerifyPurgeableListStatusCallback, 724 base::Unretained(storage()->database_.get()), 725 &verify_ids, 726 &was_called, 727 &result)); 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()); 733 verify_ids.clear(); 734 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 735 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 736 EXPECT_EQ(2u, verify_ids.size()); 737 738 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true)); 739 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true)); 740 741 // Removing the controllee should cause the resources to be deleted. 742 registration_->active_version()->RemoveControllee(host.get()); 743 base::RunLoop().RunUntilIdle(); 744 verify_ids.clear(); 745 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 746 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 747 EXPECT_TRUE(verify_ids.empty()); 748 749 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false)); 750 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false)); 751 } 752 753 // Android has flaky IO error: http://crbug.com/387045 754 #if defined(OS_ANDROID) 755 #define MAYBE_CleanupOnRestart DISABLED_CleanupOnRestart 756 #else 757 #define MAYBE_CleanupOnRestart CleanupOnRestart 758 #endif 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(), 769 NULL)); 770 registration_->active_version()->AddControllee(host.get()); 771 772 bool was_called = false; 773 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; 774 std::set<int64> verify_ids; 775 776 // Deleting the registration should move the resources to the purgeable list 777 // but keep them available. 778 storage()->DeleteRegistration( 779 registration_->id(), 780 scope_.GetOrigin(), 781 base::Bind(&VerifyPurgeableListStatusCallback, 782 base::Unretained(storage()->database_.get()), 783 &verify_ids, 784 &was_called, 785 &result)); 786 base::RunLoop().RunUntilIdle(); 787 ASSERT_TRUE(was_called); 788 EXPECT_EQ(SERVICE_WORKER_OK, result); 789 EXPECT_EQ(2u, verify_ids.size()); 790 verify_ids.clear(); 791 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 792 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 793 EXPECT_EQ(2u, verify_ids.size()); 794 795 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true)); 796 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true)); 797 798 // Also add an uncommitted resource. 799 int64 kStaleUncommittedResourceId = storage()->NewResourceId(); 800 storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId); 801 base::RunLoop().RunUntilIdle(); 802 verify_ids.clear(); 803 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 804 storage()->database_->GetUncommittedResourceIds(&verify_ids)); 805 EXPECT_EQ(1u, verify_ids.size()); 806 WriteBasicResponse(storage(), kStaleUncommittedResourceId); 807 EXPECT_TRUE( 808 VerifyBasicResponse(storage(), kStaleUncommittedResourceId, true)); 809 810 // Simulate browser shutdown. The purgeable and uncommitted resources are now 811 // stale. 812 context_.reset(); 813 context_.reset( 814 new ServiceWorkerContextCore(GetUserDataDirectory(), 815 base::ThreadTaskRunnerHandle::Get(), 816 base::ThreadTaskRunnerHandle::Get(), 817 base::ThreadTaskRunnerHandle::Get(), 818 NULL, 819 NULL, 820 NULL)); 821 storage()->LazyInitialize(base::Bind(&base::DoNothing)); 822 base::RunLoop().RunUntilIdle(); 823 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(); 829 830 // The stale resources should be purged, but the new resource should persist. 831 verify_ids.clear(); 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()); 836 837 verify_ids.clear(); 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)); 843 EXPECT_FALSE( 844 VerifyBasicResponse(storage(), kStaleUncommittedResourceId, false)); 845 EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId, true)); 846 } 847 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(), 857 NULL)); 858 registration_->active_version()->AddControllee(host.get()); 859 860 bool was_called = false; 861 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; 862 std::set<int64> verify_ids; 863 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()); 869 870 // Writing the registration should move the old version's resources to the 871 // purgeable list but keep them available. 872 storage()->StoreRegistration( 873 registration_.get(), 874 registration_->waiting_version(), 875 base::Bind(&VerifyPurgeableListStatusCallback, 876 base::Unretained(storage()->database_.get()), 877 &verify_ids, 878 &was_called, 879 &result)); 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()); 885 verify_ids.clear(); 886 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 887 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 888 EXPECT_EQ(2u, verify_ids.size()); 889 890 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false)); 891 EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false)); 892 893 // Removing the controllee should cause the old version's resources to be 894 // deleted. 895 registration_->active_version()->RemoveControllee(host.get()); 896 base::RunLoop().RunUntilIdle(); 897 verify_ids.clear(); 898 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, 899 storage()->database_->GetPurgeableResourceIds(&verify_ids)); 900 EXPECT_TRUE(verify_ids.empty()); 901 902 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false)); 903 EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false)); 904 } 905 906 TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) { 907 const GURL kDocumentUrl("http://www.example.com/scope/foo"); 908 scoped_refptr<ServiceWorkerRegistration> found_registration; 909 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()); 923 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()); 937 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()); 951 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()); 956 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; 962 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)); 970 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); 978 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); 983 } 984 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( 992 1, 2, 993 base::Bind(&OnCompareComplete, &status, &are_equal)); 994 base::RunLoop().RunUntilIdle(); 995 EXPECT_EQ(SERVICE_WORKER_OK, status); 996 EXPECT_TRUE(are_equal); 997 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); 1004 are_equal = true; 1005 storage()->CompareScriptResources( 1006 1, 3, 1007 base::Bind(&OnCompareComplete, &status, &are_equal)); 1008 base::RunLoop().RunUntilIdle(); 1009 EXPECT_EQ(SERVICE_WORKER_OK, status); 1010 EXPECT_FALSE(are_equal); 1011 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); 1017 are_equal = false; 1018 storage()->CompareScriptResources( 1019 4, 5, 1020 base::Bind(&OnCompareComplete, &status, &are_equal)); 1021 base::RunLoop().RunUntilIdle(); 1022 EXPECT_EQ(SERVICE_WORKER_OK, status); 1023 EXPECT_TRUE(are_equal); 1024 1025 // Compare a large and small response. 1026 status = static_cast<ServiceWorkerStatusCode>(-1); 1027 are_equal = true; 1028 storage()->CompareScriptResources( 1029 1, 5, 1030 base::Bind(&OnCompareComplete, &status, &are_equal)); 1031 base::RunLoop().RunUntilIdle(); 1032 EXPECT_EQ(SERVICE_WORKER_OK, status); 1033 EXPECT_FALSE(are_equal); 1034 1035 // Compare two large responses with different data. 1036 WriteResponseOfSize(storage(), 6, 'b', k32K); 1037 status = static_cast<ServiceWorkerStatusCode>(-1); 1038 are_equal = true; 1039 storage()->CompareScriptResources( 1040 5, 6, 1041 base::Bind(&OnCompareComplete, &status, &are_equal)); 1042 base::RunLoop().RunUntilIdle(); 1043 EXPECT_EQ(SERVICE_WORKER_OK, status); 1044 EXPECT_FALSE(are_equal); 1045 } 1046 1047 } // namespace content 1048