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