Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / common / service_process_util_unittest.cc
blob8844f91305e794b793448122c816c4a24050053a
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/location.h"
12 #include "base/process/kill.h"
13 #include "base/process/launch.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_split.h"
17 #if !defined(OS_MACOSX)
18 #include "base/at_exit.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/test/multiprocess_test.h"
23 #include "base/test/test_timeouts.h"
24 #include "base/threading/thread.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "components/version_info/version_info.h"
27 #include "testing/multiprocess_func_list.h"
29 #if defined(OS_WIN)
30 #include "base/win/win_util.h"
31 #endif
33 #if defined(OS_POSIX)
34 #include "chrome/common/auto_start_linux.h"
35 #endif
37 #if defined(USE_AURA)
38 // This test fails http://crbug.com/84854, and is very flaky on CrOS and
39 // somewhat flaky on other Linux.
40 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
41 #else
42 #if defined(OS_LINUX) || defined(OS_WIN)
43 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
44 #else
45 #define MAYBE_ForceShutdown ForceShutdown
46 #endif
47 #endif
49 namespace {
51 bool g_good_shutdown = false;
53 void ShutdownTask(base::MessageLoop* loop) {
54 // Quit the main message loop.
55 ASSERT_FALSE(g_good_shutdown);
56 g_good_shutdown = true;
57 loop->task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
60 } // namespace
62 TEST(ServiceProcessUtilTest, ScopedVersionedName) {
63 std::string test_str = "test";
64 std::string scoped_name = GetServiceProcessScopedVersionedName(test_str);
65 EXPECT_TRUE(base::EndsWith(scoped_name, test_str,
66 base::CompareCase::SENSITIVE));
67 EXPECT_NE(std::string::npos,
68 scoped_name.find(version_info::GetVersionNumber()));
71 class ServiceProcessStateTest : public base::MultiProcessTest {
72 public:
73 ServiceProcessStateTest();
74 ~ServiceProcessStateTest() override;
75 void SetUp() override;
76 base::SingleThreadTaskRunner* IOMessageLoopProxy() {
77 return io_thread_.task_runner().get();
79 void LaunchAndWait(const std::string& name);
81 private:
82 // This is used to release the ServiceProcessState singleton after each test.
83 base::ShadowingAtExitManager at_exit_manager_;
84 base::Thread io_thread_;
87 ServiceProcessStateTest::ServiceProcessStateTest()
88 : io_thread_("ServiceProcessStateTestThread") {
91 ServiceProcessStateTest::~ServiceProcessStateTest() {
94 void ServiceProcessStateTest::SetUp() {
95 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
96 ASSERT_TRUE(io_thread_.StartWithOptions(options));
99 void ServiceProcessStateTest::LaunchAndWait(const std::string& name) {
100 base::Process process = SpawnChild(name);
101 ASSERT_TRUE(process.IsValid());
102 int exit_code = 0;
103 ASSERT_TRUE(process.WaitForExit(&exit_code));
104 ASSERT_EQ(exit_code, 0);
107 TEST_F(ServiceProcessStateTest, Singleton) {
108 ServiceProcessState state;
109 ASSERT_TRUE(state.Initialize());
110 LaunchAndWait("ServiceProcessStateTestSingleton");
113 // http://crbug.com/396390
114 TEST_F(ServiceProcessStateTest, DISABLED_ReadyState) {
115 ASSERT_FALSE(CheckServiceProcessReady());
116 ServiceProcessState state;
117 ASSERT_TRUE(state.Initialize());
118 ASSERT_TRUE(state.SignalReady(IOMessageLoopProxy(), base::Closure()));
119 LaunchAndWait("ServiceProcessStateTestReadyTrue");
120 state.SignalStopped();
121 LaunchAndWait("ServiceProcessStateTestReadyFalse");
124 TEST_F(ServiceProcessStateTest, AutoRun) {
125 ServiceProcessState state;
126 ASSERT_TRUE(state.AddToAutoRun());
127 scoped_ptr<base::CommandLine> autorun_command_line;
128 #if defined(OS_WIN)
129 std::string value_name = GetServiceProcessScopedName("_service_run");
130 base::string16 value;
131 EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
132 base::UTF8ToWide(value_name),
133 &value));
134 autorun_command_line.reset(
135 new base::CommandLine(base::CommandLine::FromString(value)));
136 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
137 #if defined(GOOGLE_CHROME_BUILD)
138 std::string base_desktop_name = "google-chrome-service.desktop";
139 #else // CHROMIUM_BUILD
140 std::string base_desktop_name = "chromium-service.desktop";
141 #endif
142 std::string exec_value;
143 EXPECT_TRUE(AutoStart::GetAutostartFileValue(
144 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
146 // Make sure |exec_value| doesn't contain strings a shell would
147 // treat specially.
148 ASSERT_EQ(std::string::npos, exec_value.find('#'));
149 ASSERT_EQ(std::string::npos, exec_value.find('\n'));
150 ASSERT_EQ(std::string::npos, exec_value.find('"'));
151 ASSERT_EQ(std::string::npos, exec_value.find('\''));
153 base::CommandLine::StringVector argv = base::SplitString(
154 exec_value, base::CommandLine::StringType(1, ' '),
155 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
156 ASSERT_GE(argv.size(), 2U)
157 << "Expected at least one command-line option in: " << exec_value;
158 autorun_command_line.reset(new base::CommandLine(argv));
159 #endif // defined(OS_WIN)
160 if (autorun_command_line.get()) {
161 EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType),
162 std::string(switches::kServiceProcess));
164 ASSERT_TRUE(state.RemoveFromAutoRun());
165 #if defined(OS_WIN)
166 EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
167 base::UTF8ToWide(value_name),
168 &value));
169 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
170 EXPECT_FALSE(AutoStart::GetAutostartFileValue(
171 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
172 #endif // defined(OS_WIN)
175 // http://crbug.com/396390
176 TEST_F(ServiceProcessStateTest, DISABLED_SharedMem) {
177 std::string version;
178 base::ProcessId pid;
179 #if defined(OS_WIN)
180 // On Posix, named shared memory uses a file on disk. This file
181 // could be lying around from previous crashes which could cause
182 // GetServiceProcessPid to lie. On Windows, we use a named event so we
183 // don't have this issue. Until we have a more stable shared memory
184 // implementation on Posix, this check will only execute on Windows.
185 ASSERT_FALSE(GetServiceProcessData(&version, &pid));
186 #endif // defined(OS_WIN)
187 ServiceProcessState state;
188 ASSERT_TRUE(state.Initialize());
189 ASSERT_TRUE(GetServiceProcessData(&version, &pid));
190 ASSERT_EQ(base::GetCurrentProcId(), pid);
193 TEST_F(ServiceProcessStateTest, MAYBE_ForceShutdown) {
194 base::Process process = SpawnChild("ServiceProcessStateTestShutdown");
195 ASSERT_TRUE(process.IsValid());
196 for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) {
197 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
199 ASSERT_TRUE(CheckServiceProcessReady());
200 std::string version;
201 base::ProcessId pid;
202 ASSERT_TRUE(GetServiceProcessData(&version, &pid));
203 ASSERT_TRUE(ForceServiceProcessShutdown(version, pid));
204 int exit_code = 0;
205 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
206 &exit_code));
207 ASSERT_EQ(exit_code, 0);
210 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) {
211 ServiceProcessState state;
212 EXPECT_FALSE(state.Initialize());
213 return 0;
216 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) {
217 EXPECT_TRUE(CheckServiceProcessReady());
218 return 0;
221 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) {
222 EXPECT_FALSE(CheckServiceProcessReady());
223 return 0;
226 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) {
227 base::MessageLoop message_loop;
228 message_loop.set_thread_name("ServiceProcessStateTestShutdownMainThread");
229 base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread");
230 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
231 EXPECT_TRUE(io_thread_.StartWithOptions(options));
232 ServiceProcessState state;
233 EXPECT_TRUE(state.Initialize());
234 EXPECT_TRUE(state.SignalReady(
235 io_thread_.task_runner().get(),
236 base::Bind(&ShutdownTask, base::MessageLoop::current())));
237 message_loop.task_runner()->PostDelayedTask(
238 FROM_HERE, base::MessageLoop::QuitClosure(),
239 TestTimeouts::action_max_timeout());
240 EXPECT_FALSE(g_good_shutdown);
241 message_loop.Run();
242 EXPECT_TRUE(g_good_shutdown);
243 return 0;
246 #else // !OS_MACOSX
248 #include <CoreFoundation/CoreFoundation.h>
250 #include "base/files/file_path.h"
251 #include "base/files/file_util.h"
252 #include "base/files/scoped_temp_dir.h"
253 #include "base/mac/mac_util.h"
254 #include "base/test/test_timeouts.h"
255 #include "base/threading/thread.h"
256 #include "chrome/common/mac/launchd.h"
257 #include "chrome/common/mac/mock_launchd.h"
258 #include "testing/gtest/include/gtest/gtest.h"
260 class ServiceProcessStateFileManipulationTest : public ::testing::Test {
261 protected:
262 ServiceProcessStateFileManipulationTest()
263 : io_thread_("ServiceProcessStateFileManipulationTest_IO") {
266 void SetUp() override {
267 base::Thread::Options options;
268 options.message_loop_type = base::MessageLoop::TYPE_IO;
269 ASSERT_TRUE(io_thread_.StartWithOptions(options));
270 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
271 ASSERT_TRUE(MockLaunchd::MakeABundle(GetTempDirPath(),
272 "Test",
273 &bundle_path_,
274 &executable_path_));
275 mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_,
276 false, false));
277 scoped_launchd_instance_.reset(
278 new Launchd::ScopedInstance(mock_launchd_.get()));
279 ASSERT_TRUE(service_process_state_.Initialize());
280 ASSERT_TRUE(service_process_state_.SignalReady(
281 io_thread_.task_runner().get(), base::Closure()));
282 loop_.PostDelayedTask(FROM_HERE,
283 base::MessageLoop::QuitClosure(),
284 TestTimeouts::action_max_timeout());
287 const MockLaunchd* mock_launchd() const { return mock_launchd_.get(); }
288 const base::FilePath& executable_path() const { return executable_path_; }
289 const base::FilePath& bundle_path() const { return bundle_path_; }
290 const base::FilePath& GetTempDirPath() const { return temp_dir_.path(); }
292 base::SingleThreadTaskRunner* GetIOMessageLoopProxy() {
293 return io_thread_.task_runner().get();
295 void Run() { loop_.Run(); }
297 private:
298 base::ScopedTempDir temp_dir_;
299 base::MessageLoopForUI loop_;
300 base::Thread io_thread_;
301 base::FilePath executable_path_, bundle_path_;
302 scoped_ptr<MockLaunchd> mock_launchd_;
303 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_;
304 ServiceProcessState service_process_state_;
307 void DeleteFunc(const base::FilePath& file) {
308 EXPECT_TRUE(base::DeleteFile(file, true));
311 void MoveFunc(const base::FilePath& from, const base::FilePath& to) {
312 EXPECT_TRUE(base::Move(from, to));
315 void ChangeAttr(const base::FilePath& from, int mode) {
316 EXPECT_EQ(chmod(from.value().c_str(), mode), 0);
319 class ScopedAttributesRestorer {
320 public:
321 ScopedAttributesRestorer(const base::FilePath& path, int mode)
322 : path_(path), mode_(mode) {
324 ~ScopedAttributesRestorer() {
325 ChangeAttr(path_, mode_);
327 private:
328 base::FilePath path_;
329 int mode_;
332 void TrashFunc(const base::FilePath& src) {
333 FSRef path_ref;
334 FSRef new_path_ref;
335 EXPECT_TRUE(base::mac::FSRefFromPath(src.value(), &path_ref));
336 OSStatus status = FSMoveObjectToTrashSync(&path_ref,
337 &new_path_ref,
338 kFSFileOperationDefaultOptions);
339 EXPECT_EQ(status, noErr) << "FSMoveObjectToTrashSync " << status;
342 TEST_F(ServiceProcessStateFileManipulationTest, VerifyLaunchD) {
343 // There have been problems where launchd has gotten into a bad state, usually
344 // because something had deleted all the files in /tmp. launchd depends on
345 // a Unix Domain Socket that it creates at /tmp/launchd*/sock.
346 // The symptom of this problem is that the service process connect fails
347 // on Mac and "launch_msg(): Socket is not connected" appears.
348 // This test is designed to make sure that launchd is working.
349 // http://crbug/75518
350 // Note: This particular problem no longer affects launchd in 10.10+, since
351 // there is no user owned launchd process and sockets are no longer made at
352 // /tmp/launchd*/sock. This test is still useful as a sanity check to make
353 // sure that launchd appears to be working.
355 base::CommandLine cl(base::FilePath("/bin/launchctl"));
356 cl.AppendArg("limit");
358 std::string output;
359 int exit_code = -1;
360 ASSERT_TRUE(base::GetAppOutputWithExitCode(cl, &output, &exit_code)
361 && exit_code == 0)
362 << " exit_code:" << exit_code << " " << output;
365 TEST_F(ServiceProcessStateFileManipulationTest, DeleteFile) {
366 GetIOMessageLoopProxy()->PostTask(
367 FROM_HERE,
368 base::Bind(&DeleteFunc, executable_path()));
369 Run();
370 ASSERT_TRUE(mock_launchd()->remove_called());
371 ASSERT_TRUE(mock_launchd()->delete_called());
374 TEST_F(ServiceProcessStateFileManipulationTest, DeleteBundle) {
375 GetIOMessageLoopProxy()->PostTask(
376 FROM_HERE,
377 base::Bind(&DeleteFunc, bundle_path()));
378 Run();
379 ASSERT_TRUE(mock_launchd()->remove_called());
380 ASSERT_TRUE(mock_launchd()->delete_called());
383 TEST_F(ServiceProcessStateFileManipulationTest, MoveBundle) {
384 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveBundle");
385 GetIOMessageLoopProxy()->PostTask(
386 FROM_HERE,
387 base::Bind(&MoveFunc, bundle_path(), new_loc));
388 Run();
389 ASSERT_TRUE(mock_launchd()->restart_called());
390 ASSERT_TRUE(mock_launchd()->write_called());
393 TEST_F(ServiceProcessStateFileManipulationTest, MoveFile) {
394 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveFile");
395 GetIOMessageLoopProxy()->PostTask(
396 FROM_HERE,
397 base::Bind(&MoveFunc, executable_path(), new_loc));
398 Run();
399 ASSERT_TRUE(mock_launchd()->remove_called());
400 ASSERT_TRUE(mock_launchd()->delete_called());
403 TEST_F(ServiceProcessStateFileManipulationTest, TrashBundle) {
404 FSRef bundle_ref;
405 ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path().value(), &bundle_ref));
406 GetIOMessageLoopProxy()->PostTask(
407 FROM_HERE,
408 base::Bind(&TrashFunc, bundle_path()));
409 Run();
410 ASSERT_TRUE(mock_launchd()->remove_called());
411 ASSERT_TRUE(mock_launchd()->delete_called());
412 std::string path(base::mac::PathFromFSRef(bundle_ref));
413 base::FilePath file_path(path);
414 ASSERT_TRUE(base::DeleteFile(file_path, true));
417 TEST_F(ServiceProcessStateFileManipulationTest, ChangeAttr) {
418 ScopedAttributesRestorer restorer(bundle_path(), 0777);
419 GetIOMessageLoopProxy()->PostTask(
420 FROM_HERE,
421 base::Bind(&ChangeAttr, bundle_path(), 0222));
422 Run();
423 ASSERT_TRUE(mock_launchd()->remove_called());
424 ASSERT_TRUE(mock_launchd()->delete_called());
427 #endif // !OS_MACOSX