Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: content/browser/service_worker/embedded_worker_instance_unittest.cc

Issue 1327723005: Fix crash during EmbeddedWorkerInstance startup sequence failures (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix asan Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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/basictypes.h" 5 #include "base/basictypes.h"
6 #include "base/run_loop.h" 6 #include "base/run_loop.h"
7 #include "base/stl_util.h" 7 #include "base/stl_util.h"
8 #include "content/browser/service_worker/embedded_worker_instance.h" 8 #include "content/browser/service_worker/embedded_worker_instance.h"
9 #include "content/browser/service_worker/embedded_worker_registry.h" 9 #include "content/browser/service_worker/embedded_worker_registry.h"
10 #include "content/browser/service_worker/embedded_worker_test_helper.h" 10 #include "content/browser/service_worker/embedded_worker_test_helper.h"
11 #include "content/browser/service_worker/service_worker_context_core.h" 11 #include "content/browser/service_worker/service_worker_context_core.h"
12 #include "content/browser/service_worker/service_worker_context_wrapper.h" 12 #include "content/browser/service_worker/service_worker_context_wrapper.h"
13 #include "content/common/service_worker/embedded_worker_messages.h" 13 #include "content/common/service_worker/embedded_worker_messages.h"
14 #include "content/public/test/test_browser_thread_bundle.h" 14 #include "content/public/test/test_browser_thread_bundle.h"
15 #include "testing/gmock/include/gmock/gmock.h" 15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/gtest/include/gtest/gtest.h"
17 17
18 namespace content { 18 namespace content {
19 19
20 namespace { 20 namespace {
21 21
22 const int kRenderProcessId = 11; 22 const int kRenderProcessId = 11;
23 23
24 void SaveStatus(ServiceWorkerStatusCode* out, ServiceWorkerStatusCode status) { 24 void DestroyWorker(scoped_ptr<EmbeddedWorkerInstance> worker,
25 *out = status; 25 ServiceWorkerStatusCode* out_status,
26 ServiceWorkerStatusCode status) {
27 *out_status = status;
28 worker.reset();
26 } 29 }
27 30
28 void SaveStatusAndCall(ServiceWorkerStatusCode* out, 31 void SaveStatusAndCall(ServiceWorkerStatusCode* out,
29 const base::Closure& callback, 32 const base::Closure& callback,
30 ServiceWorkerStatusCode status) { 33 ServiceWorkerStatusCode status) {
31 *out = status; 34 *out = status;
32 callback.Run(); 35 callback.Run();
33 } 36 }
34 37
35 } // namespace 38 } // namespace
36 39
37 class EmbeddedWorkerInstanceTest : public testing::Test, 40 class EmbeddedWorkerInstanceTest : public testing::Test,
38 public EmbeddedWorkerInstance::Listener { 41 public EmbeddedWorkerInstance::Listener {
39 protected: 42 protected:
40 EmbeddedWorkerInstanceTest() 43 EmbeddedWorkerInstanceTest()
41 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} 44 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
42 45
46 void OnStopped(EmbeddedWorkerInstance::Status old_status) override {
47 stopped_ = true;
48 stopped_old_status_ = old_status;
49 }
50
43 void OnDetached(EmbeddedWorkerInstance::Status old_status) override { 51 void OnDetached(EmbeddedWorkerInstance::Status old_status) override {
44 detached_ = true; 52 detached_ = true;
45 detached_old_status_ = old_status; 53 detached_old_status_ = old_status;
46 } 54 }
47 55
48 bool OnMessageReceived(const IPC::Message& message) override { return false; } 56 bool OnMessageReceived(const IPC::Message& message) override { return false; }
49 57
50 void SetUp() override { 58 void SetUp() override {
51 helper_.reset( 59 helper_.reset(
52 new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId)); 60 new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
(...skipping 19 matching lines...) Expand all
72 return context()->embedded_worker_registry(); 80 return context()->embedded_worker_registry();
73 } 81 }
74 82
75 IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); } 83 IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
76 84
77 TestBrowserThreadBundle thread_bundle_; 85 TestBrowserThreadBundle thread_bundle_;
78 scoped_ptr<EmbeddedWorkerTestHelper> helper_; 86 scoped_ptr<EmbeddedWorkerTestHelper> helper_;
79 bool detached_ = false; 87 bool detached_ = false;
80 EmbeddedWorkerInstance::Status detached_old_status_ = 88 EmbeddedWorkerInstance::Status detached_old_status_ =
81 EmbeddedWorkerInstance::STOPPED; 89 EmbeddedWorkerInstance::STOPPED;
90 bool stopped_ = false;
91 EmbeddedWorkerInstance::Status stopped_old_status_ =
92 EmbeddedWorkerInstance::STOPPED;
82 93
83 private: 94 private:
84 DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest); 95 DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
85 }; 96 };
86 97
98 class FailToSendIPCHelper : public EmbeddedWorkerTestHelper {
99 public:
100 FailToSendIPCHelper()
101 : EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId) {}
102 ~FailToSendIPCHelper() override {}
103
104 bool Send(IPC::Message* message) override {
105 delete message;
106 return false;
107 }
108 };
109
87 TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) { 110 TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
88 scoped_ptr<EmbeddedWorkerInstance> worker = 111 scoped_ptr<EmbeddedWorkerInstance> worker =
89 embedded_worker_registry()->CreateWorker(); 112 embedded_worker_registry()->CreateWorker();
90 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); 113 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
91 114
92 const int64 service_worker_version_id = 55L; 115 const int64 service_worker_version_id = 55L;
93 const GURL pattern("http://example.com/"); 116 const GURL pattern("http://example.com/");
94 const GURL url("http://example.com/worker.js"); 117 const GURL url("http://example.com/worker.js");
95 118
96 // Simulate adding one process to the pattern. 119 // Simulate adding one process to the pattern.
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 EXPECT_EQ(1UL, registry->worker_process_map_[kRenderProcessId].count( 248 EXPECT_EQ(1UL, registry->worker_process_map_[kRenderProcessId].count(
226 worker2->embedded_worker_id())); 249 worker2->embedded_worker_id()));
227 250
228 worker2->Stop(); 251 worker2->Stop();
229 } 252 }
230 253
231 // Test detaching in the middle of the start worker sequence. 254 // Test detaching in the middle of the start worker sequence.
232 TEST_F(EmbeddedWorkerInstanceTest, DetachDuringStart) { 255 TEST_F(EmbeddedWorkerInstanceTest, DetachDuringStart) {
233 scoped_ptr<EmbeddedWorkerInstance> worker = 256 scoped_ptr<EmbeddedWorkerInstance> worker =
234 embedded_worker_registry()->CreateWorker(); 257 embedded_worker_registry()->CreateWorker();
258 worker->AddListener(this);
259
235 scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params( 260 scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
236 new EmbeddedWorkerMsg_StartWorker_Params()); 261 new EmbeddedWorkerMsg_StartWorker_Params());
237 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 262 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
238 // Pretend we had a process allocated but then got detached before 263
239 // the start sequence reached SendStartWorker. 264 // Pretend the worker got stopped before the start sequence reached
240 worker->process_id_ = -1; 265 // SendStartWorker.
241 worker->SendStartWorker(params.Pass(), base::Bind(&SaveStatus, &status), true, 266 worker->status_ = EmbeddedWorkerInstance::STOPPED;
242 -1, false); 267 base::RunLoop run_loop;
268 worker->SendStartWorker(params.Pass(), base::Bind(&SaveStatusAndCall, &status,
269 run_loop.QuitClosure()),
270 true, -1, false);
271 run_loop.Run();
272 EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
273 // Don't expect SendStartWorker() to dispatch an OnStopped/Detached() message
274 // since the worker was already stopped.
275 EXPECT_FALSE(stopped_);
276 EXPECT_FALSE(detached_);
277
278 // Repeat, this time have the start callback destroy the worker, as is
279 // usual when starting a worker fails, and ensure a crash doesn't occur.
280 worker->status_ = EmbeddedWorkerInstance::STOPPED;
281 EmbeddedWorkerInstance* worker_ptr = worker.get();
282 worker_ptr->SendStartWorker(
283 params.Pass(), base::Bind(&DestroyWorker, base::Passed(&worker), &status),
284 true, -1, false);
285 // No crash.
243 EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status); 286 EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
244 } 287 }
245 288
246 // Test stopping in the middle of the start worker sequence, before 289 // Test stopping in the middle of the start worker sequence, before
247 // a process is allocated. 290 // a process is allocated.
248 TEST_F(EmbeddedWorkerInstanceTest, StopDuringStart) { 291 TEST_F(EmbeddedWorkerInstanceTest, StopDuringStart) {
249 scoped_ptr<EmbeddedWorkerInstance> worker = 292 scoped_ptr<EmbeddedWorkerInstance> worker =
250 embedded_worker_registry()->CreateWorker(); 293 embedded_worker_registry()->CreateWorker();
251 worker->AddListener(this); 294 worker->AddListener(this);
252 scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
253 new EmbeddedWorkerMsg_StartWorker_Params());
254 // Pretend we stop during starting before we got a process allocated. 295 // Pretend we stop during starting before we got a process allocated.
255 worker->status_ = EmbeddedWorkerInstance::STARTING; 296 worker->status_ = EmbeddedWorkerInstance::STARTING;
256 worker->process_id_ = -1; 297 worker->process_id_ = -1;
257 worker->Stop(); 298 worker->Stop();
258 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); 299 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
259 EXPECT_TRUE(detached_); 300 EXPECT_TRUE(detached_);
260 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, detached_old_status_); 301 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, detached_old_status_);
261 } 302 }
262 303
304 // Test for when sending the start IPC failed.
305 TEST_F(EmbeddedWorkerInstanceTest, FailToSendStartIPC) {
306 helper_.reset(new FailToSendIPCHelper());
307
308 const int64 version_id = 55L;
309 const GURL pattern("http://example.com/");
310 const GURL url("http://example.com/worker.js");
311
312 scoped_ptr<EmbeddedWorkerInstance> worker =
313 embedded_worker_registry()->CreateWorker();
314 helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
315 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
316 worker->AddListener(this);
317
318 // Attempt to start the worker.
319 base::RunLoop run_loop;
320 worker->Start(
321 version_id, pattern, url,
322 base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
323 run_loop.Run();
324
325 // The callback should have run, and we should have got an OnStopped message.
326 EXPECT_EQ(SERVICE_WORKER_ERROR_IPC_FAILED, status);
327 EXPECT_TRUE(stopped_);
328 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, stopped_old_status_);
329 }
330
263 } // namespace content 331 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698