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. 4 5#include "chrome/browser/service_process/service_process_control.h" 6 7#include "base/bind.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" 24 25class ServiceProcessControlBrowserTest 26 : public InProcessBrowserTest { 27 public: 28 ServiceProcessControlBrowserTest() 29 : service_process_handle_(base::kNullProcessHandle) { 30 } 31 virtual ~ServiceProcessControlBrowserTest() { 32 base::CloseProcessHandle(service_process_handle_); 33 service_process_handle_ = base::kNullProcessHandle; 34 } 35 36 void HistogramsCallback() { 37 MockHistogramsCallback(); 38 QuitMessageLoop(); 39 } 40 41 MOCK_METHOD0(MockHistogramsCallback, void()); 42 43 protected: 44 void LaunchServiceProcessControl() { 45 // Launch the process asynchronously. 46 ServiceProcessControl::GetInstance()->Launch( 47 base::Bind(&ServiceProcessControlBrowserTest::ProcessControlLaunched, 48 this), 49 base::Bind( 50 &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed, 51 this)); 52 53 // Then run the message loop to keep things running. 54 content::RunMessageLoop(); 55 } 56 57 static void QuitMessageLoop() { 58 base::MessageLoop::current()->Quit(); 59 } 60 61 static void CloudPrintInfoCallback( 62 const cloud_print::CloudPrintProxyInfo& proxy_info) { 63 QuitMessageLoop(); 64 } 65 66 void Disconnect() { 67 // This will close the IPC connection. 68 ServiceProcessControl::GetInstance()->Disconnect(); 69 } 70 71 virtual void SetUp() OVERRIDE { 72 service_process_handle_ = base::kNullProcessHandle; 73 } 74 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); 81#endif // OS_MACOSX 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; 87 } 88 } 89 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( 95 service_pid, 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()); 105 } 106 107 void ProcessControlLaunchFailed() { 108 ADD_FAILURE(); 109 // Quit the current message. 110 base::MessageLoop::current()->PostTask(FROM_HERE, 111 base::MessageLoop::QuitClosure()); 112 } 113 114 private: 115 base::ProcessHandle service_process_handle_; 116}; 117 118class RealServiceProcessControlBrowserTest 119 : public ServiceProcessControlBrowserTest { 120 public: 121 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 122 ServiceProcessControlBrowserTest::SetUpCommandLine(command_line); 123 base::FilePath exe; 124 PathService::Get(base::DIR_EXE, &exe); 125#if defined(OS_MACOSX) 126 exe = exe.DirName().DirName().DirName(); 127#endif 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); 132 } 133}; 134 135// TODO(vitalybuka): Fix crbug.com/340563 136IN_PROC_BROWSER_TEST_F(RealServiceProcessControlBrowserTest, 137 DISABLED_LaunchAndIPC) { 138 LaunchServiceProcessControl(); 139 140 // Make sure we are connected to the service process. 141 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 142 ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( 143 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback)); 144 content::RunMessageLoop(); 145 146 // And then shutdown the service process. 147 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); 148} 149 150IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchAndIPC) { 151 LaunchServiceProcessControl(); 152 153 // Make sure we are connected to the service process. 154 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 155 ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( 156 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback)); 157 content::RunMessageLoop(); 158 159 // And then shutdown the service process. 160 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); 161} 162 163// This tests the case when a service process is launched when the browser 164// starts but we try to launch it again while setting up Cloud Print. 165IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchTwice) { 166 // Launch the service process the first time. 167 LaunchServiceProcessControl(); 168 169 // Make sure we are connected to the service process. 170 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 171 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( 172 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback))); 173 content::RunMessageLoop(); 174 175 // Launch the service process again. 176 LaunchServiceProcessControl(); 177 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 178 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( 179 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback))); 180 content::RunMessageLoop(); 181} 182 183static void DecrementUntilZero(int* count) { 184 (*count)--; 185 if (!(*count)) 186 base::MessageLoop::current()->PostTask(FROM_HERE, 187 base::MessageLoop::QuitClosure()); 188} 189 190// Invoke multiple Launch calls in succession and ensure that all the tasks 191// get invoked. 192IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, 193 MultipleLaunchTasks) { 194 ServiceProcessControl* process = ServiceProcessControl::GetInstance(); 195 int launch_count = 5; 196 for (int i = 0; i < launch_count; i++) { 197 // Launch the process asynchronously. 198 process->Launch(base::Bind(&DecrementUntilZero, &launch_count), 199 base::MessageLoop::QuitClosure()); 200 } 201 // Then run the message loop to keep things running. 202 content::RunMessageLoop(); 203 EXPECT_EQ(0, launch_count); 204} 205 206// Make sure using the same task for success and failure tasks works. 207IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, SameLaunchTask) { 208 ServiceProcessControl* process = ServiceProcessControl::GetInstance(); 209 int launch_count = 5; 210 for (int i = 0; i < launch_count; i++) { 211 // Launch the process asynchronously. 212 base::Closure task = base::Bind(&DecrementUntilZero, &launch_count); 213 process->Launch(task, task); 214 } 215 // Then run the message loop to keep things running. 216 content::RunMessageLoop(); 217 EXPECT_EQ(0, launch_count); 218} 219 220// Tests whether disconnecting from the service IPC causes the service process 221// to die. 222IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, DieOnDisconnect) { 223 // Launch the service process. 224 LaunchServiceProcessControl(); 225 // Make sure we are connected to the service process. 226 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 227 Disconnect(); 228} 229 230IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, ForceShutdown) { 231 // Launch the service process. 232 LaunchServiceProcessControl(); 233 // Make sure we are connected to the service process. 234 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 235 base::ProcessId service_pid; 236 EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); 237 EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); 238 chrome::VersionInfo version_info; 239 ForceServiceProcessShutdown(version_info.Version(), service_pid); 240} 241 242IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, CheckPid) { 243 base::ProcessId service_pid; 244 EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid)); 245 // Launch the service process. 246 LaunchServiceProcessControl(); 247 EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); 248 EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); 249 // Disconnect from service process. 250 Disconnect(); 251} 252 253IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, HistogramsNoService) { 254 ASSERT_FALSE(ServiceProcessControl::GetInstance()->IsConnected()); 255 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0); 256 EXPECT_FALSE(ServiceProcessControl::GetInstance()->GetHistograms( 257 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback, 258 base::Unretained(this)), 259 base::TimeDelta())); 260} 261 262IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, HistogramsTimeout) { 263 LaunchServiceProcessControl(); 264 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 265 // Callback should not be called during GetHistograms call. 266 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0); 267 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms( 268 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback, 269 base::Unretained(this)), 270 base::TimeDelta::FromMilliseconds(100))); 271 EXPECT_CALL(*this, MockHistogramsCallback()).Times(1); 272 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); 273 content::RunMessageLoop(); 274} 275 276IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, Histograms) { 277 LaunchServiceProcessControl(); 278 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 279 // Callback should not be called during GetHistograms call. 280 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0); 281 // Wait for real callback by providing large timeout value. 282 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms( 283 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback, 284 base::Unretained(this)), 285 base::TimeDelta::FromHours(1))); 286 EXPECT_CALL(*this, MockHistogramsCallback()).Times(1); 287 content::RunMessageLoop(); 288} 289