// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/process_util.h" #include "base/test/test_timeouts.h" #include "chrome/browser/service/service_process_control.h" #include "chrome/browser/service/service_process_control_manager.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_version_info.h" #include "chrome/common/service_process_util.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" class ServiceProcessControlBrowserTest : public InProcessBrowserTest { public: ServiceProcessControlBrowserTest() : service_process_handle_(base::kNullProcessHandle) { } ~ServiceProcessControlBrowserTest() { base::CloseProcessHandle(service_process_handle_); service_process_handle_ = base::kNullProcessHandle; // Delete all instances of ServiceProcessControl. ServiceProcessControlManager::GetInstance()->Shutdown(); } #if defined(OS_MACOSX) virtual void TearDown() { // ForceServiceProcessShutdown removes the process from launchd on Mac. ForceServiceProcessShutdown("", 0); } #endif // OS_MACOSX protected: void LaunchServiceProcessControl() { ServiceProcessControl* process = ServiceProcessControlManager::GetInstance()->GetProcessControl( browser()->profile()); process_ = process; // Launch the process asynchronously. process->Launch( NewRunnableMethod( this, &ServiceProcessControlBrowserTest::ProcessControlLaunched), NewRunnableMethod( this, &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed)); // Then run the message loop to keep things running. ui_test_utils::RunMessageLoop(); } // Send a remoting host status request and wait reply from the service. void SendRequestAndWait() { process()->GetCloudPrintProxyStatus(NewCallback( this, &ServiceProcessControlBrowserTest::CloudPrintStatusCallback)); ui_test_utils::RunMessageLoop(); } void CloudPrintStatusCallback( bool enabled, std::string email) { MessageLoop::current()->Quit(); } void Disconnect() { // This will delete all instances of ServiceProcessControl and close the IPC // connections. ServiceProcessControlManager::GetInstance()->Shutdown(); process_ = NULL; } void WaitForShutdown() { EXPECT_TRUE(base::WaitForSingleProcess( service_process_handle_, TestTimeouts::wait_for_terminate_timeout_ms())); } void ProcessControlLaunched() { base::ProcessId service_pid; EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); EXPECT_TRUE(base::OpenProcessHandleWithAccess( service_pid, base::kProcessAccessWaitForTermination, &service_process_handle_)); // Quit the current message. Post a QuitTask instead of just calling Quit() // because this can get invoked in the context of a Launch() call and we // may not be in Run() yet. MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); } void ProcessControlLaunchFailed() { ADD_FAILURE(); // Quit the current message. MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); } ServiceProcessControl* process() { return process_; } private: ServiceProcessControl* process_; base::ProcessHandle service_process_handle_; }; // They way that the IPC is implemented only works on windows. This has to // change when we implement a different scheme for IPC. // Times out flakily, http://crbug.com/70076. IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, DISABLED_LaunchAndIPC) { LaunchServiceProcessControl(); // Make sure we are connected to the service process. EXPECT_TRUE(process()->is_connected()); SendRequestAndWait(); // And then shutdown the service process. EXPECT_TRUE(process()->Shutdown()); } // This tests the case when a service process is launched when browser // starts but we try to launch it again in the remoting setup dialog. // Crashes on mac. http://crbug.com/75518 #if defined(OS_MACOSX) #define MAYBE_LaunchTwice DISABLED_LaunchTwice #else #define MAYBE_LaunchTwice LaunchTwice #endif IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_LaunchTwice) { // Launch the service process the first time. LaunchServiceProcessControl(); // Make sure we are connected to the service process. EXPECT_TRUE(process()->is_connected()); SendRequestAndWait(); // Launch the service process again. LaunchServiceProcessControl(); EXPECT_TRUE(process()->is_connected()); SendRequestAndWait(); // And then shutdown the service process. EXPECT_TRUE(process()->Shutdown()); } static void DecrementUntilZero(int* count) { (*count)--; if (!(*count)) MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); } // Invoke multiple Launch calls in succession and ensure that all the tasks // get invoked. // Crashes on mac. http://crbug.com/75518 #if defined(OS_MACOSX) #define MAYBE_MultipleLaunchTasks DISABLED_MultipleLaunchTasks #else #define MAYBE_MultipleLaunchTasks MultipleLaunchTasks #endif IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_MultipleLaunchTasks) { ServiceProcessControl* process = ServiceProcessControlManager::GetInstance()->GetProcessControl( browser()->profile()); int launch_count = 5; for (int i = 0; i < launch_count; i++) { // Launch the process asynchronously. process->Launch( NewRunnableFunction(&DecrementUntilZero, &launch_count), new MessageLoop::QuitTask()); } // Then run the message loop to keep things running. ui_test_utils::RunMessageLoop(); EXPECT_EQ(0, launch_count); // And then shutdown the service process. EXPECT_TRUE(process->Shutdown()); } // Make sure using the same task for success and failure tasks works. // Crashes on mac. http://crbug.com/75518 #if defined(OS_MACOSX) #define MAYBE_SameLaunchTask DISABLED_SameLaunchTask #else #define MAYBE_SameLaunchTask SameLaunchTask #endif IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_SameLaunchTask) { ServiceProcessControl* process = ServiceProcessControlManager::GetInstance()->GetProcessControl( browser()->profile()); int launch_count = 5; for (int i = 0; i < launch_count; i++) { // Launch the process asynchronously. Task * task = NewRunnableFunction(&DecrementUntilZero, &launch_count); process->Launch(task, task); } // Then run the message loop to keep things running. ui_test_utils::RunMessageLoop(); EXPECT_EQ(0, launch_count); // And then shutdown the service process. EXPECT_TRUE(process->Shutdown()); } // Tests whether disconnecting from the service IPC causes the service process // to die. // Crashes on mac. http://crbug.com/75518 #if defined(OS_MACOSX) #define MAYBE_DieOnDisconnect DISABLED_DieOnDisconnect #else #define MAYBE_DieOnDisconnect DieOnDisconnect #endif IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_DieOnDisconnect) { // Launch the service process. LaunchServiceProcessControl(); // Make sure we are connected to the service process. EXPECT_TRUE(process()->is_connected()); Disconnect(); WaitForShutdown(); } //http://code.google.com/p/chromium/issues/detail?id=70793 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, DISABLED_ForceShutdown) { // Launch the service process. LaunchServiceProcessControl(); // Make sure we are connected to the service process. EXPECT_TRUE(process()->is_connected()); base::ProcessId service_pid; EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); chrome::VersionInfo version_info; ForceServiceProcessShutdown(version_info.Version(), service_pid); WaitForShutdown(); } // Crashes on mac. http://crbug.com/75518 #if defined(OS_MACOSX) #define MAYBE_CheckPid DISABLED_CheckPid #else #define MAYBE_CheckPid CheckPid #endif IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_CheckPid) { base::ProcessId service_pid; EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid)); // Launch the service process. LaunchServiceProcessControl(); EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); } DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControlBrowserTest);