1 // Copyright (c) 2012 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.
5 #include "chrome/browser/service_process/service_process_control.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/path_service.h"
11 #include "base/process/kill.h"
12 #include "base/process/process_handle.h"
13 #include "base/process/process_iterator.h"
14 #include "base/test/test_timeouts.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/chrome_version_info.h"
18 #include "chrome/common/service_process_util.h"
19 #include "chrome/test/base/in_process_browser_test.h"
20 #include "chrome/test/base/ui_test_utils.h"
21 #include "content/public/common/content_paths.h"
22 #include "content/public/common/content_switches.h"
23 #include "testing/gmock/include/gmock/gmock.h"
25 class ServiceProcessControlBrowserTest
26 : public InProcessBrowserTest
{
28 ServiceProcessControlBrowserTest()
29 : service_process_handle_(base::kNullProcessHandle
) {
31 virtual ~ServiceProcessControlBrowserTest() {
32 base::CloseProcessHandle(service_process_handle_
);
33 service_process_handle_
= base::kNullProcessHandle
;
36 void HistogramsCallback() {
37 MockHistogramsCallback();
41 MOCK_METHOD0(MockHistogramsCallback
, void());
44 void LaunchServiceProcessControl() {
45 // Launch the process asynchronously.
46 ServiceProcessControl::GetInstance()->Launch(
47 base::Bind(&ServiceProcessControlBrowserTest::ProcessControlLaunched
,
50 &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed
,
53 // Then run the message loop to keep things running.
54 content::RunMessageLoop();
57 static void QuitMessageLoop() {
58 base::MessageLoop::current()->Quit();
61 static void CloudPrintInfoCallback(
62 const cloud_print::CloudPrintProxyInfo
& proxy_info
) {
67 // This will close the IPC connection.
68 ServiceProcessControl::GetInstance()->Disconnect();
71 virtual void SetUp() OVERRIDE
{
72 service_process_handle_
= base::kNullProcessHandle
;
75 virtual void TearDown() OVERRIDE
{
76 if (ServiceProcessControl::GetInstance()->IsConnected())
77 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
78 #if defined(OS_MACOSX)
79 // ForceServiceProcessShutdown removes the process from launched on Mac.
80 ForceServiceProcessShutdown("", 0);
82 if (service_process_handle_
!= base::kNullProcessHandle
) {
83 EXPECT_TRUE(base::WaitForSingleProcess(
84 service_process_handle_
,
85 TestTimeouts::action_max_timeout()));
86 service_process_handle_
= base::kNullProcessHandle
;
90 void ProcessControlLaunched() {
91 base::ProcessId service_pid
;
92 EXPECT_TRUE(GetServiceProcessData(NULL
, &service_pid
));
93 EXPECT_NE(static_cast<base::ProcessId
>(0), service_pid
);
94 EXPECT_TRUE(base::OpenProcessHandleWithAccess(
96 base::kProcessAccessWaitForTermination
|
97 // we need query permission to get exit code
98 base::kProcessAccessQueryInformation
,
99 &service_process_handle_
));
100 // Quit the current message. Post a QuitTask instead of just calling Quit()
101 // because this can get invoked in the context of a Launch() call and we
102 // may not be in Run() yet.
103 base::MessageLoop::current()->PostTask(FROM_HERE
,
104 base::MessageLoop::QuitClosure());
107 void ProcessControlLaunchFailed() {
109 // Quit the current message.
110 base::MessageLoop::current()->PostTask(FROM_HERE
,
111 base::MessageLoop::QuitClosure());
115 base::ProcessHandle service_process_handle_
;
118 class RealServiceProcessControlBrowserTest
119 : public ServiceProcessControlBrowserTest
{
121 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
122 ServiceProcessControlBrowserTest::SetUpCommandLine(command_line
);
124 PathService::Get(base::DIR_EXE
, &exe
);
125 #if defined(OS_MACOSX)
126 exe
= exe
.DirName().DirName().DirName();
128 exe
= exe
.Append(chrome::kHelperProcessExecutablePath
);
129 // Run chrome instead of browser_tests.exe.
130 EXPECT_TRUE(base::PathExists(exe
));
131 command_line
->AppendSwitchPath(switches::kBrowserSubprocessPath
, exe
);
135 #if defined(OS_MACOSX)
136 // Does not work on MACOSX.
137 #define MAYBE_LaunchAndIPC DISABLED_LaunchAndIPC
139 #define MAYBE_LaunchAndIPC LaunchAndIPC
142 IN_PROC_BROWSER_TEST_F(RealServiceProcessControlBrowserTest
,
143 MAYBE_LaunchAndIPC
) {
144 LaunchServiceProcessControl();
146 // Make sure we are connected to the service process.
147 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
148 ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
149 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
));
150 content::RunMessageLoop();
152 // And then shutdown the service process.
153 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
156 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, LaunchAndIPC
) {
157 LaunchServiceProcessControl();
159 // Make sure we are connected to the service process.
160 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
161 ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
162 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
));
163 content::RunMessageLoop();
165 // And then shutdown the service process.
166 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
169 // This tests the case when a service process is launched when the browser
170 // starts but we try to launch it again while setting up Cloud Print.
171 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, LaunchTwice
) {
172 // Launch the service process the first time.
173 LaunchServiceProcessControl();
175 // Make sure we are connected to the service process.
176 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
177 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
178 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
)));
179 content::RunMessageLoop();
181 // Launch the service process again.
182 LaunchServiceProcessControl();
183 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
184 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
185 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
)));
186 content::RunMessageLoop();
189 static void DecrementUntilZero(int* count
) {
192 base::MessageLoop::current()->PostTask(FROM_HERE
,
193 base::MessageLoop::QuitClosure());
196 // Invoke multiple Launch calls in succession and ensure that all the tasks
198 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
,
199 MultipleLaunchTasks
) {
200 ServiceProcessControl
* process
= ServiceProcessControl::GetInstance();
201 int launch_count
= 5;
202 for (int i
= 0; i
< launch_count
; i
++) {
203 // Launch the process asynchronously.
204 process
->Launch(base::Bind(&DecrementUntilZero
, &launch_count
),
205 base::MessageLoop::QuitClosure());
207 // Then run the message loop to keep things running.
208 content::RunMessageLoop();
209 EXPECT_EQ(0, launch_count
);
212 // Make sure using the same task for success and failure tasks works.
213 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, SameLaunchTask
) {
214 ServiceProcessControl
* process
= ServiceProcessControl::GetInstance();
215 int launch_count
= 5;
216 for (int i
= 0; i
< launch_count
; i
++) {
217 // Launch the process asynchronously.
218 base::Closure task
= base::Bind(&DecrementUntilZero
, &launch_count
);
219 process
->Launch(task
, task
);
221 // Then run the message loop to keep things running.
222 content::RunMessageLoop();
223 EXPECT_EQ(0, launch_count
);
226 // Tests whether disconnecting from the service IPC causes the service process
228 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, DieOnDisconnect
) {
229 // Launch the service process.
230 LaunchServiceProcessControl();
231 // Make sure we are connected to the service process.
232 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
236 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, ForceShutdown
) {
237 // Launch the service process.
238 LaunchServiceProcessControl();
239 // Make sure we are connected to the service process.
240 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
241 base::ProcessId service_pid
;
242 EXPECT_TRUE(GetServiceProcessData(NULL
, &service_pid
));
243 EXPECT_NE(static_cast<base::ProcessId
>(0), service_pid
);
244 chrome::VersionInfo version_info
;
245 ForceServiceProcessShutdown(version_info
.Version(), service_pid
);
248 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, CheckPid
) {
249 base::ProcessId service_pid
;
250 EXPECT_FALSE(GetServiceProcessData(NULL
, &service_pid
));
251 // Launch the service process.
252 LaunchServiceProcessControl();
253 EXPECT_TRUE(GetServiceProcessData(NULL
, &service_pid
));
254 EXPECT_NE(static_cast<base::ProcessId
>(0), service_pid
);
255 // Disconnect from service process.
259 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, HistogramsNoService
) {
260 ASSERT_FALSE(ServiceProcessControl::GetInstance()->IsConnected());
261 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
262 EXPECT_FALSE(ServiceProcessControl::GetInstance()->GetHistograms(
263 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback
,
264 base::Unretained(this)),
268 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, HistogramsTimeout
) {
269 LaunchServiceProcessControl();
270 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
271 // Callback should not be called during GetHistograms call.
272 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
273 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms(
274 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback
,
275 base::Unretained(this)),
276 base::TimeDelta::FromMilliseconds(100)));
277 EXPECT_CALL(*this, MockHistogramsCallback()).Times(1);
278 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
279 content::RunMessageLoop();
282 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, Histograms
) {
283 LaunchServiceProcessControl();
284 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
285 // Callback should not be called during GetHistograms call.
286 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
287 // Wait for real callback by providing large timeout value.
288 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms(
289 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback
,
290 base::Unretained(this)),
291 base::TimeDelta::FromHours(1)));
292 EXPECT_CALL(*this, MockHistogramsCallback()).Times(1);
293 content::RunMessageLoop();