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
23IPC_MESSAGE_CONTROL0(TestMsg_Message);
24IPC_MESSAGE_ROUTED1(TestMsg_MessageFromWorker, int);
25
26// ---------------------------------------------------------------------------
27
28namespace content {
29
30namespace {
31
32static const int kRenderProcessId = 1;
33
34class 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
70void VerifyCalled(bool* called) {
71  *called = true;
72}
73
74void 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.
82class 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
114class 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    pattern_ = GURL("http://www.example.com/");
123    registration_ = new ServiceWorkerRegistration(
124        pattern_,
125        1L,
126        helper_->context()->AsWeakPtr());
127    version_ = new ServiceWorkerVersion(
128        registration_.get(),
129        GURL("http://www.example.com/service_worker.js"),
130        1L,
131        helper_->context()->AsWeakPtr());
132
133    // Simulate adding one process to the pattern.
134    helper_->SimulateAddProcessToPattern(pattern_, kRenderProcessId);
135    ASSERT_TRUE(helper_->context()->process_manager()
136        ->PatternHasProcessToRun(pattern_));
137  }
138
139  virtual void TearDown() OVERRIDE {
140    version_ = 0;
141    registration_ = 0;
142    helper_.reset();
143  }
144
145  TestBrowserThreadBundle thread_bundle_;
146  scoped_ptr<MessageReceiver> helper_;
147  scoped_refptr<ServiceWorkerRegistration> registration_;
148  scoped_refptr<ServiceWorkerVersion> version_;
149  GURL pattern_;
150
151 private:
152  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersionTest);
153};
154
155TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
156  // Call StartWorker() multiple times.
157  ServiceWorkerStatusCode status1 = SERVICE_WORKER_ERROR_FAILED;
158  ServiceWorkerStatusCode status2 = SERVICE_WORKER_ERROR_FAILED;
159  ServiceWorkerStatusCode status3 = SERVICE_WORKER_ERROR_FAILED;
160  version_->StartWorker(CreateReceiverOnCurrentThread(&status1));
161  version_->StartWorker(CreateReceiverOnCurrentThread(&status2));
162
163  EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
164  base::RunLoop().RunUntilIdle();
165  EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
166
167  // Call StartWorker() after it's started.
168  version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
169  base::RunLoop().RunUntilIdle();
170
171  // All should just succeed.
172  EXPECT_EQ(SERVICE_WORKER_OK, status1);
173  EXPECT_EQ(SERVICE_WORKER_OK, status2);
174  EXPECT_EQ(SERVICE_WORKER_OK, status3);
175
176  // Call StopWorker() multiple times.
177  status1 = SERVICE_WORKER_ERROR_FAILED;
178  status2 = SERVICE_WORKER_ERROR_FAILED;
179  status3 = SERVICE_WORKER_ERROR_FAILED;
180  version_->StopWorker(CreateReceiverOnCurrentThread(&status1));
181  version_->StopWorker(CreateReceiverOnCurrentThread(&status2));
182
183  // Also try calling StartWorker while StopWorker is in queue.
184  version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
185
186  EXPECT_EQ(ServiceWorkerVersion::STOPPING, version_->running_status());
187  base::RunLoop().RunUntilIdle();
188  EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
189
190  // All StopWorker should just succeed, while StartWorker fails.
191  EXPECT_EQ(SERVICE_WORKER_OK, status1);
192  EXPECT_EQ(SERVICE_WORKER_OK, status2);
193  EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status3);
194}
195
196TEST_F(ServiceWorkerVersionTest, SendMessage) {
197  EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
198
199  // Send a message without starting the worker.
200  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
201  version_->SendMessage(TestMsg_Message(),
202                        CreateReceiverOnCurrentThread(&status));
203  base::RunLoop().RunUntilIdle();
204  EXPECT_EQ(SERVICE_WORKER_OK, status);
205
206  // The worker should be now started.
207  EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
208
209  // Stop the worker, and then send the message immediately.
210  ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED;
211  ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
212  version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
213  version_->SendMessage(TestMsg_Message(),
214                       CreateReceiverOnCurrentThread(&msg_status));
215  base::RunLoop().RunUntilIdle();
216  EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
217
218  // SendMessage should return START_WORKER_FAILED error since it tried to
219  // start a worker while it was stopping.
220  EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, msg_status);
221}
222
223TEST_F(ServiceWorkerVersionTest, ReSendMessageAfterStop) {
224  EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
225
226  // Start the worker.
227  ServiceWorkerStatusCode start_status = SERVICE_WORKER_ERROR_FAILED;
228  version_->StartWorker(CreateReceiverOnCurrentThread(&start_status));
229  base::RunLoop().RunUntilIdle();
230  EXPECT_EQ(SERVICE_WORKER_OK, start_status);
231  EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
232
233  // Stop the worker, and then send the message immediately.
234  ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED;
235  ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
236  version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
237  version_->SendMessage(TestMsg_Message(),
238                       CreateReceiverOnCurrentThread(&msg_status));
239  base::RunLoop().RunUntilIdle();
240  EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
241
242  // SendMessage should return START_WORKER_FAILED error since it tried to
243  // start a worker while it was stopping.
244  EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, msg_status);
245
246  // Resend the message, which should succeed and restart the worker.
247  version_->SendMessage(TestMsg_Message(),
248                       CreateReceiverOnCurrentThread(&msg_status));
249  base::RunLoop().RunUntilIdle();
250  EXPECT_EQ(SERVICE_WORKER_OK, msg_status);
251  EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
252}
253
254TEST_F(ServiceWorkerVersionTest, ReceiveMessageFromWorker) {
255  MessageReceiverFromWorker receiver(version_->embedded_worker());
256
257  // Simulate sending some dummy values from the worker.
258  helper_->SimulateSendValueToBrowser(
259      version_->embedded_worker()->embedded_worker_id(), 555);
260  helper_->SimulateSendValueToBrowser(
261      version_->embedded_worker()->embedded_worker_id(), 777);
262
263  // Verify the receiver received the values.
264  ASSERT_EQ(2U, receiver.received_values().size());
265  EXPECT_EQ(555, receiver.received_values()[0]);
266  EXPECT_EQ(777, receiver.received_values()[1]);
267}
268
269TEST_F(ServiceWorkerVersionTest, InstallAndWaitCompletion) {
270  version_->SetStatus(ServiceWorkerVersion::INSTALLING);
271
272  // Dispatch an install event.
273  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
274  version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
275
276  // Wait for the completion.
277  bool status_change_called = false;
278  version_->RegisterStatusChangeCallback(
279      base::Bind(&VerifyCalled, &status_change_called));
280
281  base::RunLoop().RunUntilIdle();
282
283  // Version's status must not have changed during installation.
284  EXPECT_EQ(SERVICE_WORKER_OK, status);
285  EXPECT_FALSE(status_change_called);
286  EXPECT_EQ(ServiceWorkerVersion::INSTALLING, version_->status());
287}
288
289TEST_F(ServiceWorkerVersionTest, ActivateAndWaitCompletion) {
290  version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
291
292  // Dispatch an activate event.
293  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
294  version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
295
296  // Wait for the completion.
297  bool status_change_called = false;
298  version_->RegisterStatusChangeCallback(
299      base::Bind(&VerifyCalled, &status_change_called));
300
301  base::RunLoop().RunUntilIdle();
302
303  // Version's status must not have changed during activation.
304  EXPECT_EQ(SERVICE_WORKER_OK, status);
305  EXPECT_FALSE(status_change_called);
306  EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
307}
308
309TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) {
310  EXPECT_EQ(ServiceWorkerVersion::NEW, version_->status());
311
312  // Repeatedly observe status changes (the callback re-registers itself).
313  std::vector<ServiceWorkerVersion::Status> statuses;
314  version_->RegisterStatusChangeCallback(
315      base::Bind(&ObserveStatusChanges, version_, &statuses));
316
317  version_->SetStatus(ServiceWorkerVersion::INSTALLING);
318  version_->SetStatus(ServiceWorkerVersion::INSTALLED);
319  version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
320  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
321  version_->SetStatus(ServiceWorkerVersion::REDUNDANT);
322
323  // Verify that we could successfully observe repeated status changes.
324  ASSERT_EQ(5U, statuses.size());
325  ASSERT_EQ(ServiceWorkerVersion::INSTALLING, statuses[0]);
326  ASSERT_EQ(ServiceWorkerVersion::INSTALLED, statuses[1]);
327  ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, statuses[2]);
328  ASSERT_EQ(ServiceWorkerVersion::ACTIVATED, statuses[3]);
329  ASSERT_EQ(ServiceWorkerVersion::REDUNDANT, statuses[4]);
330}
331
332TEST_F(ServiceWorkerVersionTest, ScheduleStopWorker) {
333  // Verify the timer is not running when version initializes its status.
334  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
335  EXPECT_FALSE(version_->stop_worker_timer_.IsRunning());
336
337  // Verify the timer is running when version status changes frome ACTIVATING
338  // to ACTIVATED.
339  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
340  version_->StartWorker(CreateReceiverOnCurrentThread(&status));
341  base::RunLoop().RunUntilIdle();
342  EXPECT_EQ(SERVICE_WORKER_OK, status);
343  version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
344  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
345  EXPECT_TRUE(version_->stop_worker_timer_.IsRunning());
346
347  // The timer should be running if the worker is restarted without controllee.
348  status = SERVICE_WORKER_ERROR_FAILED;
349  version_->StopWorker(CreateReceiverOnCurrentThread(&status));
350  base::RunLoop().RunUntilIdle();
351  EXPECT_EQ(SERVICE_WORKER_OK, status);
352  status = SERVICE_WORKER_ERROR_FAILED;
353  version_->StartWorker(CreateReceiverOnCurrentThread(&status));
354  base::RunLoop().RunUntilIdle();
355  EXPECT_EQ(SERVICE_WORKER_OK, status);
356  EXPECT_TRUE(version_->stop_worker_timer_.IsRunning());
357
358  // The timer should not be running if a controllee is added.
359  scoped_ptr<ServiceWorkerProviderHost> host(
360      new ServiceWorkerProviderHost(33 /* dummy render process id */,
361                                    1 /* dummy provider_id */,
362                                    helper_->context()->AsWeakPtr(),
363                                    NULL));
364  version_->AddControllee(host.get());
365  EXPECT_FALSE(version_->stop_worker_timer_.IsRunning());
366
367  // The timer should be running if the controllee is removed.
368  version_->RemoveControllee(host.get());
369  EXPECT_TRUE(version_->stop_worker_timer_.IsRunning());
370}
371
372}  // namespace content
373