1 // Copyright 2013 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 "content/public/browser/service_worker_context.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "content/browser/browser_thread_impl.h"
11 #include "content/browser/service_worker/embedded_worker_registry.h"
12 #include "content/browser/service_worker/embedded_worker_test_helper.h"
13 #include "content/browser/service_worker/service_worker_context_core.h"
14 #include "content/browser/service_worker/service_worker_context_observer.h"
15 #include "content/browser/service_worker/service_worker_context_wrapper.h"
16 #include "content/browser/service_worker/service_worker_registration.h"
17 #include "content/browser/service_worker/service_worker_storage.h"
18 #include "content/common/service_worker/embedded_worker_messages.h"
19 #include "content/common/service_worker/service_worker_messages.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "content/public/test/test_utils.h"
22 #include "testing/gtest/include/gtest/gtest.h"
28 void SaveResponseCallback(bool* called
,
29 int64
* store_registration_id
,
30 ServiceWorkerStatusCode status
,
31 int64 registration_id
) {
32 EXPECT_EQ(SERVICE_WORKER_OK
, status
) << ServiceWorkerStatusToString(status
);
34 *store_registration_id
= registration_id
;
37 ServiceWorkerContextCore::RegistrationCallback
MakeRegisteredCallback(
39 int64
* store_registration_id
) {
40 return base::Bind(&SaveResponseCallback
, called
, store_registration_id
);
43 void CallCompletedCallback(bool* called
, ServiceWorkerStatusCode
) {
47 ServiceWorkerContextCore::UnregistrationCallback
MakeUnregisteredCallback(
49 return base::Bind(&CallCompletedCallback
, called
);
52 void ExpectRegisteredWorkers(
53 ServiceWorkerStatusCode expect_status
,
56 ServiceWorkerStatusCode status
,
57 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
58 ASSERT_EQ(expect_status
, status
);
59 if (status
!= SERVICE_WORKER_OK
) {
60 EXPECT_FALSE(registration
.get());
65 EXPECT_TRUE(registration
->waiting_version());
67 EXPECT_FALSE(registration
->waiting_version());
71 EXPECT_TRUE(registration
->active_version());
73 EXPECT_FALSE(registration
->active_version());
77 class RejectInstallTestHelper
: public EmbeddedWorkerTestHelper
{
79 explicit RejectInstallTestHelper(int mock_render_process_id
)
80 : EmbeddedWorkerTestHelper(mock_render_process_id
) {}
82 void OnInstallEvent(int embedded_worker_id
,
84 int active_version_id
) override
{
86 new ServiceWorkerHostMsg_InstallEventFinished(
87 embedded_worker_id
, request_id
,
88 blink::WebServiceWorkerEventResultRejected
));
92 class RejectActivateTestHelper
: public EmbeddedWorkerTestHelper
{
94 explicit RejectActivateTestHelper(int mock_render_process_id
)
95 : EmbeddedWorkerTestHelper(mock_render_process_id
) {}
97 void OnActivateEvent(int embedded_worker_id
, int request_id
) override
{
99 new ServiceWorkerHostMsg_ActivateEventFinished(
100 embedded_worker_id
, request_id
,
101 blink::WebServiceWorkerEventResultRejected
));
105 enum NotificationType
{
107 REGISTRATION_DELETED
,
111 struct NotificationLog
{
112 NotificationType type
;
118 class ServiceWorkerContextTest
: public ServiceWorkerContextObserver
,
119 public testing::Test
{
121 ServiceWorkerContextTest()
122 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
123 render_process_id_(99) {}
125 void SetUp() override
{
126 helper_
.reset(new EmbeddedWorkerTestHelper(render_process_id_
));
127 helper_
->context_wrapper()->AddObserver(this);
130 void TearDown() override
{ helper_
.reset(); }
132 // ServiceWorkerContextObserver overrides.
133 void OnRegistrationStored(const GURL
& pattern
) override
{
135 log
.type
= REGISTRATION_STORED
;
136 log
.pattern
= pattern
;
137 notifications_
.push_back(log
);
139 void OnRegistrationDeleted(const GURL
& pattern
) override
{
141 log
.type
= REGISTRATION_DELETED
;
142 log
.pattern
= pattern
;
143 notifications_
.push_back(log
);
145 void OnStorageWiped() override
{
147 log
.type
= STORAGE_RECOVERED
;
148 notifications_
.push_back(log
);
151 ServiceWorkerContextCore
* context() { return helper_
->context(); }
154 TestBrowserThreadBundle browser_thread_bundle_
;
155 scoped_ptr
<EmbeddedWorkerTestHelper
> helper_
;
156 const int render_process_id_
;
157 std::vector
<NotificationLog
> notifications_
;
160 // Make sure basic registration is working.
161 TEST_F(ServiceWorkerContextTest
, Register
) {
162 GURL
pattern("http://www.example.com/");
163 GURL
script_url("http://www.example.com/service_worker.js");
165 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
167 context()->RegisterServiceWorker(
171 MakeRegisteredCallback(&called
, ®istration_id
));
173 ASSERT_FALSE(called
);
174 base::RunLoop().RunUntilIdle();
177 EXPECT_EQ(4UL, helper_
->ipc_sink()->message_count());
178 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
179 EmbeddedWorkerMsg_StartWorker::ID
));
180 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
181 ServiceWorkerMsg_InstallEvent::ID
));
182 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
183 ServiceWorkerMsg_ActivateEvent::ID
));
184 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
185 EmbeddedWorkerMsg_StopWorker::ID
));
186 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
188 context()->storage()->FindRegistrationForId(
191 base::Bind(&ExpectRegisteredWorkers
,
193 false /* expect_waiting */,
194 true /* expect_active */));
195 base::RunLoop().RunUntilIdle();
197 ASSERT_EQ(1u, notifications_
.size());
198 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
199 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
202 // Test registration when the service worker rejects the install event. The
203 // registration callback should indicate success, but there should be no waiting
204 // or active worker in the registration.
205 TEST_F(ServiceWorkerContextTest
, Register_RejectInstall
) {
206 GURL
pattern("http://www.example.com/");
207 GURL
script_url("http://www.example.com/service_worker.js");
209 helper_
.reset(); // Make sure the process lookups stay overridden.
210 helper_
.reset(new RejectInstallTestHelper(render_process_id_
));
211 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
213 context()->RegisterServiceWorker(
217 MakeRegisteredCallback(&called
, ®istration_id
));
219 ASSERT_FALSE(called
);
220 base::RunLoop().RunUntilIdle();
223 EXPECT_EQ(3UL, helper_
->ipc_sink()->message_count());
224 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
225 EmbeddedWorkerMsg_StartWorker::ID
));
226 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
227 ServiceWorkerMsg_InstallEvent::ID
));
228 EXPECT_FALSE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
229 ServiceWorkerMsg_ActivateEvent::ID
));
230 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
231 EmbeddedWorkerMsg_StopWorker::ID
));
232 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
234 context()->storage()->FindRegistrationForId(
237 base::Bind(&ExpectRegisteredWorkers
,
238 SERVICE_WORKER_ERROR_NOT_FOUND
,
239 false /* expect_waiting */,
240 false /* expect_active */));
241 base::RunLoop().RunUntilIdle();
243 EXPECT_TRUE(notifications_
.empty());
246 // Test registration when the service worker rejects the activate event. The
247 // registration callback should indicate success, but there should be no waiting
248 // or active worker in the registration.
249 TEST_F(ServiceWorkerContextTest
, Register_RejectActivate
) {
250 helper_
.reset(); // Make sure the process lookups stay overridden.
251 helper_
.reset(new RejectActivateTestHelper(render_process_id_
));
252 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
254 context()->RegisterServiceWorker(
255 GURL("http://www.example.com/"),
256 GURL("http://www.example.com/service_worker.js"),
258 MakeRegisteredCallback(&called
, ®istration_id
));
260 ASSERT_FALSE(called
);
261 base::RunLoop().RunUntilIdle();
264 EXPECT_EQ(4UL, helper_
->ipc_sink()->message_count());
265 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
266 EmbeddedWorkerMsg_StartWorker::ID
));
267 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
268 ServiceWorkerMsg_InstallEvent::ID
));
269 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
270 ServiceWorkerMsg_ActivateEvent::ID
));
271 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
272 EmbeddedWorkerMsg_StopWorker::ID
));
273 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
275 context()->storage()->FindRegistrationForId(
277 GURL("http://www.example.com"),
278 base::Bind(&ExpectRegisteredWorkers
,
279 SERVICE_WORKER_ERROR_NOT_FOUND
,
280 false /* expect_waiting */,
281 false /* expect_active */));
282 base::RunLoop().RunUntilIdle();
284 EXPECT_TRUE(notifications_
.empty());
287 // Make sure registrations are cleaned up when they are unregistered.
288 TEST_F(ServiceWorkerContextTest
, Unregister
) {
289 GURL
pattern("http://www.example.com/");
292 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
293 context()->RegisterServiceWorker(
295 GURL("http://www.example.com/service_worker.js"),
297 MakeRegisteredCallback(&called
, ®istration_id
));
299 ASSERT_FALSE(called
);
300 base::RunLoop().RunUntilIdle();
302 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
305 context()->UnregisterServiceWorker(pattern
,
306 MakeUnregisteredCallback(&called
));
308 ASSERT_FALSE(called
);
309 base::RunLoop().RunUntilIdle();
312 context()->storage()->FindRegistrationForId(
315 base::Bind(&ExpectRegisteredWorkers
,
316 SERVICE_WORKER_ERROR_NOT_FOUND
,
317 false /* expect_waiting */,
318 false /* expect_active */));
319 base::RunLoop().RunUntilIdle();
321 ASSERT_EQ(2u, notifications_
.size());
322 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
323 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
324 EXPECT_EQ(REGISTRATION_DELETED
, notifications_
[1].type
);
325 EXPECT_EQ(pattern
, notifications_
[1].pattern
);
328 // Make sure registrations are cleaned up when they are unregistered in bulk.
329 TEST_F(ServiceWorkerContextTest
, UnregisterMultiple
) {
330 GURL
origin1_p1("http://www.example.com/test");
331 GURL
origin1_p2("http://www.example.com/hello");
332 GURL
origin2_p1("http://www.example.com:8080/again");
333 GURL
origin3_p1("http://www.other.com/");
336 int64 registration_id1
= kInvalidServiceWorkerRegistrationId
;
337 int64 registration_id2
= kInvalidServiceWorkerRegistrationId
;
338 int64 registration_id3
= kInvalidServiceWorkerRegistrationId
;
339 int64 registration_id4
= kInvalidServiceWorkerRegistrationId
;
340 context()->RegisterServiceWorker(
342 GURL("http://www.example.com/service_worker.js"),
344 MakeRegisteredCallback(&called
, ®istration_id1
));
345 context()->RegisterServiceWorker(
347 GURL("http://www.example.com/service_worker2.js"),
349 MakeRegisteredCallback(&called
, ®istration_id2
));
350 context()->RegisterServiceWorker(
352 GURL("http://www.example.com:8080/service_worker3.js"),
354 MakeRegisteredCallback(&called
, ®istration_id3
));
355 context()->RegisterServiceWorker(
357 GURL("http://www.other.com/service_worker4.js"),
359 MakeRegisteredCallback(&called
, ®istration_id4
));
361 ASSERT_FALSE(called
);
362 base::RunLoop().RunUntilIdle();
365 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id1
);
366 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id2
);
367 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id3
);
368 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id4
);
371 context()->UnregisterServiceWorkers(origin1_p1
.GetOrigin(),
372 MakeUnregisteredCallback(&called
));
374 ASSERT_FALSE(called
);
375 base::RunLoop().RunUntilIdle();
378 context()->storage()->FindRegistrationForId(
380 origin1_p1
.GetOrigin(),
381 base::Bind(&ExpectRegisteredWorkers
,
382 SERVICE_WORKER_ERROR_NOT_FOUND
,
383 false /* expect_waiting */,
384 false /* expect_active */));
385 context()->storage()->FindRegistrationForId(
387 origin1_p2
.GetOrigin(),
388 base::Bind(&ExpectRegisteredWorkers
,
389 SERVICE_WORKER_ERROR_NOT_FOUND
,
390 false /* expect_waiting */,
391 false /* expect_active */));
392 context()->storage()->FindRegistrationForId(
394 origin2_p1
.GetOrigin(),
395 base::Bind(&ExpectRegisteredWorkers
,
397 false /* expect_waiting */,
398 true /* expect_active */));
400 context()->storage()->FindRegistrationForId(
402 origin3_p1
.GetOrigin(),
403 base::Bind(&ExpectRegisteredWorkers
,
405 false /* expect_waiting */,
406 true /* expect_active */));
408 base::RunLoop().RunUntilIdle();
410 ASSERT_EQ(6u, notifications_
.size());
411 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
412 EXPECT_EQ(origin1_p1
, notifications_
[0].pattern
);
413 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[1].type
);
414 EXPECT_EQ(origin1_p2
, notifications_
[1].pattern
);
415 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[2].type
);
416 EXPECT_EQ(origin2_p1
, notifications_
[2].pattern
);
417 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[3].type
);
418 EXPECT_EQ(origin3_p1
, notifications_
[3].pattern
);
419 EXPECT_EQ(REGISTRATION_DELETED
, notifications_
[4].type
);
420 EXPECT_EQ(origin1_p2
, notifications_
[4].pattern
);
421 EXPECT_EQ(REGISTRATION_DELETED
, notifications_
[5].type
);
422 EXPECT_EQ(origin1_p1
, notifications_
[5].pattern
);
425 // Make sure registering a new script shares an existing registration.
426 TEST_F(ServiceWorkerContextTest
, RegisterNewScript
) {
427 GURL
pattern("http://www.example.com/");
430 int64 old_registration_id
= kInvalidServiceWorkerRegistrationId
;
431 context()->RegisterServiceWorker(
433 GURL("http://www.example.com/service_worker.js"),
435 MakeRegisteredCallback(&called
, &old_registration_id
));
437 ASSERT_FALSE(called
);
438 base::RunLoop().RunUntilIdle();
440 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, old_registration_id
);
443 int64 new_registration_id
= kInvalidServiceWorkerRegistrationId
;
444 context()->RegisterServiceWorker(
446 GURL("http://www.example.com/service_worker_new.js"),
448 MakeRegisteredCallback(&called
, &new_registration_id
));
450 ASSERT_FALSE(called
);
451 base::RunLoop().RunUntilIdle();
454 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, new_registration_id
);
455 EXPECT_EQ(old_registration_id
, new_registration_id
);
457 ASSERT_EQ(2u, notifications_
.size());
458 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
459 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
460 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[1].type
);
461 EXPECT_EQ(pattern
, notifications_
[1].pattern
);
464 // Make sure that when registering a duplicate pattern+script_url
465 // combination, that the same registration is used.
466 TEST_F(ServiceWorkerContextTest
, RegisterDuplicateScript
) {
467 GURL
pattern("http://www.example.com/");
468 GURL
script_url("http://www.example.com/service_worker.js");
471 int64 old_registration_id
= kInvalidServiceWorkerRegistrationId
;
472 context()->RegisterServiceWorker(
476 MakeRegisteredCallback(&called
, &old_registration_id
));
478 ASSERT_FALSE(called
);
479 base::RunLoop().RunUntilIdle();
481 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, old_registration_id
);
484 int64 new_registration_id
= kInvalidServiceWorkerRegistrationId
;
485 context()->RegisterServiceWorker(
489 MakeRegisteredCallback(&called
, &new_registration_id
));
491 ASSERT_FALSE(called
);
492 base::RunLoop().RunUntilIdle();
494 EXPECT_EQ(old_registration_id
, new_registration_id
);
496 ASSERT_EQ(2u, notifications_
.size());
497 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
498 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
499 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[1].type
);
500 EXPECT_EQ(pattern
, notifications_
[1].pattern
);
503 // TODO(nhiroki): Test this for on-disk storage.
504 TEST_F(ServiceWorkerContextTest
, DeleteAndStartOver
) {
505 GURL
pattern("http://www.example.com/");
506 GURL
script_url("http://www.example.com/service_worker.js");
508 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
510 context()->RegisterServiceWorker(
514 MakeRegisteredCallback(&called
, ®istration_id
));
516 ASSERT_FALSE(called
);
517 base::RunLoop().RunUntilIdle();
520 context()->storage()->FindRegistrationForId(
523 base::Bind(&ExpectRegisteredWorkers
,
525 false /* expect_waiting */,
526 true /* expect_active */));
527 base::RunLoop().RunUntilIdle();
529 // Next handle ids should be 0 (the next call should return 1).
530 EXPECT_EQ(0, context()->GetNewServiceWorkerHandleId());
531 EXPECT_EQ(0, context()->GetNewRegistrationHandleId());
533 context()->ScheduleDeleteAndStartOver();
535 // The storage is disabled while the recovery process is running, so the
536 // operation should be failed.
537 context()->storage()->FindRegistrationForId(
540 base::Bind(&ExpectRegisteredWorkers
,
541 SERVICE_WORKER_ERROR_FAILED
,
542 false /* expect_waiting */,
543 true /* expect_active */));
544 base::RunLoop().RunUntilIdle();
546 // The context started over and the storage was re-initialized, so the
547 // registration should not be found.
548 context()->storage()->FindRegistrationForId(
551 base::Bind(&ExpectRegisteredWorkers
,
552 SERVICE_WORKER_ERROR_NOT_FOUND
,
553 false /* expect_waiting */,
554 true /* expect_active */));
555 base::RunLoop().RunUntilIdle();
558 context()->RegisterServiceWorker(
562 MakeRegisteredCallback(&called
, ®istration_id
));
564 ASSERT_FALSE(called
);
565 base::RunLoop().RunUntilIdle();
568 context()->storage()->FindRegistrationForId(
571 base::Bind(&ExpectRegisteredWorkers
,
573 false /* expect_waiting */,
574 true /* expect_active */));
575 base::RunLoop().RunUntilIdle();
577 // The new context should take over next handle ids.
578 EXPECT_EQ(1, context()->GetNewServiceWorkerHandleId());
579 EXPECT_EQ(1, context()->GetNewRegistrationHandleId());
581 ASSERT_EQ(3u, notifications_
.size());
582 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
583 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
584 EXPECT_EQ(STORAGE_RECOVERED
, notifications_
[1].type
);
585 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[2].type
);
586 EXPECT_EQ(pattern
, notifications_
[2].pattern
);
589 } // namespace content