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 18 namespace content { 19 20 static const int kRenderProcessId = 11; 21 22 class 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 DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest); 48 }; 49 50 static void SaveStatusAndCall(ServiceWorkerStatusCode* out, 51 const base::Closure& callback, 52 ServiceWorkerStatusCode status) { 53 *out = status; 54 callback.Run(); 55 } 56 57 TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) { 58 scoped_ptr<EmbeddedWorkerInstance> worker = 59 embedded_worker_registry()->CreateWorker(); 60 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); 61 62 const int embedded_worker_id = worker->embedded_worker_id(); 63 const int64 service_worker_version_id = 55L; 64 const GURL scope("http://example.com/*"); 65 const GURL url("http://example.com/worker.js"); 66 67 // Simulate adding one process to the worker. 68 helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId); 69 70 // Start should succeed. 71 ServiceWorkerStatusCode status; 72 base::RunLoop run_loop; 73 worker->Start( 74 service_worker_version_id, 75 scope, 76 url, 77 std::vector<int>(), 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 103 TEST_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 scope("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 std::vector<int> available_process; 116 available_process.push_back(kRenderProcessId); 117 worker->Start( 118 service_worker_version_id, 119 scope, 120 url, 121 available_process, 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 TEST_F(EmbeddedWorkerInstanceTest, SortProcesses) { 134 scoped_ptr<EmbeddedWorkerInstance> worker = 135 embedded_worker_registry()->CreateWorker(); 136 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); 137 138 // Simulate adding processes to the worker. 139 // Process 1 has 1 ref, 2 has 2 refs and 3 has 3 refs. 140 const int embedded_worker_id = worker->embedded_worker_id(); 141 helper_->SimulateAddProcessToWorker(embedded_worker_id, 1); 142 helper_->SimulateAddProcessToWorker(embedded_worker_id, 2); 143 helper_->SimulateAddProcessToWorker(embedded_worker_id, 2); 144 helper_->SimulateAddProcessToWorker(embedded_worker_id, 3); 145 helper_->SimulateAddProcessToWorker(embedded_worker_id, 3); 146 helper_->SimulateAddProcessToWorker(embedded_worker_id, 3); 147 148 // Process 3 has the biggest # of references and it should be chosen. 149 EXPECT_THAT(worker->SortProcesses(std::vector<int>()), 150 testing::ElementsAre(3, 2, 1)); 151 EXPECT_EQ(-1, worker->process_id()); 152 153 // Argument processes are added to the existing set, but only for a single 154 // call. 155 std::vector<int> registering_processes; 156 registering_processes.push_back(1); 157 registering_processes.push_back(1); 158 registering_processes.push_back(1); 159 registering_processes.push_back(4); 160 EXPECT_THAT(worker->SortProcesses(registering_processes), 161 testing::ElementsAre(1, 3, 2, 4)); 162 163 EXPECT_THAT(worker->SortProcesses(std::vector<int>()), 164 testing::ElementsAre(3, 2, 1)); 165 } 166 167 } // namespace content 168