service_process_control_browsertest.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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/process_util.h"
6#include "base/test/test_timeouts.h"
7#include "chrome/browser/browser.h"
8#include "chrome/browser/service/service_process_control.h"
9#include "chrome/browser/service/service_process_control_manager.h"
10#include "chrome/common/chrome_version_info.h"
11#include "chrome/common/service_process_util.h"
12#include "chrome/test/in_process_browser_test.h"
13#include "chrome/test/ui_test_utils.h"
14
15class ServiceProcessControlBrowserTest
16    : public InProcessBrowserTest,
17      public ServiceProcessControl::MessageHandler {
18 public:
19  ServiceProcessControlBrowserTest()
20      : service_process_handle_(base::kNullProcessHandle) {
21  }
22  ~ServiceProcessControlBrowserTest() {
23    base::CloseProcessHandle(service_process_handle_);
24    service_process_handle_ = base::kNullProcessHandle;
25    // Delete all instances of ServiceProcessControl.
26    ServiceProcessControlManager::instance()->Shutdown();
27  }
28
29 protected:
30  void LaunchServiceProcessControl() {
31    ServiceProcessControl* process =
32        ServiceProcessControlManager::instance()->GetProcessControl(
33            browser()->profile());
34    process_ = process;
35
36    // Launch the process asynchronously.
37    process->Launch(
38        NewRunnableMethod(
39            this,
40            &ServiceProcessControlBrowserTest::ProcessControlLaunched),
41        NewRunnableMethod(
42            this,
43            &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed));
44
45    // Then run the message loop to keep things running.
46    ui_test_utils::RunMessageLoop();
47  }
48
49  void SayHelloAndWait() {
50    // Send a hello message to the service process and wait for a reply.
51    process()->SendHello();
52    ui_test_utils::RunMessageLoop();
53  }
54
55  void Disconnect() {
56    // This will delete all instances of ServiceProcessControl and close the IPC
57    // connections.
58    ServiceProcessControlManager::instance()->Shutdown();
59    process_ = NULL;
60  }
61
62  void WaitForShutdown() {
63    EXPECT_TRUE(base::WaitForSingleProcess(
64        service_process_handle_,
65        TestTimeouts::wait_for_terminate_timeout_ms()));
66  }
67
68  void ProcessControlLaunched() {
69    base::ProcessId service_pid = GetServiceProcessPid();
70    EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
71    EXPECT_TRUE(base::OpenProcessHandleWithAccess(
72        service_pid,
73        base::kProcessAccessWaitForTermination,
74        &service_process_handle_));
75    process()->SetMessageHandler(this);
76    // Quit the current message. Post a QuitTask instead of just calling Quit()
77    // because this can get invoked in the context of a Launch() call and we
78    // may not be in Run() yet.
79    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
80  }
81
82  void ProcessControlLaunchFailed() {
83    ADD_FAILURE();
84    // Quit the current message.
85    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
86  }
87
88  // ServiceProcessControl::MessageHandler implementations.
89  virtual void OnGoodDay() {
90    MessageLoop::current()->Quit();
91  }
92
93  ServiceProcessControl* process() { return process_; }
94
95 private:
96  ServiceProcessControl* process_;
97  base::ProcessHandle service_process_handle_;
98};
99
100#if defined(OS_WIN)
101// They way that the IPC is implemented only works on windows. This has to
102// change when we implement a different scheme for IPC.
103IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchAndIPC) {
104  LaunchServiceProcessControl();
105
106  // Make sure we are connected to the service process.
107  EXPECT_TRUE(process()->is_connected());
108  SayHelloAndWait();
109
110  // And then shutdown the service process.
111  EXPECT_TRUE(process()->Shutdown());
112}
113
114// This tests the case when a service process is launched when browser
115// starts but we try to launch it again in the remoting setup dialog.
116IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchTwice) {
117  // Launch the service process the first time.
118  LaunchServiceProcessControl();
119
120  // Make sure we are connected to the service process.
121  EXPECT_TRUE(process()->is_connected());
122  SayHelloAndWait();
123
124  // Launch the service process again.
125  LaunchServiceProcessControl();
126  EXPECT_TRUE(process()->is_connected());
127  SayHelloAndWait();
128
129  // And then shutdown the service process.
130  EXPECT_TRUE(process()->Shutdown());
131}
132
133static void DecrementUntilZero(int* count) {
134  (*count)--;
135  if (!(*count))
136    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
137}
138
139// Invoke multiple Launch calls in succession and ensure that all the tasks
140// get invoked.
141IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MultipleLaunchTasks) {
142  ServiceProcessControl* process =
143      ServiceProcessControlManager::instance()->GetProcessControl(
144          browser()->profile());
145  int launch_count = 5;
146  for (int i = 0; i < launch_count; i++) {
147    // Launch the process asynchronously.
148    process->Launch(
149        NewRunnableFunction(&DecrementUntilZero, &launch_count),
150        new MessageLoop::QuitTask());
151  }
152  // Then run the message loop to keep things running.
153  ui_test_utils::RunMessageLoop();
154  EXPECT_EQ(0, launch_count);
155  // And then shutdown the service process.
156  EXPECT_TRUE(process->Shutdown());
157}
158
159// Make sure using the same task for success and failure tasks works.
160IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, SameLaunchTask) {
161  ServiceProcessControl* process =
162      ServiceProcessControlManager::instance()->GetProcessControl(
163          browser()->profile());
164  int launch_count = 5;
165  for (int i = 0; i < launch_count; i++) {
166    // Launch the process asynchronously.
167    Task * task = NewRunnableFunction(&DecrementUntilZero, &launch_count);
168    process->Launch(task, task);
169  }
170  // Then run the message loop to keep things running.
171  ui_test_utils::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.
179IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, DieOnDisconnect) {
180  // Launch the service process.
181  LaunchServiceProcessControl();
182  // Make sure we are connected to the service process.
183  EXPECT_TRUE(process()->is_connected());
184  Disconnect();
185  WaitForShutdown();
186}
187
188IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, ForceShutdown) {
189  // Launch the service process.
190  LaunchServiceProcessControl();
191  // Make sure we are connected to the service process.
192  EXPECT_TRUE(process()->is_connected());
193  chrome::VersionInfo version_info;
194  ForceServiceProcessShutdown(version_info.Version());
195  WaitForShutdown();
196}
197
198IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, CheckPid) {
199  EXPECT_EQ(0, GetServiceProcessPid());
200  // Launch the service process.
201  LaunchServiceProcessControl();
202  EXPECT_NE(static_cast<base::ProcessId>(0), GetServiceProcessPid());
203}
204
205#endif
206
207DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControlBrowserTest);
208