Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_job_unittest.cc
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.
4
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"
18
19 // Unit tests for testing all job registration tasks.
20 namespace content {
21
22 namespace {
23
24 void SaveRegistrationCallback(
25     ServiceWorkerStatusCode expected_status,
26     bool* called,
27     scoped_refptr<ServiceWorkerRegistration>* registration_out,
28     ServiceWorkerStatusCode status,
29     ServiceWorkerRegistration* registration,
30     ServiceWorkerVersion* version) {
31   ASSERT_TRUE(!version || version->registration_id() == registration->id())
32       << version << " " << registration;
33   EXPECT_EQ(expected_status, status);
34   *called = true;
35   *registration_out = registration;
36 }
37
38 void SaveFoundRegistrationCallback(
39     ServiceWorkerStatusCode expected_status,
40     bool* called,
41     scoped_refptr<ServiceWorkerRegistration>* registration,
42     ServiceWorkerStatusCode status,
43     const scoped_refptr<ServiceWorkerRegistration>& result) {
44   EXPECT_EQ(expected_status, status);
45   *called = true;
46   *registration = result;
47 }
48
49 // Creates a callback which both keeps track of if it's been called,
50 // as well as the resulting registration. Whent the callback is fired,
51 // it ensures that the resulting status matches the expectation.
52 // 'called' is useful for making sure a sychronous callback is or
53 // isn't called.
54 ServiceWorkerRegisterJob::RegistrationCallback SaveRegistration(
55     ServiceWorkerStatusCode expected_status,
56     bool* called,
57     scoped_refptr<ServiceWorkerRegistration>* registration) {
58   *called = false;
59   return base::Bind(
60       &SaveRegistrationCallback, expected_status, called, registration);
61 }
62
63 ServiceWorkerStorage::FindRegistrationCallback SaveFoundRegistration(
64     ServiceWorkerStatusCode expected_status,
65     bool* called,
66     scoped_refptr<ServiceWorkerRegistration>* registration) {
67   *called = false;
68   return base::Bind(&SaveFoundRegistrationCallback,
69                     expected_status,
70                     called,
71                     registration);
72 }
73
74 void SaveUnregistrationCallback(ServiceWorkerStatusCode expected_status,
75                                 bool* called,
76                                 ServiceWorkerStatusCode status) {
77   EXPECT_EQ(expected_status, status);
78   *called = true;
79 }
80
81 ServiceWorkerUnregisterJob::UnregistrationCallback SaveUnregistration(
82     ServiceWorkerStatusCode expected_status,
83     bool* called) {
84   *called = false;
85   return base::Bind(&SaveUnregistrationCallback, expected_status, called);
86 }
87
88 }  // namespace
89
90 class ServiceWorkerJobTest : public testing::Test {
91  public:
92   ServiceWorkerJobTest()
93       : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
94         render_process_id_(88) {}
95
96   virtual void SetUp() OVERRIDE {
97     helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
98   }
99
100   virtual void TearDown() OVERRIDE {
101     helper_.reset();
102   }
103
104   ServiceWorkerContextCore* context() const { return helper_->context(); }
105
106   ServiceWorkerJobCoordinator* job_coordinator() const {
107     return context()->job_coordinator();
108   }
109   ServiceWorkerStorage* storage() const { return context()->storage(); }
110
111  protected:
112   TestBrowserThreadBundle browser_thread_bundle_;
113   scoped_ptr<EmbeddedWorkerTestHelper> helper_;
114
115   int render_process_id_;
116 };
117
118 TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) {
119   scoped_refptr<ServiceWorkerRegistration> original_registration;
120   bool called;
121   job_coordinator()->Register(
122       GURL("http://www.example.com/*"),
123       GURL("http://www.example.com/service_worker.js"),
124       render_process_id_,
125       SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
126   EXPECT_FALSE(called);
127   base::RunLoop().RunUntilIdle();
128   EXPECT_TRUE(called);
129
130   scoped_refptr<ServiceWorkerRegistration> registration1;
131   storage()->FindRegistrationForDocument(
132       GURL("http://www.example.com/"),
133       SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration1));
134   scoped_refptr<ServiceWorkerRegistration> registration2;
135   storage()->FindRegistrationForDocument(
136       GURL("http://www.example.com/"),
137       SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration2));
138   base::RunLoop().RunUntilIdle();
139   EXPECT_TRUE(called);
140   ASSERT_TRUE(registration1);
141   ASSERT_EQ(registration1, original_registration);
142   ASSERT_EQ(registration1, registration2);
143 }
144
145 TEST_F(ServiceWorkerJobTest, SameMatchSameRegistration) {
146   bool called;
147   scoped_refptr<ServiceWorkerRegistration> original_registration;
148   job_coordinator()->Register(
149       GURL("http://www.example.com/*"),
150       GURL("http://www.example.com/service_worker.js"),
151       render_process_id_,
152       SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
153   EXPECT_FALSE(called);
154   base::RunLoop().RunUntilIdle();
155   EXPECT_TRUE(called);
156   ASSERT_NE(static_cast<ServiceWorkerRegistration*>(NULL),
157             original_registration.get());
158
159   scoped_refptr<ServiceWorkerRegistration> registration1;
160   storage()->FindRegistrationForDocument(
161       GURL("http://www.example.com/one"),
162       SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration1));
163   base::RunLoop().RunUntilIdle();
164   EXPECT_TRUE(called);
165
166   scoped_refptr<ServiceWorkerRegistration> registration2;
167   storage()->FindRegistrationForDocument(
168       GURL("http://www.example.com/two"),
169       SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration2));
170   base::RunLoop().RunUntilIdle();
171   EXPECT_TRUE(called);
172   ASSERT_EQ(registration1, original_registration);
173   ASSERT_EQ(registration1, registration2);
174 }
175
176 TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) {
177   bool called1;
178   scoped_refptr<ServiceWorkerRegistration> original_registration1;
179   job_coordinator()->Register(
180       GURL("http://www.example.com/one/*"),
181       GURL("http://www.example.com/service_worker.js"),
182       render_process_id_,
183       SaveRegistration(SERVICE_WORKER_OK, &called1, &original_registration1));
184
185   bool called2;
186   scoped_refptr<ServiceWorkerRegistration> original_registration2;
187   job_coordinator()->Register(
188       GURL("http://www.example.com/two/*"),
189       GURL("http://www.example.com/service_worker.js"),
190       render_process_id_,
191       SaveRegistration(SERVICE_WORKER_OK, &called2, &original_registration2));
192
193   EXPECT_FALSE(called1);
194   EXPECT_FALSE(called2);
195   base::RunLoop().RunUntilIdle();
196   EXPECT_TRUE(called2);
197   EXPECT_TRUE(called1);
198
199   scoped_refptr<ServiceWorkerRegistration> registration1;
200   storage()->FindRegistrationForDocument(
201       GURL("http://www.example.com/one/"),
202       SaveFoundRegistration(SERVICE_WORKER_OK, &called1, &registration1));
203   scoped_refptr<ServiceWorkerRegistration> registration2;
204   storage()->FindRegistrationForDocument(
205       GURL("http://www.example.com/two/"),
206       SaveFoundRegistration(SERVICE_WORKER_OK, &called2, &registration2));
207
208   base::RunLoop().RunUntilIdle();
209   EXPECT_TRUE(called2);
210   EXPECT_TRUE(called1);
211   ASSERT_NE(registration1, registration2);
212 }
213
214 // Make sure basic registration is working.
215 TEST_F(ServiceWorkerJobTest, Register) {
216   bool called = false;
217   scoped_refptr<ServiceWorkerRegistration> registration;
218   job_coordinator()->Register(
219       GURL("http://www.example.com/*"),
220       GURL("http://www.example.com/service_worker.js"),
221       render_process_id_,
222       SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
223
224   ASSERT_FALSE(called);
225   base::RunLoop().RunUntilIdle();
226   ASSERT_TRUE(called);
227
228   ASSERT_NE(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
229 }
230
231 // Make sure registrations are cleaned up when they are unregistered.
232 TEST_F(ServiceWorkerJobTest, Unregister) {
233   GURL pattern("http://www.example.com/*");
234
235   bool called;
236   scoped_refptr<ServiceWorkerRegistration> registration;
237   job_coordinator()->Register(
238       pattern,
239       GURL("http://www.example.com/service_worker.js"),
240       render_process_id_,
241       SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
242
243   ASSERT_FALSE(called);
244   base::RunLoop().RunUntilIdle();
245   ASSERT_TRUE(called);
246
247   job_coordinator()->Unregister(pattern,
248                                 SaveUnregistration(SERVICE_WORKER_OK, &called));
249
250   ASSERT_FALSE(called);
251   base::RunLoop().RunUntilIdle();
252   ASSERT_TRUE(called);
253
254   ASSERT_TRUE(registration->HasOneRef());
255
256   storage()->FindRegistrationForPattern(
257       pattern,
258       SaveFoundRegistration(SERVICE_WORKER_ERROR_NOT_FOUND,
259                             &called, &registration));
260
261   ASSERT_FALSE(called);
262   base::RunLoop().RunUntilIdle();
263   ASSERT_TRUE(called);
264
265   ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
266 }
267
268 TEST_F(ServiceWorkerJobTest, Unregister_NothingRegistered) {
269   GURL pattern("http://www.example.com/*");
270
271   bool called;
272   job_coordinator()->Unregister(pattern,
273                                 SaveUnregistration(SERVICE_WORKER_OK, &called));
274
275   ASSERT_FALSE(called);
276   base::RunLoop().RunUntilIdle();
277   ASSERT_TRUE(called);
278 }
279
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/*");
284
285   bool called;
286   scoped_refptr<ServiceWorkerRegistration> old_registration;
287   job_coordinator()->Register(
288       pattern,
289       GURL("http://www.example.com/service_worker.js"),
290       render_process_id_,
291       SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
292
293   ASSERT_FALSE(called);
294   base::RunLoop().RunUntilIdle();
295   ASSERT_TRUE(called);
296
297   scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern;
298   storage()->FindRegistrationForPattern(
299       pattern,
300       SaveFoundRegistration(
301           SERVICE_WORKER_OK, &called, &old_registration_by_pattern));
302
303   ASSERT_FALSE(called);
304   base::RunLoop().RunUntilIdle();
305   ASSERT_TRUE(called);
306
307   ASSERT_EQ(old_registration, old_registration_by_pattern);
308   old_registration_by_pattern = NULL;
309
310   scoped_refptr<ServiceWorkerRegistration> new_registration;
311   job_coordinator()->Register(
312       pattern,
313       GURL("http://www.example.com/service_worker_new.js"),
314       render_process_id_,
315       SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
316
317   ASSERT_FALSE(called);
318   base::RunLoop().RunUntilIdle();
319   ASSERT_TRUE(called);
320
321   ASSERT_TRUE(old_registration->HasOneRef());
322
323   ASSERT_NE(old_registration, new_registration);
324
325   scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern;
326   storage()->FindRegistrationForPattern(
327       pattern,
328       SaveFoundRegistration(
329           SERVICE_WORKER_OK, &called, &new_registration));
330
331   ASSERT_FALSE(called);
332   base::RunLoop().RunUntilIdle();
333   ASSERT_TRUE(called);
334
335   ASSERT_NE(new_registration_by_pattern, old_registration);
336 }
337
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");
343
344   bool called;
345   scoped_refptr<ServiceWorkerRegistration> old_registration;
346   job_coordinator()->Register(
347       pattern,
348       script_url,
349       render_process_id_,
350       SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
351
352   ASSERT_FALSE(called);
353   base::RunLoop().RunUntilIdle();
354   ASSERT_TRUE(called);
355
356   scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern;
357   storage()->FindRegistrationForPattern(
358       pattern,
359       SaveFoundRegistration(
360           SERVICE_WORKER_OK, &called, &old_registration_by_pattern));
361   ASSERT_FALSE(called);
362   base::RunLoop().RunUntilIdle();
363   ASSERT_TRUE(called);
364
365   ASSERT_TRUE(old_registration_by_pattern);
366
367   scoped_refptr<ServiceWorkerRegistration> new_registration;
368   job_coordinator()->Register(
369       pattern,
370       script_url,
371       render_process_id_,
372       SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
373
374   ASSERT_FALSE(called);
375   base::RunLoop().RunUntilIdle();
376   ASSERT_TRUE(called);
377
378   ASSERT_EQ(old_registration, new_registration);
379
380   ASSERT_FALSE(old_registration->HasOneRef());
381
382   scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern;
383   storage()->FindRegistrationForPattern(
384       pattern,
385       SaveFoundRegistration(
386           SERVICE_WORKER_OK, &called, &new_registration_by_pattern));
387
388   ASSERT_FALSE(called);
389   base::RunLoop().RunUntilIdle();
390   ASSERT_TRUE(called);
391
392   ASSERT_EQ(new_registration, old_registration);
393 }
394
395 class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
396  public:
397   FailToStartWorkerTestHelper(int mock_render_process_id)
398       : EmbeddedWorkerTestHelper(mock_render_process_id) {}
399
400   virtual void OnStartWorker(int embedded_worker_id,
401                              int64 service_worker_version_id,
402                              const GURL& scope,
403                              const GURL& script_url) OVERRIDE {
404     // Simulate failure by sending worker stopped instead of started.
405     EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
406     registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id);
407   }
408 };
409
410 TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) {
411   helper_.reset(new FailToStartWorkerTestHelper(render_process_id_));
412
413   bool called = false;
414   scoped_refptr<ServiceWorkerRegistration> registration;
415   job_coordinator()->Register(
416       GURL("http://www.example.com/*"),
417       GURL("http://www.example.com/service_worker.js"),
418       render_process_id_,
419       SaveRegistration(
420           SERVICE_WORKER_ERROR_START_WORKER_FAILED, &called, &registration));
421
422   ASSERT_FALSE(called);
423   base::RunLoop().RunUntilIdle();
424
425   ASSERT_TRUE(called);
426   ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
427 }
428
429 // Register and then unregister the pattern, in parallel. Job coordinator should
430 // process jobs until the last job.
431 TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) {
432   GURL pattern("http://www.example.com/*");
433   GURL script_url("http://www.example.com/service_worker.js");
434
435   bool registration_called = false;
436   scoped_refptr<ServiceWorkerRegistration> registration;
437   job_coordinator()->Register(
438       pattern,
439       script_url,
440       render_process_id_,
441       SaveRegistration(SERVICE_WORKER_OK, &registration_called, &registration));
442
443   bool unregistration_called = false;
444   job_coordinator()->Unregister(
445       pattern,
446       SaveUnregistration(SERVICE_WORKER_OK, &unregistration_called));
447
448   ASSERT_FALSE(registration_called);
449   ASSERT_FALSE(unregistration_called);
450   base::RunLoop().RunUntilIdle();
451   ASSERT_TRUE(registration_called);
452   ASSERT_TRUE(unregistration_called);
453
454   bool find_called = false;
455   storage()->FindRegistrationForPattern(
456       pattern,
457       SaveFoundRegistration(
458           SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
459
460   base::RunLoop().RunUntilIdle();
461
462   ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
463 }
464
465 // Register conflicting scripts for the same pattern. The most recent
466 // registration should win, and the old registration should have been
467 // shutdown.
468 TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
469   GURL pattern("http://www.example.com/*");
470
471   GURL script_url1("http://www.example.com/service_worker1.js");
472   bool registration1_called = false;
473   scoped_refptr<ServiceWorkerRegistration> registration1;
474   job_coordinator()->Register(
475       pattern,
476       script_url1,
477       render_process_id_,
478       SaveRegistration(
479           SERVICE_WORKER_OK, &registration1_called, &registration1));
480
481   GURL script_url2("http://www.example.com/service_worker2.js");
482   bool registration2_called = false;
483   scoped_refptr<ServiceWorkerRegistration> registration2;
484   job_coordinator()->Register(
485       pattern,
486       script_url2,
487       render_process_id_,
488       SaveRegistration(
489           SERVICE_WORKER_OK, &registration2_called, &registration2));
490
491   ASSERT_FALSE(registration1_called);
492   ASSERT_FALSE(registration2_called);
493   base::RunLoop().RunUntilIdle();
494   ASSERT_TRUE(registration1_called);
495   ASSERT_TRUE(registration2_called);
496
497   scoped_refptr<ServiceWorkerRegistration> registration;
498   bool find_called = false;
499   storage()->FindRegistrationForPattern(
500       pattern,
501       SaveFoundRegistration(
502           SERVICE_WORKER_OK, &find_called, &registration));
503
504   base::RunLoop().RunUntilIdle();
505
506   ASSERT_EQ(registration2, registration);
507 }
508
509 // Register the exact same pattern + script. Requests should be
510 // coalesced such that both callers get the exact same registration
511 // object.
512 TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
513   GURL pattern("http://www.example.com/*");
514
515   GURL script_url("http://www.example.com/service_worker1.js");
516   bool registration1_called = false;
517   scoped_refptr<ServiceWorkerRegistration> registration1;
518   job_coordinator()->Register(
519       pattern,
520       script_url,
521       render_process_id_,
522       SaveRegistration(
523           SERVICE_WORKER_OK, &registration1_called, &registration1));
524
525   bool registration2_called = false;
526   scoped_refptr<ServiceWorkerRegistration> registration2;
527   job_coordinator()->Register(
528       pattern,
529       script_url,
530       render_process_id_,
531       SaveRegistration(
532           SERVICE_WORKER_OK, &registration2_called, &registration2));
533
534   ASSERT_FALSE(registration1_called);
535   ASSERT_FALSE(registration2_called);
536   base::RunLoop().RunUntilIdle();
537   ASSERT_TRUE(registration1_called);
538   ASSERT_TRUE(registration2_called);
539
540   ASSERT_EQ(registration1, registration2);
541
542   scoped_refptr<ServiceWorkerRegistration> registration;
543   bool find_called = false;
544   storage()->FindRegistrationForPattern(
545       pattern,
546       SaveFoundRegistration(
547           SERVICE_WORKER_OK, &find_called, &registration));
548
549   base::RunLoop().RunUntilIdle();
550   ASSERT_EQ(registration, registration1);
551 }
552
553 // Call simulataneous unregister calls.
554 TEST_F(ServiceWorkerJobTest, ParallelUnreg) {
555   GURL pattern("http://www.example.com/*");
556
557   GURL script_url("http://www.example.com/service_worker.js");
558   bool unregistration1_called = false;
559   job_coordinator()->Unregister(
560       pattern,
561       SaveUnregistration(SERVICE_WORKER_OK, &unregistration1_called));
562
563   bool unregistration2_called = false;
564   job_coordinator()->Unregister(
565       pattern, SaveUnregistration(SERVICE_WORKER_OK, &unregistration2_called));
566
567   ASSERT_FALSE(unregistration1_called);
568   ASSERT_FALSE(unregistration2_called);
569   base::RunLoop().RunUntilIdle();
570   ASSERT_TRUE(unregistration1_called);
571   ASSERT_TRUE(unregistration2_called);
572
573   // There isn't really a way to test that they are being coalesced,
574   // but we can make sure they can exist simultaneously without
575   // crashing.
576   scoped_refptr<ServiceWorkerRegistration> registration;
577   bool find_called = false;
578   storage()->FindRegistrationForPattern(
579       pattern,
580       SaveFoundRegistration(
581           SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
582
583   base::RunLoop().RunUntilIdle();
584   ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
585 }
586
587 }  // namespace content