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 ServiceWorkerVersion
* version
) {
43 ASSERT_TRUE(!version
|| version
->registration_id() == registration
->id())
44 << version
<< " " << registration
;
45 EXPECT_EQ(expected_status
, status
);
47 *registration_out
= registration
;
50 void SaveFoundRegistrationCallback(
51 ServiceWorkerStatusCode expected_status
,
53 scoped_refptr
<ServiceWorkerRegistration
>* registration
,
54 ServiceWorkerStatusCode status
,
55 const scoped_refptr
<ServiceWorkerRegistration
>& result
) {
56 EXPECT_EQ(expected_status
, status
);
58 *registration
= result
;
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
66 ServiceWorkerRegisterJob::RegistrationCallback
SaveRegistration(
67 ServiceWorkerStatusCode expected_status
,
69 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
72 &SaveRegistrationCallback
, expected_status
, called
, registration
);
75 ServiceWorkerStorage::FindRegistrationCallback
SaveFoundRegistration(
76 ServiceWorkerStatusCode expected_status
,
78 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
80 return base::Bind(&SaveFoundRegistrationCallback
,
86 void SaveUnregistrationCallback(ServiceWorkerStatusCode expected_status
,
88 ServiceWorkerStatusCode status
) {
89 EXPECT_EQ(expected_status
, status
);
93 ServiceWorkerUnregisterJob::UnregistrationCallback
SaveUnregistration(
94 ServiceWorkerStatusCode expected_status
,
97 return base::Bind(&SaveUnregistrationCallback
, expected_status
, called
);
102 class ServiceWorkerJobTest
: public testing::Test
{
104 ServiceWorkerJobTest()
105 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
106 render_process_id_(kMockRenderProcessId
) {}
108 virtual void SetUp() OVERRIDE
{
109 helper_
.reset(new EmbeddedWorkerTestHelper(render_process_id_
));
112 virtual void TearDown() OVERRIDE
{
116 ServiceWorkerContextCore
* context() const { return helper_
->context(); }
118 ServiceWorkerJobCoordinator
* job_coordinator() const {
119 return context()->job_coordinator();
121 ServiceWorkerStorage
* storage() const { return context()->storage(); }
124 TestBrowserThreadBundle browser_thread_bundle_
;
125 scoped_ptr
<EmbeddedWorkerTestHelper
> helper_
;
126 int render_process_id_
;
129 TEST_F(ServiceWorkerJobTest
, SameDocumentSameRegistration
) {
130 scoped_refptr
<ServiceWorkerRegistration
> original_registration
;
132 job_coordinator()->Register(
133 GURL("http://www.example.com/"),
134 GURL("http://www.example.com/service_worker.js"),
136 SaveRegistration(SERVICE_WORKER_OK
, &called
, &original_registration
));
137 EXPECT_FALSE(called
);
138 base::RunLoop().RunUntilIdle();
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();
151 ASSERT_TRUE(registration1
.get());
152 ASSERT_EQ(registration1
, original_registration
);
153 ASSERT_EQ(registration1
, registration2
);
156 TEST_F(ServiceWorkerJobTest
, SameMatchSameRegistration
) {
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"),
163 SaveRegistration(SERVICE_WORKER_OK
, &called
, &original_registration
));
164 EXPECT_FALSE(called
);
165 base::RunLoop().RunUntilIdle();
167 ASSERT_NE(static_cast<ServiceWorkerRegistration
*>(NULL
),
168 original_registration
.get());
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();
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();
183 ASSERT_EQ(registration1
, original_registration
);
184 ASSERT_EQ(registration1
, registration2
);
187 TEST_F(ServiceWorkerJobTest
, DifferentMatchDifferentRegistration
) {
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"),
194 SaveRegistration(SERVICE_WORKER_OK
, &called1
, &original_registration1
));
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"),
202 SaveRegistration(SERVICE_WORKER_OK
, &called2
, &original_registration2
));
204 EXPECT_FALSE(called1
);
205 EXPECT_FALSE(called2
);
206 base::RunLoop().RunUntilIdle();
207 EXPECT_TRUE(called2
);
208 EXPECT_TRUE(called1
);
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
));
219 base::RunLoop().RunUntilIdle();
220 EXPECT_TRUE(called2
);
221 EXPECT_TRUE(called1
);
222 ASSERT_NE(registration1
, registration2
);
225 // Make sure basic registration is working.
226 TEST_F(ServiceWorkerJobTest
, Register
) {
228 scoped_refptr
<ServiceWorkerRegistration
> registration
;
229 job_coordinator()->Register(
230 GURL("http://www.example.com/"),
231 GURL("http://www.example.com/service_worker.js"),
233 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
235 ASSERT_FALSE(called
);
236 base::RunLoop().RunUntilIdle();
239 ASSERT_NE(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
242 // Make sure registrations are cleaned up when they are unregistered.
243 TEST_F(ServiceWorkerJobTest
, Unregister
) {
244 GURL
pattern("http://www.example.com/");
247 scoped_refptr
<ServiceWorkerRegistration
> registration
;
248 job_coordinator()->Register(
250 GURL("http://www.example.com/service_worker.js"),
252 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
254 ASSERT_FALSE(called
);
255 base::RunLoop().RunUntilIdle();
258 job_coordinator()->Unregister(pattern
,
259 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
261 ASSERT_FALSE(called
);
262 base::RunLoop().RunUntilIdle();
265 ASSERT_TRUE(registration
->HasOneRef());
267 storage()->FindRegistrationForPattern(
269 SaveFoundRegistration(SERVICE_WORKER_ERROR_NOT_FOUND
,
270 &called
, ®istration
));
272 ASSERT_FALSE(called
);
273 base::RunLoop().RunUntilIdle();
276 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
279 TEST_F(ServiceWorkerJobTest
, Unregister_NothingRegistered
) {
280 GURL
pattern("http://www.example.com/");
283 job_coordinator()->Unregister(pattern
,
284 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
286 ASSERT_FALSE(called
);
287 base::RunLoop().RunUntilIdle();
291 // Make sure registering a new script creates a new version and shares an
292 // existing registration.
293 TEST_F(ServiceWorkerJobTest
, RegisterNewScript
) {
294 GURL
pattern("http://www.example.com/");
297 scoped_refptr
<ServiceWorkerRegistration
> old_registration
;
298 job_coordinator()->Register(
300 GURL("http://www.example.com/service_worker.js"),
302 SaveRegistration(SERVICE_WORKER_OK
, &called
, &old_registration
));
304 ASSERT_FALSE(called
);
305 base::RunLoop().RunUntilIdle();
308 scoped_refptr
<ServiceWorkerRegistration
> old_registration_by_pattern
;
309 storage()->FindRegistrationForPattern(
311 SaveFoundRegistration(
312 SERVICE_WORKER_OK
, &called
, &old_registration_by_pattern
));
314 ASSERT_FALSE(called
);
315 base::RunLoop().RunUntilIdle();
318 ASSERT_EQ(old_registration
, old_registration_by_pattern
);
319 old_registration_by_pattern
= NULL
;
321 scoped_refptr
<ServiceWorkerRegistration
> new_registration
;
322 job_coordinator()->Register(
324 GURL("http://www.example.com/service_worker_new.js"),
326 SaveRegistration(SERVICE_WORKER_OK
, &called
, &new_registration
));
328 ASSERT_FALSE(called
);
329 base::RunLoop().RunUntilIdle();
332 ASSERT_EQ(old_registration
, new_registration
);
334 scoped_refptr
<ServiceWorkerRegistration
> new_registration_by_pattern
;
335 storage()->FindRegistrationForPattern(
337 SaveFoundRegistration(
338 SERVICE_WORKER_OK
, &called
, &new_registration
));
340 ASSERT_FALSE(called
);
341 base::RunLoop().RunUntilIdle();
344 ASSERT_NE(new_registration_by_pattern
, old_registration
);
347 // Make sure that when registering a duplicate pattern+script_url
348 // combination, that the same registration is used.
349 TEST_F(ServiceWorkerJobTest
, RegisterDuplicateScript
) {
350 GURL
pattern("http://www.example.com/");
351 GURL
script_url("http://www.example.com/service_worker.js");
354 scoped_refptr
<ServiceWorkerRegistration
> old_registration
;
355 job_coordinator()->Register(
359 SaveRegistration(SERVICE_WORKER_OK
, &called
, &old_registration
));
361 ASSERT_FALSE(called
);
362 base::RunLoop().RunUntilIdle();
365 scoped_refptr
<ServiceWorkerRegistration
> old_registration_by_pattern
;
366 storage()->FindRegistrationForPattern(
368 SaveFoundRegistration(
369 SERVICE_WORKER_OK
, &called
, &old_registration_by_pattern
));
370 ASSERT_FALSE(called
);
371 base::RunLoop().RunUntilIdle();
374 ASSERT_TRUE(old_registration_by_pattern
.get());
376 scoped_refptr
<ServiceWorkerRegistration
> new_registration
;
377 job_coordinator()->Register(
381 SaveRegistration(SERVICE_WORKER_OK
, &called
, &new_registration
));
383 ASSERT_FALSE(called
);
384 base::RunLoop().RunUntilIdle();
387 ASSERT_EQ(old_registration
, new_registration
);
389 ASSERT_FALSE(old_registration
->HasOneRef());
391 scoped_refptr
<ServiceWorkerRegistration
> new_registration_by_pattern
;
392 storage()->FindRegistrationForPattern(
394 SaveFoundRegistration(
395 SERVICE_WORKER_OK
, &called
, &new_registration_by_pattern
));
397 ASSERT_FALSE(called
);
398 base::RunLoop().RunUntilIdle();
401 ASSERT_EQ(new_registration
, old_registration
);
404 class FailToStartWorkerTestHelper
: public EmbeddedWorkerTestHelper
{
406 explicit FailToStartWorkerTestHelper(int mock_render_process_id
)
407 : EmbeddedWorkerTestHelper(mock_render_process_id
) {}
409 virtual void OnStartWorker(int embedded_worker_id
,
410 int64 service_worker_version_id
,
412 const GURL
& script_url
,
413 bool pause_after_download
) OVERRIDE
{
414 EmbeddedWorkerInstance
* worker
= registry()->GetWorker(embedded_worker_id
);
415 registry()->OnWorkerStopped(worker
->process_id(), embedded_worker_id
);
419 TEST_F(ServiceWorkerJobTest
, Register_FailToStartWorker
) {
420 helper_
.reset(new FailToStartWorkerTestHelper(render_process_id_
));
423 scoped_refptr
<ServiceWorkerRegistration
> registration
;
424 job_coordinator()->Register(
425 GURL("http://www.example.com/"),
426 GURL("http://www.example.com/service_worker.js"),
429 SERVICE_WORKER_ERROR_START_WORKER_FAILED
, &called
, ®istration
));
431 ASSERT_FALSE(called
);
432 base::RunLoop().RunUntilIdle();
435 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
438 // Register and then unregister the pattern, in parallel. Job coordinator should
439 // process jobs until the last job.
440 TEST_F(ServiceWorkerJobTest
, ParallelRegUnreg
) {
441 GURL
pattern("http://www.example.com/");
442 GURL
script_url("http://www.example.com/service_worker.js");
444 bool registration_called
= false;
445 scoped_refptr
<ServiceWorkerRegistration
> registration
;
446 job_coordinator()->Register(
450 SaveRegistration(SERVICE_WORKER_OK
, ®istration_called
, ®istration
));
452 bool unregistration_called
= false;
453 job_coordinator()->Unregister(
455 SaveUnregistration(SERVICE_WORKER_OK
, &unregistration_called
));
457 ASSERT_FALSE(registration_called
);
458 ASSERT_FALSE(unregistration_called
);
459 base::RunLoop().RunUntilIdle();
460 ASSERT_TRUE(registration_called
);
461 ASSERT_TRUE(unregistration_called
);
463 bool find_called
= false;
464 storage()->FindRegistrationForPattern(
466 SaveFoundRegistration(
467 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
469 base::RunLoop().RunUntilIdle();
471 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
474 // Register conflicting scripts for the same pattern. The most recent
475 // registration should win, and the old registration should have been
477 TEST_F(ServiceWorkerJobTest
, ParallelRegNewScript
) {
478 GURL
pattern("http://www.example.com/");
480 GURL
script_url1("http://www.example.com/service_worker1.js");
481 bool registration1_called
= false;
482 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
483 job_coordinator()->Register(
488 SERVICE_WORKER_OK
, ®istration1_called
, ®istration1
));
490 GURL
script_url2("http://www.example.com/service_worker2.js");
491 bool registration2_called
= false;
492 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
493 job_coordinator()->Register(
498 SERVICE_WORKER_OK
, ®istration2_called
, ®istration2
));
500 ASSERT_FALSE(registration1_called
);
501 ASSERT_FALSE(registration2_called
);
502 base::RunLoop().RunUntilIdle();
503 ASSERT_TRUE(registration1_called
);
504 ASSERT_TRUE(registration2_called
);
506 scoped_refptr
<ServiceWorkerRegistration
> registration
;
507 bool find_called
= false;
508 storage()->FindRegistrationForPattern(
510 SaveFoundRegistration(
511 SERVICE_WORKER_OK
, &find_called
, ®istration
));
513 base::RunLoop().RunUntilIdle();
515 ASSERT_EQ(registration2
, registration
);
518 // Register the exact same pattern + script. Requests should be
519 // coalesced such that both callers get the exact same registration
521 TEST_F(ServiceWorkerJobTest
, ParallelRegSameScript
) {
522 GURL
pattern("http://www.example.com/");
524 GURL
script_url("http://www.example.com/service_worker1.js");
525 bool registration1_called
= false;
526 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
527 job_coordinator()->Register(
532 SERVICE_WORKER_OK
, ®istration1_called
, ®istration1
));
534 bool registration2_called
= false;
535 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
536 job_coordinator()->Register(
541 SERVICE_WORKER_OK
, ®istration2_called
, ®istration2
));
543 ASSERT_FALSE(registration1_called
);
544 ASSERT_FALSE(registration2_called
);
545 base::RunLoop().RunUntilIdle();
546 ASSERT_TRUE(registration1_called
);
547 ASSERT_TRUE(registration2_called
);
549 ASSERT_EQ(registration1
, registration2
);
551 scoped_refptr
<ServiceWorkerRegistration
> registration
;
552 bool find_called
= false;
553 storage()->FindRegistrationForPattern(
555 SaveFoundRegistration(
556 SERVICE_WORKER_OK
, &find_called
, ®istration
));
558 base::RunLoop().RunUntilIdle();
559 ASSERT_EQ(registration
, registration1
);
562 // Call simulataneous unregister calls.
563 TEST_F(ServiceWorkerJobTest
, ParallelUnreg
) {
564 GURL
pattern("http://www.example.com/");
566 GURL
script_url("http://www.example.com/service_worker.js");
567 bool unregistration1_called
= false;
568 job_coordinator()->Unregister(
570 SaveUnregistration(SERVICE_WORKER_OK
, &unregistration1_called
));
572 bool unregistration2_called
= false;
573 job_coordinator()->Unregister(
574 pattern
, SaveUnregistration(SERVICE_WORKER_OK
, &unregistration2_called
));
576 ASSERT_FALSE(unregistration1_called
);
577 ASSERT_FALSE(unregistration2_called
);
578 base::RunLoop().RunUntilIdle();
579 ASSERT_TRUE(unregistration1_called
);
580 ASSERT_TRUE(unregistration2_called
);
582 // There isn't really a way to test that they are being coalesced,
583 // but we can make sure they can exist simultaneously without
585 scoped_refptr
<ServiceWorkerRegistration
> registration
;
586 bool find_called
= false;
587 storage()->FindRegistrationForPattern(
589 SaveFoundRegistration(
590 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
592 base::RunLoop().RunUntilIdle();
593 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
596 TEST_F(ServiceWorkerJobTest
, AbortAll_Register
) {
597 GURL
pattern1("http://www1.example.com/");
598 GURL
pattern2("http://www2.example.com/");
599 GURL
script_url1("http://www1.example.com/service_worker.js");
600 GURL
script_url2("http://www2.example.com/service_worker.js");
602 bool registration_called1
= false;
603 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
604 job_coordinator()->Register(
608 SaveRegistration(SERVICE_WORKER_ERROR_ABORT
,
609 ®istration_called1
, ®istration1
));
611 bool registration_called2
= false;
612 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
613 job_coordinator()->Register(
617 SaveRegistration(SERVICE_WORKER_ERROR_ABORT
,
618 ®istration_called2
, ®istration2
));
620 ASSERT_FALSE(registration_called1
);
621 ASSERT_FALSE(registration_called2
);
622 job_coordinator()->AbortAll();
624 base::RunLoop().RunUntilIdle();
625 ASSERT_TRUE(registration_called1
);
626 ASSERT_TRUE(registration_called2
);
628 bool find_called1
= false;
629 storage()->FindRegistrationForPattern(
631 SaveFoundRegistration(
632 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called1
, ®istration1
));
634 bool find_called2
= false;
635 storage()->FindRegistrationForPattern(
637 SaveFoundRegistration(
638 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called2
, ®istration2
));
640 base::RunLoop().RunUntilIdle();
641 ASSERT_TRUE(find_called1
);
642 ASSERT_TRUE(find_called2
);
643 EXPECT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration1
);
644 EXPECT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration2
);
647 TEST_F(ServiceWorkerJobTest
, AbortAll_Unregister
) {
648 GURL
pattern1("http://www1.example.com/");
649 GURL
pattern2("http://www2.example.com/");
651 bool unregistration_called1
= false;
652 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
653 job_coordinator()->Unregister(
655 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT
,
656 &unregistration_called1
));
658 bool unregistration_called2
= false;
659 job_coordinator()->Unregister(
661 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT
,
662 &unregistration_called2
));
664 ASSERT_FALSE(unregistration_called1
);
665 ASSERT_FALSE(unregistration_called2
);
666 job_coordinator()->AbortAll();
668 base::RunLoop().RunUntilIdle();
669 ASSERT_TRUE(unregistration_called1
);
670 ASSERT_TRUE(unregistration_called2
);
673 TEST_F(ServiceWorkerJobTest
, AbortAll_RegUnreg
) {
674 GURL
pattern("http://www.example.com/");
675 GURL
script_url("http://www.example.com/service_worker.js");
677 bool registration_called
= false;
678 scoped_refptr
<ServiceWorkerRegistration
> registration
;
679 job_coordinator()->Register(
683 SaveRegistration(SERVICE_WORKER_ERROR_ABORT
,
684 ®istration_called
, ®istration
));
686 bool unregistration_called
= false;
687 job_coordinator()->Unregister(
689 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT
,
690 &unregistration_called
));
692 ASSERT_FALSE(registration_called
);
693 ASSERT_FALSE(unregistration_called
);
694 job_coordinator()->AbortAll();
696 base::RunLoop().RunUntilIdle();
697 ASSERT_TRUE(registration_called
);
698 ASSERT_TRUE(unregistration_called
);
700 bool find_called
= false;
701 storage()->FindRegistrationForPattern(
703 SaveFoundRegistration(
704 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
706 base::RunLoop().RunUntilIdle();
707 ASSERT_TRUE(find_called
);
708 EXPECT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
711 // Tests that the waiting worker enters the 'redundant' state upon
713 TEST_F(ServiceWorkerJobTest
, UnregisterWaitingSetsRedundant
) {
714 scoped_refptr
<ServiceWorkerRegistration
> registration
;
716 GURL
script_url("http://www.example.com/service_worker.js");
717 job_coordinator()->Register(
718 GURL("http://www.example.com/"),
721 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
722 base::RunLoop().RunUntilIdle();
724 ASSERT_TRUE(registration
.get());
726 // Manually create the waiting worker since there is no way to become a
727 // waiting worker until Update is implemented.
728 scoped_refptr
<ServiceWorkerVersion
> version
= new ServiceWorkerVersion(
729 registration
.get(), script_url
, 1L, helper_
->context()->AsWeakPtr());
730 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
731 version
->StartWorker(CreateReceiverOnCurrentThread(&status
));
732 base::RunLoop().RunUntilIdle();
733 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
735 version
->SetStatus(ServiceWorkerVersion::INSTALLED
);
736 registration
->SetWaitingVersion(version
.get());
737 EXPECT_EQ(ServiceWorkerVersion::RUNNING
,
738 version
->running_status());
739 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
, version
->status());
742 job_coordinator()->Unregister(GURL("http://www.example.com/"),
743 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
744 base::RunLoop().RunUntilIdle();
747 // The version should be stopped since there is no controllee after
749 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version
->running_status());
750 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
, version
->status());
753 // Tests that the active worker enters the 'redundant' state upon
755 TEST_F(ServiceWorkerJobTest
, UnregisterActiveSetsRedundant
) {
756 scoped_refptr
<ServiceWorkerRegistration
> registration
;
758 job_coordinator()->Register(
759 GURL("http://www.example.com/"),
760 GURL("http://www.example.com/service_worker.js"),
762 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
763 base::RunLoop().RunUntilIdle();
765 ASSERT_TRUE(registration
.get());
767 scoped_refptr
<ServiceWorkerVersion
> version
= registration
->active_version();
768 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version
->running_status());
769 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
, version
->status());
772 job_coordinator()->Unregister(GURL("http://www.example.com/"),
773 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
774 base::RunLoop().RunUntilIdle();
777 // The version should be stopped since there is no controllee after
779 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version
->running_status());
780 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
, version
->status());
783 // Tests that the active worker enters the 'redundant' state upon
785 TEST_F(ServiceWorkerJobTest
,
786 UnregisterActiveSetsRedundant_WaitForNoControllee
) {
787 scoped_refptr
<ServiceWorkerRegistration
> registration
;
789 job_coordinator()->Register(
790 GURL("http://www.example.com/"),
791 GURL("http://www.example.com/service_worker.js"),
793 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
794 base::RunLoop().RunUntilIdle();
796 ASSERT_TRUE(registration
.get());
798 scoped_ptr
<ServiceWorkerProviderHost
> host(
799 new ServiceWorkerProviderHost(33 /* dummy render process 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 virtual ~UpdateJobTestHelper() {
899 if (registration_
.get())
900 registration_
->RemoveListener(this);
903 ServiceWorkerStorage
* storage() { return context()->storage(); }
904 ServiceWorkerJobCoordinator
* job_coordinator() {
905 return context()->job_coordinator();
908 scoped_refptr
<ServiceWorkerRegistration
> SetupInitialRegistration(
909 const GURL
& test_origin
) {
910 scoped_refptr
<ServiceWorkerRegistration
> registration
;
912 job_coordinator()->Register(
913 test_origin
.Resolve(kScope
),
914 test_origin
.Resolve(kScript
),
915 mock_render_process_id(),
916 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
917 base::RunLoop().RunUntilIdle();
919 EXPECT_TRUE(registration
.get());
920 EXPECT_TRUE(registration
->active_version());
921 EXPECT_FALSE(registration
->installing_version());
922 EXPECT_FALSE(registration
->waiting_version());
923 registration_
= registration
;
927 // EmbeddedWorkerTestHelper overrides
928 virtual void OnStartWorker(int embedded_worker_id
,
932 bool pause_after_download
) OVERRIDE
{
933 const std::string kMockScriptBody
= "mock_script";
934 ServiceWorkerVersion
* version
= context()->GetLiveVersion(version_id
);
935 ASSERT_TRUE(version
);
936 version
->AddListener(this);
938 if (!pause_after_download
) {
939 // Spoof caching the script for the initial version.
940 int64 resource_id
= storage()->NewResourceId();
941 version
->script_cache_map()->NotifyStartedCaching(script
, resource_id
);
942 WriteStringResponse(storage(), resource_id
, kMockScriptBody
);
943 version
->script_cache_map()->NotifyFinishedCaching(script
, true);
945 // Spoof caching the script for the new version.
946 int64 resource_id
= storage()->NewResourceId();
947 version
->script_cache_map()->NotifyStartedCaching(script
, resource_id
);
948 if (script
.GetOrigin() == kNoChangeOrigin
)
949 WriteStringResponse(storage(), resource_id
, kMockScriptBody
);
951 WriteStringResponse(storage(), resource_id
, "mock_different_script");
952 version
->script_cache_map()->NotifyFinishedCaching(script
, true);
954 EmbeddedWorkerTestHelper::OnStartWorker(
955 embedded_worker_id
, version_id
, scope
, script
, pause_after_download
);
958 // ServiceWorkerRegistration::Listener overrides
959 virtual void OnVersionAttributesChanged(
960 ServiceWorkerRegistration
* registration
,
961 ChangedVersionAttributesMask changed_mask
,
962 const ServiceWorkerRegistrationInfo
& info
) OVERRIDE
{
963 AttributeChangeLogEntry entry
;
964 entry
.registration_id
= registration
->id();
965 entry
.mask
= changed_mask
;
967 attribute_change_log_
.push_back(entry
);
970 virtual void OnRegistrationFailed(
971 ServiceWorkerRegistration
* registration
) OVERRIDE
{
975 // ServiceWorkerVersion::Listener overrides
976 virtual void OnVersionStateChanged(ServiceWorkerVersion
* version
) OVERRIDE
{
977 StateChangeLogEntry entry
;
978 entry
.version_id
= version
->version_id();
979 entry
.status
= version
->status();
980 state_change_log_
.push_back(entry
);
983 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
985 std::vector
<AttributeChangeLogEntry
> attribute_change_log_
;
986 std::vector
<StateChangeLogEntry
> state_change_log_
;
991 TEST_F(ServiceWorkerJobTest
, Update_NoChange
) {
992 UpdateJobTestHelper
* update_helper
=
993 new UpdateJobTestHelper(render_process_id_
);
994 helper_
.reset(update_helper
);
995 scoped_refptr
<ServiceWorkerRegistration
> registration
=
996 update_helper
->SetupInitialRegistration(kNoChangeOrigin
);
997 ASSERT_TRUE(registration
.get());
998 ASSERT_EQ(4u, update_helper
->state_change_log_
.size());
999 EXPECT_EQ(ServiceWorkerVersion::INSTALLING
,
1000 update_helper
->state_change_log_
[0].status
);
1001 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
,
1002 update_helper
->state_change_log_
[1].status
);
1003 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING
,
1004 update_helper
->state_change_log_
[2].status
);
1005 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
,
1006 update_helper
->state_change_log_
[3].status
);
1007 update_helper
->state_change_log_
.clear();
1009 // Run the update job.
1010 registration
->AddListener(update_helper
);
1011 scoped_refptr
<ServiceWorkerVersion
> first_version
=
1012 registration
->active_version();
1013 first_version
->StartUpdate();
1014 base::RunLoop().RunUntilIdle();
1017 ASSERT_TRUE(registration
->active_version());
1018 EXPECT_EQ(first_version
.get(), registration
->active_version());
1019 EXPECT_FALSE(registration
->installing_version());
1020 EXPECT_FALSE(registration
->waiting_version());
1021 EXPECT_TRUE(update_helper
->attribute_change_log_
.empty());
1022 ASSERT_EQ(1u, update_helper
->state_change_log_
.size());
1023 EXPECT_NE(registration
->active_version()->version_id(),
1024 update_helper
->state_change_log_
[0].version_id
);
1025 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
,
1026 update_helper
->state_change_log_
[0].status
);
1029 TEST_F(ServiceWorkerJobTest
, Update_NewVersion
) {
1030 UpdateJobTestHelper
* update_helper
=
1031 new UpdateJobTestHelper(render_process_id_
);
1032 helper_
.reset(update_helper
);
1033 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1034 update_helper
->SetupInitialRegistration(kNewVersionOrigin
);
1035 ASSERT_TRUE(registration
.get());
1036 update_helper
->state_change_log_
.clear();
1038 // Run the update job.
1039 registration
->AddListener(update_helper
);
1040 scoped_refptr
<ServiceWorkerVersion
> first_version
=
1041 registration
->active_version();
1042 first_version
->StartUpdate();
1043 base::RunLoop().RunUntilIdle();
1046 ASSERT_TRUE(registration
->active_version());
1047 EXPECT_NE(first_version
.get(), registration
->active_version());
1048 EXPECT_FALSE(registration
->installing_version());
1049 EXPECT_FALSE(registration
->waiting_version());
1050 ASSERT_EQ(3u, update_helper
->attribute_change_log_
.size());
1052 UpdateJobTestHelper::AttributeChangeLogEntry entry
;
1053 entry
= update_helper
->attribute_change_log_
[0];
1054 EXPECT_TRUE(entry
.mask
.installing_changed());
1055 EXPECT_FALSE(entry
.mask
.waiting_changed());
1056 EXPECT_FALSE(entry
.mask
.active_changed());
1057 EXPECT_FALSE(entry
.info
.installing_version
.is_null
);
1058 EXPECT_TRUE(entry
.info
.waiting_version
.is_null
);
1059 EXPECT_FALSE(entry
.info
.active_version
.is_null
);
1061 entry
= update_helper
->attribute_change_log_
[1];
1062 EXPECT_TRUE(entry
.mask
.installing_changed());
1063 EXPECT_TRUE(entry
.mask
.waiting_changed());
1064 EXPECT_FALSE(entry
.mask
.active_changed());
1065 EXPECT_TRUE(entry
.info
.installing_version
.is_null
);
1066 EXPECT_FALSE(entry
.info
.waiting_version
.is_null
);
1067 EXPECT_FALSE(entry
.info
.active_version
.is_null
);
1069 entry
= update_helper
->attribute_change_log_
[2];
1070 EXPECT_FALSE(entry
.mask
.installing_changed());
1071 EXPECT_TRUE(entry
.mask
.waiting_changed());
1072 EXPECT_TRUE(entry
.mask
.active_changed());
1073 EXPECT_TRUE(entry
.info
.installing_version
.is_null
);
1074 EXPECT_TRUE(entry
.info
.waiting_version
.is_null
);
1075 EXPECT_FALSE(entry
.info
.active_version
.is_null
);
1077 // expected version state transitions:
1078 // new.installing, new.installed,
1080 // new.activating, new.activated
1081 ASSERT_EQ(5u, update_helper
->state_change_log_
.size());
1083 EXPECT_EQ(registration
->active_version()->version_id(),
1084 update_helper
->state_change_log_
[0].version_id
);
1085 EXPECT_EQ(ServiceWorkerVersion::INSTALLING
,
1086 update_helper
->state_change_log_
[0].status
);
1088 EXPECT_EQ(registration
->active_version()->version_id(),
1089 update_helper
->state_change_log_
[1].version_id
);
1090 EXPECT_EQ(ServiceWorkerVersion::INSTALLED
,
1091 update_helper
->state_change_log_
[1].status
);
1093 EXPECT_EQ(first_version
->version_id(),
1094 update_helper
->state_change_log_
[2].version_id
);
1095 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
,
1096 update_helper
->state_change_log_
[2].status
);
1098 EXPECT_EQ(registration
->active_version()->version_id(),
1099 update_helper
->state_change_log_
[3].version_id
);
1100 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING
,
1101 update_helper
->state_change_log_
[3].status
);
1103 EXPECT_EQ(registration
->active_version()->version_id(),
1104 update_helper
->state_change_log_
[4].version_id
);
1105 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED
,
1106 update_helper
->state_change_log_
[4].status
);
1109 TEST_F(ServiceWorkerJobTest
, Update_NewestVersionChanged
) {
1111 scoped_refptr
<ServiceWorkerRegistration
> registration
;
1112 job_coordinator()->Register(
1113 GURL("http://www.example.com/one/"),
1114 GURL("http://www.example.com/service_worker.js"),
1116 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
1118 EXPECT_FALSE(called
);
1119 base::RunLoop().RunUntilIdle();
1120 EXPECT_TRUE(called
);
1121 ServiceWorkerVersion
* active_version
= registration
->active_version();
1123 // Queue an Update, it should abort when it starts and sees the new version.
1124 job_coordinator()->Update(registration
.get());
1126 // Add a waiting version with new script.
1127 scoped_refptr
<ServiceWorkerVersion
> version
=
1128 new ServiceWorkerVersion(registration
.get(),
1129 GURL("http://www.example.com/new_worker.js"),
1130 2L /* dummy version id */,
1131 helper_
->context()->AsWeakPtr());
1132 registration
->SetWaitingVersion(version
.get());
1134 base::RunLoop().RunUntilIdle();
1136 // Verify the registration was not modified by the Update.
1137 EXPECT_EQ(active_version
, registration
->active_version());
1138 EXPECT_EQ(version
.get(), registration
->waiting_version());
1139 EXPECT_EQ(NULL
, registration
->installing_version());
1142 TEST_F(ServiceWorkerJobTest
, Update_UninstallingRegistration
) {
1144 scoped_refptr
<ServiceWorkerRegistration
> registration
;
1145 job_coordinator()->Register(
1146 GURL("http://www.example.com/one/"),
1147 GURL("http://www.example.com/service_worker.js"),
1149 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
1151 EXPECT_FALSE(called
);
1152 base::RunLoop().RunUntilIdle();
1153 EXPECT_TRUE(called
);
1155 // Add a controllee and queue an unregister to force the uninstalling state.
1156 scoped_ptr
<ServiceWorkerProviderHost
> host(
1157 new ServiceWorkerProviderHost(33 /* dummy render_process id */,
1158 1 /* dummy provider_id */,
1159 helper_
->context()->AsWeakPtr(),
1161 ServiceWorkerVersion
* active_version
= registration
->active_version();
1162 active_version
->AddControllee(host
.get());
1163 job_coordinator()->Unregister(GURL("http://www.example.com/one/"),
1164 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
1166 // Update should abort after it starts and sees uninstalling.
1167 job_coordinator()->Update(registration
.get());
1169 EXPECT_FALSE(called
);
1170 base::RunLoop().RunUntilIdle();
1171 EXPECT_TRUE(called
);
1173 // Verify the registration was not modified by the Update.
1174 EXPECT_TRUE(registration
->is_uninstalling());
1175 EXPECT_EQ(active_version
, registration
->active_version());
1176 EXPECT_EQ(NULL
, registration
->waiting_version());
1177 EXPECT_EQ(NULL
, registration
->installing_version());
1180 } // namespace content