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 "base/bind.h" 6 #include "base/bind_helpers.h" 7 #include "base/process/kill.h" 8 #include "base/process/process_handle.h" 9 #include "base/process/process_iterator.h" 10 #include "base/test/test_timeouts.h" 11 #include "chrome/browser/service/service_process_control.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/common/chrome_version_info.h" 14 #include "chrome/common/service_process_util.h" 15 #include "chrome/test/base/in_process_browser_test.h" 16 #include "chrome/test/base/ui_test_utils.h" 17 18 class ServiceProcessControlBrowserTest 19 : public InProcessBrowserTest { 20 public: 21 ServiceProcessControlBrowserTest() 22 : service_process_handle_(base::kNullProcessHandle) { 23 } 24 virtual ~ServiceProcessControlBrowserTest() { 25 base::CloseProcessHandle(service_process_handle_); 26 service_process_handle_ = base::kNullProcessHandle; 27 } 28 29 #if defined(OS_MACOSX) 30 virtual void TearDown() { 31 // ForceServiceProcessShutdown removes the process from launched on Mac. 32 ForceServiceProcessShutdown("", 0); 33 } 34 #endif // OS_MACOSX 35 36 protected: 37 void LaunchServiceProcessControl() { 38 // Launch the process asynchronously. 39 ServiceProcessControl::GetInstance()->Launch( 40 base::Bind(&ServiceProcessControlBrowserTest::ProcessControlLaunched, 41 this), 42 base::Bind( 43 &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed, 44 this)); 45 46 // Then run the message loop to keep things running. 47 content::RunMessageLoop(); 48 } 49 50 // Send a Cloud Print status request and wait for a reply from the service. 51 void SendRequestAndWait() { 52 ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( 53 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback, 54 base::Unretained(this))); 55 content::RunMessageLoop(); 56 } 57 58 void CloudPrintInfoCallback( 59 const cloud_print::CloudPrintProxyInfo& proxy_info) { 60 base::MessageLoop::current()->Quit(); 61 } 62 63 void Disconnect() { 64 // This will close the IPC connection. 65 ServiceProcessControl::GetInstance()->Disconnect(); 66 } 67 68 void WaitForShutdown() { 69 EXPECT_TRUE(base::WaitForSingleProcess( 70 service_process_handle_, 71 TestTimeouts::action_max_timeout())); 72 } 73 74 void ProcessControlLaunched() { 75 base::ProcessId service_pid; 76 EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); 77 EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); 78 EXPECT_TRUE(base::OpenProcessHandleWithAccess( 79 service_pid, 80 base::kProcessAccessWaitForTermination | 81 // we need query permission to get exit code 82 base::kProcessAccessQueryInformation, 83 &service_process_handle_)); 84 // Quit the current message. Post a QuitTask instead of just calling Quit() 85 // because this can get invoked in the context of a Launch() call and we 86 // may not be in Run() yet. 87 base::MessageLoop::current()->PostTask(FROM_HERE, 88 base::MessageLoop::QuitClosure()); 89 } 90 91 void ProcessControlLaunchFailed() { 92 ADD_FAILURE(); 93 // Quit the current message. 94 base::MessageLoop::current()->PostTask(FROM_HERE, 95 base::MessageLoop::QuitClosure()); 96 } 97 98 private: 99 base::ProcessHandle service_process_handle_; 100 }; 101 102 // They way that the IPC is implemented only works on windows. This has to 103 // change when we implement a different scheme for IPC. 104 // Times out flakily, http://crbug.com/70076. 105 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, 106 DISABLED_LaunchAndIPC) { 107 LaunchServiceProcessControl(); 108 109 // Make sure we are connected to the service process. 110 EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 111 SendRequestAndWait(); 112 113 // And then shutdown the service process. 114 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); 115 } 116 117 // This tests the case when a service process is launched when the browser 118 // starts but we try to launch it again while setting up Cloud Print. 119 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchTwice) { 120 // Launch the service process the first time. 121 LaunchServiceProcessControl(); 122 123 // Make sure we are connected to the service process. 124 EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 125 SendRequestAndWait(); 126 127 // Launch the service process again. 128 LaunchServiceProcessControl(); 129 EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 130 SendRequestAndWait(); 131 132 // And then shutdown the service process. 133 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); 134 } 135 136 static void DecrementUntilZero(int* count) { 137 (*count)--; 138 if (!(*count)) 139 base::MessageLoop::current()->PostTask(FROM_HERE, 140 base::MessageLoop::QuitClosure()); 141 } 142 143 // Invoke multiple Launch calls in succession and ensure that all the tasks 144 // get invoked. 145 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, 146 MultipleLaunchTasks) { 147 ServiceProcessControl* process = ServiceProcessControl::GetInstance(); 148 int launch_count = 5; 149 for (int i = 0; i < launch_count; i++) { 150 // Launch the process asynchronously. 151 process->Launch(base::Bind(&DecrementUntilZero, &launch_count), 152 base::MessageLoop::QuitClosure()); 153 } 154 // Then run the message loop to keep things running. 155 content::RunMessageLoop(); 156 EXPECT_EQ(0, launch_count); 157 // And then shutdown the service process. 158 EXPECT_TRUE(process->Shutdown()); 159 } 160 161 // Make sure using the same task for success and failure tasks works. 162 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, SameLaunchTask) { 163 ServiceProcessControl* process = ServiceProcessControl::GetInstance(); 164 int launch_count = 5; 165 for (int i = 0; i < launch_count; i++) { 166 // Launch the process asynchronously. 167 base::Closure task = base::Bind(&DecrementUntilZero, &launch_count); 168 process->Launch(task, task); 169 } 170 // Then run the message loop to keep things running. 171 content::RunMessageLoop(); 172 EXPECT_EQ(0, launch_count); 173 // And then shutdown the service process. 174 EXPECT_TRUE(process->Shutdown()); 175 } 176 177 // Tests whether disconnecting from the service IPC causes the service process 178 // to die. 179 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, 180 DieOnDisconnect) { 181 // Launch the service process. 182 LaunchServiceProcessControl(); 183 // Make sure we are connected to the service process. 184 EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 185 Disconnect(); 186 WaitForShutdown(); 187 } 188 189 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, 190 ForceShutdown) { 191 // Launch the service process. 192 LaunchServiceProcessControl(); 193 // Make sure we are connected to the service process. 194 EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); 195 base::ProcessId service_pid; 196 EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); 197 EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); 198 chrome::VersionInfo version_info; 199 ForceServiceProcessShutdown(version_info.Version(), service_pid); 200 WaitForShutdown(); 201 } 202 203 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, CheckPid) { 204 base::ProcessId service_pid; 205 EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid)); 206 // Launch the service process. 207 LaunchServiceProcessControl(); 208 EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); 209 EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); 210 // Disconnect from service process. 211 ServiceProcessControl::GetInstance()->Disconnect(); 212 } 213