Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_version_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/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"
15
16 // IPC messages for testing ---------------------------------------------------
17
18 #define IPC_MESSAGE_IMPL
19 #include "ipc/ipc_message_macros.h"
20
21 #define IPC_MESSAGE_START TestMsgStart
22
23 IPC_MESSAGE_CONTROL0(TestMsg_Message);
24 IPC_MESSAGE_ROUTED1(TestMsg_MessageFromWorker, int);
25
26 // ---------------------------------------------------------------------------
27
28 namespace content {
29
30 namespace {
31
32 static const int kRenderProcessId = 1;
33
34 class MessageReceiver : public EmbeddedWorkerTestHelper {
35  public:
36   MessageReceiver()
37       : EmbeddedWorkerTestHelper(kRenderProcessId),
38         current_embedded_worker_id_(0) {}
39   virtual ~MessageReceiver() {}
40
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)) {
46       return true;
47     }
48     current_embedded_worker_id_ = embedded_worker_id;
49     bool handled = true;
50     IPC_BEGIN_MESSAGE_MAP(MessageReceiver, message)
51       IPC_MESSAGE_HANDLER(TestMsg_Message, OnMessage)
52       IPC_MESSAGE_UNHANDLED(handled = false)
53     IPC_END_MESSAGE_MAP()
54     return handled;
55   }
56
57   void SimulateSendValueToBrowser(int embedded_worker_id, int value) {
58     SimulateSend(new TestMsg_MessageFromWorker(embedded_worker_id, value));
59   }
60
61  private:
62   void OnMessage() {
63     // Do nothing.
64   }
65
66   int current_embedded_worker_id_;
67   DISALLOW_COPY_AND_ASSIGN(MessageReceiver);
68 };
69
70 void VerifyCalled(bool* called) {
71   *called = true;
72 }
73
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));
79 }
80
81 // A specialized listener class to receive test messages from a worker.
82 class MessageReceiverFromWorker : public EmbeddedWorkerInstance::Listener {
83  public:
84   explicit MessageReceiverFromWorker(EmbeddedWorkerInstance* instance)
85       : instance_(instance) {
86     instance_->AddListener(this);
87   }
88   virtual ~MessageReceiverFromWorker() {
89     instance_->RemoveListener(this);
90   }
91
92   virtual void OnStarted() OVERRIDE { NOTREACHED(); }
93   virtual void OnStopped() OVERRIDE { NOTREACHED(); }
94   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
95     bool handled = true;
96     IPC_BEGIN_MESSAGE_MAP(MessageReceiverFromWorker, message)
97       IPC_MESSAGE_HANDLER(TestMsg_MessageFromWorker, OnMessageFromWorker)
98       IPC_MESSAGE_UNHANDLED(handled = false)
99     IPC_END_MESSAGE_MAP()
100     return handled;
101   }
102
103   void OnMessageFromWorker(int value) { received_values_.push_back(value); }
104   const std::vector<int>& received_values() const { return received_values_; }
105
106  private:
107   EmbeddedWorkerInstance* instance_;
108   std::vector<int> received_values_;
109   DISALLOW_COPY_AND_ASSIGN(MessageReceiverFromWorker);
110 };
111
112 }  // namespace
113
114 class ServiceWorkerVersionTest : public testing::Test {
115  protected:
116   ServiceWorkerVersionTest()
117       : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
118
119   virtual void SetUp() OVERRIDE {
120     helper_.reset(new MessageReceiver());
121
122     registration_ = new ServiceWorkerRegistration(
123         GURL("http://www.example.com/*"),
124         GURL("http://www.example.com/service_worker.js"),
125         1L,
126         helper_->context()->AsWeakPtr());
127     version_ = new ServiceWorkerVersion(
128         registration_, 1L, helper_->context()->AsWeakPtr());
129
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());
134   }
135
136   virtual void TearDown() OVERRIDE {
137     version_ = 0;
138     registration_ = 0;
139     helper_.reset();
140   }
141
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);
147 };
148
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));
156
157   EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
158   base::RunLoop().RunUntilIdle();
159   EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
160
161   // Call StartWorker() after it's started.
162   version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
163   base::RunLoop().RunUntilIdle();
164
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);
169
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));
176
177   // Also try calling StartWorker while StopWorker is in queue.
178   version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
179
180   EXPECT_EQ(ServiceWorkerVersion::STOPPING, version_->running_status());
181   base::RunLoop().RunUntilIdle();
182   EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
183
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);
188 }
189
190 TEST_F(ServiceWorkerVersionTest, SendMessage) {
191   EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
192
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);
199
200   // The worker should be now started.
201   EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
202
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);
211
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);
215 }
216
217 TEST_F(ServiceWorkerVersionTest, ReSendMessageAfterStop) {
218   EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
219
220   // Start the worker.
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());
226
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);
235
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);
239
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());
246 }
247
248 TEST_F(ServiceWorkerVersionTest, ReceiveMessageFromWorker) {
249   MessageReceiverFromWorker receiver(version_->embedded_worker());
250
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);
256
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]);
261 }
262
263 TEST_F(ServiceWorkerVersionTest, InstallAndWaitCompletion) {
264   EXPECT_EQ(ServiceWorkerVersion::NEW, version_->status());
265
266   // Dispatch an install event.
267   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
268   version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
269
270   // Wait for the completion.
271   bool status_change_called = false;
272   version_->RegisterStatusChangeCallback(
273       base::Bind(&VerifyCalled, &status_change_called));
274
275   base::RunLoop().RunUntilIdle();
276
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());
282 }
283
284 TEST_F(ServiceWorkerVersionTest, ActivateAndWaitCompletion) {
285   version_->SetStatus(ServiceWorkerVersion::INSTALLED);
286   EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version_->status());
287
288   // Dispatch an activate event.
289   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
290   version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
291
292   // Wait for the completion.
293   bool status_change_called = false;
294   version_->RegisterStatusChangeCallback(
295       base::Bind(&VerifyCalled, &status_change_called));
296
297   base::RunLoop().RunUntilIdle();
298
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());
304 }
305
306 TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) {
307   EXPECT_EQ(ServiceWorkerVersion::NEW, version_->status());
308
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));
313
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);
319
320   status = SERVICE_WORKER_ERROR_FAILED;
321   version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
322   base::RunLoop().RunUntilIdle();
323   EXPECT_EQ(SERVICE_WORKER_OK, status);
324
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]);
331 }
332
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());
338
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);
344
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());
348
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());
353 }
354
355 }  // namespace content