Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_job_unittest.cc
blob515e0f82fdc896a1a2099d7b16e9dc2a5d738187
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 1 /* dummy provider_id */,
800 context()->AsWeakPtr(),
801 NULL));
802 registration->active_version()->AddControllee(host.get());
804 scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
805 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status());
806 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
808 called = false;
809 job_coordinator()->Unregister(GURL("http://www.example.com/"),
810 SaveUnregistration(SERVICE_WORKER_OK, &called));
811 base::RunLoop().RunUntilIdle();
812 ASSERT_TRUE(called);
814 // The version should be running since there is still a controllee.
815 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status());
816 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
818 registration->active_version()->RemoveControllee(host.get());
819 base::RunLoop().RunUntilIdle();
821 // The version should be stopped since there is no controllee.
822 EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status());
823 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
826 namespace { // Helpers for the update job tests.
828 const GURL kNoChangeOrigin("http://nochange/");
829 const GURL kNewVersionOrigin("http://newversion/");
830 const std::string kScope("scope/");
831 const std::string kScript("script.js");
833 void RunNestedUntilIdle() {
834 base::MessageLoop::ScopedNestableTaskAllower allow(
835 base::MessageLoop::current());
836 base::MessageLoop::current()->RunUntilIdle();
839 void OnIOComplete(int* rv_out, int rv) {
840 *rv_out = rv;
843 void WriteResponse(
844 ServiceWorkerStorage* storage, int64 id,
845 const std::string& headers,
846 IOBuffer* body, int length) {
847 scoped_ptr<ServiceWorkerResponseWriter> writer =
848 storage->CreateResponseWriter(id);
850 scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
851 info->request_time = base::Time::Now();
852 info->response_time = base::Time::Now();
853 info->was_cached = false;
854 info->headers = new net::HttpResponseHeaders(headers);
855 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
856 new HttpResponseInfoIOBuffer(info.release());
858 int rv = -1234;
859 writer->WriteInfo(info_buffer.get(), base::Bind(&OnIOComplete, &rv));
860 RunNestedUntilIdle();
861 EXPECT_LT(0, rv);
863 rv = -1234;
864 writer->WriteData(body, length,
865 base::Bind(&OnIOComplete, &rv));
866 RunNestedUntilIdle();
867 EXPECT_EQ(length, rv);
870 void WriteStringResponse(
871 ServiceWorkerStorage* storage, int64 id,
872 const std::string& body) {
873 scoped_refptr<IOBuffer> body_buffer(new WrappedIOBuffer(body.data()));
874 const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0";
875 std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
876 WriteResponse(storage, id, headers, body_buffer.get(), body.length());
879 class UpdateJobTestHelper
880 : public EmbeddedWorkerTestHelper,
881 public ServiceWorkerRegistration::Listener,
882 public ServiceWorkerVersion::Listener {
883 public:
884 struct AttributeChangeLogEntry {
885 int64 registration_id;
886 ChangedVersionAttributesMask mask;
887 ServiceWorkerRegistrationInfo info;
890 struct StateChangeLogEntry {
891 int64 version_id;
892 ServiceWorkerVersion::Status status;
895 UpdateJobTestHelper(int mock_render_process_id)
896 : EmbeddedWorkerTestHelper(mock_render_process_id),
897 update_found_(false) {}
898 ~UpdateJobTestHelper() override {
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;
911 bool called = false;
912 job_coordinator()->Register(
913 test_origin.Resolve(kScope),
914 test_origin.Resolve(kScript),
915 NULL,
916 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
917 base::RunLoop().RunUntilIdle();
918 EXPECT_TRUE(called);
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;
924 return registration;
927 // EmbeddedWorkerTestHelper overrides
928 void OnStartWorker(int embedded_worker_id,
929 int64 version_id,
930 const GURL& scope,
931 const GURL& script,
932 bool pause_after_download) override {
933 const std::string kMockScriptBody = "mock_script";
934 const uint64 kMockScriptSize = 19284;
935 ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
936 ASSERT_TRUE(version);
937 version->AddListener(this);
939 if (!pause_after_download) {
940 // Spoof caching the script for the initial version.
941 int64 resource_id = storage()->NewResourceId();
942 version->script_cache_map()->NotifyStartedCaching(script, resource_id);
943 WriteStringResponse(storage(), resource_id, kMockScriptBody);
944 version->script_cache_map()->NotifyFinishedCaching(
945 script, kMockScriptSize, net::URLRequestStatus());
946 } else {
947 // Spoof caching the script for the new version.
948 int64 resource_id = storage()->NewResourceId();
949 version->script_cache_map()->NotifyStartedCaching(script, resource_id);
950 if (script.GetOrigin() == kNoChangeOrigin)
951 WriteStringResponse(storage(), resource_id, kMockScriptBody);
952 else
953 WriteStringResponse(storage(), resource_id, "mock_different_script");
954 version->script_cache_map()->NotifyFinishedCaching(
955 script, kMockScriptSize, net::URLRequestStatus());
957 EmbeddedWorkerTestHelper::OnStartWorker(
958 embedded_worker_id, version_id, scope, script, pause_after_download);
961 // ServiceWorkerRegistration::Listener overrides
962 void OnVersionAttributesChanged(
963 ServiceWorkerRegistration* registration,
964 ChangedVersionAttributesMask changed_mask,
965 const ServiceWorkerRegistrationInfo& info) override {
966 AttributeChangeLogEntry entry;
967 entry.registration_id = registration->id();
968 entry.mask = changed_mask;
969 entry.info = info;
970 attribute_change_log_.push_back(entry);
973 void OnRegistrationFailed(ServiceWorkerRegistration* registration) override {
974 NOTREACHED();
977 void OnRegistrationFinishedUninstalling(
978 ServiceWorkerRegistration* registration) override {
979 NOTREACHED();
982 void OnUpdateFound(ServiceWorkerRegistration* registration) override {
983 ASSERT_FALSE(update_found_);
984 update_found_ = true;
987 // ServiceWorkerVersion::Listener overrides
988 void OnVersionStateChanged(ServiceWorkerVersion* version) override {
989 StateChangeLogEntry entry;
990 entry.version_id = version->version_id();
991 entry.status = version->status();
992 state_change_log_.push_back(entry);
995 scoped_refptr<ServiceWorkerRegistration> registration_;
997 std::vector<AttributeChangeLogEntry> attribute_change_log_;
998 std::vector<StateChangeLogEntry> state_change_log_;
999 bool update_found_;
1002 } // namespace
1004 TEST_F(ServiceWorkerJobTest, Update_NoChange) {
1005 UpdateJobTestHelper* update_helper =
1006 new UpdateJobTestHelper(render_process_id_);
1007 helper_.reset(update_helper);
1008 scoped_refptr<ServiceWorkerRegistration> registration =
1009 update_helper->SetupInitialRegistration(kNoChangeOrigin);
1010 ASSERT_TRUE(registration.get());
1011 ASSERT_EQ(4u, update_helper->state_change_log_.size());
1012 EXPECT_EQ(ServiceWorkerVersion::INSTALLING,
1013 update_helper->state_change_log_[0].status);
1014 EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
1015 update_helper->state_change_log_[1].status);
1016 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING,
1017 update_helper->state_change_log_[2].status);
1018 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
1019 update_helper->state_change_log_[3].status);
1020 update_helper->state_change_log_.clear();
1022 // Run the update job.
1023 registration->AddListener(update_helper);
1024 scoped_refptr<ServiceWorkerVersion> first_version =
1025 registration->active_version();
1026 first_version->StartUpdate();
1027 base::RunLoop().RunUntilIdle();
1029 // Verify results.
1030 ASSERT_TRUE(registration->active_version());
1031 EXPECT_EQ(first_version.get(), registration->active_version());
1032 EXPECT_FALSE(registration->installing_version());
1033 EXPECT_FALSE(registration->waiting_version());
1034 EXPECT_TRUE(update_helper->attribute_change_log_.empty());
1035 ASSERT_EQ(1u, update_helper->state_change_log_.size());
1036 EXPECT_NE(registration->active_version()->version_id(),
1037 update_helper->state_change_log_[0].version_id);
1038 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT,
1039 update_helper->state_change_log_[0].status);
1040 EXPECT_FALSE(update_helper->update_found_);
1043 TEST_F(ServiceWorkerJobTest, Update_NewVersion) {
1044 UpdateJobTestHelper* update_helper =
1045 new UpdateJobTestHelper(render_process_id_);
1046 helper_.reset(update_helper);
1047 scoped_refptr<ServiceWorkerRegistration> registration =
1048 update_helper->SetupInitialRegistration(kNewVersionOrigin);
1049 ASSERT_TRUE(registration.get());
1050 update_helper->state_change_log_.clear();
1052 // Run the update job.
1053 registration->AddListener(update_helper);
1054 scoped_refptr<ServiceWorkerVersion> first_version =
1055 registration->active_version();
1056 first_version->StartUpdate();
1057 base::RunLoop().RunUntilIdle();
1059 // Verify results.
1060 ASSERT_TRUE(registration->active_version());
1061 EXPECT_NE(first_version.get(), registration->active_version());
1062 EXPECT_FALSE(registration->installing_version());
1063 EXPECT_FALSE(registration->waiting_version());
1064 ASSERT_EQ(3u, update_helper->attribute_change_log_.size());
1066 UpdateJobTestHelper::AttributeChangeLogEntry entry;
1067 entry = update_helper->attribute_change_log_[0];
1068 EXPECT_TRUE(entry.mask.installing_changed());
1069 EXPECT_FALSE(entry.mask.waiting_changed());
1070 EXPECT_FALSE(entry.mask.active_changed());
1071 EXPECT_NE(entry.info.installing_version.version_id,
1072 kInvalidServiceWorkerVersionId);
1073 EXPECT_EQ(entry.info.waiting_version.version_id,
1074 kInvalidServiceWorkerVersionId);
1075 EXPECT_NE(entry.info.active_version.version_id,
1076 kInvalidServiceWorkerVersionId);
1078 entry = update_helper->attribute_change_log_[1];
1079 EXPECT_TRUE(entry.mask.installing_changed());
1080 EXPECT_TRUE(entry.mask.waiting_changed());
1081 EXPECT_FALSE(entry.mask.active_changed());
1082 EXPECT_EQ(entry.info.installing_version.version_id,
1083 kInvalidServiceWorkerVersionId);
1084 EXPECT_NE(entry.info.waiting_version.version_id,
1085 kInvalidServiceWorkerVersionId);
1086 EXPECT_NE(entry.info.active_version.version_id,
1087 kInvalidServiceWorkerVersionId);
1089 entry = update_helper->attribute_change_log_[2];
1090 EXPECT_FALSE(entry.mask.installing_changed());
1091 EXPECT_TRUE(entry.mask.waiting_changed());
1092 EXPECT_TRUE(entry.mask.active_changed());
1093 EXPECT_EQ(entry.info.installing_version.version_id,
1094 kInvalidServiceWorkerVersionId);
1095 EXPECT_EQ(entry.info.waiting_version.version_id,
1096 kInvalidServiceWorkerVersionId);
1097 EXPECT_NE(entry.info.active_version.version_id,
1098 kInvalidServiceWorkerVersionId);
1100 // expected version state transitions:
1101 // new.installing, new.installed,
1102 // old.redundant,
1103 // new.activating, new.activated
1104 ASSERT_EQ(5u, update_helper->state_change_log_.size());
1106 EXPECT_EQ(registration->active_version()->version_id(),
1107 update_helper->state_change_log_[0].version_id);
1108 EXPECT_EQ(ServiceWorkerVersion::INSTALLING,
1109 update_helper->state_change_log_[0].status);
1111 EXPECT_EQ(registration->active_version()->version_id(),
1112 update_helper->state_change_log_[1].version_id);
1113 EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
1114 update_helper->state_change_log_[1].status);
1116 EXPECT_EQ(first_version->version_id(),
1117 update_helper->state_change_log_[2].version_id);
1118 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT,
1119 update_helper->state_change_log_[2].status);
1121 EXPECT_EQ(registration->active_version()->version_id(),
1122 update_helper->state_change_log_[3].version_id);
1123 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING,
1124 update_helper->state_change_log_[3].status);
1126 EXPECT_EQ(registration->active_version()->version_id(),
1127 update_helper->state_change_log_[4].version_id);
1128 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
1129 update_helper->state_change_log_[4].status);
1131 EXPECT_TRUE(update_helper->update_found_);
1134 TEST_F(ServiceWorkerJobTest, Update_NewestVersionChanged) {
1135 bool called;
1136 scoped_refptr<ServiceWorkerRegistration> registration;
1137 job_coordinator()->Register(
1138 GURL("http://www.example.com/one/"),
1139 GURL("http://www.example.com/service_worker.js"),
1140 NULL,
1141 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
1143 EXPECT_FALSE(called);
1144 base::RunLoop().RunUntilIdle();
1145 EXPECT_TRUE(called);
1146 ServiceWorkerVersion* active_version = registration->active_version();
1148 // Queue an Update, it should abort when it starts and sees the new version.
1149 job_coordinator()->Update(registration.get());
1151 // Add a waiting version with new script.
1152 scoped_refptr<ServiceWorkerVersion> version =
1153 new ServiceWorkerVersion(registration.get(),
1154 GURL("http://www.example.com/new_worker.js"),
1155 2L /* dummy version id */,
1156 helper_->context()->AsWeakPtr());
1157 registration->SetWaitingVersion(version.get());
1159 base::RunLoop().RunUntilIdle();
1161 // Verify the registration was not modified by the Update.
1162 EXPECT_EQ(active_version, registration->active_version());
1163 EXPECT_EQ(version.get(), registration->waiting_version());
1164 EXPECT_EQ(NULL, registration->installing_version());
1167 TEST_F(ServiceWorkerJobTest, Update_UninstallingRegistration) {
1168 bool called;
1169 scoped_refptr<ServiceWorkerRegistration> registration;
1170 job_coordinator()->Register(
1171 GURL("http://www.example.com/one/"),
1172 GURL("http://www.example.com/service_worker.js"),
1173 NULL,
1174 SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
1176 EXPECT_FALSE(called);
1177 base::RunLoop().RunUntilIdle();
1178 EXPECT_TRUE(called);
1180 // Add a controllee and queue an unregister to force the uninstalling state.
1181 scoped_ptr<ServiceWorkerProviderHost> host(
1182 new ServiceWorkerProviderHost(33 /* dummy render_process id */,
1183 1 /* dummy provider_id */,
1184 helper_->context()->AsWeakPtr(),
1185 NULL));
1186 ServiceWorkerVersion* active_version = registration->active_version();
1187 active_version->AddControllee(host.get());
1188 job_coordinator()->Unregister(GURL("http://www.example.com/one/"),
1189 SaveUnregistration(SERVICE_WORKER_OK, &called));
1191 // Update should abort after it starts and sees uninstalling.
1192 job_coordinator()->Update(registration.get());
1194 EXPECT_FALSE(called);
1195 base::RunLoop().RunUntilIdle();
1196 EXPECT_TRUE(called);
1198 // Verify the registration was not modified by the Update.
1199 EXPECT_TRUE(registration->is_uninstalling());
1200 EXPECT_EQ(active_version, registration->active_version());
1201 EXPECT_EQ(NULL, registration->waiting_version());
1202 EXPECT_EQ(NULL, registration->installing_version());
1205 } // namespace content