Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_browsertest.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/bind.h"
6 #include "base/callback.h"
7 #include "base/command_line.h"
8 #include "base/location.h"
9 #include "base/run_loop.h"
10 #include "content/browser/service_worker/embedded_worker_instance.h"
11 #include "content/browser/service_worker/embedded_worker_registry.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_context_wrapper.h"
14 #include "content/browser/service_worker/service_worker_registration.h"
15 #include "content/browser/service_worker/service_worker_version.h"
16 #include "content/common/service_worker/service_worker_messages.h"
17 #include "content/public/browser/browser_context.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/storage_partition.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/shell/browser/shell.h"
23 #include "content/test/content_browser_test.h"
24 #include "content/test/content_browser_test_utils.h"
25 #include "net/test/embedded_test_server/embedded_test_server.h"
26
27 namespace content {
28
29 namespace {
30
31 void RunAndQuit(const base::Closure& closure,
32                 const base::Closure& quit,
33                 base::MessageLoopProxy* original_message_loop) {
34   closure.Run();
35   original_message_loop->PostTask(FROM_HERE, quit);
36 }
37
38 void RunOnIOThread(const base::Closure& closure) {
39   base::RunLoop run_loop;
40   BrowserThread::PostTask(
41       BrowserThread::IO, FROM_HERE,
42       base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
43                  base::MessageLoopProxy::current()));
44   run_loop.Run();
45 }
46
47 // TODO(kinuko): Factor out these common test helpers to a separate file.
48 template <typename Arg>
49 void VerifyResult(const tracked_objects::Location& where,
50                   const base::Closure& quit,
51                   Arg expected, Arg actual) {
52   EXPECT_EQ(expected, actual) << where.ToString();
53   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
54 }
55
56 template <typename Arg> base::Callback<void(Arg)>
57 CreateVerifier(const tracked_objects::Location& where,
58                const base::Closure& quit, Arg expected) {
59   return base::Bind(&VerifyResult<Arg>, where, quit, expected);
60 }
61
62 }  // namespace
63
64 class ServiceWorkerBrowserTest : public ContentBrowserTest {
65  protected:
66   typedef ServiceWorkerBrowserTest self;
67
68   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
69     command_line->AppendSwitch(switches::kEnableServiceWorker);
70   }
71
72   virtual void SetUpOnMainThread() OVERRIDE {
73     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
74     StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
75         shell()->web_contents()->GetBrowserContext());
76     wrapper_ = partition->GetServiceWorkerContext();
77   }
78
79   virtual void TearDownOnMainThread() OVERRIDE {
80     RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
81     wrapper_ = NULL;
82   }
83
84   virtual void TearDownOnIOThread() {}
85
86   ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
87
88   void AssociateProcessToWorker(EmbeddedWorkerInstance* worker) {
89     // TODO(kinuko): this manual wiring should go away when this gets wired
90     // in the actual code path.
91     ServiceWorkerProviderHost* provider_host = GetRegisteredProviderHost();
92     worker->AddProcessReference(provider_host->process_id());
93   }
94
95  private:
96   ServiceWorkerProviderHost* GetRegisteredProviderHost() {
97     // Assumes only one provider host is registered at this point.
98     std::vector<ServiceWorkerProviderHost*> providers;
99     wrapper_->context()->GetAllProviderHosts(&providers);
100     DCHECK_EQ(1U, providers.size());
101     return providers[0];
102   }
103
104   scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
105 };
106
107 class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
108                                   public EmbeddedWorkerInstance::Observer {
109  public:
110   typedef EmbeddedWorkerBrowserTest self;
111
112   EmbeddedWorkerBrowserTest()
113       : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {}
114   virtual ~EmbeddedWorkerBrowserTest() {}
115
116   virtual void TearDownOnIOThread() OVERRIDE {
117     if (worker_) {
118       worker_->RemoveObserver(this);
119       worker_.reset();
120     }
121   }
122
123   void StartOnIOThread() {
124     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
125     worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
126     EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
127     worker_->AddObserver(this);
128
129     AssociateProcessToWorker(worker_.get());
130
131     const int64 service_worker_version_id = 33L;
132     const GURL script_url = embedded_test_server()->GetURL(
133         "/service_worker/worker.js");
134     const bool started = worker_->Start(
135         service_worker_version_id, script_url);
136
137     last_worker_status_ = worker_->status();
138     EXPECT_TRUE(started);
139     EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
140
141     if (!started && !done_closure_.is_null())
142       done_closure_.Run();
143   }
144
145   void StopOnIOThread() {
146     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
147     EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());
148
149     const bool stopped = worker_->Stop();
150
151     last_worker_status_ = worker_->status();
152     EXPECT_TRUE(stopped);
153     EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);
154
155     if (!stopped && !done_closure_.is_null())
156       done_closure_.Run();
157   }
158
159  protected:
160   // EmbeddedWorkerInstance::Observer overrides:
161   virtual void OnStarted() OVERRIDE {
162     ASSERT_TRUE(worker_ != NULL);
163     ASSERT_FALSE(done_closure_.is_null());
164     last_worker_status_ = worker_->status();
165     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
166   }
167   virtual void OnStopped() OVERRIDE {
168     ASSERT_TRUE(worker_ != NULL);
169     ASSERT_FALSE(done_closure_.is_null());
170     last_worker_status_ = worker_->status();
171     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
172   }
173   virtual void OnMessageReceived(const IPC::Message& message) OVERRIDE {
174     NOTREACHED();
175   }
176
177   scoped_ptr<EmbeddedWorkerInstance> worker_;
178   EmbeddedWorkerInstance::Status last_worker_status_;
179
180   // Called by EmbeddedWorkerInstance::Observer overrides so that
181   // test code can wait for the worker status notifications.
182   base::Closure done_closure_;
183 };
184
185 class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
186  public:
187   typedef ServiceWorkerVersionBrowserTest self;
188
189   ServiceWorkerVersionBrowserTest() {}
190   virtual ~ServiceWorkerVersionBrowserTest() {}
191
192   virtual void TearDownOnIOThread() OVERRIDE {
193     if (registration_) {
194       registration_->Shutdown();
195       registration_ = NULL;
196     }
197     if (version_) {
198       version_->Shutdown();
199       version_ = NULL;
200     }
201   }
202
203   void StartOnIOThread(const std::string& worker_url,
204                        ServiceWorkerStatusCode expected,
205                        const base::Closure& done) {
206     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
207
208     const int64 registration_id = 1L;
209     const int64 version_id = 1L;
210     registration_ = new ServiceWorkerRegistration(
211         embedded_test_server()->GetURL("/*"),
212         embedded_test_server()->GetURL(worker_url),
213         registration_id);
214     version_ = new ServiceWorkerVersion(
215         registration_,
216         wrapper()->context()->embedded_worker_registry(),
217         version_id);
218     AssociateProcessToWorker(version_->embedded_worker());
219     version_->StartWorker(CreateVerifier(FROM_HERE, done, expected));
220   }
221
222   void StopOnIOThread(const base::Closure& done) {
223     ASSERT_TRUE(version_);
224     version_->StopWorker(
225         CreateVerifier(FROM_HERE, done, SERVICE_WORKER_OK));
226   }
227
228  protected:
229   scoped_refptr<ServiceWorkerRegistration> registration_;
230   scoped_refptr<ServiceWorkerVersion> version_;
231 };
232
233 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
234   // Navigate to the page to set up a provider.
235   NavigateToURLBlockUntilNavigationsComplete(
236       shell(), embedded_test_server()->GetURL("/service_worker/index.html"), 1);
237
238   // Start a worker and wait until OnStarted() is called.
239   base::RunLoop start_run_loop;
240   done_closure_ = start_run_loop.QuitClosure();
241   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
242                           base::Bind(&self::StartOnIOThread, this));
243   start_run_loop.Run();
244
245   ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
246
247   // Stop a worker and wait until OnStopped() is called.
248   base::RunLoop stop_run_loop;
249   done_closure_ = stop_run_loop.QuitClosure();
250   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
251                           base::Bind(&self::StopOnIOThread, this));
252   stop_run_loop.Run();
253
254   ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
255 }
256
257 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
258   // Navigate to the page to set up a provider.
259   NavigateToURLBlockUntilNavigationsComplete(
260       shell(), embedded_test_server()->GetURL("/service_worker/index.html"), 1);
261
262   // Start a worker.
263   base::RunLoop start_run_loop;
264   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
265                           base::Bind(&self::StartOnIOThread, this,
266                                      "/service_worker/worker.js",
267                                      SERVICE_WORKER_OK,
268                                      start_run_loop.QuitClosure()));
269   start_run_loop.Run();
270
271   // Stop the worker.
272   base::RunLoop stop_run_loop;
273   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
274                           base::Bind(&self::StopOnIOThread, this,
275                                      stop_run_loop.QuitClosure()));
276   stop_run_loop.Run();
277 }
278
279 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
280   // Navigate to the page to set up a provider.
281   NavigateToURLBlockUntilNavigationsComplete(
282       shell(), embedded_test_server()->GetURL("/service_worker/index.html"), 1);
283
284   // Start a worker for nonexistent URL.
285   base::RunLoop start_run_loop;
286   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
287                           base::Bind(&self::StartOnIOThread, this,
288                                      "/service_worker/nonexistent.js",
289                                      SERVICE_WORKER_ERROR_START_WORKER_FAILED,
290                                      start_run_loop.QuitClosure()));
291   start_run_loop.Run();
292 }
293
294 }  // namespace content