OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/callback.h" | 6 #include "base/callback.h" |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
10 #include "content/browser/service_worker/embedded_worker_instance.h" | 10 #include "content/browser/service_worker/embedded_worker_instance.h" |
11 #include "content/browser/service_worker/embedded_worker_registry.h" | 11 #include "content/browser/service_worker/embedded_worker_registry.h" |
12 #include "content/browser/service_worker/service_worker_context_core.h" | 12 #include "content/browser/service_worker/service_worker_context_core.h" |
13 #include "content/browser/service_worker/service_worker_context_wrapper.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" |
14 #include "content/public/browser/browser_context.h" | 17 #include "content/public/browser/browser_context.h" |
15 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
16 #include "content/public/browser/storage_partition.h" | 19 #include "content/public/browser/storage_partition.h" |
17 #include "content/public/browser/web_contents.h" | 20 #include "content/public/browser/web_contents.h" |
18 #include "content/public/common/content_switches.h" | 21 #include "content/public/common/content_switches.h" |
19 #include "content/shell/browser/shell.h" | 22 #include "content/shell/browser/shell.h" |
20 #include "content/test/content_browser_test.h" | 23 #include "content/test/content_browser_test.h" |
21 #include "content/test/content_browser_test_utils.h" | 24 #include "content/test/content_browser_test_utils.h" |
22 #include "net/test/embedded_test_server/embedded_test_server.h" | 25 #include "net/test/embedded_test_server/embedded_test_server.h" |
23 | 26 |
24 namespace content { | 27 namespace content { |
25 | 28 |
26 class ServiceWorkerBrowserTest : public ContentBrowserTest, | 29 namespace { |
27 public EmbeddedWorkerInstance::Observer { | 30 |
28 public: | 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: |
29 typedef ServiceWorkerBrowserTest self; | 66 typedef ServiceWorkerBrowserTest self; |
30 | 67 |
31 ServiceWorkerBrowserTest() | |
32 : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {} | |
33 virtual ~ServiceWorkerBrowserTest() {} | |
34 | |
35 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | 68 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
36 command_line->AppendSwitch(switches::kEnableServiceWorker); | 69 command_line->AppendSwitch(switches::kEnableServiceWorker); |
37 } | 70 } |
38 | 71 |
39 virtual void SetUpOnMainThread() OVERRIDE { | 72 virtual void SetUpOnMainThread() OVERRIDE { |
40 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | 73 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
41 StoragePartition* partition = BrowserContext::GetDefaultStoragePartition( | 74 StoragePartition* partition = BrowserContext::GetDefaultStoragePartition( |
42 shell()->web_contents()->GetBrowserContext()); | 75 shell()->web_contents()->GetBrowserContext()); |
43 wrapper_ = partition->GetServiceWorkerContext(); | 76 wrapper_ = partition->GetServiceWorkerContext(); |
44 } | 77 } |
45 | 78 |
46 virtual void TearDownOnMainThread() OVERRIDE { | 79 virtual void TearDownOnMainThread() OVERRIDE { |
47 base::RunLoop run_loop; | 80 RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this)); |
48 BrowserThread::PostTask( | |
49 BrowserThread::IO, FROM_HERE, | |
50 base::Bind(&self::TearDownOnIOThread, this, run_loop.QuitClosure())); | |
51 run_loop.Run(); | |
52 wrapper_ = NULL; | 81 wrapper_ = NULL; |
53 } | 82 } |
54 | 83 |
55 void TearDownOnIOThread(const base::Closure& done_closure) { | 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 { |
56 if (worker_) { | 117 if (worker_) { |
57 worker_->RemoveObserver(this); | 118 worker_->RemoveObserver(this); |
58 worker_.reset(); | 119 worker_.reset(); |
59 } | 120 } |
60 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure); | |
61 } | 121 } |
62 | 122 |
63 void StartEmbeddedWorkerOnIOThread() { | 123 void StartOnIOThread() { |
64 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 124 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
65 worker_ = wrapper_->context()->embedded_worker_registry()->CreateWorker(); | 125 worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker(); |
66 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status()); | 126 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status()); |
67 worker_->AddObserver(this); | 127 worker_->AddObserver(this); |
68 | 128 |
69 // TODO(kinuko): this manual wiring should go away when this gets wired | 129 AssociateProcessToWorker(worker_.get()); |
70 // in the actual code path. | |
71 ServiceWorkerProviderHost* provider_host = GetRegisteredProviderHost(); | |
72 worker_->AddProcessReference(provider_host->process_id()); | |
73 | 130 |
74 const int64 service_worker_version_id = 33L; | 131 const int64 service_worker_version_id = 33L; |
75 const GURL script_url = embedded_test_server()->GetURL( | 132 const GURL script_url = embedded_test_server()->GetURL( |
76 "/service_worker/worker.js"); | 133 "/service_worker/worker.js"); |
77 const bool started = worker_->Start(service_worker_version_id, script_url); | 134 const bool started = worker_->Start( |
| 135 service_worker_version_id, script_url); |
78 | 136 |
79 last_worker_status_ = worker_->status(); | 137 last_worker_status_ = worker_->status(); |
80 EXPECT_TRUE(started); | 138 EXPECT_TRUE(started); |
81 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_); | 139 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_); |
82 | 140 |
83 if (!started && !done_closure_.is_null()) | 141 if (!started && !done_closure_.is_null()) |
84 done_closure_.Run(); | 142 done_closure_.Run(); |
85 } | 143 } |
86 | 144 |
87 void StopEmbeddedWorkerOnIOThread() { | 145 void StopOnIOThread() { |
88 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 146 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
89 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status()); | 147 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status()); |
90 | 148 |
91 const bool stopped = worker_->Stop(); | 149 const bool stopped = worker_->Stop(); |
92 | 150 |
93 last_worker_status_ = worker_->status(); | 151 last_worker_status_ = worker_->status(); |
94 EXPECT_TRUE(stopped); | 152 EXPECT_TRUE(stopped); |
95 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_); | 153 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_); |
96 | 154 |
97 if (!stopped && !done_closure_.is_null()) | 155 if (!stopped && !done_closure_.is_null()) |
98 done_closure_.Run(); | 156 done_closure_.Run(); |
99 } | 157 } |
100 | 158 |
101 protected: | 159 protected: |
102 // Embe3ddedWorkerInstance::Observer overrides: | 160 // EmbeddedWorkerInstance::Observer overrides: |
103 virtual void OnStarted() OVERRIDE { | 161 virtual void OnStarted() OVERRIDE { |
104 ASSERT_TRUE(worker_ != NULL); | 162 ASSERT_TRUE(worker_ != NULL); |
105 ASSERT_FALSE(done_closure_.is_null()); | 163 ASSERT_FALSE(done_closure_.is_null()); |
106 last_worker_status_ = worker_->status(); | 164 last_worker_status_ = worker_->status(); |
107 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_); | 165 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_); |
108 } | 166 } |
109 virtual void OnStopped() OVERRIDE { | 167 virtual void OnStopped() OVERRIDE { |
110 ASSERT_TRUE(worker_ != NULL); | 168 ASSERT_TRUE(worker_ != NULL); |
111 ASSERT_FALSE(done_closure_.is_null()); | 169 ASSERT_FALSE(done_closure_.is_null()); |
112 last_worker_status_ = worker_->status(); | 170 last_worker_status_ = worker_->status(); |
113 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_); | 171 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_); |
114 } | 172 } |
115 virtual void OnMessageReceived(const IPC::Message& message) OVERRIDE { | 173 virtual void OnMessageReceived(const IPC::Message& message) OVERRIDE { |
116 NOTREACHED(); | 174 NOTREACHED(); |
117 } | 175 } |
118 | 176 |
119 ServiceWorkerProviderHost* GetRegisteredProviderHost() { | |
120 // Assumes only one provider host is registered at this point. | |
121 std::vector<ServiceWorkerProviderHost*> providers; | |
122 wrapper_->context()->GetAllProviderHosts(&providers); | |
123 DCHECK_EQ(1U, providers.size()); | |
124 return providers[0]; | |
125 } | |
126 | |
127 scoped_refptr<ServiceWorkerContextWrapper> wrapper_; | |
128 scoped_ptr<EmbeddedWorkerInstance> worker_; | 177 scoped_ptr<EmbeddedWorkerInstance> worker_; |
129 EmbeddedWorkerInstance::Status last_worker_status_; | 178 EmbeddedWorkerInstance::Status last_worker_status_; |
130 | 179 |
131 // Called by EmbeddedWorkerInstance::Observer overrides so that | 180 // Called by EmbeddedWorkerInstance::Observer overrides so that |
132 // test code can wait for the worker status notifications. | 181 // test code can wait for the worker status notifications. |
133 base::Closure done_closure_; | 182 base::Closure done_closure_; |
134 }; | 183 }; |
135 | 184 |
136 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, EmbeddedWorkerBasic) { | 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) { |
137 // Navigate to the page to set up a provider. | 234 // Navigate to the page to set up a provider. |
138 NavigateToURLBlockUntilNavigationsComplete( | 235 NavigateToURLBlockUntilNavigationsComplete( |
139 shell(), embedded_test_server()->GetURL("/service_worker/index.html"), 1); | 236 shell(), embedded_test_server()->GetURL("/service_worker/index.html"), 1); |
140 | 237 |
141 // Start a worker and wait until OnStarted() is called. | 238 // Start a worker and wait until OnStarted() is called. |
142 base::RunLoop start_run_loop; | 239 base::RunLoop start_run_loop; |
143 done_closure_ = start_run_loop.QuitClosure(); | 240 done_closure_ = start_run_loop.QuitClosure(); |
144 BrowserThread::PostTask( | 241 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
145 BrowserThread::IO, FROM_HERE, | 242 base::Bind(&self::StartOnIOThread, this)); |
146 base::Bind(&self::StartEmbeddedWorkerOnIOThread, this)); | |
147 start_run_loop.Run(); | 243 start_run_loop.Run(); |
148 | 244 |
149 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_); | 245 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_); |
150 | 246 |
151 // Stop a worker and wait until OnStopped() is called. | 247 // Stop a worker and wait until OnStopped() is called. |
152 base::RunLoop stop_run_loop; | 248 base::RunLoop stop_run_loop; |
153 done_closure_ = stop_run_loop.QuitClosure(); | 249 done_closure_ = stop_run_loop.QuitClosure(); |
154 BrowserThread::PostTask( | 250 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
155 BrowserThread::IO, FROM_HERE, | 251 base::Bind(&self::StopOnIOThread, this)); |
156 base::Bind(&self::StopEmbeddedWorkerOnIOThread, this)); | |
157 stop_run_loop.Run(); | 252 stop_run_loop.Run(); |
158 | 253 |
159 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_); | 254 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_); |
160 } | 255 } |
161 | 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 |
162 } // namespace content | 294 } // namespace content |
OLD | NEW |