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 const std::string
& status_message
,
32 int64 registration_id
) {
33 EXPECT_EQ(SERVICE_WORKER_OK
, status
) << ServiceWorkerStatusToString(status
);
35 *store_registration_id
= registration_id
;
38 ServiceWorkerContextCore::RegistrationCallback
MakeRegisteredCallback(
40 int64
* store_registration_id
) {
41 return base::Bind(&SaveResponseCallback
, called
, store_registration_id
);
44 void CallCompletedCallback(bool* called
, ServiceWorkerStatusCode
) {
48 ServiceWorkerContextCore::UnregistrationCallback
MakeUnregisteredCallback(
50 return base::Bind(&CallCompletedCallback
, called
);
53 void ExpectRegisteredWorkers(
54 ServiceWorkerStatusCode expect_status
,
57 ServiceWorkerStatusCode status
,
58 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
59 ASSERT_EQ(expect_status
, status
);
60 if (status
!= SERVICE_WORKER_OK
) {
61 EXPECT_FALSE(registration
.get());
66 EXPECT_TRUE(registration
->waiting_version());
68 EXPECT_FALSE(registration
->waiting_version());
72 EXPECT_TRUE(registration
->active_version());
74 EXPECT_FALSE(registration
->active_version());
78 class RejectInstallTestHelper
: public EmbeddedWorkerTestHelper
{
80 explicit RejectInstallTestHelper(int mock_render_process_id
)
81 : EmbeddedWorkerTestHelper(mock_render_process_id
) {}
83 void OnInstallEvent(int embedded_worker_id
,
85 int active_version_id
) override
{
87 new ServiceWorkerHostMsg_InstallEventFinished(
88 embedded_worker_id
, request_id
,
89 blink::WebServiceWorkerEventResultRejected
));
93 class RejectActivateTestHelper
: public EmbeddedWorkerTestHelper
{
95 explicit RejectActivateTestHelper(int mock_render_process_id
)
96 : EmbeddedWorkerTestHelper(mock_render_process_id
) {}
98 void OnActivateEvent(int embedded_worker_id
, int request_id
) override
{
100 new ServiceWorkerHostMsg_ActivateEventFinished(
101 embedded_worker_id
, request_id
,
102 blink::WebServiceWorkerEventResultRejected
));
106 enum NotificationType
{
108 REGISTRATION_DELETED
,
112 struct NotificationLog
{
113 NotificationType type
;
115 int64 registration_id
;
120 class ServiceWorkerContextTest
: public ServiceWorkerContextObserver
,
121 public testing::Test
{
123 ServiceWorkerContextTest()
124 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
125 render_process_id_(99) {}
127 void SetUp() override
{
128 helper_
.reset(new EmbeddedWorkerTestHelper(render_process_id_
));
129 helper_
->context_wrapper()->AddObserver(this);
132 void TearDown() override
{ helper_
.reset(); }
134 // ServiceWorkerContextObserver overrides.
135 void OnRegistrationStored(const GURL
& pattern
) override
{
137 log
.type
= REGISTRATION_STORED
;
138 log
.pattern
= pattern
;
139 notifications_
.push_back(log
);
141 void OnRegistrationDeleted(int64 registration_id
,
142 const GURL
& pattern
) override
{
144 log
.type
= REGISTRATION_DELETED
;
145 log
.pattern
= pattern
;
146 log
.registration_id
= registration_id
;
147 notifications_
.push_back(log
);
149 void OnStorageWiped() override
{
151 log
.type
= STORAGE_RECOVERED
;
152 notifications_
.push_back(log
);
155 ServiceWorkerContextCore
* context() { return helper_
->context(); }
158 TestBrowserThreadBundle browser_thread_bundle_
;
159 scoped_ptr
<EmbeddedWorkerTestHelper
> helper_
;
160 const int render_process_id_
;
161 std::vector
<NotificationLog
> notifications_
;
164 // Make sure basic registration is working.
165 TEST_F(ServiceWorkerContextTest
, Register
) {
166 GURL
pattern("http://www.example.com/");
167 GURL
script_url("http://www.example.com/service_worker.js");
169 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
171 context()->RegisterServiceWorker(
175 MakeRegisteredCallback(&called
, ®istration_id
));
177 ASSERT_FALSE(called
);
178 base::RunLoop().RunUntilIdle();
181 EXPECT_EQ(4UL, helper_
->ipc_sink()->message_count());
182 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
183 EmbeddedWorkerMsg_StartWorker::ID
));
184 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
185 ServiceWorkerMsg_InstallEvent::ID
));
186 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
187 ServiceWorkerMsg_ActivateEvent::ID
));
188 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
189 EmbeddedWorkerMsg_StopWorker::ID
));
190 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
192 context()->storage()->FindRegistrationForId(
195 base::Bind(&ExpectRegisteredWorkers
,
197 false /* expect_waiting */,
198 true /* expect_active */));
199 base::RunLoop().RunUntilIdle();
201 ASSERT_EQ(1u, notifications_
.size());
202 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
203 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
206 // Test registration when the service worker rejects the install event. The
207 // registration callback should indicate success, but there should be no waiting
208 // or active worker in the registration.
209 TEST_F(ServiceWorkerContextTest
, Register_RejectInstall
) {
210 GURL
pattern("http://www.example.com/");
211 GURL
script_url("http://www.example.com/service_worker.js");
213 helper_
.reset(); // Make sure the process lookups stay overridden.
214 helper_
.reset(new RejectInstallTestHelper(render_process_id_
));
215 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
217 context()->RegisterServiceWorker(
221 MakeRegisteredCallback(&called
, ®istration_id
));
223 ASSERT_FALSE(called
);
224 base::RunLoop().RunUntilIdle();
227 EXPECT_EQ(3UL, helper_
->ipc_sink()->message_count());
228 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
229 EmbeddedWorkerMsg_StartWorker::ID
));
230 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
231 ServiceWorkerMsg_InstallEvent::ID
));
232 EXPECT_FALSE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
233 ServiceWorkerMsg_ActivateEvent::ID
));
234 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
235 EmbeddedWorkerMsg_StopWorker::ID
));
236 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
238 context()->storage()->FindRegistrationForId(
241 base::Bind(&ExpectRegisteredWorkers
,
242 SERVICE_WORKER_ERROR_NOT_FOUND
,
243 false /* expect_waiting */,
244 false /* expect_active */));
245 base::RunLoop().RunUntilIdle();
247 EXPECT_TRUE(notifications_
.empty());
250 // Test registration when the service worker rejects the activate event. The
251 // registration callback should indicate success, but there should be no waiting
252 // or active worker in the registration.
253 TEST_F(ServiceWorkerContextTest
, Register_RejectActivate
) {
254 helper_
.reset(); // Make sure the process lookups stay overridden.
255 helper_
.reset(new RejectActivateTestHelper(render_process_id_
));
256 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
258 context()->RegisterServiceWorker(
259 GURL("http://www.example.com/"),
260 GURL("http://www.example.com/service_worker.js"),
262 MakeRegisteredCallback(&called
, ®istration_id
));
264 ASSERT_FALSE(called
);
265 base::RunLoop().RunUntilIdle();
268 EXPECT_EQ(4UL, helper_
->ipc_sink()->message_count());
269 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
270 EmbeddedWorkerMsg_StartWorker::ID
));
271 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
272 ServiceWorkerMsg_InstallEvent::ID
));
273 EXPECT_TRUE(helper_
->inner_ipc_sink()->GetUniqueMessageMatching(
274 ServiceWorkerMsg_ActivateEvent::ID
));
275 EXPECT_TRUE(helper_
->ipc_sink()->GetUniqueMessageMatching(
276 EmbeddedWorkerMsg_StopWorker::ID
));
277 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
279 context()->storage()->FindRegistrationForId(
281 GURL("http://www.example.com"),
282 base::Bind(&ExpectRegisteredWorkers
,
283 SERVICE_WORKER_ERROR_NOT_FOUND
,
284 false /* expect_waiting */,
285 false /* expect_active */));
286 base::RunLoop().RunUntilIdle();
288 EXPECT_TRUE(notifications_
.empty());
291 // Make sure registrations are cleaned up when they are unregistered.
292 TEST_F(ServiceWorkerContextTest
, Unregister
) {
293 GURL
pattern("http://www.example.com/");
296 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
297 context()->RegisterServiceWorker(
299 GURL("http://www.example.com/service_worker.js"),
301 MakeRegisteredCallback(&called
, ®istration_id
));
303 ASSERT_FALSE(called
);
304 base::RunLoop().RunUntilIdle();
306 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id
);
309 context()->UnregisterServiceWorker(pattern
,
310 MakeUnregisteredCallback(&called
));
312 ASSERT_FALSE(called
);
313 base::RunLoop().RunUntilIdle();
316 context()->storage()->FindRegistrationForId(
319 base::Bind(&ExpectRegisteredWorkers
,
320 SERVICE_WORKER_ERROR_NOT_FOUND
,
321 false /* expect_waiting */,
322 false /* expect_active */));
323 base::RunLoop().RunUntilIdle();
325 ASSERT_EQ(2u, notifications_
.size());
326 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
327 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
328 EXPECT_EQ(REGISTRATION_DELETED
, notifications_
[1].type
);
329 EXPECT_EQ(pattern
, notifications_
[1].pattern
);
330 EXPECT_EQ(registration_id
, notifications_
[1].registration_id
);
333 // Make sure registrations are cleaned up when they are unregistered in bulk.
334 TEST_F(ServiceWorkerContextTest
, UnregisterMultiple
) {
335 GURL
origin1_p1("http://www.example.com/test");
336 GURL
origin1_p2("http://www.example.com/hello");
337 GURL
origin2_p1("http://www.example.com:8080/again");
338 GURL
origin3_p1("http://www.other.com/");
341 int64 registration_id1
= kInvalidServiceWorkerRegistrationId
;
342 int64 registration_id2
= kInvalidServiceWorkerRegistrationId
;
343 int64 registration_id3
= kInvalidServiceWorkerRegistrationId
;
344 int64 registration_id4
= kInvalidServiceWorkerRegistrationId
;
345 context()->RegisterServiceWorker(
347 GURL("http://www.example.com/service_worker.js"),
349 MakeRegisteredCallback(&called
, ®istration_id1
));
350 context()->RegisterServiceWorker(
352 GURL("http://www.example.com/service_worker2.js"),
354 MakeRegisteredCallback(&called
, ®istration_id2
));
355 context()->RegisterServiceWorker(
357 GURL("http://www.example.com:8080/service_worker3.js"),
359 MakeRegisteredCallback(&called
, ®istration_id3
));
360 context()->RegisterServiceWorker(
362 GURL("http://www.other.com/service_worker4.js"),
364 MakeRegisteredCallback(&called
, ®istration_id4
));
366 ASSERT_FALSE(called
);
367 base::RunLoop().RunUntilIdle();
370 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id1
);
371 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id2
);
372 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id3
);
373 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, registration_id4
);
376 context()->UnregisterServiceWorkers(origin1_p1
.GetOrigin(),
377 MakeUnregisteredCallback(&called
));
379 ASSERT_FALSE(called
);
380 base::RunLoop().RunUntilIdle();
383 context()->storage()->FindRegistrationForId(
385 origin1_p1
.GetOrigin(),
386 base::Bind(&ExpectRegisteredWorkers
,
387 SERVICE_WORKER_ERROR_NOT_FOUND
,
388 false /* expect_waiting */,
389 false /* expect_active */));
390 context()->storage()->FindRegistrationForId(
392 origin1_p2
.GetOrigin(),
393 base::Bind(&ExpectRegisteredWorkers
,
394 SERVICE_WORKER_ERROR_NOT_FOUND
,
395 false /* expect_waiting */,
396 false /* expect_active */));
397 context()->storage()->FindRegistrationForId(
399 origin2_p1
.GetOrigin(),
400 base::Bind(&ExpectRegisteredWorkers
,
402 false /* expect_waiting */,
403 true /* expect_active */));
405 context()->storage()->FindRegistrationForId(
407 origin3_p1
.GetOrigin(),
408 base::Bind(&ExpectRegisteredWorkers
,
410 false /* expect_waiting */,
411 true /* expect_active */));
413 base::RunLoop().RunUntilIdle();
415 ASSERT_EQ(6u, notifications_
.size());
416 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
417 EXPECT_EQ(origin1_p1
, notifications_
[0].pattern
);
418 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[1].type
);
419 EXPECT_EQ(origin1_p2
, notifications_
[1].pattern
);
420 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[2].type
);
421 EXPECT_EQ(origin2_p1
, notifications_
[2].pattern
);
422 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[3].type
);
423 EXPECT_EQ(origin3_p1
, notifications_
[3].pattern
);
424 EXPECT_EQ(REGISTRATION_DELETED
, notifications_
[4].type
);
425 EXPECT_EQ(origin1_p2
, notifications_
[4].pattern
);
426 EXPECT_EQ(registration_id2
, notifications_
[4].registration_id
);
427 EXPECT_EQ(REGISTRATION_DELETED
, notifications_
[5].type
);
428 EXPECT_EQ(origin1_p1
, notifications_
[5].pattern
);
429 EXPECT_EQ(registration_id1
, notifications_
[5].registration_id
);
432 // Make sure registering a new script shares an existing registration.
433 TEST_F(ServiceWorkerContextTest
, RegisterNewScript
) {
434 GURL
pattern("http://www.example.com/");
437 int64 old_registration_id
= kInvalidServiceWorkerRegistrationId
;
438 context()->RegisterServiceWorker(
440 GURL("http://www.example.com/service_worker.js"),
442 MakeRegisteredCallback(&called
, &old_registration_id
));
444 ASSERT_FALSE(called
);
445 base::RunLoop().RunUntilIdle();
447 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, old_registration_id
);
450 int64 new_registration_id
= kInvalidServiceWorkerRegistrationId
;
451 context()->RegisterServiceWorker(
453 GURL("http://www.example.com/service_worker_new.js"),
455 MakeRegisteredCallback(&called
, &new_registration_id
));
457 ASSERT_FALSE(called
);
458 base::RunLoop().RunUntilIdle();
461 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, new_registration_id
);
462 EXPECT_EQ(old_registration_id
, new_registration_id
);
464 ASSERT_EQ(2u, notifications_
.size());
465 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
466 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
467 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[1].type
);
468 EXPECT_EQ(pattern
, notifications_
[1].pattern
);
471 // Make sure that when registering a duplicate pattern+script_url
472 // combination, that the same registration is used.
473 TEST_F(ServiceWorkerContextTest
, RegisterDuplicateScript
) {
474 GURL
pattern("http://www.example.com/");
475 GURL
script_url("http://www.example.com/service_worker.js");
478 int64 old_registration_id
= kInvalidServiceWorkerRegistrationId
;
479 context()->RegisterServiceWorker(
483 MakeRegisteredCallback(&called
, &old_registration_id
));
485 ASSERT_FALSE(called
);
486 base::RunLoop().RunUntilIdle();
488 EXPECT_NE(kInvalidServiceWorkerRegistrationId
, old_registration_id
);
491 int64 new_registration_id
= kInvalidServiceWorkerRegistrationId
;
492 context()->RegisterServiceWorker(
496 MakeRegisteredCallback(&called
, &new_registration_id
));
498 ASSERT_FALSE(called
);
499 base::RunLoop().RunUntilIdle();
501 EXPECT_EQ(old_registration_id
, new_registration_id
);
503 ASSERT_EQ(2u, notifications_
.size());
504 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
505 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
506 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[1].type
);
507 EXPECT_EQ(pattern
, notifications_
[1].pattern
);
510 // TODO(nhiroki): Test this for on-disk storage.
511 TEST_F(ServiceWorkerContextTest
, DeleteAndStartOver
) {
512 GURL
pattern("http://www.example.com/");
513 GURL
script_url("http://www.example.com/service_worker.js");
515 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
517 context()->RegisterServiceWorker(
521 MakeRegisteredCallback(&called
, ®istration_id
));
523 ASSERT_FALSE(called
);
524 base::RunLoop().RunUntilIdle();
527 context()->storage()->FindRegistrationForId(
530 base::Bind(&ExpectRegisteredWorkers
,
532 false /* expect_waiting */,
533 true /* expect_active */));
534 base::RunLoop().RunUntilIdle();
536 // Next handle ids should be 0 (the next call should return 1).
537 EXPECT_EQ(0, context()->GetNewServiceWorkerHandleId());
538 EXPECT_EQ(0, context()->GetNewRegistrationHandleId());
540 context()->ScheduleDeleteAndStartOver();
542 // The storage is disabled while the recovery process is running, so the
543 // operation should be failed.
544 context()->storage()->FindRegistrationForId(
547 base::Bind(&ExpectRegisteredWorkers
,
548 SERVICE_WORKER_ERROR_FAILED
,
549 false /* expect_waiting */,
550 true /* expect_active */));
551 base::RunLoop().RunUntilIdle();
553 // The context started over and the storage was re-initialized, so the
554 // registration should not be found.
555 context()->storage()->FindRegistrationForId(
558 base::Bind(&ExpectRegisteredWorkers
,
559 SERVICE_WORKER_ERROR_NOT_FOUND
,
560 false /* expect_waiting */,
561 true /* expect_active */));
562 base::RunLoop().RunUntilIdle();
565 context()->RegisterServiceWorker(
569 MakeRegisteredCallback(&called
, ®istration_id
));
571 ASSERT_FALSE(called
);
572 base::RunLoop().RunUntilIdle();
575 context()->storage()->FindRegistrationForId(
578 base::Bind(&ExpectRegisteredWorkers
,
580 false /* expect_waiting */,
581 true /* expect_active */));
582 base::RunLoop().RunUntilIdle();
584 // The new context should take over next handle ids.
585 EXPECT_EQ(1, context()->GetNewServiceWorkerHandleId());
586 EXPECT_EQ(1, context()->GetNewRegistrationHandleId());
588 ASSERT_EQ(3u, notifications_
.size());
589 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[0].type
);
590 EXPECT_EQ(pattern
, notifications_
[0].pattern
);
591 EXPECT_EQ(STORAGE_RECOVERED
, notifications_
[1].type
);
592 EXPECT_EQ(REGISTRATION_STORED
, notifications_
[2].type
);
593 EXPECT_EQ(pattern
, notifications_
[2].pattern
);
596 } // namespace content