Make ServiceWorkerProviderHost aware of the render_frame_id if any.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_job_unittest.cc
blob62e75418add8212cdefcea8ae9b983a4e13f75c3
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"
25 using net::IOBuffer;
26 using net::TestCompletionCallback;
27 using net::WrappedIOBuffer;
29 // Unit tests for testing all job registration tasks.
30 namespace content {
32 namespace {
34 int kMockRenderProcessId = 88;
36 void SaveRegistrationCallback(
37 ServiceWorkerStatusCode expected_status,
38 bool* called,
39 scoped_refptr<ServiceWorkerRegistration>* registration_out,
40 ServiceWorkerStatusCode status,
41 ServiceWorkerRegistration* registration) {
42 EXPECT_EQ(expected_status, status);
43 *called = true;
44 *registration_out = registration;
47 void SaveFoundRegistrationCallback(
48 ServiceWorkerStatusCode expected_status,
49 bool* called,
50 scoped_refptr<ServiceWorkerRegistration>* registration,
51 ServiceWorkerStatusCode status,
52 const scoped_refptr<ServiceWorkerRegistration>& result) {
53 EXPECT_EQ(expected_status, status);
54 *called = true;
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
62 // isn't called.
63 ServiceWorkerRegisterJob::RegistrationCallback SaveRegistration(
64 ServiceWorkerStatusCode expected_status,
65 bool* called,
66 scoped_refptr<ServiceWorkerRegistration>* registration) {
67 *called = false;
68 return base::Bind(
69 &SaveRegistrationCallback, expected_status, called, registration);
72 ServiceWorkerStorage::FindRegistrationCallback SaveFoundRegistration(
73 ServiceWorkerStatusCode expected_status,
74 bool* called,
75 scoped_refptr<ServiceWorkerRegistration>* registration) {
76 *called = false;
77 return base::Bind(&SaveFoundRegistrationCallback,
78 expected_status,
79 called,
80 registration);
83 void SaveUnregistrationCallback(ServiceWorkerStatusCode expected_status,
84 bool* called,
85 ServiceWorkerStatusCode status) {
86 EXPECT_EQ(expected_status, status);
87 *called = true;
90 ServiceWorkerUnregisterJob::UnregistrationCallback SaveUnregistration(
91 ServiceWorkerStatusCode expected_status,
92 bool* called) {
93 *called = false;
94 return base::Bind(&SaveUnregistrationCallback, expected_status, called);
97 } // namespace
99 class ServiceWorkerJobTest : public testing::Test {
100 public:
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(); }
118 protected:
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;
126 bool called;
127 job_coordinator()->Register(
128 GURL("http://www.example.com/"),
129 GURL("http://www.example.com/service_worker.js"),
130 NULL,
131 SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
132 EXPECT_FALSE(called);
133 base::RunLoop().RunUntilIdle();
134 EXPECT_TRUE(called);
136 scoped_refptr<ServiceWorkerRegistration> registration1;
137 storage()->FindRegistrationForDocument(
138 GURL("http://www.example.com/"),
139 SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration1));
140 scoped_refptr<ServiceWorkerRegistration> registration2;
141 storage()->FindRegistrationForDocument(
142 GURL("http://www.example.com/"),
143 SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration2));
144 base::RunLoop().RunUntilIdle();
145 EXPECT_TRUE(called);
146 ASSERT_TRUE(registration1.get());
147 ASSERT_EQ(registration1, original_registration);
148 ASSERT_EQ(registration1, registration2);
151 TEST_F(ServiceWorkerJobTest, SameMatchSameRegistration) {
152 bool called;
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"),
157 NULL,
158 SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
159 EXPECT_FALSE(called);
160 base::RunLoop().RunUntilIdle();
161 EXPECT_TRUE(called);
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, &registration1));
169 base::RunLoop().RunUntilIdle();
170 EXPECT_TRUE(called);
172 scoped_refptr<ServiceWorkerRegistration> registration2;
173 storage()->FindRegistrationForDocument(
174 GURL("http://www.example.com/two"),
175 SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration2));
176 base::RunLoop().RunUntilIdle();
177 EXPECT_TRUE(called);
178 ASSERT_EQ(registration1, original_registration);
179 ASSERT_EQ(registration1, registration2);
182 TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) {
183 bool called1;
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"),
188 NULL,
189 SaveRegistration(SERVICE_WORKER_OK, &called1, &original_registration1));
191 bool called2;
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"),
196 NULL,
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, &registration1));
209 scoped_refptr<ServiceWorkerRegistration> registration2;
210 storage()->FindRegistrationForDocument(
211 GURL("http://www.example.com/two/"),
212 SaveFoundRegistration(SERVICE_WORKER_OK, &called2, &registration2));
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) {
222 bool called = false;
223 scoped_refptr<ServiceWorkerRegistration> registration;
224 job_coordinator()->Register(
225 GURL("http://www.example.com/"),
226 GURL("http://www.example.com/service_worker.js"),
227 NULL,
228 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
230 ASSERT_FALSE(called);
231 base::RunLoop().RunUntilIdle();
232 ASSERT_TRUE(called);
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/");
241 bool called;
242 scoped_refptr<ServiceWorkerRegistration> registration;
243 job_coordinator()->Register(
244 pattern,
245 GURL("http://www.example.com/service_worker.js"),
246 NULL,
247 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
249 ASSERT_FALSE(called);
250 base::RunLoop().RunUntilIdle();
251 ASSERT_TRUE(called);
253 job_coordinator()->Unregister(pattern,
254 SaveUnregistration(SERVICE_WORKER_OK, &called));
256 ASSERT_FALSE(called);
257 base::RunLoop().RunUntilIdle();
258 ASSERT_TRUE(called);
260 ASSERT_TRUE(registration->HasOneRef());
262 storage()->FindRegistrationForPattern(
263 pattern,
264 SaveFoundRegistration(SERVICE_WORKER_ERROR_NOT_FOUND,
265 &called, &registration));
267 ASSERT_FALSE(called);
268 base::RunLoop().RunUntilIdle();
269 ASSERT_TRUE(called);
271 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
274 TEST_F(ServiceWorkerJobTest, Unregister_NothingRegistered) {
275 GURL pattern("http://www.example.com/");
277 bool called;
278 job_coordinator()->Unregister(
279 pattern,
280 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND, &called));
282 ASSERT_FALSE(called);
283 base::RunLoop().RunUntilIdle();
284 ASSERT_TRUE(called);
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/");
292 bool called;
293 scoped_refptr<ServiceWorkerRegistration> old_registration;
294 job_coordinator()->Register(
295 pattern,
296 GURL("http://www.example.com/service_worker.js"),
297 NULL,
298 SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
300 ASSERT_FALSE(called);
301 base::RunLoop().RunUntilIdle();
302 ASSERT_TRUE(called);
304 scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern;
305 storage()->FindRegistrationForPattern(
306 pattern,
307 SaveFoundRegistration(
308 SERVICE_WORKER_OK, &called, &old_registration_by_pattern));
310 ASSERT_FALSE(called);
311 base::RunLoop().RunUntilIdle();
312 ASSERT_TRUE(called);
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(
319 pattern,
320 GURL("http://www.example.com/service_worker_new.js"),
321 NULL,
322 SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
324 ASSERT_FALSE(called);
325 base::RunLoop().RunUntilIdle();
326 ASSERT_TRUE(called);
328 ASSERT_EQ(old_registration, new_registration);
330 scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern;
331 storage()->FindRegistrationForPattern(
332 pattern,
333 SaveFoundRegistration(
334 SERVICE_WORKER_OK, &called, &new_registration));
336 ASSERT_FALSE(called);
337 base::RunLoop().RunUntilIdle();
338 ASSERT_TRUE(called);
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");
349 bool called;
350 scoped_refptr<ServiceWorkerRegistration> old_registration;
351 job_coordinator()->Register(
352 pattern,
353 script_url,
354 NULL,
355 SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
357 ASSERT_FALSE(called);
358 base::RunLoop().RunUntilIdle();
359 ASSERT_TRUE(called);
361 scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern;
362 storage()->FindRegistrationForPattern(
363 pattern,
364 SaveFoundRegistration(
365 SERVICE_WORKER_OK, &called, &old_registration_by_pattern));
366 ASSERT_FALSE(called);
367 base::RunLoop().RunUntilIdle();
368 ASSERT_TRUE(called);
370 ASSERT_TRUE(old_registration_by_pattern.get());
372 scoped_refptr<ServiceWorkerRegistration> new_registration;
373 job_coordinator()->Register(
374 pattern,
375 script_url,
376 NULL,
377 SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
379 ASSERT_FALSE(called);
380 base::RunLoop().RunUntilIdle();
381 ASSERT_TRUE(called);
383 ASSERT_EQ(old_registration, new_registration);
385 ASSERT_FALSE(old_registration->HasOneRef());
387 scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern;
388 storage()->FindRegistrationForPattern(
389 pattern,
390 SaveFoundRegistration(
391 SERVICE_WORKER_OK, &called, &new_registration_by_pattern));
393 ASSERT_FALSE(called);
394 base::RunLoop().RunUntilIdle();
395 ASSERT_TRUE(called);
397 ASSERT_EQ(new_registration, old_registration);
400 class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
401 public:
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,
407 const GURL& scope,
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_));
418 bool called = false;
419 scoped_refptr<ServiceWorkerRegistration> registration;
420 job_coordinator()->Register(
421 GURL("http://www.example.com/"),
422 GURL("http://www.example.com/service_worker.js"),
423 NULL,
424 SaveRegistration(
425 SERVICE_WORKER_ERROR_START_WORKER_FAILED, &called, &registration));
427 ASSERT_FALSE(called);
428 base::RunLoop().RunUntilIdle();
430 ASSERT_TRUE(called);
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(
443 pattern,
444 script_url,
445 NULL,
446 SaveRegistration(SERVICE_WORKER_OK, &registration_called, &registration));
448 bool unregistration_called = false;
449 job_coordinator()->Unregister(
450 pattern,
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(
461 pattern,
462 SaveFoundRegistration(
463 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
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
472 // shutdown.
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(
480 pattern,
481 script_url1,
482 NULL,
483 SaveRegistration(
484 SERVICE_WORKER_OK, &registration1_called, &registration1));
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(
490 pattern,
491 script_url2,
492 NULL,
493 SaveRegistration(
494 SERVICE_WORKER_OK, &registration2_called, &registration2));
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(
505 pattern,
506 SaveFoundRegistration(
507 SERVICE_WORKER_OK, &find_called, &registration));
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
516 // object.
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(
524 pattern,
525 script_url,
526 NULL,
527 SaveRegistration(
528 SERVICE_WORKER_OK, &registration1_called, &registration1));
530 bool registration2_called = false;
531 scoped_refptr<ServiceWorkerRegistration> registration2;
532 job_coordinator()->Register(
533 pattern,
534 script_url,
535 NULL,
536 SaveRegistration(
537 SERVICE_WORKER_OK, &registration2_called, &registration2));
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(
550 pattern,
551 SaveFoundRegistration(
552 SERVICE_WORKER_OK, &find_called, &registration));
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(
565 pattern,
566 SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND,
567 &unregistration1_called));
569 bool unregistration2_called = false;
570 job_coordinator()->Unregister(
571 pattern,
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
583 // crashing.
584 scoped_refptr<ServiceWorkerRegistration> registration;
585 bool find_called = false;
586 storage()->FindRegistrationForPattern(
587 pattern,
588 SaveFoundRegistration(
589 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
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(
604 pattern1,
605 script_url1,
606 NULL,
607 SaveRegistration(SERVICE_WORKER_ERROR_ABORT,
608 &registration_called1, &registration1));
610 bool registration_called2 = false;
611 scoped_refptr<ServiceWorkerRegistration> registration2;
612 job_coordinator()->Register(
613 pattern2,
614 script_url2,
615 NULL,
616 SaveRegistration(SERVICE_WORKER_ERROR_ABORT,
617 &registration_called2, &registration2));
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(
629 pattern1,
630 SaveFoundRegistration(
631 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called1, &registration1));
633 bool find_called2 = false;
634 storage()->FindRegistrationForPattern(
635 pattern2,
636 SaveFoundRegistration(
637 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called2, &registration2));
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(
653 pattern1,
654 SaveUnregistration(SERVICE_WORKER_ERROR_ABORT,
655 &unregistration_called1));
657 bool unregistration_called2 = false;
658 job_coordinator()->Unregister(
659 pattern2,
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(
679 pattern,
680 script_url,
681 NULL,
682 SaveRegistration(SERVICE_WORKER_ERROR_ABORT,
683 &registration_called, &registration));
685 bool unregistration_called = false;
686 job_coordinator()->Unregister(
687 pattern,
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(
701 pattern,
702 SaveFoundRegistration(
703 SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
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
711 // unregistration.
712 TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) {
713 scoped_refptr<ServiceWorkerRegistration> registration;
714 bool called = false;
715 GURL script_url("http://www.example.com/service_worker.js");
716 job_coordinator()->Register(
717 GURL("http://www.example.com/"),
718 script_url,
719 NULL,
720 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
721 base::RunLoop().RunUntilIdle();
722 ASSERT_TRUE(called);
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());
740 called = false;
741 job_coordinator()->Unregister(GURL("http://www.example.com/"),
742 SaveUnregistration(SERVICE_WORKER_OK, &called));
743 base::RunLoop().RunUntilIdle();
744 ASSERT_TRUE(called);
746 // The version should be stopped since there is no controllee after
747 // unregistration.
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
753 // unregistration.
754 TEST_F(ServiceWorkerJobTest, UnregisterActiveSetsRedundant) {
755 scoped_refptr<ServiceWorkerRegistration> registration;
756 bool called = false;
757 job_coordinator()->Register(
758 GURL("http://www.example.com/"),
759 GURL("http://www.example.com/service_worker.js"),
760 NULL,
761 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
762 base::RunLoop().RunUntilIdle();
763 ASSERT_TRUE(called);
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());
770 called = false;
771 job_coordinator()->Unregister(GURL("http://www.example.com/"),
772 SaveUnregistration(SERVICE_WORKER_OK, &called));
773 base::RunLoop().RunUntilIdle();
774 ASSERT_TRUE(called);
776 // The version should be stopped since there is no controllee after
777 // unregistration.
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
783 // unregistration.
784 TEST_F(ServiceWorkerJobTest,
785 UnregisterActiveSetsRedundant_WaitForNoControllee) {
786 scoped_refptr<ServiceWorkerRegistration> registration;
787 bool called = false;
788 job_coordinator()->Register(
789 GURL("http://www.example.com/"),
790 GURL("http://www.example.com/service_worker.js"),
791 NULL,
792 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
793 base::RunLoop().RunUntilIdle();
794 ASSERT_TRUE(called);
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(),
802 NULL));
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());
809 called = false;
810 job_coordinator()->Unregister(GURL("http://www.example.com/"),
811 SaveUnregistration(SERVICE_WORKER_OK, &called));
812 base::RunLoop().RunUntilIdle();
813 ASSERT_TRUE(called);
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) {
841 *rv_out = rv;
844 void WriteResponse(
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());
859 int rv = -1234;
860 writer->WriteInfo(info_buffer.get(), base::Bind(&OnIOComplete, &rv));
861 RunNestedUntilIdle();
862 EXPECT_LT(0, rv);
864 rv = -1234;
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 {
884 public:
885 struct AttributeChangeLogEntry {
886 int64 registration_id;
887 ChangedVersionAttributesMask mask;
888 ServiceWorkerRegistrationInfo info;
891 struct StateChangeLogEntry {
892 int64 version_id;
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;
912 bool called = false;
913 job_coordinator()->Register(
914 test_origin.Resolve(kScope),
915 test_origin.Resolve(kScript),
916 NULL,
917 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
918 base::RunLoop().RunUntilIdle();
919 EXPECT_TRUE(called);
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;
925 return registration;
928 // EmbeddedWorkerTestHelper overrides
929 void OnStartWorker(int embedded_worker_id,
930 int64 version_id,
931 const GURL& scope,
932 const GURL& script,
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());
947 } else {
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);
953 else
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;
970 entry.info = info;
971 attribute_change_log_.push_back(entry);
974 void OnRegistrationFailed(ServiceWorkerRegistration* registration) override {
975 NOTREACHED();
978 void OnRegistrationFinishedUninstalling(
979 ServiceWorkerRegistration* registration) override {
980 NOTREACHED();
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_;
1000 bool update_found_;
1003 } // namespace
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();
1030 // Verify results.
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();
1060 // Verify results.
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,
1103 // old.redundant,
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) {
1136 bool called;
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"),
1141 NULL,
1142 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
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) {
1169 bool called;
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"),
1174 NULL,
1175 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
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(),
1187 NULL));
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