Home | History | Annotate | Download | only in service
      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