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_job_coordinator.h"
13 #include "content/browser/service_worker/service_worker_registration.h"
14 #include "content/browser/service_worker/service_worker_registration_status.h"
15 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "ipc/ipc_test_sink.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 // Unit tests for testing all job registration tasks.
24 void SaveRegistrationCallback(
25 ServiceWorkerStatusCode expected_status
,
27 scoped_refptr
<ServiceWorkerRegistration
>* registration
,
28 ServiceWorkerStatusCode status
,
29 const scoped_refptr
<ServiceWorkerRegistration
>& result
) {
30 EXPECT_EQ(expected_status
, status
);
32 *registration
= result
;
35 void SaveFoundRegistrationCallback(
36 ServiceWorkerStatusCode expected_status
,
38 scoped_refptr
<ServiceWorkerRegistration
>* registration
,
39 ServiceWorkerStatusCode status
,
40 const scoped_refptr
<ServiceWorkerRegistration
>& result
) {
41 EXPECT_EQ(expected_status
, status
);
43 *registration
= result
;
46 // Creates a callback which both keeps track of if it's been called,
47 // as well as the resulting registration. Whent the callback is fired,
48 // it ensures that the resulting status matches the expectation.
49 // 'called' is useful for making sure a sychronous callback is or
51 ServiceWorkerRegisterJob::RegistrationCallback
SaveRegistration(
52 ServiceWorkerStatusCode expected_status
,
54 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
57 &SaveRegistrationCallback
, expected_status
, called
, registration
);
60 ServiceWorkerStorage::FindRegistrationCallback
SaveFoundRegistration(
61 ServiceWorkerStatusCode expected_status
,
63 scoped_refptr
<ServiceWorkerRegistration
>* registration
) {
65 return base::Bind(&SaveFoundRegistrationCallback
,
71 void SaveUnregistrationCallback(ServiceWorkerStatusCode expected_status
,
73 ServiceWorkerStatusCode status
) {
74 EXPECT_EQ(expected_status
, status
);
78 ServiceWorkerRegisterJob::UnregistrationCallback
SaveUnregistration(
79 ServiceWorkerStatusCode expected_status
,
82 return base::Bind(&SaveUnregistrationCallback
, expected_status
, called
);
87 class ServiceWorkerJobTest
: public testing::Test
{
89 ServiceWorkerJobTest()
90 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
),
91 render_process_id_(88) {}
93 virtual void SetUp() OVERRIDE
{
94 context_
.reset(new ServiceWorkerContextCore(base::FilePath(), NULL
));
95 helper_
.reset(new EmbeddedWorkerTestHelper(context_
.get(),
99 virtual void TearDown() OVERRIDE
{
104 ServiceWorkerJobCoordinator
* job_coordinator() const {
105 return context_
->job_coordinator();
107 ServiceWorkerStorage
* storage() const { return context_
->storage(); }
110 TestBrowserThreadBundle browser_thread_bundle_
;
111 scoped_ptr
<ServiceWorkerContextCore
> context_
;
112 scoped_ptr
<EmbeddedWorkerTestHelper
> helper_
;
114 int render_process_id_
;
117 TEST_F(ServiceWorkerJobTest
, SameDocumentSameRegistration
) {
118 scoped_refptr
<ServiceWorkerRegistration
> original_registration
;
120 job_coordinator()->Register(
121 GURL("http://www.example.com/*"),
122 GURL("http://www.example.com/service_worker.js"),
124 SaveRegistration(SERVICE_WORKER_OK
, &called
, &original_registration
));
125 EXPECT_FALSE(called
);
126 base::RunLoop().RunUntilIdle();
129 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
130 storage()->FindRegistrationForDocument(
131 GURL("http://www.example.com/"),
132 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration1
));
133 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
134 storage()->FindRegistrationForDocument(
135 GURL("http://www.example.com/"),
136 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration2
));
138 ServiceWorkerRegistration
* null_registration(NULL
);
139 ASSERT_EQ(null_registration
, registration1
);
140 ASSERT_EQ(null_registration
, registration2
);
141 EXPECT_FALSE(called
);
142 base::RunLoop().RunUntilIdle();
144 ASSERT_NE(null_registration
, registration1
);
145 ASSERT_NE(null_registration
, registration2
);
147 ASSERT_EQ(registration1
, registration2
);
150 TEST_F(ServiceWorkerJobTest
, SameMatchSameRegistration
) {
152 scoped_refptr
<ServiceWorkerRegistration
> original_registration
;
153 job_coordinator()->Register(
154 GURL("http://www.example.com/*"),
155 GURL("http://www.example.com/service_worker.js"),
157 SaveRegistration(SERVICE_WORKER_OK
, &called
, &original_registration
));
158 EXPECT_FALSE(called
);
159 base::RunLoop().RunUntilIdle();
161 ASSERT_NE(static_cast<ServiceWorkerRegistration
*>(NULL
),
162 original_registration
.get());
164 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
165 storage()->FindRegistrationForDocument(
166 GURL("http://www.example.com/one"),
167 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration1
));
169 EXPECT_FALSE(called
);
170 base::RunLoop().RunUntilIdle();
173 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
174 storage()->FindRegistrationForDocument(
175 GURL("http://www.example.com/two"),
176 SaveFoundRegistration(SERVICE_WORKER_OK
, &called
, ®istration2
));
177 EXPECT_FALSE(called
);
178 base::RunLoop().RunUntilIdle();
181 ASSERT_EQ(registration1
, registration2
);
184 TEST_F(ServiceWorkerJobTest
, DifferentMatchDifferentRegistration
) {
186 scoped_refptr
<ServiceWorkerRegistration
> original_registration1
;
187 job_coordinator()->Register(
188 GURL("http://www.example.com/one/*"),
189 GURL("http://www.example.com/service_worker.js"),
191 SaveRegistration(SERVICE_WORKER_OK
, &called1
, &original_registration1
));
194 scoped_refptr
<ServiceWorkerRegistration
> original_registration2
;
195 job_coordinator()->Register(
196 GURL("http://www.example.com/two/*"),
197 GURL("http://www.example.com/service_worker.js"),
199 SaveRegistration(SERVICE_WORKER_OK
, &called2
, &original_registration2
));
201 EXPECT_FALSE(called1
);
202 EXPECT_FALSE(called2
);
203 base::RunLoop().RunUntilIdle();
204 EXPECT_TRUE(called2
);
205 EXPECT_TRUE(called1
);
207 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
208 storage()->FindRegistrationForDocument(
209 GURL("http://www.example.com/one/"),
210 SaveFoundRegistration(SERVICE_WORKER_OK
, &called1
, ®istration1
));
211 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
212 storage()->FindRegistrationForDocument(
213 GURL("http://www.example.com/two/"),
214 SaveFoundRegistration(SERVICE_WORKER_OK
, &called2
, ®istration2
));
216 EXPECT_FALSE(called1
);
217 EXPECT_FALSE(called2
);
218 base::RunLoop().RunUntilIdle();
219 EXPECT_TRUE(called2
);
220 EXPECT_TRUE(called1
);
222 ASSERT_NE(registration1
, registration2
);
225 // Make sure basic registration is working.
226 TEST_F(ServiceWorkerJobTest
, Register
) {
228 scoped_refptr
<ServiceWorkerRegistration
> registration
;
229 job_coordinator()->Register(
230 GURL("http://www.example.com/*"),
231 GURL("http://www.example.com/service_worker.js"),
233 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
235 ASSERT_FALSE(called
);
236 base::RunLoop().RunUntilIdle();
239 ASSERT_NE(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
242 // Make sure registrations are cleaned up when they are unregistered.
243 TEST_F(ServiceWorkerJobTest
, Unregister
) {
244 GURL
pattern("http://www.example.com/*");
247 scoped_refptr
<ServiceWorkerRegistration
> registration
;
248 job_coordinator()->Register(
250 GURL("http://www.example.com/service_worker.js"),
252 SaveRegistration(SERVICE_WORKER_OK
, &called
, ®istration
));
254 ASSERT_FALSE(called
);
255 base::RunLoop().RunUntilIdle();
258 job_coordinator()->Unregister(pattern
,
260 SaveUnregistration(SERVICE_WORKER_OK
, &called
));
262 ASSERT_FALSE(called
);
263 base::RunLoop().RunUntilIdle();
266 ASSERT_TRUE(registration
->HasOneRef());
268 storage()->FindRegistrationForPattern(
270 SaveFoundRegistration(SERVICE_WORKER_ERROR_NOT_FOUND
,
271 &called
, ®istration
));
273 ASSERT_FALSE(called
);
274 base::RunLoop().RunUntilIdle();
277 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(NULL
), registration
);
280 // Make sure that when a new registration replaces an existing
281 // registration, that the old one is cleaned up.
282 TEST_F(ServiceWorkerJobTest
, RegisterNewScript
) {
283 GURL
pattern("http://www.example.com/*");
286 scoped_refptr
<ServiceWorkerRegistration
> old_registration
;
287 job_coordinator()->Register(
289 GURL("http://www.example.com/service_worker.js"),
291 SaveRegistration(SERVICE_WORKER_OK
, &called
, &old_registration
));
293 ASSERT_FALSE(called
);
294 base::RunLoop().RunUntilIdle();
297 scoped_refptr
<ServiceWorkerRegistration
> old_registration_by_pattern
;
298 storage()->FindRegistrationForPattern(
300 SaveFoundRegistration(
301 SERVICE_WORKER_OK
, &called
, &old_registration_by_pattern
));
303 ASSERT_FALSE(called
);
304 base::RunLoop().RunUntilIdle();
307 ASSERT_EQ(old_registration
, old_registration_by_pattern
);
308 old_registration_by_pattern
= NULL
;
310 scoped_refptr
<ServiceWorkerRegistration
> new_registration
;
311 job_coordinator()->Register(
313 GURL("http://www.example.com/service_worker_new.js"),
315 SaveRegistration(SERVICE_WORKER_OK
, &called
, &new_registration
));
317 ASSERT_FALSE(called
);
318 base::RunLoop().RunUntilIdle();
321 ASSERT_TRUE(old_registration
->HasOneRef());
323 ASSERT_NE(old_registration
, new_registration
);
325 scoped_refptr
<ServiceWorkerRegistration
> new_registration_by_pattern
;
326 storage()->FindRegistrationForPattern(
328 SaveFoundRegistration(
329 SERVICE_WORKER_OK
, &called
, &new_registration
));
331 ASSERT_FALSE(called
);
332 base::RunLoop().RunUntilIdle();
335 ASSERT_NE(new_registration_by_pattern
, old_registration
);
338 // Make sure that when registering a duplicate pattern+script_url
339 // combination, that the same registration is used.
340 TEST_F(ServiceWorkerJobTest
, RegisterDuplicateScript
) {
341 GURL
pattern("http://www.example.com/*");
342 GURL
script_url("http://www.example.com/service_worker.js");
345 scoped_refptr
<ServiceWorkerRegistration
> old_registration
;
346 job_coordinator()->Register(
350 SaveRegistration(SERVICE_WORKER_OK
, &called
, &old_registration
));
352 ASSERT_FALSE(called
);
353 base::RunLoop().RunUntilIdle();
356 scoped_refptr
<ServiceWorkerRegistration
> old_registration_by_pattern
;
357 storage()->FindRegistrationForPattern(
359 SaveFoundRegistration(
360 SERVICE_WORKER_OK
, &called
, &old_registration_by_pattern
));
361 ASSERT_FALSE(called
);
362 base::RunLoop().RunUntilIdle();
365 ASSERT_TRUE(old_registration_by_pattern
);
367 scoped_refptr
<ServiceWorkerRegistration
> new_registration
;
368 job_coordinator()->Register(
372 SaveRegistration(SERVICE_WORKER_OK
, &called
, &new_registration
));
374 ASSERT_FALSE(called
);
375 base::RunLoop().RunUntilIdle();
378 ASSERT_EQ(old_registration
, new_registration
);
380 ASSERT_FALSE(old_registration
->HasOneRef());
382 scoped_refptr
<ServiceWorkerRegistration
> new_registration_by_pattern
;
383 storage()->FindRegistrationForPattern(
385 SaveFoundRegistration(
386 SERVICE_WORKER_OK
, &called
, &new_registration_by_pattern
));
388 ASSERT_FALSE(called
);
389 base::RunLoop().RunUntilIdle();
392 ASSERT_EQ(new_registration
, old_registration
);
395 // Register and then unregister the pattern, in parallel. Job coordinator should
396 // process jobs until the last job.
397 TEST_F(ServiceWorkerJobTest
, ParallelRegUnreg
) {
398 GURL
pattern("http://www.example.com/*");
399 GURL
script_url("http://www.example.com/service_worker.js");
401 bool registration_called
= false;
402 scoped_refptr
<ServiceWorkerRegistration
> registration
;
403 job_coordinator()->Register(
407 SaveRegistration(SERVICE_WORKER_OK
, ®istration_called
, ®istration
));
409 bool unregistration_called
= false;
410 job_coordinator()->Unregister(
413 SaveUnregistration(SERVICE_WORKER_OK
, &unregistration_called
));
415 ASSERT_FALSE(registration_called
);
416 ASSERT_FALSE(unregistration_called
);
417 base::RunLoop().RunUntilIdle();
418 ASSERT_TRUE(registration_called
);
419 ASSERT_TRUE(unregistration_called
);
421 ASSERT_TRUE(registration
->is_shutdown());
423 bool find_called
= false;
424 storage()->FindRegistrationForPattern(
426 SaveFoundRegistration(
427 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
429 base::RunLoop().RunUntilIdle();
431 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
434 // Register conflicting scripts for the same pattern. The most recent
435 // registration should win, and the old registration should have been
437 TEST_F(ServiceWorkerJobTest
, ParallelRegNewScript
) {
438 GURL
pattern("http://www.example.com/*");
440 GURL
script_url1("http://www.example.com/service_worker1.js");
441 bool registration1_called
= false;
442 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
443 job_coordinator()->Register(
448 SERVICE_WORKER_OK
, ®istration1_called
, ®istration1
));
450 GURL
script_url2("http://www.example.com/service_worker2.js");
451 bool registration2_called
= false;
452 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
453 job_coordinator()->Register(
458 SERVICE_WORKER_OK
, ®istration2_called
, ®istration2
));
460 ASSERT_FALSE(registration1_called
);
461 ASSERT_FALSE(registration2_called
);
462 base::RunLoop().RunUntilIdle();
463 ASSERT_TRUE(registration1_called
);
464 ASSERT_TRUE(registration2_called
);
466 scoped_refptr
<ServiceWorkerRegistration
> registration
;
467 bool find_called
= false;
468 storage()->FindRegistrationForPattern(
470 SaveFoundRegistration(
471 SERVICE_WORKER_OK
, &find_called
, ®istration
));
473 base::RunLoop().RunUntilIdle();
475 EXPECT_TRUE(registration1
->is_shutdown());
476 EXPECT_FALSE(registration2
->is_shutdown());
477 ASSERT_EQ(registration2
, registration
);
480 // Register the exact same pattern + script. Requests should be
481 // coalesced such that both callers get the exact same registration
483 TEST_F(ServiceWorkerJobTest
, ParallelRegSameScript
) {
484 GURL
pattern("http://www.example.com/*");
486 GURL
script_url("http://www.example.com/service_worker1.js");
487 bool registration1_called
= false;
488 scoped_refptr
<ServiceWorkerRegistration
> registration1
;
489 job_coordinator()->Register(
494 SERVICE_WORKER_OK
, ®istration1_called
, ®istration1
));
496 bool registration2_called
= false;
497 scoped_refptr
<ServiceWorkerRegistration
> registration2
;
498 job_coordinator()->Register(
503 SERVICE_WORKER_OK
, ®istration2_called
, ®istration2
));
505 ASSERT_FALSE(registration1_called
);
506 ASSERT_FALSE(registration2_called
);
507 base::RunLoop().RunUntilIdle();
508 ASSERT_TRUE(registration1_called
);
509 ASSERT_TRUE(registration2_called
);
511 ASSERT_EQ(registration1
, registration2
);
513 scoped_refptr
<ServiceWorkerRegistration
> registration
;
514 bool find_called
= false;
515 storage()->FindRegistrationForPattern(
517 SaveFoundRegistration(
518 SERVICE_WORKER_OK
, &find_called
, ®istration
));
520 base::RunLoop().RunUntilIdle();
521 ASSERT_EQ(registration
, registration1
);
524 // Call simulataneous unregister calls.
525 TEST_F(ServiceWorkerJobTest
, ParallelUnreg
) {
526 GURL
pattern("http://www.example.com/*");
528 GURL
script_url("http://www.example.com/service_worker.js");
529 bool unregistration1_called
= false;
530 job_coordinator()->Unregister(
533 SaveUnregistration(SERVICE_WORKER_OK
, &unregistration1_called
));
535 bool unregistration2_called
= false;
536 job_coordinator()->Unregister(
539 SaveUnregistration(SERVICE_WORKER_OK
, &unregistration2_called
));
541 ASSERT_FALSE(unregistration1_called
);
542 ASSERT_FALSE(unregistration2_called
);
543 base::RunLoop().RunUntilIdle();
544 ASSERT_TRUE(unregistration1_called
);
545 ASSERT_TRUE(unregistration2_called
);
547 // There isn't really a way to test that they are being coalesced,
548 // but we can make sure they can exist simultaneously without
550 scoped_refptr
<ServiceWorkerRegistration
> registration
;
551 bool find_called
= false;
552 storage()->FindRegistrationForPattern(
554 SaveFoundRegistration(
555 SERVICE_WORKER_ERROR_NOT_FOUND
, &find_called
, ®istration
));
557 base::RunLoop().RunUntilIdle();
558 ASSERT_EQ(scoped_refptr
<ServiceWorkerRegistration
>(), registration
);
561 } // namespace content