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/basictypes.h"
6 #include "base/run_loop.h"
7 #include "content/browser/service_worker/embedded_worker_registry.h"
8 #include "content/browser/service_worker/embedded_worker_test_helper.h"
9 #include "content/browser/service_worker/service_worker_context_core.h"
10 #include "content/browser/service_worker/service_worker_registration.h"
11 #include "content/browser/service_worker/service_worker_test_utils.h"
12 #include "content/browser/service_worker/service_worker_version.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 // IPC messages for testing ---------------------------------------------------
18 #define IPC_MESSAGE_IMPL
19 #include "ipc/ipc_message_macros.h"
21 #define IPC_MESSAGE_START TestMsgStart
23 IPC_MESSAGE_CONTROL0(TestMsg_Message
);
24 IPC_MESSAGE_ROUTED1(TestMsg_MessageFromWorker
, int);
26 // ---------------------------------------------------------------------------
32 static const int kRenderProcessId
= 1;
34 class MessageReceiver
: public EmbeddedWorkerTestHelper
{
37 : EmbeddedWorkerTestHelper(kRenderProcessId
),
38 current_embedded_worker_id_(0) {}
39 virtual ~MessageReceiver() {}
41 virtual bool OnMessageToWorker(int thread_id
,
42 int embedded_worker_id
,
43 const IPC::Message
& message
) OVERRIDE
{
44 if (EmbeddedWorkerTestHelper::OnMessageToWorker(
45 thread_id
, embedded_worker_id
, message
)) {
48 current_embedded_worker_id_
= embedded_worker_id
;
50 IPC_BEGIN_MESSAGE_MAP(MessageReceiver
, message
)
51 IPC_MESSAGE_HANDLER(TestMsg_Message
, OnMessage
)
52 IPC_MESSAGE_UNHANDLED(handled
= false)
57 void SimulateSendValueToBrowser(int embedded_worker_id
, int value
) {
58 SimulateSend(new TestMsg_MessageFromWorker(embedded_worker_id
, value
));
66 int current_embedded_worker_id_
;
67 DISALLOW_COPY_AND_ASSIGN(MessageReceiver
);
70 void VerifyCalled(bool* called
) {
74 void ObserveStatusChanges(ServiceWorkerVersion
* version
,
75 std::vector
<ServiceWorkerVersion::Status
>* statuses
) {
76 statuses
->push_back(version
->status());
77 version
->RegisterStatusChangeCallback(
78 base::Bind(&ObserveStatusChanges
, base::Unretained(version
), statuses
));
81 // A specialized listener class to receive test messages from a worker.
82 class MessageReceiverFromWorker
: public EmbeddedWorkerInstance::Listener
{
84 explicit MessageReceiverFromWorker(EmbeddedWorkerInstance
* instance
)
85 : instance_(instance
) {
86 instance_
->AddListener(this);
88 virtual ~MessageReceiverFromWorker() {
89 instance_
->RemoveListener(this);
92 virtual void OnStarted() OVERRIDE
{ NOTREACHED(); }
93 virtual void OnStopped() OVERRIDE
{ NOTREACHED(); }
94 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
96 IPC_BEGIN_MESSAGE_MAP(MessageReceiverFromWorker
, message
)
97 IPC_MESSAGE_HANDLER(TestMsg_MessageFromWorker
, OnMessageFromWorker
)
98 IPC_MESSAGE_UNHANDLED(handled
= false)
103 void OnMessageFromWorker(int value
) { received_values_
.push_back(value
); }
104 const std::vector
<int>& received_values() const { return received_values_
; }
107 EmbeddedWorkerInstance
* instance_
;
108 std::vector
<int> received_values_
;
109 DISALLOW_COPY_AND_ASSIGN(MessageReceiverFromWorker
);
114 class ServiceWorkerVersionTest
: public testing::Test
{
116 ServiceWorkerVersionTest()
117 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP
) {}
119 virtual void SetUp() OVERRIDE
{
120 helper_
.reset(new MessageReceiver());
122 registration_
= new ServiceWorkerRegistration(
123 GURL("http://www.example.com/"),
125 helper_
->context()->AsWeakPtr());
126 version_
= new ServiceWorkerVersion(
128 GURL("http://www.example.com/service_worker.js"),
130 helper_
->context()->AsWeakPtr());
132 // Simulate adding one process to the worker.
133 int embedded_worker_id
= version_
->embedded_worker()->embedded_worker_id();
134 helper_
->SimulateAddProcessToWorker(embedded_worker_id
, kRenderProcessId
);
135 ASSERT_TRUE(version_
->HasProcessToRun());
138 virtual void TearDown() OVERRIDE
{
144 TestBrowserThreadBundle thread_bundle_
;
145 scoped_ptr
<MessageReceiver
> helper_
;
146 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
147 scoped_refptr
<ServiceWorkerVersion
> version_
;
150 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersionTest
);
153 TEST_F(ServiceWorkerVersionTest
, ConcurrentStartAndStop
) {
154 // Call StartWorker() multiple times.
155 ServiceWorkerStatusCode status1
= SERVICE_WORKER_ERROR_FAILED
;
156 ServiceWorkerStatusCode status2
= SERVICE_WORKER_ERROR_FAILED
;
157 ServiceWorkerStatusCode status3
= SERVICE_WORKER_ERROR_FAILED
;
158 version_
->StartWorker(CreateReceiverOnCurrentThread(&status1
));
159 version_
->StartWorker(CreateReceiverOnCurrentThread(&status2
));
161 EXPECT_EQ(ServiceWorkerVersion::STARTING
, version_
->running_status());
162 base::RunLoop().RunUntilIdle();
163 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version_
->running_status());
165 // Call StartWorker() after it's started.
166 version_
->StartWorker(CreateReceiverOnCurrentThread(&status3
));
167 base::RunLoop().RunUntilIdle();
169 // All should just succeed.
170 EXPECT_EQ(SERVICE_WORKER_OK
, status1
);
171 EXPECT_EQ(SERVICE_WORKER_OK
, status2
);
172 EXPECT_EQ(SERVICE_WORKER_OK
, status3
);
174 // Call StopWorker() multiple times.
175 status1
= SERVICE_WORKER_ERROR_FAILED
;
176 status2
= SERVICE_WORKER_ERROR_FAILED
;
177 status3
= SERVICE_WORKER_ERROR_FAILED
;
178 version_
->StopWorker(CreateReceiverOnCurrentThread(&status1
));
179 version_
->StopWorker(CreateReceiverOnCurrentThread(&status2
));
181 // Also try calling StartWorker while StopWorker is in queue.
182 version_
->StartWorker(CreateReceiverOnCurrentThread(&status3
));
184 EXPECT_EQ(ServiceWorkerVersion::STOPPING
, version_
->running_status());
185 base::RunLoop().RunUntilIdle();
186 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version_
->running_status());
188 // All StopWorker should just succeed, while StartWorker fails.
189 EXPECT_EQ(SERVICE_WORKER_OK
, status1
);
190 EXPECT_EQ(SERVICE_WORKER_OK
, status2
);
191 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED
, status3
);
194 TEST_F(ServiceWorkerVersionTest
, SendMessage
) {
195 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version_
->running_status());
197 // Send a message without starting the worker.
198 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
199 version_
->SendMessage(TestMsg_Message(),
200 CreateReceiverOnCurrentThread(&status
));
201 base::RunLoop().RunUntilIdle();
202 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
204 // The worker should be now started.
205 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version_
->running_status());
207 // Stop the worker, and then send the message immediately.
208 ServiceWorkerStatusCode msg_status
= SERVICE_WORKER_ERROR_FAILED
;
209 ServiceWorkerStatusCode stop_status
= SERVICE_WORKER_ERROR_FAILED
;
210 version_
->StopWorker(CreateReceiverOnCurrentThread(&stop_status
));
211 version_
->SendMessage(TestMsg_Message(),
212 CreateReceiverOnCurrentThread(&msg_status
));
213 base::RunLoop().RunUntilIdle();
214 EXPECT_EQ(SERVICE_WORKER_OK
, stop_status
);
216 // SendMessage should return START_WORKER_FAILED error since it tried to
217 // start a worker while it was stopping.
218 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED
, msg_status
);
221 TEST_F(ServiceWorkerVersionTest
, ReSendMessageAfterStop
) {
222 EXPECT_EQ(ServiceWorkerVersion::STOPPED
, version_
->running_status());
225 ServiceWorkerStatusCode start_status
= SERVICE_WORKER_ERROR_FAILED
;
226 version_
->StartWorker(CreateReceiverOnCurrentThread(&start_status
));
227 base::RunLoop().RunUntilIdle();
228 EXPECT_EQ(SERVICE_WORKER_OK
, start_status
);
229 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version_
->running_status());
231 // Stop the worker, and then send the message immediately.
232 ServiceWorkerStatusCode msg_status
= SERVICE_WORKER_ERROR_FAILED
;
233 ServiceWorkerStatusCode stop_status
= SERVICE_WORKER_ERROR_FAILED
;
234 version_
->StopWorker(CreateReceiverOnCurrentThread(&stop_status
));
235 version_
->SendMessage(TestMsg_Message(),
236 CreateReceiverOnCurrentThread(&msg_status
));
237 base::RunLoop().RunUntilIdle();
238 EXPECT_EQ(SERVICE_WORKER_OK
, stop_status
);
240 // SendMessage should return START_WORKER_FAILED error since it tried to
241 // start a worker while it was stopping.
242 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED
, msg_status
);
244 // Resend the message, which should succeed and restart the worker.
245 version_
->SendMessage(TestMsg_Message(),
246 CreateReceiverOnCurrentThread(&msg_status
));
247 base::RunLoop().RunUntilIdle();
248 EXPECT_EQ(SERVICE_WORKER_OK
, msg_status
);
249 EXPECT_EQ(ServiceWorkerVersion::RUNNING
, version_
->running_status());
252 TEST_F(ServiceWorkerVersionTest
, ReceiveMessageFromWorker
) {
253 MessageReceiverFromWorker
receiver(version_
->embedded_worker());
255 // Simulate sending some dummy values from the worker.
256 helper_
->SimulateSendValueToBrowser(
257 version_
->embedded_worker()->embedded_worker_id(), 555);
258 helper_
->SimulateSendValueToBrowser(
259 version_
->embedded_worker()->embedded_worker_id(), 777);
261 // Verify the receiver received the values.
262 ASSERT_EQ(2U, receiver
.received_values().size());
263 EXPECT_EQ(555, receiver
.received_values()[0]);
264 EXPECT_EQ(777, receiver
.received_values()[1]);
267 TEST_F(ServiceWorkerVersionTest
, InstallAndWaitCompletion
) {
268 version_
->SetStatus(ServiceWorkerVersion::INSTALLING
);
270 // Dispatch an install event.
271 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
272 version_
->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status
));
274 // Wait for the completion.
275 bool status_change_called
= false;
276 version_
->RegisterStatusChangeCallback(
277 base::Bind(&VerifyCalled
, &status_change_called
));
279 base::RunLoop().RunUntilIdle();
281 // Version's status must not have changed during installation.
282 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
283 EXPECT_FALSE(status_change_called
);
284 EXPECT_EQ(ServiceWorkerVersion::INSTALLING
, version_
->status());
287 TEST_F(ServiceWorkerVersionTest
, ActivateAndWaitCompletion
) {
288 version_
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
290 // Dispatch an activate event.
291 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
292 version_
->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status
));
294 // Wait for the completion.
295 bool status_change_called
= false;
296 version_
->RegisterStatusChangeCallback(
297 base::Bind(&VerifyCalled
, &status_change_called
));
299 base::RunLoop().RunUntilIdle();
301 // Version's status must not have changed during activation.
302 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
303 EXPECT_FALSE(status_change_called
);
304 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING
, version_
->status());
307 TEST_F(ServiceWorkerVersionTest
, RepeatedlyObserveStatusChanges
) {
308 EXPECT_EQ(ServiceWorkerVersion::NEW
, version_
->status());
310 // Repeatedly observe status changes (the callback re-registers itself).
311 std::vector
<ServiceWorkerVersion::Status
> statuses
;
312 version_
->RegisterStatusChangeCallback(
313 base::Bind(&ObserveStatusChanges
, version_
, &statuses
));
315 version_
->SetStatus(ServiceWorkerVersion::INSTALLING
);
316 version_
->SetStatus(ServiceWorkerVersion::INSTALLED
);
317 version_
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
318 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
319 version_
->SetStatus(ServiceWorkerVersion::REDUNDANT
);
321 // Verify that we could successfully observe repeated status changes.
322 ASSERT_EQ(5U, statuses
.size());
323 ASSERT_EQ(ServiceWorkerVersion::INSTALLING
, statuses
[0]);
324 ASSERT_EQ(ServiceWorkerVersion::INSTALLED
, statuses
[1]);
325 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING
, statuses
[2]);
326 ASSERT_EQ(ServiceWorkerVersion::ACTIVATED
, statuses
[3]);
327 ASSERT_EQ(ServiceWorkerVersion::REDUNDANT
, statuses
[4]);
330 TEST_F(ServiceWorkerVersionTest
, AddAndRemoveProcesses
) {
331 // Preparation (to reset the process count to 0).
332 ASSERT_TRUE(version_
->HasProcessToRun());
333 version_
->RemoveProcessFromWorker(kRenderProcessId
);
334 ASSERT_FALSE(version_
->HasProcessToRun());
336 // Add another process to the worker twice, and then remove process once.
337 const int another_process_id
= kRenderProcessId
+ 1;
338 version_
->AddProcessToWorker(another_process_id
);
339 version_
->AddProcessToWorker(another_process_id
);
340 version_
->RemoveProcessFromWorker(another_process_id
);
342 // We're ref-counting the process internally, so adding the same process
343 // multiple times should be handled correctly.
344 ASSERT_TRUE(version_
->HasProcessToRun());
346 // Removing the process again (so that # of AddProcess == # of RemoveProcess
347 // for the process) should remove all process references.
348 version_
->RemoveProcessFromWorker(another_process_id
);
349 ASSERT_FALSE(version_
->HasProcessToRun());
352 TEST_F(ServiceWorkerVersionTest
, ScheduleStopWorker
) {
353 // Verify the timer is not running when version initializes its status.
354 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
355 EXPECT_FALSE(version_
->stop_worker_timer_
.IsRunning());
357 // Verify the timer is running when version status changes frome ACTIVATING
359 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
360 version_
->StartWorker(CreateReceiverOnCurrentThread(&status
));
361 base::RunLoop().RunUntilIdle();
362 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
363 version_
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
364 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
365 EXPECT_TRUE(version_
->stop_worker_timer_
.IsRunning());
367 // The timer should be running if the worker is restarted without controllee.
368 status
= SERVICE_WORKER_ERROR_FAILED
;
369 version_
->StopWorker(CreateReceiverOnCurrentThread(&status
));
370 base::RunLoop().RunUntilIdle();
371 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
372 status
= SERVICE_WORKER_ERROR_FAILED
;
373 version_
->StartWorker(CreateReceiverOnCurrentThread(&status
));
374 base::RunLoop().RunUntilIdle();
375 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
376 EXPECT_TRUE(version_
->stop_worker_timer_
.IsRunning());
378 // The timer should not be running if a controllee is added.
379 scoped_ptr
<ServiceWorkerProviderHost
> host(
380 new ServiceWorkerProviderHost(33 /* dummy render process id */,
381 1 /* dummy provider_id */,
382 helper_
->context()->AsWeakPtr(),
384 version_
->AddControllee(host
.get());
385 EXPECT_FALSE(version_
->stop_worker_timer_
.IsRunning());
387 // The timer should be running if the controllee is removed.
388 version_
->RemoveControllee(host
.get());
389 EXPECT_TRUE(version_
->stop_worker_timer_
.IsRunning());
392 } // namespace content