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/*"),
124 GURL("http://www.example.com/service_worker.js"),
126 helper_->context()->AsWeakPtr());
127 version_ = new ServiceWorkerVersion(
128 registration_, 1L, helper_->context()->AsWeakPtr());
130 // Simulate adding one process to the worker.
131 int embedded_worker_id = version_->embedded_worker()->embedded_worker_id();
132 helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId);
133 ASSERT_TRUE(version_->HasProcessToRun());
136 virtual void TearDown() OVERRIDE {
142 TestBrowserThreadBundle thread_bundle_;
143 scoped_ptr<MessageReceiver> helper_;
144 scoped_refptr<ServiceWorkerRegistration> registration_;
145 scoped_refptr<ServiceWorkerVersion> version_;
146 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersionTest);
149 TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
150 // Call StartWorker() multiple times.
151 ServiceWorkerStatusCode status1 = SERVICE_WORKER_ERROR_FAILED;
152 ServiceWorkerStatusCode status2 = SERVICE_WORKER_ERROR_FAILED;
153 ServiceWorkerStatusCode status3 = SERVICE_WORKER_ERROR_FAILED;
154 version_->StartWorker(CreateReceiverOnCurrentThread(&status1));
155 version_->StartWorker(CreateReceiverOnCurrentThread(&status2));
157 EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
158 base::RunLoop().RunUntilIdle();
159 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
161 // Call StartWorker() after it's started.
162 version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
163 base::RunLoop().RunUntilIdle();
165 // All should just succeed.
166 EXPECT_EQ(SERVICE_WORKER_OK, status1);
167 EXPECT_EQ(SERVICE_WORKER_OK, status2);
168 EXPECT_EQ(SERVICE_WORKER_OK, status3);
170 // Call StopWorker() multiple times.
171 status1 = SERVICE_WORKER_ERROR_FAILED;
172 status2 = SERVICE_WORKER_ERROR_FAILED;
173 status3 = SERVICE_WORKER_ERROR_FAILED;
174 version_->StopWorker(CreateReceiverOnCurrentThread(&status1));
175 version_->StopWorker(CreateReceiverOnCurrentThread(&status2));
177 // Also try calling StartWorker while StopWorker is in queue.
178 version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
180 EXPECT_EQ(ServiceWorkerVersion::STOPPING, version_->running_status());
181 base::RunLoop().RunUntilIdle();
182 EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
184 // All StopWorker should just succeed, while StartWorker fails.
185 EXPECT_EQ(SERVICE_WORKER_OK, status1);
186 EXPECT_EQ(SERVICE_WORKER_OK, status2);
187 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status3);
190 TEST_F(ServiceWorkerVersionTest, SendMessage) {
191 EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
193 // Send a message without starting the worker.
194 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
195 version_->SendMessage(TestMsg_Message(),
196 CreateReceiverOnCurrentThread(&status));
197 base::RunLoop().RunUntilIdle();
198 EXPECT_EQ(SERVICE_WORKER_OK, status);
200 // The worker should be now started.
201 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
203 // Stop the worker, and then send the message immediately.
204 ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED;
205 ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
206 version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
207 version_->SendMessage(TestMsg_Message(),
208 CreateReceiverOnCurrentThread(&msg_status));
209 base::RunLoop().RunUntilIdle();
210 EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
212 // SendMessage should return START_WORKER_FAILED error since it tried to
213 // start a worker while it was stopping.
214 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, msg_status);
217 TEST_F(ServiceWorkerVersionTest, ReSendMessageAfterStop) {
218 EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
221 ServiceWorkerStatusCode start_status = SERVICE_WORKER_ERROR_FAILED;
222 version_->StartWorker(CreateReceiverOnCurrentThread(&start_status));
223 base::RunLoop().RunUntilIdle();
224 EXPECT_EQ(SERVICE_WORKER_OK, start_status);
225 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
227 // Stop the worker, and then send the message immediately.
228 ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED;
229 ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
230 version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
231 version_->SendMessage(TestMsg_Message(),
232 CreateReceiverOnCurrentThread(&msg_status));
233 base::RunLoop().RunUntilIdle();
234 EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
236 // SendMessage should return START_WORKER_FAILED error since it tried to
237 // start a worker while it was stopping.
238 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, msg_status);
240 // Resend the message, which should succeed and restart the worker.
241 version_->SendMessage(TestMsg_Message(),
242 CreateReceiverOnCurrentThread(&msg_status));
243 base::RunLoop().RunUntilIdle();
244 EXPECT_EQ(SERVICE_WORKER_OK, msg_status);
245 EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
248 TEST_F(ServiceWorkerVersionTest, ReceiveMessageFromWorker) {
249 MessageReceiverFromWorker receiver(version_->embedded_worker());
251 // Simulate sending some dummy values from the worker.
252 helper_->SimulateSendValueToBrowser(
253 version_->embedded_worker()->embedded_worker_id(), 555);
254 helper_->SimulateSendValueToBrowser(
255 version_->embedded_worker()->embedded_worker_id(), 777);
257 // Verify the receiver received the values.
258 ASSERT_EQ(2U, receiver.received_values().size());
259 EXPECT_EQ(555, receiver.received_values()[0]);
260 EXPECT_EQ(777, receiver.received_values()[1]);
263 TEST_F(ServiceWorkerVersionTest, InstallAndWaitCompletion) {
264 EXPECT_EQ(ServiceWorkerVersion::NEW, version_->status());
266 // Dispatch an install event.
267 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
268 version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
270 // Wait for the completion.
271 bool status_change_called = false;
272 version_->RegisterStatusChangeCallback(
273 base::Bind(&VerifyCalled, &status_change_called));
275 base::RunLoop().RunUntilIdle();
277 // After successful completion, version's status must be changed to
278 // INSTALLED, and status change callback must have been fired.
279 EXPECT_EQ(SERVICE_WORKER_OK, status);
280 EXPECT_TRUE(status_change_called);
281 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version_->status());
284 TEST_F(ServiceWorkerVersionTest, ActivateAndWaitCompletion) {
285 version_->SetStatus(ServiceWorkerVersion::INSTALLED);
286 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version_->status());
288 // Dispatch an activate event.
289 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
290 version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
292 // Wait for the completion.
293 bool status_change_called = false;
294 version_->RegisterStatusChangeCallback(
295 base::Bind(&VerifyCalled, &status_change_called));
297 base::RunLoop().RunUntilIdle();
299 // After successful completion, version's status must be changed to
300 // ACTIVE, and status change callback must have been fired.
301 EXPECT_EQ(SERVICE_WORKER_OK, status);
302 EXPECT_TRUE(status_change_called);
303 EXPECT_EQ(ServiceWorkerVersion::ACTIVE, version_->status());
306 TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) {
307 EXPECT_EQ(ServiceWorkerVersion::NEW, version_->status());
309 // Repeatedly observe status changes (the callback re-registers itself).
310 std::vector<ServiceWorkerVersion::Status> statuses;
311 version_->RegisterStatusChangeCallback(
312 base::Bind(&ObserveStatusChanges, version_, &statuses));
314 // Dispatch some events.
315 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
316 version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
317 base::RunLoop().RunUntilIdle();
318 EXPECT_EQ(SERVICE_WORKER_OK, status);
320 status = SERVICE_WORKER_ERROR_FAILED;
321 version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
322 base::RunLoop().RunUntilIdle();
323 EXPECT_EQ(SERVICE_WORKER_OK, status);
325 // Verify that we could successfully observe repeated status changes.
326 ASSERT_EQ(4U, statuses.size());
327 ASSERT_EQ(ServiceWorkerVersion::INSTALLING, statuses[0]);
328 ASSERT_EQ(ServiceWorkerVersion::INSTALLED, statuses[1]);
329 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, statuses[2]);
330 ASSERT_EQ(ServiceWorkerVersion::ACTIVE, statuses[3]);
333 TEST_F(ServiceWorkerVersionTest, AddAndRemoveProcesses) {
334 // Preparation (to reset the process count to 0).
335 ASSERT_TRUE(version_->HasProcessToRun());
336 version_->RemoveProcessFromWorker(kRenderProcessId);
337 ASSERT_FALSE(version_->HasProcessToRun());
339 // Add another process to the worker twice, and then remove process once.
340 const int another_process_id = kRenderProcessId + 1;
341 version_->AddProcessToWorker(another_process_id);
342 version_->AddProcessToWorker(another_process_id);
343 version_->RemoveProcessFromWorker(another_process_id);
345 // We're ref-counting the process internally, so adding the same process
346 // multiple times should be handled correctly.
347 ASSERT_TRUE(version_->HasProcessToRun());
349 // Removing the process again (so that # of AddProcess == # of RemoveProcess
350 // for the process) should remove all process references.
351 version_->RemoveProcessFromWorker(another_process_id);
352 ASSERT_FALSE(version_->HasProcessToRun());
355 } // namespace content