Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / service_process_util_unittest.cc
blobd1ca2c4278bac51decc431649c766346a949ecd6
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.
5 #include "chrome/common/service_process_util.h"
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/process/kill.h"
12 #include "base/process/launch.h"
14 #if !defined(OS_MACOSX)
15 #include "base/at_exit.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/test/multiprocess_test.h"
20 #include "base/test/test_timeouts.h"
21 #include "base/threading/thread.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/chrome_version_info.h"
24 #include "testing/multiprocess_func_list.h"
26 #if defined(OS_WIN)
27 #include "base/win/win_util.h"
28 #endif
30 #if defined(OS_POSIX)
31 #include <glib.h>
32 #include "chrome/common/auto_start_linux.h"
33 #endif
35 #if defined(USE_AURA)
36 // This test fails http://crbug.com/84854, and is very flaky on CrOS and
37 // somewhat flaky on other Linux.
38 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
39 #else
40 #if defined(OS_LINUX) || defined(OS_WIN)
41 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
42 #else
43 #define MAYBE_ForceShutdown ForceShutdown
44 #endif
45 #endif
47 namespace {
49 bool g_good_shutdown = false;
51 void ShutdownTask(base::MessageLoop* loop) {
52 // Quit the main message loop.
53 ASSERT_FALSE(g_good_shutdown);
54 g_good_shutdown = true;
55 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
58 } // namespace
60 TEST(ServiceProcessUtilTest, ScopedVersionedName) {
61 std::string test_str = "test";
62 std::string scoped_name = GetServiceProcessScopedVersionedName(test_str);
63 chrome::VersionInfo version_info;
64 DCHECK(version_info.is_valid());
65 EXPECT_TRUE(EndsWith(scoped_name, test_str, true));
66 EXPECT_NE(std::string::npos, scoped_name.find(version_info.Version()));
69 class ServiceProcessStateTest : public base::MultiProcessTest {
70 public:
71 ServiceProcessStateTest();
72 virtual ~ServiceProcessStateTest();
73 virtual void SetUp();
74 base::MessageLoopProxy* IOMessageLoopProxy() {
75 return io_thread_.message_loop_proxy().get();
77 void LaunchAndWait(const std::string& name);
79 private:
80 // This is used to release the ServiceProcessState singleton after each test.
81 base::ShadowingAtExitManager at_exit_manager_;
82 base::Thread io_thread_;
85 ServiceProcessStateTest::ServiceProcessStateTest()
86 : io_thread_("ServiceProcessStateTestThread") {
89 ServiceProcessStateTest::~ServiceProcessStateTest() {
92 void ServiceProcessStateTest::SetUp() {
93 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
94 ASSERT_TRUE(io_thread_.StartWithOptions(options));
97 void ServiceProcessStateTest::LaunchAndWait(const std::string& name) {
98 base::ProcessHandle handle = SpawnChild(name, false);
99 ASSERT_TRUE(handle);
100 int exit_code = 0;
101 ASSERT_TRUE(base::WaitForExitCode(handle, &exit_code));
102 ASSERT_EQ(exit_code, 0);
105 TEST_F(ServiceProcessStateTest, Singleton) {
106 ServiceProcessState state;
107 ASSERT_TRUE(state.Initialize());
108 LaunchAndWait("ServiceProcessStateTestSingleton");
111 TEST_F(ServiceProcessStateTest, ReadyState) {
112 ASSERT_FALSE(CheckServiceProcessReady());
113 ServiceProcessState state;
114 ASSERT_TRUE(state.Initialize());
115 ASSERT_TRUE(state.SignalReady(IOMessageLoopProxy(), base::Closure()));
116 LaunchAndWait("ServiceProcessStateTestReadyTrue");
117 state.SignalStopped();
118 LaunchAndWait("ServiceProcessStateTestReadyFalse");
121 TEST_F(ServiceProcessStateTest, AutoRun) {
122 ServiceProcessState state;
123 ASSERT_TRUE(state.AddToAutoRun());
124 scoped_ptr<CommandLine> autorun_command_line;
125 #if defined(OS_WIN)
126 std::string value_name = GetServiceProcessScopedName("_service_run");
127 base::string16 value;
128 EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
129 base::UTF8ToWide(value_name),
130 &value));
131 autorun_command_line.reset(new CommandLine(CommandLine::FromString(value)));
132 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
133 #if defined(GOOGLE_CHROME_BUILD)
134 std::string base_desktop_name = "google-chrome-service.desktop";
135 #else // CHROMIUM_BUILD
136 std::string base_desktop_name = "chromium-service.desktop";
137 #endif
138 std::string exec_value;
139 EXPECT_TRUE(AutoStart::GetAutostartFileValue(
140 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
141 GError *error = NULL;
142 gchar **argv = NULL;
143 gint argc = 0;
144 if (g_shell_parse_argv(exec_value.c_str(), &argc, &argv, &error)) {
145 autorun_command_line.reset(new CommandLine(argc, argv));
146 g_strfreev(argv);
147 } else {
148 ADD_FAILURE();
149 g_error_free(error);
151 #endif // defined(OS_WIN)
152 if (autorun_command_line.get()) {
153 EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType),
154 std::string(switches::kServiceProcess));
156 ASSERT_TRUE(state.RemoveFromAutoRun());
157 #if defined(OS_WIN)
158 EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
159 base::UTF8ToWide(value_name),
160 &value));
161 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
162 EXPECT_FALSE(AutoStart::GetAutostartFileValue(
163 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
164 #endif // defined(OS_WIN)
167 TEST_F(ServiceProcessStateTest, SharedMem) {
168 std::string version;
169 base::ProcessId pid;
170 #if defined(OS_WIN)
171 // On Posix, named shared memory uses a file on disk. This file
172 // could be lying around from previous crashes which could cause
173 // GetServiceProcessPid to lie. On Windows, we use a named event so we
174 // don't have this issue. Until we have a more stable shared memory
175 // implementation on Posix, this check will only execute on Windows.
176 ASSERT_FALSE(GetServiceProcessData(&version, &pid));
177 #endif // defined(OS_WIN)
178 ServiceProcessState state;
179 ASSERT_TRUE(state.Initialize());
180 ASSERT_TRUE(GetServiceProcessData(&version, &pid));
181 ASSERT_EQ(base::GetCurrentProcId(), pid);
184 TEST_F(ServiceProcessStateTest, MAYBE_ForceShutdown) {
185 base::ProcessHandle handle = SpawnChild("ServiceProcessStateTestShutdown",
186 true);
187 ASSERT_TRUE(handle);
188 for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) {
189 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
191 ASSERT_TRUE(CheckServiceProcessReady());
192 std::string version;
193 base::ProcessId pid;
194 ASSERT_TRUE(GetServiceProcessData(&version, &pid));
195 ASSERT_TRUE(ForceServiceProcessShutdown(version, pid));
196 int exit_code = 0;
197 ASSERT_TRUE(base::WaitForExitCodeWithTimeout(handle,
198 &exit_code, TestTimeouts::action_max_timeout()));
199 base::CloseProcessHandle(handle);
200 ASSERT_EQ(exit_code, 0);
203 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) {
204 ServiceProcessState state;
205 EXPECT_FALSE(state.Initialize());
206 return 0;
209 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) {
210 EXPECT_TRUE(CheckServiceProcessReady());
211 return 0;
214 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) {
215 EXPECT_FALSE(CheckServiceProcessReady());
216 return 0;
219 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) {
220 base::MessageLoop message_loop;
221 message_loop.set_thread_name("ServiceProcessStateTestShutdownMainThread");
222 base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread");
223 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
224 EXPECT_TRUE(io_thread_.StartWithOptions(options));
225 ServiceProcessState state;
226 EXPECT_TRUE(state.Initialize());
227 EXPECT_TRUE(state.SignalReady(
228 io_thread_.message_loop_proxy().get(),
229 base::Bind(&ShutdownTask, base::MessageLoop::current())));
230 message_loop.PostDelayedTask(FROM_HERE,
231 base::MessageLoop::QuitClosure(),
232 TestTimeouts::action_max_timeout());
233 EXPECT_FALSE(g_good_shutdown);
234 message_loop.Run();
235 EXPECT_TRUE(g_good_shutdown);
236 return 0;
239 #else // !OS_MACOSX
241 #include <CoreFoundation/CoreFoundation.h>
243 #include "base/file_util.h"
244 #include "base/files/file_path.h"
245 #include "base/files/scoped_temp_dir.h"
246 #include "base/mac/mac_util.h"
247 #include "base/test/test_timeouts.h"
248 #include "base/threading/thread.h"
249 #include "chrome/common/mac/launchd.h"
250 #include "chrome/common/mac/mock_launchd.h"
251 #include "testing/gtest/include/gtest/gtest.h"
253 class ServiceProcessStateFileManipulationTest : public ::testing::Test {
254 protected:
255 ServiceProcessStateFileManipulationTest()
256 : io_thread_("ServiceProcessStateFileManipulationTest_IO") {
258 virtual ~ServiceProcessStateFileManipulationTest() { }
260 virtual void SetUp() {
261 base::Thread::Options options;
262 options.message_loop_type = base::MessageLoop::TYPE_IO;
263 ASSERT_TRUE(io_thread_.StartWithOptions(options));
264 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
265 ASSERT_TRUE(MockLaunchd::MakeABundle(GetTempDirPath(),
266 "Test",
267 &bundle_path_,
268 &executable_path_));
269 mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_,
270 false, false));
271 scoped_launchd_instance_.reset(
272 new Launchd::ScopedInstance(mock_launchd_.get()));
273 ASSERT_TRUE(service_process_state_.Initialize());
274 ASSERT_TRUE(service_process_state_.SignalReady(
275 io_thread_.message_loop_proxy().get(), base::Closure()));
276 loop_.PostDelayedTask(FROM_HERE,
277 base::MessageLoop::QuitClosure(),
278 TestTimeouts::action_max_timeout());
281 const MockLaunchd* mock_launchd() const { return mock_launchd_.get(); }
282 const base::FilePath& executable_path() const { return executable_path_; }
283 const base::FilePath& bundle_path() const { return bundle_path_; }
284 const base::FilePath& GetTempDirPath() const { return temp_dir_.path(); }
286 base::MessageLoopProxy* GetIOMessageLoopProxy() {
287 return io_thread_.message_loop_proxy().get();
289 void Run() { loop_.Run(); }
291 private:
292 base::ScopedTempDir temp_dir_;
293 base::MessageLoopForUI loop_;
294 base::Thread io_thread_;
295 base::FilePath executable_path_, bundle_path_;
296 scoped_ptr<MockLaunchd> mock_launchd_;
297 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_;
298 ServiceProcessState service_process_state_;
301 void DeleteFunc(const base::FilePath& file) {
302 EXPECT_TRUE(base::DeleteFile(file, true));
305 void MoveFunc(const base::FilePath& from, const base::FilePath& to) {
306 EXPECT_TRUE(base::Move(from, to));
309 void ChangeAttr(const base::FilePath& from, int mode) {
310 EXPECT_EQ(chmod(from.value().c_str(), mode), 0);
313 class ScopedAttributesRestorer {
314 public:
315 ScopedAttributesRestorer(const base::FilePath& path, int mode)
316 : path_(path), mode_(mode) {
318 ~ScopedAttributesRestorer() {
319 ChangeAttr(path_, mode_);
321 private:
322 base::FilePath path_;
323 int mode_;
326 void TrashFunc(const base::FilePath& src) {
327 FSRef path_ref;
328 FSRef new_path_ref;
329 EXPECT_TRUE(base::mac::FSRefFromPath(src.value(), &path_ref));
330 OSStatus status = FSMoveObjectToTrashSync(&path_ref,
331 &new_path_ref,
332 kFSFileOperationDefaultOptions);
333 EXPECT_EQ(status, noErr) << "FSMoveObjectToTrashSync " << status;
336 TEST_F(ServiceProcessStateFileManipulationTest, VerifyLaunchD) {
337 // There have been problems where launchd has gotten into a bad state, usually
338 // because something had deleted all the files in /tmp. launchd depends on
339 // a Unix Domain Socket that it creates at /tmp/launchd*/sock.
340 // The symptom of this problem is that the service process connect fails
341 // on Mac and "launch_msg(): Socket is not connected" appears.
342 // This test is designed to make sure that launchd is working.
343 // http://crbug/75518
345 CommandLine cl(base::FilePath("/bin/launchctl"));
346 cl.AppendArg("list");
347 cl.AppendArg("com.apple.launchctl.Aqua");
349 std::string output;
350 int exit_code = -1;
351 ASSERT_TRUE(base::GetAppOutputWithExitCode(cl, &output, &exit_code)
352 && exit_code == 0)
353 << " exit_code:" << exit_code << " " << output;
356 TEST_F(ServiceProcessStateFileManipulationTest, DeleteFile) {
357 GetIOMessageLoopProxy()->PostTask(
358 FROM_HERE,
359 base::Bind(&DeleteFunc, executable_path()));
360 Run();
361 ASSERT_TRUE(mock_launchd()->remove_called());
362 ASSERT_TRUE(mock_launchd()->delete_called());
365 TEST_F(ServiceProcessStateFileManipulationTest, DeleteBundle) {
366 GetIOMessageLoopProxy()->PostTask(
367 FROM_HERE,
368 base::Bind(&DeleteFunc, bundle_path()));
369 Run();
370 ASSERT_TRUE(mock_launchd()->remove_called());
371 ASSERT_TRUE(mock_launchd()->delete_called());
374 TEST_F(ServiceProcessStateFileManipulationTest, MoveBundle) {
375 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveBundle");
376 GetIOMessageLoopProxy()->PostTask(
377 FROM_HERE,
378 base::Bind(&MoveFunc, bundle_path(), new_loc));
379 Run();
380 ASSERT_TRUE(mock_launchd()->restart_called());
381 ASSERT_TRUE(mock_launchd()->write_called());
384 TEST_F(ServiceProcessStateFileManipulationTest, MoveFile) {
385 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveFile");
386 GetIOMessageLoopProxy()->PostTask(
387 FROM_HERE,
388 base::Bind(&MoveFunc, executable_path(), new_loc));
389 Run();
390 ASSERT_TRUE(mock_launchd()->remove_called());
391 ASSERT_TRUE(mock_launchd()->delete_called());
394 TEST_F(ServiceProcessStateFileManipulationTest, TrashBundle) {
395 FSRef bundle_ref;
396 ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path().value(), &bundle_ref));
397 GetIOMessageLoopProxy()->PostTask(
398 FROM_HERE,
399 base::Bind(&TrashFunc, bundle_path()));
400 Run();
401 ASSERT_TRUE(mock_launchd()->remove_called());
402 ASSERT_TRUE(mock_launchd()->delete_called());
403 std::string path(base::mac::PathFromFSRef(bundle_ref));
404 base::FilePath file_path(path);
405 ASSERT_TRUE(base::DeleteFile(file_path, true));
408 TEST_F(ServiceProcessStateFileManipulationTest, ChangeAttr) {
409 ScopedAttributesRestorer restorer(bundle_path(), 0777);
410 GetIOMessageLoopProxy()->PostTask(
411 FROM_HERE,
412 base::Bind(&ChangeAttr, bundle_path(), 0222));
413 Run();
414 ASSERT_TRUE(mock_launchd()->remove_called());
415 ASSERT_TRUE(mock_launchd()->delete_called());
418 #endif // !OS_MACOSX