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.
4
5#include "base/basictypes.h"
6#include "base/run_loop.h"
7#include "base/stl_util.h"
8#include "content/browser/service_worker/embedded_worker_instance.h"
9#include "content/browser/service_worker/embedded_worker_registry.h"
10#include "content/browser/service_worker/embedded_worker_test_helper.h"
11#include "content/browser/service_worker/service_worker_context_core.h"
12#include "content/browser/service_worker/service_worker_context_wrapper.h"
13#include "content/common/service_worker/embedded_worker_messages.h"
14#include "content/public/test/test_browser_thread_bundle.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace content {
19
20static const int kRenderProcessId = 11;
21
22class EmbeddedWorkerInstanceTest : public testing::Test {
23 protected:
24  EmbeddedWorkerInstanceTest()
25      : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
26
27  virtual void SetUp() OVERRIDE {
28    helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
29  }
30
31  virtual void TearDown() OVERRIDE {
32    helper_.reset();
33  }
34
35  ServiceWorkerContextCore* context() { return helper_->context(); }
36
37  EmbeddedWorkerRegistry* embedded_worker_registry() {
38    DCHECK(context());
39    return context()->embedded_worker_registry();
40  }
41
42  IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
43
44  TestBrowserThreadBundle thread_bundle_;
45  scoped_ptr<EmbeddedWorkerTestHelper> helper_;
46
47 private:
48  DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
49};
50
51static void SaveStatusAndCall(ServiceWorkerStatusCode* out,
52                              const base::Closure& callback,
53                              ServiceWorkerStatusCode status) {
54  *out = status;
55  callback.Run();
56}
57
58TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
59  scoped_ptr<EmbeddedWorkerInstance> worker =
60      embedded_worker_registry()->CreateWorker();
61  EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
62
63  const int64 service_worker_version_id = 55L;
64  const GURL pattern("http://example.com/");
65  const GURL url("http://example.com/worker.js");
66
67  // Simulate adding one process to the pattern.
68  helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
69
70  // Start should succeed.
71  ServiceWorkerStatusCode status;
72  base::RunLoop run_loop;
73  worker->Start(
74      service_worker_version_id,
75      pattern,
76      url,
77      false,
78      base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
79  run_loop.Run();
80  EXPECT_EQ(SERVICE_WORKER_OK, status);
81  EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
82  base::RunLoop().RunUntilIdle();
83
84  // Worker started message should be notified (by EmbeddedWorkerTestHelper).
85  EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
86  EXPECT_EQ(kRenderProcessId, worker->process_id());
87
88  // Stop the worker.
89  EXPECT_EQ(SERVICE_WORKER_OK, worker->Stop());
90  EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, worker->status());
91  base::RunLoop().RunUntilIdle();
92
93  // Worker stopped message should be notified (by EmbeddedWorkerTestHelper).
94  EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
95
96  // Verify that we've sent two messages to start and terminate the worker.
97  ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
98      EmbeddedWorkerMsg_StartWorker::ID));
99  ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
100      EmbeddedWorkerMsg_StopWorker::ID));
101}
102
103TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) {
104  scoped_ptr<EmbeddedWorkerInstance> worker =
105      embedded_worker_registry()->CreateWorker();
106  EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
107
108  const int64 service_worker_version_id = 55L;
109  const GURL pattern("http://example.com/");
110  const GURL url("http://example.com/worker.js");
111
112  ServiceWorkerStatusCode status;
113  base::RunLoop run_loop;
114  // Begin starting the worker.
115  context()->process_manager()->AddProcessReferenceToPattern(
116      pattern, kRenderProcessId);
117  worker->Start(
118      service_worker_version_id,
119      pattern,
120      url,
121      false,
122      base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
123  // But destroy it before it gets a chance to complete.
124  worker.reset();
125  run_loop.Run();
126  EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
127
128  // Verify that we didn't send the message to start the worker.
129  ASSERT_FALSE(
130      ipc_sink()->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID));
131}
132
133}  // namespace content
134