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/service/service_process_control.h"
8#include "chrome/browser/service/service_process_control_manager.h"
9#include "chrome/browser/ui/browser.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:
18  ServiceProcessControlBrowserTest()
19      : service_process_handle_(base::kNullProcessHandle) {
20  }
21  ~ServiceProcessControlBrowserTest() {
22    base::CloseProcessHandle(service_process_handle_);
23    service_process_handle_ = base::kNullProcessHandle;
24    // Delete all instances of ServiceProcessControl.
25    ServiceProcessControlManager::GetInstance()->Shutdown();
26  }
27
28#if defined(OS_MACOSX)
29  virtual void TearDown() {
30    // ForceServiceProcessShutdown removes the process from launchd on Mac.
31    ForceServiceProcessShutdown("", 0);
32  }
33#endif  // OS_MACOSX
34
35 protected:
36  void LaunchServiceProcessControl() {
37    ServiceProcessControl* process =
38        ServiceProcessControlManager::GetInstance()->GetProcessControl(
39            browser()->profile());
40    process_ = process;
41
42    // Launch the process asynchronously.
43    process->Launch(
44        NewRunnableMethod(
45            this,
46            &ServiceProcessControlBrowserTest::ProcessControlLaunched),
47        NewRunnableMethod(
48            this,
49            &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed));
50
51    // Then run the message loop to keep things running.
52    ui_test_utils::RunMessageLoop();
53  }
54
55  // Send a remoting host status request and wait reply from the service.
56  void SendRequestAndWait() {
57    process()->GetCloudPrintProxyStatus(NewCallback(
58        this, &ServiceProcessControlBrowserTest::CloudPrintStatusCallback));
59    ui_test_utils::RunMessageLoop();
60  }
61
62  void CloudPrintStatusCallback(
63      bool enabled, std::string email) {
64    MessageLoop::current()->Quit();
65  }
66
67  void Disconnect() {
68    // This will delete all instances of ServiceProcessControl and close the IPC
69    // connections.
70    ServiceProcessControlManager::GetInstance()->Shutdown();
71    process_ = NULL;
72  }
73
74  void WaitForShutdown() {
75    EXPECT_TRUE(base::WaitForSingleProcess(
76        service_process_handle_,
77        TestTimeouts::wait_for_terminate_timeout_ms()));
78  }
79
80  void ProcessControlLaunched() {
81    base::ProcessId service_pid;
82    EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
83    EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
84    EXPECT_TRUE(base::OpenProcessHandleWithAccess(
85        service_pid,
86        base::kProcessAccessWaitForTermination,
87        &service_process_handle_));
88    // Quit the current message. Post a QuitTask instead of just calling Quit()
89    // because this can get invoked in the context of a Launch() call and we
90    // may not be in Run() yet.
91    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
92  }
93
94  void ProcessControlLaunchFailed() {
95    ADD_FAILURE();
96    // Quit the current message.
97    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
98  }
99
100  ServiceProcessControl* process() { return process_; }
101
102 private:
103  ServiceProcessControl* process_;
104  base::ProcessHandle service_process_handle_;
105};
106
107// They way that the IPC is implemented only works on windows. This has to
108// change when we implement a different scheme for IPC.
109// Times out flakily, http://crbug.com/70076.
110IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
111                       DISABLED_LaunchAndIPC) {
112  LaunchServiceProcessControl();
113
114  // Make sure we are connected to the service process.
115  EXPECT_TRUE(process()->is_connected());
116  SendRequestAndWait();
117
118  // And then shutdown the service process.
119  EXPECT_TRUE(process()->Shutdown());
120}
121
122// This tests the case when a service process is launched when browser
123// starts but we try to launch it again in the remoting setup dialog.
124// Crashes on mac. http://crbug.com/75518
125#if defined(OS_MACOSX)
126#define MAYBE_LaunchTwice DISABLED_LaunchTwice
127#else
128#define MAYBE_LaunchTwice LaunchTwice
129#endif
130IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_LaunchTwice) {
131  // Launch the service process the first time.
132  LaunchServiceProcessControl();
133
134  // Make sure we are connected to the service process.
135  EXPECT_TRUE(process()->is_connected());
136  SendRequestAndWait();
137
138  // Launch the service process again.
139  LaunchServiceProcessControl();
140  EXPECT_TRUE(process()->is_connected());
141  SendRequestAndWait();
142
143  // And then shutdown the service process.
144  EXPECT_TRUE(process()->Shutdown());
145}
146
147static void DecrementUntilZero(int* count) {
148  (*count)--;
149  if (!(*count))
150    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
151}
152
153// Invoke multiple Launch calls in succession and ensure that all the tasks
154// get invoked.
155// Crashes on mac. http://crbug.com/75518
156#if defined(OS_MACOSX)
157#define MAYBE_MultipleLaunchTasks DISABLED_MultipleLaunchTasks
158#else
159#define MAYBE_MultipleLaunchTasks MultipleLaunchTasks
160#endif
161IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
162                       MAYBE_MultipleLaunchTasks) {
163  ServiceProcessControl* process =
164      ServiceProcessControlManager::GetInstance()->GetProcessControl(
165          browser()->profile());
166  int launch_count = 5;
167  for (int i = 0; i < launch_count; i++) {
168    // Launch the process asynchronously.
169    process->Launch(
170        NewRunnableFunction(&DecrementUntilZero, &launch_count),
171        new MessageLoop::QuitTask());
172  }
173  // Then run the message loop to keep things running.
174  ui_test_utils::RunMessageLoop();
175  EXPECT_EQ(0, launch_count);
176  // And then shutdown the service process.
177  EXPECT_TRUE(process->Shutdown());
178}
179
180// Make sure using the same task for success and failure tasks works.
181// Crashes on mac. http://crbug.com/75518
182#if defined(OS_MACOSX)
183#define MAYBE_SameLaunchTask DISABLED_SameLaunchTask
184#else
185#define MAYBE_SameLaunchTask SameLaunchTask
186#endif
187IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_SameLaunchTask) {
188  ServiceProcessControl* process =
189      ServiceProcessControlManager::GetInstance()->GetProcessControl(
190          browser()->profile());
191  int launch_count = 5;
192  for (int i = 0; i < launch_count; i++) {
193    // Launch the process asynchronously.
194    Task * task = NewRunnableFunction(&DecrementUntilZero, &launch_count);
195    process->Launch(task, task);
196  }
197  // Then run the message loop to keep things running.
198  ui_test_utils::RunMessageLoop();
199  EXPECT_EQ(0, launch_count);
200  // And then shutdown the service process.
201  EXPECT_TRUE(process->Shutdown());
202}
203
204// Tests whether disconnecting from the service IPC causes the service process
205// to die.
206// Crashes on mac. http://crbug.com/75518
207#if defined(OS_MACOSX)
208#define MAYBE_DieOnDisconnect DISABLED_DieOnDisconnect
209#else
210#define MAYBE_DieOnDisconnect DieOnDisconnect
211#endif
212IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
213                       MAYBE_DieOnDisconnect) {
214  // Launch the service process.
215  LaunchServiceProcessControl();
216  // Make sure we are connected to the service process.
217  EXPECT_TRUE(process()->is_connected());
218  Disconnect();
219  WaitForShutdown();
220}
221
222//http://code.google.com/p/chromium/issues/detail?id=70793
223IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
224                       DISABLED_ForceShutdown) {
225  // Launch the service process.
226  LaunchServiceProcessControl();
227  // Make sure we are connected to the service process.
228  EXPECT_TRUE(process()->is_connected());
229  base::ProcessId service_pid;
230  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
231  EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
232  chrome::VersionInfo version_info;
233  ForceServiceProcessShutdown(version_info.Version(), service_pid);
234  WaitForShutdown();
235}
236
237// Crashes on mac. http://crbug.com/75518
238#if defined(OS_MACOSX)
239#define MAYBE_CheckPid DISABLED_CheckPid
240#else
241#define MAYBE_CheckPid CheckPid
242#endif
243IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_CheckPid) {
244  base::ProcessId service_pid;
245  EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid));
246  // Launch the service process.
247  LaunchServiceProcessControl();
248  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
249  EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
250}
251
252DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControlBrowserTest);
253