[Storage] Blob Storage Refactoring pt 1:
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_context_unittest.cc
blob71afa32ae246e3f5ee97b1ad62c37b196d7edeab
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"
24 namespace content {
26 namespace {
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);
34 *called = true;
35 *store_registration_id = registration_id;
38 ServiceWorkerContextCore::RegistrationCallback MakeRegisteredCallback(
39 bool* called,
40 int64* store_registration_id) {
41 return base::Bind(&SaveResponseCallback, called, store_registration_id);
44 void CallCompletedCallback(bool* called, ServiceWorkerStatusCode) {
45 *called = true;
48 ServiceWorkerContextCore::UnregistrationCallback MakeUnregisteredCallback(
49 bool* called) {
50 return base::Bind(&CallCompletedCallback, called);
53 void ExpectRegisteredWorkers(
54 ServiceWorkerStatusCode expect_status,
55 bool expect_waiting,
56 bool expect_active,
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());
62 return;
65 if (expect_waiting) {
66 EXPECT_TRUE(registration->waiting_version());
67 } else {
68 EXPECT_FALSE(registration->waiting_version());
71 if (expect_active) {
72 EXPECT_TRUE(registration->active_version());
73 } else {
74 EXPECT_FALSE(registration->active_version());
78 class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
79 public:
80 explicit RejectInstallTestHelper(int mock_render_process_id)
81 : EmbeddedWorkerTestHelper(mock_render_process_id) {}
83 void OnInstallEvent(int embedded_worker_id,
84 int request_id,
85 int active_version_id) override {
86 SimulateSend(
87 new ServiceWorkerHostMsg_InstallEventFinished(
88 embedded_worker_id, request_id,
89 blink::WebServiceWorkerEventResultRejected));
93 class RejectActivateTestHelper : public EmbeddedWorkerTestHelper {
94 public:
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 {
99 SimulateSend(
100 new ServiceWorkerHostMsg_ActivateEventFinished(
101 embedded_worker_id, request_id,
102 blink::WebServiceWorkerEventResultRejected));
106 enum NotificationType {
107 REGISTRATION_STORED,
108 REGISTRATION_DELETED,
109 STORAGE_RECOVERED,
112 struct NotificationLog {
113 NotificationType type;
114 GURL pattern;
115 int64 registration_id;
118 } // namespace
120 class ServiceWorkerContextTest : public ServiceWorkerContextObserver,
121 public testing::Test {
122 public:
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 {
136 NotificationLog log;
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 {
143 NotificationLog log;
144 log.type = REGISTRATION_DELETED;
145 log.pattern = pattern;
146 log.registration_id = registration_id;
147 notifications_.push_back(log);
149 void OnStorageWiped() override {
150 NotificationLog log;
151 log.type = STORAGE_RECOVERED;
152 notifications_.push_back(log);
155 ServiceWorkerContextCore* context() { return helper_->context(); }
157 protected:
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;
170 bool called = false;
171 context()->RegisterServiceWorker(
172 pattern,
173 script_url,
174 NULL,
175 MakeRegisteredCallback(&called, &registration_id));
177 ASSERT_FALSE(called);
178 base::RunLoop().RunUntilIdle();
179 EXPECT_TRUE(called);
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(
193 registration_id,
194 pattern.GetOrigin(),
195 base::Bind(&ExpectRegisteredWorkers,
196 SERVICE_WORKER_OK,
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;
216 bool called = false;
217 context()->RegisterServiceWorker(
218 pattern,
219 script_url,
220 NULL,
221 MakeRegisteredCallback(&called, &registration_id));
223 ASSERT_FALSE(called);
224 base::RunLoop().RunUntilIdle();
225 EXPECT_TRUE(called);
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(
239 registration_id,
240 pattern.GetOrigin(),
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;
257 bool called = false;
258 context()->RegisterServiceWorker(
259 GURL("http://www.example.com/"),
260 GURL("http://www.example.com/service_worker.js"),
261 NULL,
262 MakeRegisteredCallback(&called, &registration_id));
264 ASSERT_FALSE(called);
265 base::RunLoop().RunUntilIdle();
266 EXPECT_TRUE(called);
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(
280 registration_id,
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/");
295 bool called = false;
296 int64 registration_id = kInvalidServiceWorkerRegistrationId;
297 context()->RegisterServiceWorker(
298 pattern,
299 GURL("http://www.example.com/service_worker.js"),
300 NULL,
301 MakeRegisteredCallback(&called, &registration_id));
303 ASSERT_FALSE(called);
304 base::RunLoop().RunUntilIdle();
305 ASSERT_TRUE(called);
306 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
308 called = false;
309 context()->UnregisterServiceWorker(pattern,
310 MakeUnregisteredCallback(&called));
312 ASSERT_FALSE(called);
313 base::RunLoop().RunUntilIdle();
314 ASSERT_TRUE(called);
316 context()->storage()->FindRegistrationForId(
317 registration_id,
318 pattern.GetOrigin(),
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/");
340 bool called = false;
341 int64 registration_id1 = kInvalidServiceWorkerRegistrationId;
342 int64 registration_id2 = kInvalidServiceWorkerRegistrationId;
343 int64 registration_id3 = kInvalidServiceWorkerRegistrationId;
344 int64 registration_id4 = kInvalidServiceWorkerRegistrationId;
345 context()->RegisterServiceWorker(
346 origin1_p1,
347 GURL("http://www.example.com/service_worker.js"),
348 NULL,
349 MakeRegisteredCallback(&called, &registration_id1));
350 context()->RegisterServiceWorker(
351 origin1_p2,
352 GURL("http://www.example.com/service_worker2.js"),
353 NULL,
354 MakeRegisteredCallback(&called, &registration_id2));
355 context()->RegisterServiceWorker(
356 origin2_p1,
357 GURL("http://www.example.com:8080/service_worker3.js"),
358 NULL,
359 MakeRegisteredCallback(&called, &registration_id3));
360 context()->RegisterServiceWorker(
361 origin3_p1,
362 GURL("http://www.other.com/service_worker4.js"),
363 NULL,
364 MakeRegisteredCallback(&called, &registration_id4));
366 ASSERT_FALSE(called);
367 base::RunLoop().RunUntilIdle();
368 ASSERT_TRUE(called);
370 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id1);
371 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id2);
372 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id3);
373 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id4);
375 called = false;
376 context()->UnregisterServiceWorkers(origin1_p1.GetOrigin(),
377 MakeUnregisteredCallback(&called));
379 ASSERT_FALSE(called);
380 base::RunLoop().RunUntilIdle();
381 ASSERT_TRUE(called);
383 context()->storage()->FindRegistrationForId(
384 registration_id1,
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(
391 registration_id2,
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(
398 registration_id3,
399 origin2_p1.GetOrigin(),
400 base::Bind(&ExpectRegisteredWorkers,
401 SERVICE_WORKER_OK,
402 false /* expect_waiting */,
403 true /* expect_active */));
405 context()->storage()->FindRegistrationForId(
406 registration_id4,
407 origin3_p1.GetOrigin(),
408 base::Bind(&ExpectRegisteredWorkers,
409 SERVICE_WORKER_OK,
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/");
436 bool called = false;
437 int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
438 context()->RegisterServiceWorker(
439 pattern,
440 GURL("http://www.example.com/service_worker.js"),
441 NULL,
442 MakeRegisteredCallback(&called, &old_registration_id));
444 ASSERT_FALSE(called);
445 base::RunLoop().RunUntilIdle();
446 ASSERT_TRUE(called);
447 EXPECT_NE(kInvalidServiceWorkerRegistrationId, old_registration_id);
449 called = false;
450 int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
451 context()->RegisterServiceWorker(
452 pattern,
453 GURL("http://www.example.com/service_worker_new.js"),
454 NULL,
455 MakeRegisteredCallback(&called, &new_registration_id));
457 ASSERT_FALSE(called);
458 base::RunLoop().RunUntilIdle();
459 ASSERT_TRUE(called);
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");
477 bool called = false;
478 int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
479 context()->RegisterServiceWorker(
480 pattern,
481 script_url,
482 NULL,
483 MakeRegisteredCallback(&called, &old_registration_id));
485 ASSERT_FALSE(called);
486 base::RunLoop().RunUntilIdle();
487 ASSERT_TRUE(called);
488 EXPECT_NE(kInvalidServiceWorkerRegistrationId, old_registration_id);
490 called = false;
491 int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
492 context()->RegisterServiceWorker(
493 pattern,
494 script_url,
495 NULL,
496 MakeRegisteredCallback(&called, &new_registration_id));
498 ASSERT_FALSE(called);
499 base::RunLoop().RunUntilIdle();
500 ASSERT_TRUE(called);
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;
516 bool called = false;
517 context()->RegisterServiceWorker(
518 pattern,
519 script_url,
520 NULL,
521 MakeRegisteredCallback(&called, &registration_id));
523 ASSERT_FALSE(called);
524 base::RunLoop().RunUntilIdle();
525 EXPECT_TRUE(called);
527 context()->storage()->FindRegistrationForId(
528 registration_id,
529 pattern.GetOrigin(),
530 base::Bind(&ExpectRegisteredWorkers,
531 SERVICE_WORKER_OK,
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(
545 registration_id,
546 pattern.GetOrigin(),
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(
556 registration_id,
557 pattern.GetOrigin(),
558 base::Bind(&ExpectRegisteredWorkers,
559 SERVICE_WORKER_ERROR_NOT_FOUND,
560 false /* expect_waiting */,
561 true /* expect_active */));
562 base::RunLoop().RunUntilIdle();
564 called = false;
565 context()->RegisterServiceWorker(
566 pattern,
567 script_url,
568 NULL,
569 MakeRegisteredCallback(&called, &registration_id));
571 ASSERT_FALSE(called);
572 base::RunLoop().RunUntilIdle();
573 EXPECT_TRUE(called);
575 context()->storage()->FindRegistrationForId(
576 registration_id,
577 pattern.GetOrigin(),
578 base::Bind(&ExpectRegisteredWorkers,
579 SERVICE_WORKER_OK,
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