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_registration.h"
15 #include "content/browser/service_worker/service_worker_storage.h"
16 #include "content/common/service_worker/embedded_worker_messages.h"
17 #include "content/common/service_worker/service_worker_messages.h"
18 #include "content/public/test/test_browser_thread_bundle.h"
19 #include "content/public/test/test_utils.h"
20 #include "testing/gtest/include/gtest/gtest.h"
26 void SaveResponseCallback(bool* called,
27 int64* store_registration_id,
28 int64* store_version_id,
29 ServiceWorkerStatusCode status,
30 int64 registration_id,
32 EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
34 *store_registration_id = registration_id;
35 *store_version_id = version_id;
38 ServiceWorkerContextCore::RegistrationCallback MakeRegisteredCallback(
40 int64* store_registration_id,
41 int64* store_version_id) {
42 return base::Bind(&SaveResponseCallback, called,
43 store_registration_id,
47 void CallCompletedCallback(bool* called, ServiceWorkerStatusCode) {
51 ServiceWorkerContextCore::UnregistrationCallback MakeUnregisteredCallback(
53 return base::Bind(&CallCompletedCallback, called);
56 void ExpectRegisteredWorkers(
57 ServiceWorkerStatusCode expect_status,
58 int64 expect_version_id,
61 ServiceWorkerStatusCode status,
62 const scoped_refptr<ServiceWorkerRegistration>& registration) {
63 ASSERT_EQ(expect_status, status);
64 if (status != SERVICE_WORKER_OK) {
65 EXPECT_FALSE(registration.get());
70 EXPECT_TRUE(registration->waiting_version());
71 EXPECT_EQ(expect_version_id,
72 registration->waiting_version()->version_id());
74 EXPECT_FALSE(registration->waiting_version());
78 EXPECT_TRUE(registration->active_version());
79 EXPECT_EQ(expect_version_id,
80 registration->active_version()->version_id());
82 EXPECT_FALSE(registration->active_version());
86 class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
88 explicit RejectInstallTestHelper(int mock_render_process_id)
89 : EmbeddedWorkerTestHelper(mock_render_process_id) {}
91 virtual void OnInstallEvent(int embedded_worker_id,
93 int active_version_id) OVERRIDE {
95 new ServiceWorkerHostMsg_InstallEventFinished(
96 embedded_worker_id, request_id,
97 blink::WebServiceWorkerEventResultRejected));
101 class RejectActivateTestHelper : public EmbeddedWorkerTestHelper {
103 explicit RejectActivateTestHelper(int mock_render_process_id)
104 : EmbeddedWorkerTestHelper(mock_render_process_id) {}
106 virtual void OnActivateEvent(int embedded_worker_id,
107 int request_id) OVERRIDE {
109 new ServiceWorkerHostMsg_ActivateEventFinished(
110 embedded_worker_id, request_id,
111 blink::WebServiceWorkerEventResultRejected));
117 class ServiceWorkerContextTest : public testing::Test {
119 ServiceWorkerContextTest()
120 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
121 render_process_id_(99) {}
123 virtual void SetUp() OVERRIDE {
124 helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
127 virtual void TearDown() OVERRIDE {
131 ServiceWorkerContextCore* context() { return helper_->context(); }
134 TestBrowserThreadBundle browser_thread_bundle_;
135 scoped_ptr<EmbeddedWorkerTestHelper> helper_;
136 const int render_process_id_;
139 // Make sure basic registration is working.
140 TEST_F(ServiceWorkerContextTest, Register) {
141 int64 registration_id = kInvalidServiceWorkerRegistrationId;
142 int64 version_id = kInvalidServiceWorkerVersionId;
144 context()->RegisterServiceWorker(
145 GURL("http://www.example.com/"),
146 GURL("http://www.example.com/service_worker.js"),
148 MakeRegisteredCallback(&called, ®istration_id, &version_id));
150 ASSERT_FALSE(called);
151 base::RunLoop().RunUntilIdle();
154 EXPECT_EQ(4UL, helper_->ipc_sink()->message_count());
155 EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
156 EmbeddedWorkerMsg_StartWorker::ID));
157 EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
158 ServiceWorkerMsg_InstallEvent::ID));
159 EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
160 ServiceWorkerMsg_ActivateEvent::ID));
161 EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
162 EmbeddedWorkerMsg_StopWorker::ID));
163 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
164 EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
166 context()->storage()->FindRegistrationForId(
168 GURL("http://www.example.com"),
169 base::Bind(&ExpectRegisteredWorkers,
172 false /* expect_waiting */,
173 true /* expect_active */));
174 base::RunLoop().RunUntilIdle();
177 // Test registration when the service worker rejects the install event. The
178 // registration callback should indicate success, but there should be no waiting
179 // or active worker in the registration.
180 TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
181 helper_.reset(); // Make sure the process lookups stay overridden.
182 helper_.reset(new RejectInstallTestHelper(render_process_id_));
183 int64 registration_id = kInvalidServiceWorkerRegistrationId;
184 int64 version_id = kInvalidServiceWorkerVersionId;
186 context()->RegisterServiceWorker(
187 GURL("http://www.example.com/"),
188 GURL("http://www.example.com/service_worker.js"),
190 MakeRegisteredCallback(&called, ®istration_id, &version_id));
192 ASSERT_FALSE(called);
193 base::RunLoop().RunUntilIdle();
196 EXPECT_EQ(3UL, helper_->ipc_sink()->message_count());
197 EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
198 EmbeddedWorkerMsg_StartWorker::ID));
199 EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
200 ServiceWorkerMsg_InstallEvent::ID));
201 EXPECT_FALSE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
202 ServiceWorkerMsg_ActivateEvent::ID));
203 EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
204 EmbeddedWorkerMsg_StopWorker::ID));
205 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
206 EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
208 context()->storage()->FindRegistrationForId(
210 GURL("http://www.example.com"),
211 base::Bind(&ExpectRegisteredWorkers,
212 SERVICE_WORKER_ERROR_NOT_FOUND,
213 kInvalidServiceWorkerVersionId,
214 false /* expect_waiting */,
215 false /* expect_active */));
216 base::RunLoop().RunUntilIdle();
219 // Test registration when the service worker rejects the activate event. The
220 // registration callback should indicate success, but there should be no waiting
221 // or active worker in the registration.
222 TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
223 helper_.reset(); // Make sure the process lookups stay overridden.
224 helper_.reset(new RejectActivateTestHelper(render_process_id_));
225 int64 registration_id = kInvalidServiceWorkerRegistrationId;
226 int64 version_id = kInvalidServiceWorkerVersionId;
228 context()->RegisterServiceWorker(
229 GURL("http://www.example.com/"),
230 GURL("http://www.example.com/service_worker.js"),
232 MakeRegisteredCallback(&called, ®istration_id, &version_id));
234 ASSERT_FALSE(called);
235 base::RunLoop().RunUntilIdle();
238 EXPECT_EQ(4UL, helper_->ipc_sink()->message_count());
239 EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
240 EmbeddedWorkerMsg_StartWorker::ID));
241 EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
242 ServiceWorkerMsg_InstallEvent::ID));
243 EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
244 ServiceWorkerMsg_ActivateEvent::ID));
245 EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
246 EmbeddedWorkerMsg_StopWorker::ID));
247 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
248 EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
250 context()->storage()->FindRegistrationForId(
252 GURL("http://www.example.com"),
253 base::Bind(&ExpectRegisteredWorkers,
254 SERVICE_WORKER_ERROR_NOT_FOUND,
255 kInvalidServiceWorkerVersionId,
256 false /* expect_waiting */,
257 false /* expect_active */));
258 base::RunLoop().RunUntilIdle();
261 // Make sure registrations are cleaned up when they are unregistered.
262 TEST_F(ServiceWorkerContextTest, Unregister) {
263 GURL pattern("http://www.example.com/");
266 int64 registration_id = kInvalidServiceWorkerRegistrationId;
267 int64 version_id = kInvalidServiceWorkerVersionId;
268 context()->RegisterServiceWorker(
270 GURL("http://www.example.com/service_worker.js"),
272 MakeRegisteredCallback(&called, ®istration_id, &version_id));
274 ASSERT_FALSE(called);
275 base::RunLoop().RunUntilIdle();
277 EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
278 EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
281 context()->UnregisterServiceWorker(pattern,
282 MakeUnregisteredCallback(&called));
284 ASSERT_FALSE(called);
285 base::RunLoop().RunUntilIdle();
288 context()->storage()->FindRegistrationForId(
291 base::Bind(&ExpectRegisteredWorkers,
292 SERVICE_WORKER_ERROR_NOT_FOUND,
293 kInvalidServiceWorkerVersionId,
294 false /* expect_waiting */,
295 false /* expect_active */));
296 base::RunLoop().RunUntilIdle();
299 // Make sure registering a new script creates a new version and shares an
300 // existing registration.
301 TEST_F(ServiceWorkerContextTest, RegisterNewScript) {
302 GURL pattern("http://www.example.com/");
305 int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
306 int64 old_version_id = kInvalidServiceWorkerVersionId;
307 context()->RegisterServiceWorker(
309 GURL("http://www.example.com/service_worker.js"),
311 MakeRegisteredCallback(&called, &old_registration_id, &old_version_id));
313 ASSERT_FALSE(called);
314 base::RunLoop().RunUntilIdle();
316 EXPECT_NE(kInvalidServiceWorkerRegistrationId, old_registration_id);
317 EXPECT_NE(kInvalidServiceWorkerVersionId, old_version_id);
320 int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
321 int64 new_version_id = kInvalidServiceWorkerVersionId;
322 context()->RegisterServiceWorker(
324 GURL("http://www.example.com/service_worker_new.js"),
326 MakeRegisteredCallback(&called, &new_registration_id, &new_version_id));
328 ASSERT_FALSE(called);
329 base::RunLoop().RunUntilIdle();
332 EXPECT_NE(kInvalidServiceWorkerRegistrationId, new_registration_id);
333 EXPECT_NE(kInvalidServiceWorkerVersionId, new_version_id);
334 EXPECT_EQ(old_registration_id, new_registration_id);
335 EXPECT_NE(old_version_id, new_version_id);
338 // Make sure that when registering a duplicate pattern+script_url
339 // combination, that the same registration is used.
340 TEST_F(ServiceWorkerContextTest, RegisterDuplicateScript) {
341 GURL pattern("http://www.example.com/");
342 GURL script_url("http://www.example.com/service_worker.js");
345 int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
346 int64 old_version_id = kInvalidServiceWorkerVersionId;
347 context()->RegisterServiceWorker(
351 MakeRegisteredCallback(&called, &old_registration_id, &old_version_id));
353 ASSERT_FALSE(called);
354 base::RunLoop().RunUntilIdle();
356 EXPECT_NE(kInvalidServiceWorkerRegistrationId, old_registration_id);
357 EXPECT_NE(kInvalidServiceWorkerVersionId, old_version_id);
360 int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
361 int64 new_version_id = kInvalidServiceWorkerVersionId;
362 context()->RegisterServiceWorker(
366 MakeRegisteredCallback(&called, &new_registration_id, &new_version_id));
368 ASSERT_FALSE(called);
369 base::RunLoop().RunUntilIdle();
371 EXPECT_EQ(old_registration_id, new_registration_id);
372 EXPECT_EQ(old_version_id, new_version_id);
375 // TODO(nhiroki): Test this for on-disk storage.
376 TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
377 int64 registration_id = kInvalidServiceWorkerRegistrationId;
378 int64 version_id = kInvalidServiceWorkerVersionId;
380 context()->RegisterServiceWorker(
381 GURL("http://www.example.com/"),
382 GURL("http://www.example.com/service_worker.js"),
384 MakeRegisteredCallback(&called, ®istration_id, &version_id));
386 ASSERT_FALSE(called);
387 base::RunLoop().RunUntilIdle();
390 context()->storage()->FindRegistrationForId(
392 GURL("http://www.example.com"),
393 base::Bind(&ExpectRegisteredWorkers,
396 false /* expect_waiting */,
397 true /* expect_active */));
398 base::RunLoop().RunUntilIdle();
400 context()->ScheduleDeleteAndStartOver();
402 // The storage is disabled while the recovery process is running, so the
403 // operation should be failed.
404 context()->storage()->FindRegistrationForId(
406 GURL("http://www.example.com"),
407 base::Bind(&ExpectRegisteredWorkers,
408 SERVICE_WORKER_ERROR_FAILED,
410 false /* expect_waiting */,
411 true /* expect_active */));
412 base::RunLoop().RunUntilIdle();
414 // The context started over and the storage was re-initialized, so the
415 // registration should not be found.
416 context()->storage()->FindRegistrationForId(
418 GURL("http://www.example.com"),
419 base::Bind(&ExpectRegisteredWorkers,
420 SERVICE_WORKER_ERROR_NOT_FOUND,
422 false /* expect_waiting */,
423 true /* expect_active */));
424 base::RunLoop().RunUntilIdle();
427 context()->RegisterServiceWorker(
428 GURL("http://www.example.com/"),
429 GURL("http://www.example.com/service_worker.js"),
431 MakeRegisteredCallback(&called, ®istration_id, &version_id));
433 ASSERT_FALSE(called);
434 base::RunLoop().RunUntilIdle();
437 context()->storage()->FindRegistrationForId(
439 GURL("http://www.example.com"),
440 base::Bind(&ExpectRegisteredWorkers,
443 false /* expect_waiting */,
444 true /* expect_active */));
445 base::RunLoop().RunUntilIdle();
448 } // namespace content