1 // Copyright 2014 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 "base/files/scoped_temp_dir.h" 6 #include "base/logging.h" 7 #include "base/run_loop.h" 8 #include "content/browser/browser_thread_impl.h" 9 #include "content/browser/service_worker/embedded_worker_registry.h" 10 #include "content/browser/service_worker/embedded_worker_test_helper.h" 11 #include "content/browser/service_worker/service_worker_context_core.h" 12 #include "content/browser/service_worker/service_worker_disk_cache.h" 13 #include "content/browser/service_worker/service_worker_job_coordinator.h" 14 #include "content/browser/service_worker/service_worker_registration.h" 15 #include "content/browser/service_worker/service_worker_registration_status.h" 16 #include "content/browser/service_worker/service_worker_test_utils.h" 17 #include "content/public/test/test_browser_thread_bundle.h" 18 #include "ipc/ipc_test_sink.h" 19 #include "net/base/io_buffer.h" 20 #include "net/base/net_errors.h" 21 #include "net/base/test_completion_callback.h" 22 #include "net/http/http_response_headers.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 using net::IOBuffer; 26 using net::TestCompletionCallback; 27 using net::WrappedIOBuffer; 28 29 // Unit tests for testing all job registration tasks. 30 namespace content { 31 32 namespace { 33 34 int kMockRenderProcessId = 88; 35 36 void SaveRegistrationCallback( 37 ServiceWorkerStatusCode expected_status, 38 bool* called, 39 scoped_refptr<ServiceWorkerRegistration>* registration_out, 40 ServiceWorkerStatusCode status, 41 ServiceWorkerRegistration* registration, 42 ServiceWorkerVersion* version) { 43 ASSERT_TRUE(!version || version->registration_id() == registration->id()) 44 << version << " " << registration; 45 EXPECT_EQ(expected_status, status); 46 *called = true; 47 *registration_out = registration; 48 } 49 50 void SaveFoundRegistrationCallback( 51 ServiceWorkerStatusCode expected_status, 52 bool* called, 53 scoped_refptr<ServiceWorkerRegistration>* registration, 54 ServiceWorkerStatusCode status, 55 const scoped_refptr<ServiceWorkerRegistration>& result) { 56 EXPECT_EQ(expected_status, status); 57 *called = true; 58 *registration = result; 59 } 60 61 // Creates a callback which both keeps track of if it's been called, 62 // as well as the resulting registration. Whent the callback is fired, 63 // it ensures that the resulting status matches the expectation. 64 // 'called' is useful for making sure a sychronous callback is or 65 // isn't called. 66 ServiceWorkerRegisterJob::RegistrationCallback SaveRegistration( 67 ServiceWorkerStatusCode expected_status, 68 bool* called, 69 scoped_refptr<ServiceWorkerRegistration>* registration) { 70 *called = false; 71 return base::Bind( 72 &SaveRegistrationCallback, expected_status, called, registration); 73 } 74 75 ServiceWorkerStorage::FindRegistrationCallback SaveFoundRegistration( 76 ServiceWorkerStatusCode expected_status, 77 bool* called, 78 scoped_refptr<ServiceWorkerRegistration>* registration) { 79 *called = false; 80 return base::Bind(&SaveFoundRegistrationCallback, 81 expected_status, 82 called, 83 registration); 84 } 85 86 void SaveUnregistrationCallback(ServiceWorkerStatusCode expected_status, 87 bool* called, 88 ServiceWorkerStatusCode status) { 89 EXPECT_EQ(expected_status, status); 90 *called = true; 91 } 92 93 ServiceWorkerUnregisterJob::UnregistrationCallback SaveUnregistration( 94 ServiceWorkerStatusCode expected_status, 95 bool* called) { 96 *called = false; 97 return base::Bind(&SaveUnregistrationCallback, expected_status, called); 98 } 99 100 } // namespace 101 102 class ServiceWorkerJobTest : public testing::Test { 103 public: 104 ServiceWorkerJobTest() 105 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), 106 render_process_id_(kMockRenderProcessId) {} 107 108 virtual void SetUp() OVERRIDE { 109 helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_)); 110 } 111 112 virtual void TearDown() OVERRIDE { 113 helper_.reset(); 114 } 115 116 ServiceWorkerContextCore* context() const { return helper_->context(); } 117 118 ServiceWorkerJobCoordinator* job_coordinator() const { 119 return context()->job_coordinator(); 120 } 121 ServiceWorkerStorage* storage() const { return context()->storage(); } 122 123 protected: 124 TestBrowserThreadBundle browser_thread_bundle_; 125 scoped_ptr<EmbeddedWorkerTestHelper> helper_; 126 int render_process_id_; 127 }; 128 129 TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) { 130 scoped_refptr<ServiceWorkerRegistration> original_registration; 131 bool called; 132 job_coordinator()->Register( 133 GURL("http://www.example.com/"), 134 GURL("http://www.example.com/service_worker.js"), 135 NULL, 136 SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration)); 137 EXPECT_FALSE(called); 138 base::RunLoop().RunUntilIdle(); 139 EXPECT_TRUE(called); 140 141 scoped_refptr<ServiceWorkerRegistration> registration1; 142 storage()->FindRegistrationForDocument( 143 GURL("http://www.example.com/"), 144 SaveFoundRegistration(SERVICE_WORKER_OK, &called, ®istration1)); 145 scoped_refptr<ServiceWorkerRegistration> registration2; 146 storage()->FindRegistrationForDocument( 147 GURL("http://www.example.com/"), 148 SaveFoundRegistration(SERVICE_WORKER_OK, &called, ®istration2)); 149 base::RunLoop().RunUntilIdle(); 150 EXPECT_TRUE(called); 151 ASSERT_TRUE(registration1.get()); 152 ASSERT_EQ(registration1, original_registration); 153 ASSERT_EQ(registration1, registration2); 154 } 155 156 TEST_F(ServiceWorkerJobTest, SameMatchSameRegistration) { 157 bool called; 158 scoped_refptr<ServiceWorkerRegistration> original_registration; 159 job_coordinator()->Register( 160 GURL("http://www.example.com/"), 161 GURL("http://www.example.com/service_worker.js"), 162 NULL, 163 SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration)); 164 EXPECT_FALSE(called); 165 base::RunLoop().RunUntilIdle(); 166 EXPECT_TRUE(called); 167 ASSERT_NE(static_cast<ServiceWorkerRegistration*>(NULL), 168 original_registration.get()); 169 170 scoped_refptr<ServiceWorkerRegistration> registration1; 171 storage()->FindRegistrationForDocument( 172 GURL("http://www.example.com/one"), 173 SaveFoundRegistration(SERVICE_WORKER_OK, &called, ®istration1)); 174 base::RunLoop().RunUntilIdle(); 175 EXPECT_TRUE(called); 176 177 scoped_refptr<ServiceWorkerRegistration> registration2; 178 storage()->FindRegistrationForDocument( 179 GURL("http://www.example.com/two"), 180 SaveFoundRegistration(SERVICE_WORKER_OK, &called, ®istration2)); 181 base::RunLoop().RunUntilIdle(); 182 EXPECT_TRUE(called); 183 ASSERT_EQ(registration1, original_registration); 184 ASSERT_EQ(registration1, registration2); 185 } 186 187 TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) { 188 bool called1; 189 scoped_refptr<ServiceWorkerRegistration> original_registration1; 190 job_coordinator()->Register( 191 GURL("http://www.example.com/one/"), 192 GURL("http://www.example.com/service_worker.js"), 193 NULL, 194 SaveRegistration(SERVICE_WORKER_OK, &called1, &original_registration1)); 195 196 bool called2; 197 scoped_refptr<ServiceWorkerRegistration> original_registration2; 198 job_coordinator()->Register( 199 GURL("http://www.example.com/two/"), 200 GURL("http://www.example.com/service_worker.js"), 201 NULL, 202 SaveRegistration(SERVICE_WORKER_OK, &called2, &original_registration2)); 203 204 EXPECT_FALSE(called1); 205 EXPECT_FALSE(called2); 206 base::RunLoop().RunUntilIdle(); 207 EXPECT_TRUE(called2); 208 EXPECT_TRUE(called1); 209 210 scoped_refptr<ServiceWorkerRegistration> registration1; 211 storage()->FindRegistrationForDocument( 212 GURL("http://www.example.com/one/"), 213 SaveFoundRegistration(SERVICE_WORKER_OK, &called1, ®istration1)); 214 scoped_refptr<ServiceWorkerRegistration> registration2; 215 storage()->FindRegistrationForDocument( 216 GURL("http://www.example.com/two/"), 217 SaveFoundRegistration(SERVICE_WORKER_OK, &called2, ®istration2)); 218 219 base::RunLoop().RunUntilIdle(); 220 EXPECT_TRUE(called2); 221 EXPECT_TRUE(called1); 222 ASSERT_NE(registration1, registration2); 223 } 224 225 // Make sure basic registration is working. 226 TEST_F(ServiceWorkerJobTest, Register) { 227 bool called = false; 228 scoped_refptr<ServiceWorkerRegistration> registration; 229 job_coordinator()->Register( 230 GURL("http://www.example.com/"), 231 GURL("http://www.example.com/service_worker.js"), 232 NULL, 233 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 234 235 ASSERT_FALSE(called); 236 base::RunLoop().RunUntilIdle(); 237 ASSERT_TRUE(called); 238 239 ASSERT_NE(scoped_refptr<ServiceWorkerRegistration>(NULL), registration); 240 } 241 242 // Make sure registrations are cleaned up when they are unregistered. 243 TEST_F(ServiceWorkerJobTest, Unregister) { 244 GURL pattern("http://www.example.com/"); 245 246 bool called; 247 scoped_refptr<ServiceWorkerRegistration> registration; 248 job_coordinator()->Register( 249 pattern, 250 GURL("http://www.example.com/service_worker.js"), 251 NULL, 252 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 253 254 ASSERT_FALSE(called); 255 base::RunLoop().RunUntilIdle(); 256 ASSERT_TRUE(called); 257 258 job_coordinator()->Unregister(pattern, 259 SaveUnregistration(SERVICE_WORKER_OK, &called)); 260 261 ASSERT_FALSE(called); 262 base::RunLoop().RunUntilIdle(); 263 ASSERT_TRUE(called); 264 265 ASSERT_TRUE(registration->HasOneRef()); 266 267 storage()->FindRegistrationForPattern( 268 pattern, 269 SaveFoundRegistration(SERVICE_WORKER_ERROR_NOT_FOUND, 270 &called, ®istration)); 271 272 ASSERT_FALSE(called); 273 base::RunLoop().RunUntilIdle(); 274 ASSERT_TRUE(called); 275 276 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration); 277 } 278 279 TEST_F(ServiceWorkerJobTest, Unregister_NothingRegistered) { 280 GURL pattern("http://www.example.com/"); 281 282 bool called; 283 job_coordinator()->Unregister( 284 pattern, 285 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND, &called)); 286 287 ASSERT_FALSE(called); 288 base::RunLoop().RunUntilIdle(); 289 ASSERT_TRUE(called); 290 } 291 292 // Make sure registering a new script creates a new version and shares an 293 // existing registration. 294 TEST_F(ServiceWorkerJobTest, RegisterNewScript) { 295 GURL pattern("http://www.example.com/"); 296 297 bool called; 298 scoped_refptr<ServiceWorkerRegistration> old_registration; 299 job_coordinator()->Register( 300 pattern, 301 GURL("http://www.example.com/service_worker.js"), 302 NULL, 303 SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration)); 304 305 ASSERT_FALSE(called); 306 base::RunLoop().RunUntilIdle(); 307 ASSERT_TRUE(called); 308 309 scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern; 310 storage()->FindRegistrationForPattern( 311 pattern, 312 SaveFoundRegistration( 313 SERVICE_WORKER_OK, &called, &old_registration_by_pattern)); 314 315 ASSERT_FALSE(called); 316 base::RunLoop().RunUntilIdle(); 317 ASSERT_TRUE(called); 318 319 ASSERT_EQ(old_registration, old_registration_by_pattern); 320 old_registration_by_pattern = NULL; 321 322 scoped_refptr<ServiceWorkerRegistration> new_registration; 323 job_coordinator()->Register( 324 pattern, 325 GURL("http://www.example.com/service_worker_new.js"), 326 NULL, 327 SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration)); 328 329 ASSERT_FALSE(called); 330 base::RunLoop().RunUntilIdle(); 331 ASSERT_TRUE(called); 332 333 ASSERT_EQ(old_registration, new_registration); 334 335 scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern; 336 storage()->FindRegistrationForPattern( 337 pattern, 338 SaveFoundRegistration( 339 SERVICE_WORKER_OK, &called, &new_registration)); 340 341 ASSERT_FALSE(called); 342 base::RunLoop().RunUntilIdle(); 343 ASSERT_TRUE(called); 344 345 ASSERT_NE(new_registration_by_pattern, old_registration); 346 } 347 348 // Make sure that when registering a duplicate pattern+script_url 349 // combination, that the same registration is used. 350 TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) { 351 GURL pattern("http://www.example.com/"); 352 GURL script_url("http://www.example.com/service_worker.js"); 353 354 bool called; 355 scoped_refptr<ServiceWorkerRegistration> old_registration; 356 job_coordinator()->Register( 357 pattern, 358 script_url, 359 NULL, 360 SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration)); 361 362 ASSERT_FALSE(called); 363 base::RunLoop().RunUntilIdle(); 364 ASSERT_TRUE(called); 365 366 scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern; 367 storage()->FindRegistrationForPattern( 368 pattern, 369 SaveFoundRegistration( 370 SERVICE_WORKER_OK, &called, &old_registration_by_pattern)); 371 ASSERT_FALSE(called); 372 base::RunLoop().RunUntilIdle(); 373 ASSERT_TRUE(called); 374 375 ASSERT_TRUE(old_registration_by_pattern.get()); 376 377 scoped_refptr<ServiceWorkerRegistration> new_registration; 378 job_coordinator()->Register( 379 pattern, 380 script_url, 381 NULL, 382 SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration)); 383 384 ASSERT_FALSE(called); 385 base::RunLoop().RunUntilIdle(); 386 ASSERT_TRUE(called); 387 388 ASSERT_EQ(old_registration, new_registration); 389 390 ASSERT_FALSE(old_registration->HasOneRef()); 391 392 scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern; 393 storage()->FindRegistrationForPattern( 394 pattern, 395 SaveFoundRegistration( 396 SERVICE_WORKER_OK, &called, &new_registration_by_pattern)); 397 398 ASSERT_FALSE(called); 399 base::RunLoop().RunUntilIdle(); 400 ASSERT_TRUE(called); 401 402 ASSERT_EQ(new_registration, old_registration); 403 } 404 405 class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper { 406 public: 407 explicit FailToStartWorkerTestHelper(int mock_render_process_id) 408 : EmbeddedWorkerTestHelper(mock_render_process_id) {} 409 410 virtual void OnStartWorker(int embedded_worker_id, 411 int64 service_worker_version_id, 412 const GURL& scope, 413 const GURL& script_url, 414 bool pause_after_download) OVERRIDE { 415 EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); 416 registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); 417 } 418 }; 419 420 TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) { 421 helper_.reset(new FailToStartWorkerTestHelper(render_process_id_)); 422 423 bool called = false; 424 scoped_refptr<ServiceWorkerRegistration> registration; 425 job_coordinator()->Register( 426 GURL("http://www.example.com/"), 427 GURL("http://www.example.com/service_worker.js"), 428 NULL, 429 SaveRegistration( 430 SERVICE_WORKER_ERROR_START_WORKER_FAILED, &called, ®istration)); 431 432 ASSERT_FALSE(called); 433 base::RunLoop().RunUntilIdle(); 434 435 ASSERT_TRUE(called); 436 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration); 437 } 438 439 // Register and then unregister the pattern, in parallel. Job coordinator should 440 // process jobs until the last job. 441 TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) { 442 GURL pattern("http://www.example.com/"); 443 GURL script_url("http://www.example.com/service_worker.js"); 444 445 bool registration_called = false; 446 scoped_refptr<ServiceWorkerRegistration> registration; 447 job_coordinator()->Register( 448 pattern, 449 script_url, 450 NULL, 451 SaveRegistration(SERVICE_WORKER_OK, ®istration_called, ®istration)); 452 453 bool unregistration_called = false; 454 job_coordinator()->Unregister( 455 pattern, 456 SaveUnregistration(SERVICE_WORKER_OK, &unregistration_called)); 457 458 ASSERT_FALSE(registration_called); 459 ASSERT_FALSE(unregistration_called); 460 base::RunLoop().RunUntilIdle(); 461 ASSERT_TRUE(registration_called); 462 ASSERT_TRUE(unregistration_called); 463 464 bool find_called = false; 465 storage()->FindRegistrationForPattern( 466 pattern, 467 SaveFoundRegistration( 468 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, ®istration)); 469 470 base::RunLoop().RunUntilIdle(); 471 472 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration); 473 } 474 475 // Register conflicting scripts for the same pattern. The most recent 476 // registration should win, and the old registration should have been 477 // shutdown. 478 TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) { 479 GURL pattern("http://www.example.com/"); 480 481 GURL script_url1("http://www.example.com/service_worker1.js"); 482 bool registration1_called = false; 483 scoped_refptr<ServiceWorkerRegistration> registration1; 484 job_coordinator()->Register( 485 pattern, 486 script_url1, 487 NULL, 488 SaveRegistration( 489 SERVICE_WORKER_OK, ®istration1_called, ®istration1)); 490 491 GURL script_url2("http://www.example.com/service_worker2.js"); 492 bool registration2_called = false; 493 scoped_refptr<ServiceWorkerRegistration> registration2; 494 job_coordinator()->Register( 495 pattern, 496 script_url2, 497 NULL, 498 SaveRegistration( 499 SERVICE_WORKER_OK, ®istration2_called, ®istration2)); 500 501 ASSERT_FALSE(registration1_called); 502 ASSERT_FALSE(registration2_called); 503 base::RunLoop().RunUntilIdle(); 504 ASSERT_TRUE(registration1_called); 505 ASSERT_TRUE(registration2_called); 506 507 scoped_refptr<ServiceWorkerRegistration> registration; 508 bool find_called = false; 509 storage()->FindRegistrationForPattern( 510 pattern, 511 SaveFoundRegistration( 512 SERVICE_WORKER_OK, &find_called, ®istration)); 513 514 base::RunLoop().RunUntilIdle(); 515 516 ASSERT_EQ(registration2, registration); 517 } 518 519 // Register the exact same pattern + script. Requests should be 520 // coalesced such that both callers get the exact same registration 521 // object. 522 TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) { 523 GURL pattern("http://www.example.com/"); 524 525 GURL script_url("http://www.example.com/service_worker1.js"); 526 bool registration1_called = false; 527 scoped_refptr<ServiceWorkerRegistration> registration1; 528 job_coordinator()->Register( 529 pattern, 530 script_url, 531 NULL, 532 SaveRegistration( 533 SERVICE_WORKER_OK, ®istration1_called, ®istration1)); 534 535 bool registration2_called = false; 536 scoped_refptr<ServiceWorkerRegistration> registration2; 537 job_coordinator()->Register( 538 pattern, 539 script_url, 540 NULL, 541 SaveRegistration( 542 SERVICE_WORKER_OK, ®istration2_called, ®istration2)); 543 544 ASSERT_FALSE(registration1_called); 545 ASSERT_FALSE(registration2_called); 546 base::RunLoop().RunUntilIdle(); 547 ASSERT_TRUE(registration1_called); 548 ASSERT_TRUE(registration2_called); 549 550 ASSERT_EQ(registration1, registration2); 551 552 scoped_refptr<ServiceWorkerRegistration> registration; 553 bool find_called = false; 554 storage()->FindRegistrationForPattern( 555 pattern, 556 SaveFoundRegistration( 557 SERVICE_WORKER_OK, &find_called, ®istration)); 558 559 base::RunLoop().RunUntilIdle(); 560 ASSERT_EQ(registration, registration1); 561 } 562 563 // Call simulataneous unregister calls. 564 TEST_F(ServiceWorkerJobTest, ParallelUnreg) { 565 GURL pattern("http://www.example.com/"); 566 567 GURL script_url("http://www.example.com/service_worker.js"); 568 bool unregistration1_called = false; 569 job_coordinator()->Unregister( 570 pattern, 571 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND, 572 &unregistration1_called)); 573 574 bool unregistration2_called = false; 575 job_coordinator()->Unregister( 576 pattern, 577 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND, 578 &unregistration2_called)); 579 580 ASSERT_FALSE(unregistration1_called); 581 ASSERT_FALSE(unregistration2_called); 582 base::RunLoop().RunUntilIdle(); 583 ASSERT_TRUE(unregistration1_called); 584 ASSERT_TRUE(unregistration2_called); 585 586 // There isn't really a way to test that they are being coalesced, 587 // but we can make sure they can exist simultaneously without 588 // crashing. 589 scoped_refptr<ServiceWorkerRegistration> registration; 590 bool find_called = false; 591 storage()->FindRegistrationForPattern( 592 pattern, 593 SaveFoundRegistration( 594 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, ®istration)); 595 596 base::RunLoop().RunUntilIdle(); 597 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration); 598 } 599 600 TEST_F(ServiceWorkerJobTest, AbortAll_Register) { 601 GURL pattern1("http://www1.example.com/"); 602 GURL pattern2("http://www2.example.com/"); 603 GURL script_url1("http://www1.example.com/service_worker.js"); 604 GURL script_url2("http://www2.example.com/service_worker.js"); 605 606 bool registration_called1 = false; 607 scoped_refptr<ServiceWorkerRegistration> registration1; 608 job_coordinator()->Register( 609 pattern1, 610 script_url1, 611 NULL, 612 SaveRegistration(SERVICE_WORKER_ERROR_ABORT, 613 ®istration_called1, ®istration1)); 614 615 bool registration_called2 = false; 616 scoped_refptr<ServiceWorkerRegistration> registration2; 617 job_coordinator()->Register( 618 pattern2, 619 script_url2, 620 NULL, 621 SaveRegistration(SERVICE_WORKER_ERROR_ABORT, 622 ®istration_called2, ®istration2)); 623 624 ASSERT_FALSE(registration_called1); 625 ASSERT_FALSE(registration_called2); 626 job_coordinator()->AbortAll(); 627 628 base::RunLoop().RunUntilIdle(); 629 ASSERT_TRUE(registration_called1); 630 ASSERT_TRUE(registration_called2); 631 632 bool find_called1 = false; 633 storage()->FindRegistrationForPattern( 634 pattern1, 635 SaveFoundRegistration( 636 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called1, ®istration1)); 637 638 bool find_called2 = false; 639 storage()->FindRegistrationForPattern( 640 pattern2, 641 SaveFoundRegistration( 642 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called2, ®istration2)); 643 644 base::RunLoop().RunUntilIdle(); 645 ASSERT_TRUE(find_called1); 646 ASSERT_TRUE(find_called2); 647 EXPECT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration1); 648 EXPECT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration2); 649 } 650 651 TEST_F(ServiceWorkerJobTest, AbortAll_Unregister) { 652 GURL pattern1("http://www1.example.com/"); 653 GURL pattern2("http://www2.example.com/"); 654 655 bool unregistration_called1 = false; 656 scoped_refptr<ServiceWorkerRegistration> registration1; 657 job_coordinator()->Unregister( 658 pattern1, 659 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT, 660 &unregistration_called1)); 661 662 bool unregistration_called2 = false; 663 job_coordinator()->Unregister( 664 pattern2, 665 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT, 666 &unregistration_called2)); 667 668 ASSERT_FALSE(unregistration_called1); 669 ASSERT_FALSE(unregistration_called2); 670 job_coordinator()->AbortAll(); 671 672 base::RunLoop().RunUntilIdle(); 673 ASSERT_TRUE(unregistration_called1); 674 ASSERT_TRUE(unregistration_called2); 675 } 676 677 TEST_F(ServiceWorkerJobTest, AbortAll_RegUnreg) { 678 GURL pattern("http://www.example.com/"); 679 GURL script_url("http://www.example.com/service_worker.js"); 680 681 bool registration_called = false; 682 scoped_refptr<ServiceWorkerRegistration> registration; 683 job_coordinator()->Register( 684 pattern, 685 script_url, 686 NULL, 687 SaveRegistration(SERVICE_WORKER_ERROR_ABORT, 688 ®istration_called, ®istration)); 689 690 bool unregistration_called = false; 691 job_coordinator()->Unregister( 692 pattern, 693 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT, 694 &unregistration_called)); 695 696 ASSERT_FALSE(registration_called); 697 ASSERT_FALSE(unregistration_called); 698 job_coordinator()->AbortAll(); 699 700 base::RunLoop().RunUntilIdle(); 701 ASSERT_TRUE(registration_called); 702 ASSERT_TRUE(unregistration_called); 703 704 bool find_called = false; 705 storage()->FindRegistrationForPattern( 706 pattern, 707 SaveFoundRegistration( 708 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, ®istration)); 709 710 base::RunLoop().RunUntilIdle(); 711 ASSERT_TRUE(find_called); 712 EXPECT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration); 713 } 714 715 // Tests that the waiting worker enters the 'redundant' state upon 716 // unregistration. 717 TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) { 718 scoped_refptr<ServiceWorkerRegistration> registration; 719 bool called = false; 720 GURL script_url("http://www.example.com/service_worker.js"); 721 job_coordinator()->Register( 722 GURL("http://www.example.com/"), 723 script_url, 724 NULL, 725 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 726 base::RunLoop().RunUntilIdle(); 727 ASSERT_TRUE(called); 728 ASSERT_TRUE(registration.get()); 729 730 // Manually create the waiting worker since there is no way to become a 731 // waiting worker until Update is implemented. 732 scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion( 733 registration.get(), script_url, 1L, helper_->context()->AsWeakPtr()); 734 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 735 version->StartWorker(CreateReceiverOnCurrentThread(&status)); 736 base::RunLoop().RunUntilIdle(); 737 ASSERT_EQ(SERVICE_WORKER_OK, status); 738 739 version->SetStatus(ServiceWorkerVersion::INSTALLED); 740 registration->SetWaitingVersion(version.get()); 741 EXPECT_EQ(ServiceWorkerVersion::RUNNING, 742 version->running_status()); 743 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version->status()); 744 745 called = false; 746 job_coordinator()->Unregister(GURL("http://www.example.com/"), 747 SaveUnregistration(SERVICE_WORKER_OK, &called)); 748 base::RunLoop().RunUntilIdle(); 749 ASSERT_TRUE(called); 750 751 // The version should be stopped since there is no controllee after 752 // unregistration. 753 EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status()); 754 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status()); 755 } 756 757 // Tests that the active worker enters the 'redundant' state upon 758 // unregistration. 759 TEST_F(ServiceWorkerJobTest, UnregisterActiveSetsRedundant) { 760 scoped_refptr<ServiceWorkerRegistration> registration; 761 bool called = false; 762 job_coordinator()->Register( 763 GURL("http://www.example.com/"), 764 GURL("http://www.example.com/service_worker.js"), 765 NULL, 766 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 767 base::RunLoop().RunUntilIdle(); 768 ASSERT_TRUE(called); 769 ASSERT_TRUE(registration.get()); 770 771 scoped_refptr<ServiceWorkerVersion> version = registration->active_version(); 772 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status()); 773 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status()); 774 775 called = false; 776 job_coordinator()->Unregister(GURL("http://www.example.com/"), 777 SaveUnregistration(SERVICE_WORKER_OK, &called)); 778 base::RunLoop().RunUntilIdle(); 779 ASSERT_TRUE(called); 780 781 // The version should be stopped since there is no controllee after 782 // unregistration. 783 EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status()); 784 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status()); 785 } 786 787 // Tests that the active worker enters the 'redundant' state upon 788 // unregistration. 789 TEST_F(ServiceWorkerJobTest, 790 UnregisterActiveSetsRedundant_WaitForNoControllee) { 791 scoped_refptr<ServiceWorkerRegistration> registration; 792 bool called = false; 793 job_coordinator()->Register( 794 GURL("http://www.example.com/"), 795 GURL("http://www.example.com/service_worker.js"), 796 NULL, 797 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 798 base::RunLoop().RunUntilIdle(); 799 ASSERT_TRUE(called); 800 ASSERT_TRUE(registration.get()); 801 802 scoped_ptr<ServiceWorkerProviderHost> host( 803 new ServiceWorkerProviderHost(33 /* dummy render process id */, 804 1 /* dummy provider_id */, 805 context()->AsWeakPtr(), 806 NULL)); 807 registration->active_version()->AddControllee(host.get()); 808 809 scoped_refptr<ServiceWorkerVersion> version = registration->active_version(); 810 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status()); 811 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status()); 812 813 called = false; 814 job_coordinator()->Unregister(GURL("http://www.example.com/"), 815 SaveUnregistration(SERVICE_WORKER_OK, &called)); 816 base::RunLoop().RunUntilIdle(); 817 ASSERT_TRUE(called); 818 819 // The version should be running since there is still a controllee. 820 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status()); 821 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status()); 822 823 registration->active_version()->RemoveControllee(host.get()); 824 base::RunLoop().RunUntilIdle(); 825 826 // The version should be stopped since there is no controllee. 827 EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status()); 828 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status()); 829 } 830 831 namespace { // Helpers for the update job tests. 832 833 const GURL kNoChangeOrigin("http://nochange/"); 834 const GURL kNewVersionOrigin("http://newversion/"); 835 const std::string kScope("scope/"); 836 const std::string kScript("script.js"); 837 838 void RunNestedUntilIdle() { 839 base::MessageLoop::ScopedNestableTaskAllower allow( 840 base::MessageLoop::current()); 841 base::MessageLoop::current()->RunUntilIdle(); 842 } 843 844 void OnIOComplete(int* rv_out, int rv) { 845 *rv_out = rv; 846 } 847 848 void WriteResponse( 849 ServiceWorkerStorage* storage, int64 id, 850 const std::string& headers, 851 IOBuffer* body, int length) { 852 scoped_ptr<ServiceWorkerResponseWriter> writer = 853 storage->CreateResponseWriter(id); 854 855 scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo); 856 info->request_time = base::Time::Now(); 857 info->response_time = base::Time::Now(); 858 info->was_cached = false; 859 info->headers = new net::HttpResponseHeaders(headers); 860 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer = 861 new HttpResponseInfoIOBuffer(info.release()); 862 863 int rv = -1234; 864 writer->WriteInfo(info_buffer.get(), base::Bind(&OnIOComplete, &rv)); 865 RunNestedUntilIdle(); 866 EXPECT_LT(0, rv); 867 868 rv = -1234; 869 writer->WriteData(body, length, 870 base::Bind(&OnIOComplete, &rv)); 871 RunNestedUntilIdle(); 872 EXPECT_EQ(length, rv); 873 } 874 875 void WriteStringResponse( 876 ServiceWorkerStorage* storage, int64 id, 877 const std::string& body) { 878 scoped_refptr<IOBuffer> body_buffer(new WrappedIOBuffer(body.data())); 879 const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0"; 880 std::string headers(kHttpHeaders, arraysize(kHttpHeaders)); 881 WriteResponse(storage, id, headers, body_buffer.get(), body.length()); 882 } 883 884 class UpdateJobTestHelper 885 : public EmbeddedWorkerTestHelper, 886 public ServiceWorkerRegistration::Listener, 887 public ServiceWorkerVersion::Listener { 888 public: 889 struct AttributeChangeLogEntry { 890 int64 registration_id; 891 ChangedVersionAttributesMask mask; 892 ServiceWorkerRegistrationInfo info; 893 }; 894 895 struct StateChangeLogEntry { 896 int64 version_id; 897 ServiceWorkerVersion::Status status; 898 }; 899 900 UpdateJobTestHelper(int mock_render_process_id) 901 : EmbeddedWorkerTestHelper(mock_render_process_id), 902 update_found_(false) {} 903 virtual ~UpdateJobTestHelper() { 904 if (registration_.get()) 905 registration_->RemoveListener(this); 906 } 907 908 ServiceWorkerStorage* storage() { return context()->storage(); } 909 ServiceWorkerJobCoordinator* job_coordinator() { 910 return context()->job_coordinator(); 911 } 912 913 scoped_refptr<ServiceWorkerRegistration> SetupInitialRegistration( 914 const GURL& test_origin) { 915 scoped_refptr<ServiceWorkerRegistration> registration; 916 bool called = false; 917 job_coordinator()->Register( 918 test_origin.Resolve(kScope), 919 test_origin.Resolve(kScript), 920 NULL, 921 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 922 base::RunLoop().RunUntilIdle(); 923 EXPECT_TRUE(called); 924 EXPECT_TRUE(registration.get()); 925 EXPECT_TRUE(registration->active_version()); 926 EXPECT_FALSE(registration->installing_version()); 927 EXPECT_FALSE(registration->waiting_version()); 928 registration_ = registration; 929 return registration; 930 } 931 932 // EmbeddedWorkerTestHelper overrides 933 virtual void OnStartWorker(int embedded_worker_id, 934 int64 version_id, 935 const GURL& scope, 936 const GURL& script, 937 bool pause_after_download) OVERRIDE { 938 const std::string kMockScriptBody = "mock_script"; 939 ServiceWorkerVersion* version = context()->GetLiveVersion(version_id); 940 ASSERT_TRUE(version); 941 version->AddListener(this); 942 943 if (!pause_after_download) { 944 // Spoof caching the script for the initial version. 945 int64 resource_id = storage()->NewResourceId(); 946 version->script_cache_map()->NotifyStartedCaching(script, resource_id); 947 WriteStringResponse(storage(), resource_id, kMockScriptBody); 948 version->script_cache_map()->NotifyFinishedCaching( 949 script, net::URLRequestStatus()); 950 } else { 951 // Spoof caching the script for the new version. 952 int64 resource_id = storage()->NewResourceId(); 953 version->script_cache_map()->NotifyStartedCaching(script, resource_id); 954 if (script.GetOrigin() == kNoChangeOrigin) 955 WriteStringResponse(storage(), resource_id, kMockScriptBody); 956 else 957 WriteStringResponse(storage(), resource_id, "mock_different_script"); 958 version->script_cache_map()->NotifyFinishedCaching( 959 script, net::URLRequestStatus()); 960 } 961 EmbeddedWorkerTestHelper::OnStartWorker( 962 embedded_worker_id, version_id, scope, script, pause_after_download); 963 } 964 965 // ServiceWorkerRegistration::Listener overrides 966 virtual void OnVersionAttributesChanged( 967 ServiceWorkerRegistration* registration, 968 ChangedVersionAttributesMask changed_mask, 969 const ServiceWorkerRegistrationInfo& info) OVERRIDE { 970 AttributeChangeLogEntry entry; 971 entry.registration_id = registration->id(); 972 entry.mask = changed_mask; 973 entry.info = info; 974 attribute_change_log_.push_back(entry); 975 } 976 977 virtual void OnRegistrationFailed( 978 ServiceWorkerRegistration* registration) OVERRIDE { 979 NOTREACHED(); 980 } 981 982 virtual void OnRegistrationFinishedUninstalling( 983 ServiceWorkerRegistration* registration) OVERRIDE { 984 NOTREACHED(); 985 } 986 987 virtual void OnUpdateFound( 988 ServiceWorkerRegistration* registration) OVERRIDE { 989 ASSERT_FALSE(update_found_); 990 update_found_ = true; 991 } 992 993 // ServiceWorkerVersion::Listener overrides 994 virtual void OnVersionStateChanged(ServiceWorkerVersion* version) OVERRIDE { 995 StateChangeLogEntry entry; 996 entry.version_id = version->version_id(); 997 entry.status = version->status(); 998 state_change_log_.push_back(entry); 999 } 1000 1001 scoped_refptr<ServiceWorkerRegistration> registration_; 1002 1003 std::vector<AttributeChangeLogEntry> attribute_change_log_; 1004 std::vector<StateChangeLogEntry> state_change_log_; 1005 bool update_found_; 1006 }; 1007 1008 } // namespace 1009 1010 TEST_F(ServiceWorkerJobTest, Update_NoChange) { 1011 UpdateJobTestHelper* update_helper = 1012 new UpdateJobTestHelper(render_process_id_); 1013 helper_.reset(update_helper); 1014 scoped_refptr<ServiceWorkerRegistration> registration = 1015 update_helper->SetupInitialRegistration(kNoChangeOrigin); 1016 ASSERT_TRUE(registration.get()); 1017 ASSERT_EQ(4u, update_helper->state_change_log_.size()); 1018 EXPECT_EQ(ServiceWorkerVersion::INSTALLING, 1019 update_helper->state_change_log_[0].status); 1020 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, 1021 update_helper->state_change_log_[1].status); 1022 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, 1023 update_helper->state_change_log_[2].status); 1024 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, 1025 update_helper->state_change_log_[3].status); 1026 update_helper->state_change_log_.clear(); 1027 1028 // Run the update job. 1029 registration->AddListener(update_helper); 1030 scoped_refptr<ServiceWorkerVersion> first_version = 1031 registration->active_version(); 1032 first_version->StartUpdate(); 1033 base::RunLoop().RunUntilIdle(); 1034 1035 // Verify results. 1036 ASSERT_TRUE(registration->active_version()); 1037 EXPECT_EQ(first_version.get(), registration->active_version()); 1038 EXPECT_FALSE(registration->installing_version()); 1039 EXPECT_FALSE(registration->waiting_version()); 1040 EXPECT_TRUE(update_helper->attribute_change_log_.empty()); 1041 ASSERT_EQ(1u, update_helper->state_change_log_.size()); 1042 EXPECT_NE(registration->active_version()->version_id(), 1043 update_helper->state_change_log_[0].version_id); 1044 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, 1045 update_helper->state_change_log_[0].status); 1046 EXPECT_FALSE(update_helper->update_found_); 1047 } 1048 1049 TEST_F(ServiceWorkerJobTest, Update_NewVersion) { 1050 UpdateJobTestHelper* update_helper = 1051 new UpdateJobTestHelper(render_process_id_); 1052 helper_.reset(update_helper); 1053 scoped_refptr<ServiceWorkerRegistration> registration = 1054 update_helper->SetupInitialRegistration(kNewVersionOrigin); 1055 ASSERT_TRUE(registration.get()); 1056 update_helper->state_change_log_.clear(); 1057 1058 // Run the update job. 1059 registration->AddListener(update_helper); 1060 scoped_refptr<ServiceWorkerVersion> first_version = 1061 registration->active_version(); 1062 first_version->StartUpdate(); 1063 base::RunLoop().RunUntilIdle(); 1064 1065 // Verify results. 1066 ASSERT_TRUE(registration->active_version()); 1067 EXPECT_NE(first_version.get(), registration->active_version()); 1068 EXPECT_FALSE(registration->installing_version()); 1069 EXPECT_FALSE(registration->waiting_version()); 1070 ASSERT_EQ(3u, update_helper->attribute_change_log_.size()); 1071 1072 UpdateJobTestHelper::AttributeChangeLogEntry entry; 1073 entry = update_helper->attribute_change_log_[0]; 1074 EXPECT_TRUE(entry.mask.installing_changed()); 1075 EXPECT_FALSE(entry.mask.waiting_changed()); 1076 EXPECT_FALSE(entry.mask.active_changed()); 1077 EXPECT_FALSE(entry.info.installing_version.is_null); 1078 EXPECT_TRUE(entry.info.waiting_version.is_null); 1079 EXPECT_FALSE(entry.info.active_version.is_null); 1080 1081 entry = update_helper->attribute_change_log_[1]; 1082 EXPECT_TRUE(entry.mask.installing_changed()); 1083 EXPECT_TRUE(entry.mask.waiting_changed()); 1084 EXPECT_FALSE(entry.mask.active_changed()); 1085 EXPECT_TRUE(entry.info.installing_version.is_null); 1086 EXPECT_FALSE(entry.info.waiting_version.is_null); 1087 EXPECT_FALSE(entry.info.active_version.is_null); 1088 1089 entry = update_helper->attribute_change_log_[2]; 1090 EXPECT_FALSE(entry.mask.installing_changed()); 1091 EXPECT_TRUE(entry.mask.waiting_changed()); 1092 EXPECT_TRUE(entry.mask.active_changed()); 1093 EXPECT_TRUE(entry.info.installing_version.is_null); 1094 EXPECT_TRUE(entry.info.waiting_version.is_null); 1095 EXPECT_FALSE(entry.info.active_version.is_null); 1096 1097 // expected version state transitions: 1098 // new.installing, new.installed, 1099 // old.redundant, 1100 // new.activating, new.activated 1101 ASSERT_EQ(5u, update_helper->state_change_log_.size()); 1102 1103 EXPECT_EQ(registration->active_version()->version_id(), 1104 update_helper->state_change_log_[0].version_id); 1105 EXPECT_EQ(ServiceWorkerVersion::INSTALLING, 1106 update_helper->state_change_log_[0].status); 1107 1108 EXPECT_EQ(registration->active_version()->version_id(), 1109 update_helper->state_change_log_[1].version_id); 1110 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, 1111 update_helper->state_change_log_[1].status); 1112 1113 EXPECT_EQ(first_version->version_id(), 1114 update_helper->state_change_log_[2].version_id); 1115 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, 1116 update_helper->state_change_log_[2].status); 1117 1118 EXPECT_EQ(registration->active_version()->version_id(), 1119 update_helper->state_change_log_[3].version_id); 1120 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, 1121 update_helper->state_change_log_[3].status); 1122 1123 EXPECT_EQ(registration->active_version()->version_id(), 1124 update_helper->state_change_log_[4].version_id); 1125 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, 1126 update_helper->state_change_log_[4].status); 1127 1128 EXPECT_TRUE(update_helper->update_found_); 1129 } 1130 1131 TEST_F(ServiceWorkerJobTest, Update_NewestVersionChanged) { 1132 bool called; 1133 scoped_refptr<ServiceWorkerRegistration> registration; 1134 job_coordinator()->Register( 1135 GURL("http://www.example.com/one/"), 1136 GURL("http://www.example.com/service_worker.js"), 1137 NULL, 1138 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 1139 1140 EXPECT_FALSE(called); 1141 base::RunLoop().RunUntilIdle(); 1142 EXPECT_TRUE(called); 1143 ServiceWorkerVersion* active_version = registration->active_version(); 1144 1145 // Queue an Update, it should abort when it starts and sees the new version. 1146 job_coordinator()->Update(registration.get()); 1147 1148 // Add a waiting version with new script. 1149 scoped_refptr<ServiceWorkerVersion> version = 1150 new ServiceWorkerVersion(registration.get(), 1151 GURL("http://www.example.com/new_worker.js"), 1152 2L /* dummy version id */, 1153 helper_->context()->AsWeakPtr()); 1154 registration->SetWaitingVersion(version.get()); 1155 1156 base::RunLoop().RunUntilIdle(); 1157 1158 // Verify the registration was not modified by the Update. 1159 EXPECT_EQ(active_version, registration->active_version()); 1160 EXPECT_EQ(version.get(), registration->waiting_version()); 1161 EXPECT_EQ(NULL, registration->installing_version()); 1162 } 1163 1164 TEST_F(ServiceWorkerJobTest, Update_UninstallingRegistration) { 1165 bool called; 1166 scoped_refptr<ServiceWorkerRegistration> registration; 1167 job_coordinator()->Register( 1168 GURL("http://www.example.com/one/"), 1169 GURL("http://www.example.com/service_worker.js"), 1170 NULL, 1171 SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); 1172 1173 EXPECT_FALSE(called); 1174 base::RunLoop().RunUntilIdle(); 1175 EXPECT_TRUE(called); 1176 1177 // Add a controllee and queue an unregister to force the uninstalling state. 1178 scoped_ptr<ServiceWorkerProviderHost> host( 1179 new ServiceWorkerProviderHost(33 /* dummy render_process id */, 1180 1 /* dummy provider_id */, 1181 helper_->context()->AsWeakPtr(), 1182 NULL)); 1183 ServiceWorkerVersion* active_version = registration->active_version(); 1184 active_version->AddControllee(host.get()); 1185 job_coordinator()->Unregister(GURL("http://www.example.com/one/"), 1186 SaveUnregistration(SERVICE_WORKER_OK, &called)); 1187 1188 // Update should abort after it starts and sees uninstalling. 1189 job_coordinator()->Update(registration.get()); 1190 1191 EXPECT_FALSE(called); 1192 base::RunLoop().RunUntilIdle(); 1193 EXPECT_TRUE(called); 1194 1195 // Verify the registration was not modified by the Update. 1196 EXPECT_TRUE(registration->is_uninstalling()); 1197 EXPECT_EQ(active_version, registration->active_version()); 1198 EXPECT_EQ(NULL, registration->waiting_version()); 1199 EXPECT_EQ(NULL, registration->installing_version()); 1200 } 1201 1202 } // namespace content 1203