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.
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"
26 using net::TestCompletionCallback
;
27 using net::WrappedIOBuffer
;
29 // Unit tests for testing all job registration tasks.
34 int kMockRenderProcessId
= 88;
36 void SaveRegistrationCallback(
37 ServiceWorkerStatusCode expected_status
,
39 scoped_refptr
<ServiceWorkerRegistration
>* registration_out
,
40 ServiceWorkerStatusCode status
,
41 ServiceWorkerRegistration
* registration
) {
42 EXPECT_EQ(expected_status
, status
);
44 *registration_out
= registration
;
47 void SaveFoundRegistrationCallback(
48 ServiceWorkerStatusCode expected_status
,
50 scoped_refptr
<ServiceWorkerRegistration
>* registration
,
51 ServiceWorkerStatusCode status
,
52 const scoped_refptr
<ServiceWorkerRegistration
>& result
) {
53 EXPECT_EQ(expected_status
, status
);
55 *registration
= result
;
58 // Creates a callback which both keeps track of if it's been called,
59 // as well as the resulting registration. Whent the callback is fired,
60 // it ensures that the resulting status matches the expectation.
61 // 'called' is useful for making sure a sychronous callback is or
63 ServiceWorkerRegisterJob::RegistrationCallback
SaveRegistration(
64 ServiceWorkerStatusCode expected_status
,
66 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
69 &SaveRegistrationCallback
, expected_status
, called
, registration
);
72 ServiceWorkerStorage::FindRegistrationCallback
SaveFoundRegistration(
73 ServiceWorkerStatusCode expected_status
,
75 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
77 return base::Bind(&SaveFoundRegistrationCallback
,
83 void SaveUnregistrationCallback(ServiceWorkerStatusCode expected_status
,
85 ServiceWorkerStatusCode status
) {
86 EXPECT_EQ(expected_status
, status
);
90 ServiceWorkerUnregisterJob::UnregistrationCallback
SaveUnregistration(
91 ServiceWorkerStatusCode expected_status
,
94 return base::Bind(&SaveUnregistrationCallback
, expected_status
, called
);
99 class ServiceWorkerJobTest
: public testing::Test
{
101 ServiceWorkerJobTest()
102 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
103 render_process_id_(kMockRenderProcessId
) {}
105 void SetUp() override
{
106 helper_
.reset(new EmbeddedWorkerTestHelper(render_process_id_
));
109 void TearDown() override
{ helper_
.reset(); }
111 ServiceWorkerContextCore
* context() const { return helper_
->context(); }
113 ServiceWorkerJobCoordinator
* job_coordinator() const {
114 return context()->job_coordinator();
116 ServiceWorkerStorage
* storage() const { return context()->storage(); }
119 TestBrowserThreadBundle browser_thread_bundle_
;
120 scoped_ptr
<EmbeddedWorkerTestHelper
> helper_
;
121 int render_process_id_
;
124 TEST_F(ServiceWorkerJobTest
, SameDocumentSameRegistration
) {
125 scoped_refptr
<ServiceWorkerRegistration
> original_registration
;
127 job_coordinator()->Register(
128 GURL("http://www.example.com/"),
129 GURL("http://www.example.com/service_worker.js"),
131 SaveRegistration(SERVICE_WORKER_OK
, &called
, &original_registration
));
132 EXPECT_FALSE(called
);
133 base::RunLoop().RunUntilIdle();
136 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
137 storage()->FindRegistrationForDocument(
138 GURL("http://www.example.com/"),
139 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration1
));
140 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
141 storage()->FindRegistrationForDocument(
142 GURL("http://www.example.com/"),
143 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration2
));
144 base::RunLoop().RunUntilIdle();
146 ASSERT_TRUE(registration1
.get());
147 ASSERT_EQ(registration1
, original_registration
);
148 ASSERT_EQ(registration1
, registration2
);
151 TEST_F(ServiceWorkerJobTest
, SameMatchSameRegistration
) {
153 scoped_refptr
<ServiceWorkerRegistration
> original_registration
;
154 job_coordinator()->Register(
155 GURL("http://www.example.com/"),
156 GURL("http://www.example.com/service_worker.js"),
158 SaveRegistration(SERVICE_WORKER_OK
, &called
, &original_registration
));
159 EXPECT_FALSE(called
);
160 base::RunLoop().RunUntilIdle();
162 ASSERT_NE(static_cast<ServiceWorkerRegistration
*>(NULL
),
163 original_registration
.get());
165 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
166 storage()->FindRegistrationForDocument(
167 GURL("http://www.example.com/one"),
168 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration1
));
169 base::RunLoop().RunUntilIdle();
172 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
173 storage()->FindRegistrationForDocument(
174 GURL("http://www.example.com/two"),
175 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration2
));
176 base::RunLoop().RunUntilIdle();
178 ASSERT_EQ(registration1
, original_registration
);
179 ASSERT_EQ(registration1
, registration2
);
182 TEST_F(ServiceWorkerJobTest
, DifferentMatchDifferentRegistration
) {
184 scoped_refptr
<ServiceWorkerRegistration
> original_registration1
;
185 job_coordinator()->Register(
186 GURL("http://www.example.com/one/"),
187 GURL("http://www.example.com/service_worker.js"),
189 SaveRegistration(SERVICE_WORKER_OK
, &called1
, &original_registration1
));
192 scoped_refptr
<ServiceWorkerRegistration
> original_registration2
;
193 job_coordinator()->Register(
194 GURL("http://www.example.com/two/"),
195 GURL("http://www.example.com/service_worker.js"),
197 SaveRegistration(SERVICE_WORKER_OK
, &called2
, &original_registration2
));
199 EXPECT_FALSE(called1
);
200 EXPECT_FALSE(called2
);
201 base::RunLoop().RunUntilIdle();
202 EXPECT_TRUE(called2
);
203 EXPECT_TRUE(called1
);
205 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
206 storage()->FindRegistrationForDocument(
207 GURL("http://www.example.com/one/"),
208 SaveFoundRegistration(SERVICE_WORKER_OK
, &called1
, ®istration1
));
209 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
210 storage()->FindRegistrationForDocument(
211 GURL("http://www.example.com/two/"),
212 SaveFoundRegistration(SERVICE_WORKER_OK
, &called2
, ®istration2
));
214 base::RunLoop().RunUntilIdle();
215 EXPECT_TRUE(called2
);
216 EXPECT_TRUE(called1
);
217 ASSERT_NE(registration1
, registration2
);
220 // Make sure basic registration is working.
221 TEST_F(ServiceWorkerJobTest
, Register
) {
223 scoped_refptr
<ServiceWorkerRegistration
> registration
;
224 job_coordinator()->Register(
225 GURL("http://www.example.com/"),
226 GURL("http://www.example.com/service_worker.js"),
228 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
230 ASSERT_FALSE(called
);
231 base::RunLoop().RunUntilIdle();
234 ASSERT_NE(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
237 // Make sure registrations are cleaned up when they are unregistered.
238 TEST_F(ServiceWorkerJobTest
, Unregister
) {
239 GURL
pattern("http://www.example.com/");
242 scoped_refptr
<ServiceWorkerRegistration
> registration
;
243 job_coordinator()->Register(
245 GURL("http://www.example.com/service_worker.js"),
247 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
249 ASSERT_FALSE(called
);
250 base::RunLoop().RunUntilIdle();
253 job_coordinator()->Unregister(pattern
,
254 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
256 ASSERT_FALSE(called
);
257 base::RunLoop().RunUntilIdle();
260 ASSERT_TRUE(registration
->HasOneRef());
262 storage()->FindRegistrationForPattern(
264 SaveFoundRegistration(SERVICE_WORKER_ERROR_NOT_FOUND
,
265 &called
, ®istration
));
267 ASSERT_FALSE(called
);
268 base::RunLoop().RunUntilIdle();
271 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
274 TEST_F(ServiceWorkerJobTest
, Unregister_NothingRegistered
) {
275 GURL
pattern("http://www.example.com/");
278 job_coordinator()->Unregister(
280 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND
, &called
));
282 ASSERT_FALSE(called
);
283 base::RunLoop().RunUntilIdle();
287 // Make sure registering a new script creates a new version and shares an
288 // existing registration.
289 TEST_F(ServiceWorkerJobTest
, RegisterNewScript
) {
290 GURL
pattern("http://www.example.com/");
293 scoped_refptr
<ServiceWorkerRegistration
> old_registration
;
294 job_coordinator()->Register(
296 GURL("http://www.example.com/service_worker.js"),
298 SaveRegistration(SERVICE_WORKER_OK
, &called
, &old_registration
));
300 ASSERT_FALSE(called
);
301 base::RunLoop().RunUntilIdle();
304 scoped_refptr
<ServiceWorkerRegistration
> old_registration_by_pattern
;
305 storage()->FindRegistrationForPattern(
307 SaveFoundRegistration(
308 SERVICE_WORKER_OK
, &called
, &old_registration_by_pattern
));
310 ASSERT_FALSE(called
);
311 base::RunLoop().RunUntilIdle();
314 ASSERT_EQ(old_registration
, old_registration_by_pattern
);
315 old_registration_by_pattern
= NULL
;
317 scoped_refptr
<ServiceWorkerRegistration
> new_registration
;
318 job_coordinator()->Register(
320 GURL("http://www.example.com/service_worker_new.js"),
322 SaveRegistration(SERVICE_WORKER_OK
, &called
, &new_registration
));
324 ASSERT_FALSE(called
);
325 base::RunLoop().RunUntilIdle();
328 ASSERT_EQ(old_registration
, new_registration
);
330 scoped_refptr
<ServiceWorkerRegistration
> new_registration_by_pattern
;
331 storage()->FindRegistrationForPattern(
333 SaveFoundRegistration(
334 SERVICE_WORKER_OK
, &called
, &new_registration
));
336 ASSERT_FALSE(called
);
337 base::RunLoop().RunUntilIdle();
340 ASSERT_NE(new_registration_by_pattern
, old_registration
);
343 // Make sure that when registering a duplicate pattern+script_url
344 // combination, that the same registration is used.
345 TEST_F(ServiceWorkerJobTest
, RegisterDuplicateScript
) {
346 GURL
pattern("http://www.example.com/");
347 GURL
script_url("http://www.example.com/service_worker.js");
350 scoped_refptr
<ServiceWorkerRegistration
> old_registration
;
351 job_coordinator()->Register(
355 SaveRegistration(SERVICE_WORKER_OK
, &called
, &old_registration
));
357 ASSERT_FALSE(called
);
358 base::RunLoop().RunUntilIdle();
361 scoped_refptr
<ServiceWorkerRegistration
> old_registration_by_pattern
;
362 storage()->FindRegistrationForPattern(
364 SaveFoundRegistration(
365 SERVICE_WORKER_OK
, &called
, &old_registration_by_pattern
));
366 ASSERT_FALSE(called
);
367 base::RunLoop().RunUntilIdle();
370 ASSERT_TRUE(old_registration_by_pattern
.get());
372 scoped_refptr
<ServiceWorkerRegistration
> new_registration
;
373 job_coordinator()->Register(
377 SaveRegistration(SERVICE_WORKER_OK
, &called
, &new_registration
));
379 ASSERT_FALSE(called
);
380 base::RunLoop().RunUntilIdle();
383 ASSERT_EQ(old_registration
, new_registration
);
385 ASSERT_FALSE(old_registration
->HasOneRef());
387 scoped_refptr
<ServiceWorkerRegistration
> new_registration_by_pattern
;
388 storage()->FindRegistrationForPattern(
390 SaveFoundRegistration(
391 SERVICE_WORKER_OK
, &called
, &new_registration_by_pattern
));
393 ASSERT_FALSE(called
);
394 base::RunLoop().RunUntilIdle();
397 ASSERT_EQ(new_registration
, old_registration
);
400 class FailToStartWorkerTestHelper
: public EmbeddedWorkerTestHelper
{
402 explicit FailToStartWorkerTestHelper(int mock_render_process_id
)
403 : EmbeddedWorkerTestHelper(mock_render_process_id
) {}
405 void OnStartWorker(int embedded_worker_id
,
406 int64 service_worker_version_id
,
408 const GURL
& script_url
,
409 bool pause_after_download
) override
{
410 EmbeddedWorkerInstance
* worker
= registry()->GetWorker(embedded_worker_id
);
411 registry()->OnWorkerStopped(worker
->process_id(), embedded_worker_id
);
415 TEST_F(ServiceWorkerJobTest
, Register_FailToStartWorker
) {
416 helper_
.reset(new FailToStartWorkerTestHelper(render_process_id_
));
419 scoped_refptr
<ServiceWorkerRegistration
> registration
;
420 job_coordinator()->Register(
421 GURL("http://www.example.com/"),
422 GURL("http://www.example.com/service_worker.js"),
425 SERVICE_WORKER_ERROR_START_WORKER_FAILED
, &called
, ®istration
));
427 ASSERT_FALSE(called
);
428 base::RunLoop().RunUntilIdle();
431 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
434 // Register and then unregister the pattern, in parallel. Job coordinator should
435 // process jobs until the last job.
436 TEST_F(ServiceWorkerJobTest
, ParallelRegUnreg
) {
437 GURL
pattern("http://www.example.com/");
438 GURL
script_url("http://www.example.com/service_worker.js");
440 bool registration_called
= false;
441 scoped_refptr
<ServiceWorkerRegistration
> registration
;
442 job_coordinator()->Register(
446 SaveRegistration(SERVICE_WORKER_OK
, ®istration_called
, ®istration
));
448 bool unregistration_called
= false;
449 job_coordinator()->Unregister(
451 SaveUnregistration(SERVICE_WORKER_OK
, &unregistration_called
));
453 ASSERT_FALSE(registration_called
);
454 ASSERT_FALSE(unregistration_called
);
455 base::RunLoop().RunUntilIdle();
456 ASSERT_TRUE(registration_called
);
457 ASSERT_TRUE(unregistration_called
);
459 bool find_called
= false;
460 storage()->FindRegistrationForPattern(
462 SaveFoundRegistration(
463 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
465 base::RunLoop().RunUntilIdle();
467 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
470 // Register conflicting scripts for the same pattern. The most recent
471 // registration should win, and the old registration should have been
473 TEST_F(ServiceWorkerJobTest
, ParallelRegNewScript
) {
474 GURL
pattern("http://www.example.com/");
476 GURL
script_url1("http://www.example.com/service_worker1.js");
477 bool registration1_called
= false;
478 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
479 job_coordinator()->Register(
484 SERVICE_WORKER_OK
, ®istration1_called
, ®istration1
));
486 GURL
script_url2("http://www.example.com/service_worker2.js");
487 bool registration2_called
= false;
488 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
489 job_coordinator()->Register(
494 SERVICE_WORKER_OK
, ®istration2_called
, ®istration2
));
496 ASSERT_FALSE(registration1_called
);
497 ASSERT_FALSE(registration2_called
);
498 base::RunLoop().RunUntilIdle();
499 ASSERT_TRUE(registration1_called
);
500 ASSERT_TRUE(registration2_called
);
502 scoped_refptr
<ServiceWorkerRegistration
> registration
;
503 bool find_called
= false;
504 storage()->FindRegistrationForPattern(
506 SaveFoundRegistration(
507 SERVICE_WORKER_OK
, &find_called
, ®istration
));
509 base::RunLoop().RunUntilIdle();
511 ASSERT_EQ(registration2
, registration
);
514 // Register the exact same pattern + script. Requests should be
515 // coalesced such that both callers get the exact same registration
517 TEST_F(ServiceWorkerJobTest
, ParallelRegSameScript
) {
518 GURL
pattern("http://www.example.com/");
520 GURL
script_url("http://www.example.com/service_worker1.js");
521 bool registration1_called
= false;
522 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
523 job_coordinator()->Register(
528 SERVICE_WORKER_OK
, ®istration1_called
, ®istration1
));
530 bool registration2_called
= false;
531 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
532 job_coordinator()->Register(
537 SERVICE_WORKER_OK
, ®istration2_called
, ®istration2
));
539 ASSERT_FALSE(registration1_called
);
540 ASSERT_FALSE(registration2_called
);
541 base::RunLoop().RunUntilIdle();
542 ASSERT_TRUE(registration1_called
);
543 ASSERT_TRUE(registration2_called
);
545 ASSERT_EQ(registration1
, registration2
);
547 scoped_refptr
<ServiceWorkerRegistration
> registration
;
548 bool find_called
= false;
549 storage()->FindRegistrationForPattern(
551 SaveFoundRegistration(
552 SERVICE_WORKER_OK
, &find_called
, ®istration
));
554 base::RunLoop().RunUntilIdle();
555 ASSERT_EQ(registration
, registration1
);
558 // Call simulataneous unregister calls.
559 TEST_F(ServiceWorkerJobTest
, ParallelUnreg
) {
560 GURL
pattern("http://www.example.com/");
562 GURL
script_url("http://www.example.com/service_worker.js");
563 bool unregistration1_called
= false;
564 job_coordinator()->Unregister(
566 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND
,
567 &unregistration1_called
));
569 bool unregistration2_called
= false;
570 job_coordinator()->Unregister(
572 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND
,
573 &unregistration2_called
));
575 ASSERT_FALSE(unregistration1_called
);
576 ASSERT_FALSE(unregistration2_called
);
577 base::RunLoop().RunUntilIdle();
578 ASSERT_TRUE(unregistration1_called
);
579 ASSERT_TRUE(unregistration2_called
);
581 // There isn't really a way to test that they are being coalesced,
582 // but we can make sure they can exist simultaneously without
584 scoped_refptr
<ServiceWorkerRegistration
> registration
;
585 bool find_called
= false;
586 storage()->FindRegistrationForPattern(
588 SaveFoundRegistration(
589 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
591 base::RunLoop().RunUntilIdle();
592 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
595 TEST_F(ServiceWorkerJobTest
, AbortAll_Register
) {
596 GURL
pattern1("http://www1.example.com/");
597 GURL
pattern2("http://www2.example.com/");
598 GURL
script_url1("http://www1.example.com/service_worker.js");
599 GURL
script_url2("http://www2.example.com/service_worker.js");
601 bool registration_called1
= false;
602 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
603 job_coordinator()->Register(
607 SaveRegistration(SERVICE_WORKER_ERROR_ABORT
,
608 ®istration_called1
, ®istration1
));
610 bool registration_called2
= false;
611 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
612 job_coordinator()->Register(
616 SaveRegistration(SERVICE_WORKER_ERROR_ABORT
,
617 ®istration_called2
, ®istration2
));
619 ASSERT_FALSE(registration_called1
);
620 ASSERT_FALSE(registration_called2
);
621 job_coordinator()->AbortAll();
623 base::RunLoop().RunUntilIdle();
624 ASSERT_TRUE(registration_called1
);
625 ASSERT_TRUE(registration_called2
);
627 bool find_called1
= false;
628 storage()->FindRegistrationForPattern(
630 SaveFoundRegistration(
631 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called1
, ®istration1
));
633 bool find_called2
= false;
634 storage()->FindRegistrationForPattern(
636 SaveFoundRegistration(
637 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called2
, ®istration2
));
639 base::RunLoop().RunUntilIdle();
640 ASSERT_TRUE(find_called1
);
641 ASSERT_TRUE(find_called2
);
642 EXPECT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration1
);
643 EXPECT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration2
);
646 TEST_F(ServiceWorkerJobTest
, AbortAll_Unregister
) {
647 GURL
pattern1("http://www1.example.com/");
648 GURL
pattern2("http://www2.example.com/");
650 bool unregistration_called1
= false;
651 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
652 job_coordinator()->Unregister(
654 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT
,
655 &unregistration_called1
));
657 bool unregistration_called2
= false;
658 job_coordinator()->Unregister(
660 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT
,
661 &unregistration_called2
));
663 ASSERT_FALSE(unregistration_called1
);
664 ASSERT_FALSE(unregistration_called2
);
665 job_coordinator()->AbortAll();
667 base::RunLoop().RunUntilIdle();
668 ASSERT_TRUE(unregistration_called1
);
669 ASSERT_TRUE(unregistration_called2
);
672 TEST_F(ServiceWorkerJobTest
, AbortAll_RegUnreg
) {
673 GURL
pattern("http://www.example.com/");
674 GURL
script_url("http://www.example.com/service_worker.js");
676 bool registration_called
= false;
677 scoped_refptr
<ServiceWorkerRegistration
> registration
;
678 job_coordinator()->Register(
682 SaveRegistration(SERVICE_WORKER_ERROR_ABORT
,
683 ®istration_called
, ®istration
));
685 bool unregistration_called
= false;
686 job_coordinator()->Unregister(
688 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT
,
689 &unregistration_called
));
691 ASSERT_FALSE(registration_called
);
692 ASSERT_FALSE(unregistration_called
);
693 job_coordinator()->AbortAll();
695 base::RunLoop().RunUntilIdle();
696 ASSERT_TRUE(registration_called
);
697 ASSERT_TRUE(unregistration_called
);
699 bool find_called
= false;
700 storage()->FindRegistrationForPattern(
702 SaveFoundRegistration(
703 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
705 base::RunLoop().RunUntilIdle();
706 ASSERT_TRUE(find_called
);
707 EXPECT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
710 // Tests that the waiting worker enters the 'redundant' state upon
712 TEST_F(ServiceWorkerJobTest
, UnregisterWaitingSetsRedundant
) {
713 scoped_refptr
<ServiceWorkerRegistration
> registration
;
715 GURL
script_url("http://www.example.com/service_worker.js");
716 job_coordinator()->Register(
717 GURL("http://www.example.com/"),
720 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
721 base::RunLoop().RunUntilIdle();
723 ASSERT_TRUE(registration
.get());
725 // Manually create the waiting worker since there is no way to become a
726 // waiting worker until Update is implemented.
727 scoped_refptr
<ServiceWorkerVersion
> version
= new ServiceWorkerVersion(
728 registration
.get(), script_url
, 1L, helper_
->context()->AsWeakPtr());
729 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
730 version
->StartWorker(CreateReceiverOnCurrentThread(&status
));
731 base::RunLoop().RunUntilIdle();
732 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
734 version
->SetStatus(ServiceWorkerVersion::INSTALLED
);
735 registration
->SetWaitingVersion(version
.get());
736 EXPECT_EQ(ServiceWorkerVersion::RUNNING
,
737 version
->running_status());
738 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
, version
->status());
741 job_coordinator()->Unregister(GURL("http://www.example.com/"),
742 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
743 base::RunLoop().RunUntilIdle();
746 // The version should be stopped since there is no controllee after
748 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version
->running_status());
749 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
, version
->status());
752 // Tests that the active worker enters the 'redundant' state upon
754 TEST_F(ServiceWorkerJobTest
, UnregisterActiveSetsRedundant
) {
755 scoped_refptr
<ServiceWorkerRegistration
> registration
;
757 job_coordinator()->Register(
758 GURL("http://www.example.com/"),
759 GURL("http://www.example.com/service_worker.js"),
761 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
762 base::RunLoop().RunUntilIdle();
764 ASSERT_TRUE(registration
.get());
766 scoped_refptr
<ServiceWorkerVersion
> version
= registration
->active_version();
767 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version
->running_status());
768 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
, version
->status());
771 job_coordinator()->Unregister(GURL("http://www.example.com/"),
772 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
773 base::RunLoop().RunUntilIdle();
776 // The version should be stopped since there is no controllee after
778 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version
->running_status());
779 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
, version
->status());
782 // Tests that the active worker enters the 'redundant' state upon
784 TEST_F(ServiceWorkerJobTest
,
785 UnregisterActiveSetsRedundant_WaitForNoControllee
) {
786 scoped_refptr
<ServiceWorkerRegistration
> registration
;
788 job_coordinator()->Register(
789 GURL("http://www.example.com/"),
790 GURL("http://www.example.com/service_worker.js"),
792 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
793 base::RunLoop().RunUntilIdle();
795 ASSERT_TRUE(registration
.get());
797 scoped_ptr
<ServiceWorkerProviderHost
> host(
798 new ServiceWorkerProviderHost(33 /* dummy render process id */,
799 MSG_ROUTING_NONE
/* render_frame_id */,
800 1 /* dummy provider_id */,
801 context()->AsWeakPtr(),
803 registration
->active_version()->AddControllee(host
.get());
805 scoped_refptr
<ServiceWorkerVersion
> version
= registration
->active_version();
806 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version
->running_status());
807 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
, version
->status());
810 job_coordinator()->Unregister(GURL("http://www.example.com/"),
811 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
812 base::RunLoop().RunUntilIdle();
815 // The version should be running since there is still a controllee.
816 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version
->running_status());
817 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
, version
->status());
819 registration
->active_version()->RemoveControllee(host
.get());
820 base::RunLoop().RunUntilIdle();
822 // The version should be stopped since there is no controllee.
823 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version
->running_status());
824 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
, version
->status());
827 namespace { // Helpers for the update job tests.
829 const GURL
kNoChangeOrigin("http://nochange/");
830 const GURL
kNewVersionOrigin("http://newversion/");
831 const std::string
kScope("scope/");
832 const std::string
kScript("script.js");
834 void RunNestedUntilIdle() {
835 base::MessageLoop::ScopedNestableTaskAllower
allow(
836 base::MessageLoop::current());
837 base::MessageLoop::current()->RunUntilIdle();
840 void OnIOComplete(int* rv_out
, int rv
) {
845 ServiceWorkerStorage
* storage
, int64 id
,
846 const std::string
& headers
,
847 IOBuffer
* body
, int length
) {
848 scoped_ptr
<ServiceWorkerResponseWriter
> writer
=
849 storage
->CreateResponseWriter(id
);
851 scoped_ptr
<net::HttpResponseInfo
> info(new net::HttpResponseInfo
);
852 info
->request_time
= base::Time::Now();
853 info
->response_time
= base::Time::Now();
854 info
->was_cached
= false;
855 info
->headers
= new net::HttpResponseHeaders(headers
);
856 scoped_refptr
<HttpResponseInfoIOBuffer
> info_buffer
=
857 new HttpResponseInfoIOBuffer(info
.release());
860 writer
->WriteInfo(info_buffer
.get(), base::Bind(&OnIOComplete
, &rv
));
861 RunNestedUntilIdle();
865 writer
->WriteData(body
, length
,
866 base::Bind(&OnIOComplete
, &rv
));
867 RunNestedUntilIdle();
868 EXPECT_EQ(length
, rv
);
871 void WriteStringResponse(
872 ServiceWorkerStorage
* storage
, int64 id
,
873 const std::string
& body
) {
874 scoped_refptr
<IOBuffer
> body_buffer(new WrappedIOBuffer(body
.data()));
875 const char kHttpHeaders
[] = "HTTP/1.0 200 HONKYDORY\0\0";
876 std::string
headers(kHttpHeaders
, arraysize(kHttpHeaders
));
877 WriteResponse(storage
, id
, headers
, body_buffer
.get(), body
.length());
880 class UpdateJobTestHelper
881 : public EmbeddedWorkerTestHelper
,
882 public ServiceWorkerRegistration::Listener
,
883 public ServiceWorkerVersion::Listener
{
885 struct AttributeChangeLogEntry
{
886 int64 registration_id
;
887 ChangedVersionAttributesMask mask
;
888 ServiceWorkerRegistrationInfo info
;
891 struct StateChangeLogEntry
{
893 ServiceWorkerVersion::Status status
;
896 UpdateJobTestHelper(int mock_render_process_id
)
897 : EmbeddedWorkerTestHelper(mock_render_process_id
),
898 update_found_(false) {}
899 ~UpdateJobTestHelper() override
{
900 if (registration_
.get())
901 registration_
->RemoveListener(this);
904 ServiceWorkerStorage
* storage() { return context()->storage(); }
905 ServiceWorkerJobCoordinator
* job_coordinator() {
906 return context()->job_coordinator();
909 scoped_refptr
<ServiceWorkerRegistration
> SetupInitialRegistration(
910 const GURL
& test_origin
) {
911 scoped_refptr
<ServiceWorkerRegistration
> registration
;
913 job_coordinator()->Register(
914 test_origin
.Resolve(kScope
),
915 test_origin
.Resolve(kScript
),
917 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
918 base::RunLoop().RunUntilIdle();
920 EXPECT_TRUE(registration
.get());
921 EXPECT_TRUE(registration
->active_version());
922 EXPECT_FALSE(registration
->installing_version());
923 EXPECT_FALSE(registration
->waiting_version());
924 registration_
= registration
;
928 // EmbeddedWorkerTestHelper overrides
929 void OnStartWorker(int embedded_worker_id
,
933 bool pause_after_download
) override
{
934 const std::string kMockScriptBody
= "mock_script";
935 const uint64 kMockScriptSize
= 19284;
936 ServiceWorkerVersion
* version
= context()->GetLiveVersion(version_id
);
937 ASSERT_TRUE(version
);
938 version
->AddListener(this);
940 if (!pause_after_download
) {
941 // Spoof caching the script for the initial version.
942 int64 resource_id
= storage()->NewResourceId();
943 version
->script_cache_map()->NotifyStartedCaching(script
, resource_id
);
944 WriteStringResponse(storage(), resource_id
, kMockScriptBody
);
945 version
->script_cache_map()->NotifyFinishedCaching(
946 script
, kMockScriptSize
, net::URLRequestStatus());
948 // Spoof caching the script for the new version.
949 int64 resource_id
= storage()->NewResourceId();
950 version
->script_cache_map()->NotifyStartedCaching(script
, resource_id
);
951 if (script
.GetOrigin() == kNoChangeOrigin
)
952 WriteStringResponse(storage(), resource_id
, kMockScriptBody
);
954 WriteStringResponse(storage(), resource_id
, "mock_different_script");
955 version
->script_cache_map()->NotifyFinishedCaching(
956 script
, kMockScriptSize
, net::URLRequestStatus());
958 EmbeddedWorkerTestHelper::OnStartWorker(
959 embedded_worker_id
, version_id
, scope
, script
, pause_after_download
);
962 // ServiceWorkerRegistration::Listener overrides
963 void OnVersionAttributesChanged(
964 ServiceWorkerRegistration
* registration
,
965 ChangedVersionAttributesMask changed_mask
,
966 const ServiceWorkerRegistrationInfo
& info
) override
{
967 AttributeChangeLogEntry entry
;
968 entry
.registration_id
= registration
->id();
969 entry
.mask
= changed_mask
;
971 attribute_change_log_
.push_back(entry
);
974 void OnRegistrationFailed(ServiceWorkerRegistration
* registration
) override
{
978 void OnRegistrationFinishedUninstalling(
979 ServiceWorkerRegistration
* registration
) override
{
983 void OnUpdateFound(ServiceWorkerRegistration
* registration
) override
{
984 ASSERT_FALSE(update_found_
);
985 update_found_
= true;
988 // ServiceWorkerVersion::Listener overrides
989 void OnVersionStateChanged(ServiceWorkerVersion
* version
) override
{
990 StateChangeLogEntry entry
;
991 entry
.version_id
= version
->version_id();
992 entry
.status
= version
->status();
993 state_change_log_
.push_back(entry
);
996 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
998 std::vector
<AttributeChangeLogEntry
> attribute_change_log_
;
999 std::vector
<StateChangeLogEntry
> state_change_log_
;
1005 TEST_F(ServiceWorkerJobTest
, Update_NoChange
) {
1006 UpdateJobTestHelper
* update_helper
=
1007 new UpdateJobTestHelper(render_process_id_
);
1008 helper_
.reset(update_helper
);
1009 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1010 update_helper
->SetupInitialRegistration(kNoChangeOrigin
);
1011 ASSERT_TRUE(registration
.get());
1012 ASSERT_EQ(4u, update_helper
->state_change_log_
.size());
1013 EXPECT_EQ(ServiceWorkerVersion::INSTALLING
,
1014 update_helper
->state_change_log_
[0].status
);
1015 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
,
1016 update_helper
->state_change_log_
[1].status
);
1017 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING
,
1018 update_helper
->state_change_log_
[2].status
);
1019 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
,
1020 update_helper
->state_change_log_
[3].status
);
1021 update_helper
->state_change_log_
.clear();
1023 // Run the update job.
1024 registration
->AddListener(update_helper
);
1025 scoped_refptr
<ServiceWorkerVersion
> first_version
=
1026 registration
->active_version();
1027 first_version
->StartUpdate();
1028 base::RunLoop().RunUntilIdle();
1031 ASSERT_TRUE(registration
->active_version());
1032 EXPECT_EQ(first_version
.get(), registration
->active_version());
1033 EXPECT_FALSE(registration
->installing_version());
1034 EXPECT_FALSE(registration
->waiting_version());
1035 EXPECT_TRUE(update_helper
->attribute_change_log_
.empty());
1036 ASSERT_EQ(1u, update_helper
->state_change_log_
.size());
1037 EXPECT_NE(registration
->active_version()->version_id(),
1038 update_helper
->state_change_log_
[0].version_id
);
1039 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
,
1040 update_helper
->state_change_log_
[0].status
);
1041 EXPECT_FALSE(update_helper
->update_found_
);
1044 TEST_F(ServiceWorkerJobTest
, Update_NewVersion
) {
1045 UpdateJobTestHelper
* update_helper
=
1046 new UpdateJobTestHelper(render_process_id_
);
1047 helper_
.reset(update_helper
);
1048 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1049 update_helper
->SetupInitialRegistration(kNewVersionOrigin
);
1050 ASSERT_TRUE(registration
.get());
1051 update_helper
->state_change_log_
.clear();
1053 // Run the update job.
1054 registration
->AddListener(update_helper
);
1055 scoped_refptr
<ServiceWorkerVersion
> first_version
=
1056 registration
->active_version();
1057 first_version
->StartUpdate();
1058 base::RunLoop().RunUntilIdle();
1061 ASSERT_TRUE(registration
->active_version());
1062 EXPECT_NE(first_version
.get(), registration
->active_version());
1063 EXPECT_FALSE(registration
->installing_version());
1064 EXPECT_FALSE(registration
->waiting_version());
1065 ASSERT_EQ(3u, update_helper
->attribute_change_log_
.size());
1067 UpdateJobTestHelper::AttributeChangeLogEntry entry
;
1068 entry
= update_helper
->attribute_change_log_
[0];
1069 EXPECT_TRUE(entry
.mask
.installing_changed());
1070 EXPECT_FALSE(entry
.mask
.waiting_changed());
1071 EXPECT_FALSE(entry
.mask
.active_changed());
1072 EXPECT_NE(entry
.info
.installing_version
.version_id
,
1073 kInvalidServiceWorkerVersionId
);
1074 EXPECT_EQ(entry
.info
.waiting_version
.version_id
,
1075 kInvalidServiceWorkerVersionId
);
1076 EXPECT_NE(entry
.info
.active_version
.version_id
,
1077 kInvalidServiceWorkerVersionId
);
1079 entry
= update_helper
->attribute_change_log_
[1];
1080 EXPECT_TRUE(entry
.mask
.installing_changed());
1081 EXPECT_TRUE(entry
.mask
.waiting_changed());
1082 EXPECT_FALSE(entry
.mask
.active_changed());
1083 EXPECT_EQ(entry
.info
.installing_version
.version_id
,
1084 kInvalidServiceWorkerVersionId
);
1085 EXPECT_NE(entry
.info
.waiting_version
.version_id
,
1086 kInvalidServiceWorkerVersionId
);
1087 EXPECT_NE(entry
.info
.active_version
.version_id
,
1088 kInvalidServiceWorkerVersionId
);
1090 entry
= update_helper
->attribute_change_log_
[2];
1091 EXPECT_FALSE(entry
.mask
.installing_changed());
1092 EXPECT_TRUE(entry
.mask
.waiting_changed());
1093 EXPECT_TRUE(entry
.mask
.active_changed());
1094 EXPECT_EQ(entry
.info
.installing_version
.version_id
,
1095 kInvalidServiceWorkerVersionId
);
1096 EXPECT_EQ(entry
.info
.waiting_version
.version_id
,
1097 kInvalidServiceWorkerVersionId
);
1098 EXPECT_NE(entry
.info
.active_version
.version_id
,
1099 kInvalidServiceWorkerVersionId
);
1101 // expected version state transitions:
1102 // new.installing, new.installed,
1104 // new.activating, new.activated
1105 ASSERT_EQ(5u, update_helper
->state_change_log_
.size());
1107 EXPECT_EQ(registration
->active_version()->version_id(),
1108 update_helper
->state_change_log_
[0].version_id
);
1109 EXPECT_EQ(ServiceWorkerVersion::INSTALLING
,
1110 update_helper
->state_change_log_
[0].status
);
1112 EXPECT_EQ(registration
->active_version()->version_id(),
1113 update_helper
->state_change_log_
[1].version_id
);
1114 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
,
1115 update_helper
->state_change_log_
[1].status
);
1117 EXPECT_EQ(first_version
->version_id(),
1118 update_helper
->state_change_log_
[2].version_id
);
1119 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
,
1120 update_helper
->state_change_log_
[2].status
);
1122 EXPECT_EQ(registration
->active_version()->version_id(),
1123 update_helper
->state_change_log_
[3].version_id
);
1124 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING
,
1125 update_helper
->state_change_log_
[3].status
);
1127 EXPECT_EQ(registration
->active_version()->version_id(),
1128 update_helper
->state_change_log_
[4].version_id
);
1129 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
,
1130 update_helper
->state_change_log_
[4].status
);
1132 EXPECT_TRUE(update_helper
->update_found_
);
1135 TEST_F(ServiceWorkerJobTest
, Update_NewestVersionChanged
) {
1137 scoped_refptr
<ServiceWorkerRegistration
> registration
;
1138 job_coordinator()->Register(
1139 GURL("http://www.example.com/one/"),
1140 GURL("http://www.example.com/service_worker.js"),
1142 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
1144 EXPECT_FALSE(called
);
1145 base::RunLoop().RunUntilIdle();
1146 EXPECT_TRUE(called
);
1147 ServiceWorkerVersion
* active_version
= registration
->active_version();
1149 // Queue an Update, it should abort when it starts and sees the new version.
1150 job_coordinator()->Update(registration
.get());
1152 // Add a waiting version with new script.
1153 scoped_refptr
<ServiceWorkerVersion
> version
=
1154 new ServiceWorkerVersion(registration
.get(),
1155 GURL("http://www.example.com/new_worker.js"),
1156 2L /* dummy version id */,
1157 helper_
->context()->AsWeakPtr());
1158 registration
->SetWaitingVersion(version
.get());
1160 base::RunLoop().RunUntilIdle();
1162 // Verify the registration was not modified by the Update.
1163 EXPECT_EQ(active_version
, registration
->active_version());
1164 EXPECT_EQ(version
.get(), registration
->waiting_version());
1165 EXPECT_EQ(NULL
, registration
->installing_version());
1168 TEST_F(ServiceWorkerJobTest
, Update_UninstallingRegistration
) {
1170 scoped_refptr
<ServiceWorkerRegistration
> registration
;
1171 job_coordinator()->Register(
1172 GURL("http://www.example.com/one/"),
1173 GURL("http://www.example.com/service_worker.js"),
1175 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
1177 EXPECT_FALSE(called
);
1178 base::RunLoop().RunUntilIdle();
1179 EXPECT_TRUE(called
);
1181 // Add a controllee and queue an unregister to force the uninstalling state.
1182 scoped_ptr
<ServiceWorkerProviderHost
> host(
1183 new ServiceWorkerProviderHost(33 /* dummy render_process id */,
1184 MSG_ROUTING_NONE
/* render_frame_id */,
1185 1 /* dummy provider_id */,
1186 helper_
->context()->AsWeakPtr(),
1188 ServiceWorkerVersion
* active_version
= registration
->active_version();
1189 active_version
->AddControllee(host
.get());
1190 job_coordinator()->Unregister(GURL("http://www.example.com/one/"),
1191 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
1193 // Update should abort after it starts and sees uninstalling.
1194 job_coordinator()->Update(registration
.get());
1196 EXPECT_FALSE(called
);
1197 base::RunLoop().RunUntilIdle();
1198 EXPECT_TRUE(called
);
1200 // Verify the registration was not modified by the Update.
1201 EXPECT_TRUE(registration
->is_uninstalling());
1202 EXPECT_EQ(active_version
, registration
->active_version());
1203 EXPECT_EQ(NULL
, registration
->waiting_version());
1204 EXPECT_EQ(NULL
, registration
->installing_version());
1207 } // namespace content