Add a warning for missing fileBrowserHandler permission.
[chromium-blink-merge.git] / chrome / common / service_process_util_unittest.cc
blob9e4ba36973b8e30615e30daa0b7c38eeadd140c8
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"
13 #include "base/strings/string_split.h"
15 #if !defined(OS_MACOSX)
16 #include "base/at_exit.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/test/multiprocess_test.h"
21 #include "base/test/test_timeouts.h"
22 #include "base/threading/thread.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/chrome_version_info.h"
25 #include "testing/multiprocess_func_list.h"
27 #if defined(OS_WIN)
28 #include "base/win/win_util.h"
29 #endif
31 #if defined(OS_POSIX)
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 EXPECT_TRUE(EndsWith(scoped_name, test_str, true));
65 EXPECT_NE(std::string::npos, scoped_name.find(version_info.Version()));
68 class ServiceProcessStateTest : public base::MultiProcessTest {
69 public:
70 ServiceProcessStateTest();
71 ~ServiceProcessStateTest() override;
72 void SetUp() override;
73 base::MessageLoopProxy* IOMessageLoopProxy() {
74 return io_thread_.message_loop_proxy().get();
76 void LaunchAndWait(const std::string& name);
78 private:
79 // This is used to release the ServiceProcessState singleton after each test.
80 base::ShadowingAtExitManager at_exit_manager_;
81 base::Thread io_thread_;
84 ServiceProcessStateTest::ServiceProcessStateTest()
85 : io_thread_("ServiceProcessStateTestThread") {
88 ServiceProcessStateTest::~ServiceProcessStateTest() {
91 void ServiceProcessStateTest::SetUp() {
92 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
93 ASSERT_TRUE(io_thread_.StartWithOptions(options));
96 void ServiceProcessStateTest::LaunchAndWait(const std::string& name) {
97 base::Process process = SpawnChild(name);
98 ASSERT_TRUE(process.IsValid());
99 int exit_code = 0;
100 ASSERT_TRUE(process.WaitForExit(&exit_code));
101 ASSERT_EQ(exit_code, 0);
104 TEST_F(ServiceProcessStateTest, Singleton) {
105 ServiceProcessState state;
106 ASSERT_TRUE(state.Initialize());
107 LaunchAndWait("ServiceProcessStateTestSingleton");
110 // http://crbug.com/396390
111 TEST_F(ServiceProcessStateTest, DISABLED_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<base::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(
132 new base::CommandLine(base::CommandLine::FromString(value)));
133 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
134 #if defined(GOOGLE_CHROME_BUILD)
135 std::string base_desktop_name = "google-chrome-service.desktop";
136 #else // CHROMIUM_BUILD
137 std::string base_desktop_name = "chromium-service.desktop";
138 #endif
139 std::string exec_value;
140 EXPECT_TRUE(AutoStart::GetAutostartFileValue(
141 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
143 // Make sure |exec_value| doesn't contain strings a shell would
144 // treat specially.
145 ASSERT_EQ(std::string::npos, exec_value.find('#'));
146 ASSERT_EQ(std::string::npos, exec_value.find('\n'));
147 ASSERT_EQ(std::string::npos, exec_value.find('"'));
148 ASSERT_EQ(std::string::npos, exec_value.find('\''));
150 base::CommandLine::StringVector argv;
151 base::SplitString(exec_value, ' ', &argv);
152 ASSERT_GE(argv.size(), 2U)
153 << "Expected at least one command-line option in: " << exec_value;
154 autorun_command_line.reset(new base::CommandLine(argv));
155 #endif // defined(OS_WIN)
156 if (autorun_command_line.get()) {
157 EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType),
158 std::string(switches::kServiceProcess));
160 ASSERT_TRUE(state.RemoveFromAutoRun());
161 #if defined(OS_WIN)
162 EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
163 base::UTF8ToWide(value_name),
164 &value));
165 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
166 EXPECT_FALSE(AutoStart::GetAutostartFileValue(
167 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
168 #endif // defined(OS_WIN)
171 // http://crbug.com/396390
172 TEST_F(ServiceProcessStateTest, DISABLED_SharedMem) {
173 std::string version;
174 base::ProcessId pid;
175 #if defined(OS_WIN)
176 // On Posix, named shared memory uses a file on disk. This file
177 // could be lying around from previous crashes which could cause
178 // GetServiceProcessPid to lie. On Windows, we use a named event so we
179 // don't have this issue. Until we have a more stable shared memory
180 // implementation on Posix, this check will only execute on Windows.
181 ASSERT_FALSE(GetServiceProcessData(&version, &pid));
182 #endif // defined(OS_WIN)
183 ServiceProcessState state;
184 ASSERT_TRUE(state.Initialize());
185 ASSERT_TRUE(GetServiceProcessData(&version, &pid));
186 ASSERT_EQ(base::GetCurrentProcId(), pid);
189 TEST_F(ServiceProcessStateTest, MAYBE_ForceShutdown) {
190 base::Process process = SpawnChild("ServiceProcessStateTestShutdown");
191 ASSERT_TRUE(process.IsValid());
192 for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) {
193 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
195 ASSERT_TRUE(CheckServiceProcessReady());
196 std::string version;
197 base::ProcessId pid;
198 ASSERT_TRUE(GetServiceProcessData(&version, &pid));
199 ASSERT_TRUE(ForceServiceProcessShutdown(version, pid));
200 int exit_code = 0;
201 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
202 &exit_code));
203 ASSERT_EQ(exit_code, 0);
206 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) {
207 ServiceProcessState state;
208 EXPECT_FALSE(state.Initialize());
209 return 0;
212 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) {
213 EXPECT_TRUE(CheckServiceProcessReady());
214 return 0;
217 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) {
218 EXPECT_FALSE(CheckServiceProcessReady());
219 return 0;
222 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) {
223 base::MessageLoop message_loop;
224 message_loop.set_thread_name("ServiceProcessStateTestShutdownMainThread");
225 base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread");
226 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
227 EXPECT_TRUE(io_thread_.StartWithOptions(options));
228 ServiceProcessState state;
229 EXPECT_TRUE(state.Initialize());
230 EXPECT_TRUE(state.SignalReady(
231 io_thread_.message_loop_proxy().get(),
232 base::Bind(&ShutdownTask, base::MessageLoop::current())));
233 message_loop.PostDelayedTask(FROM_HERE,
234 base::MessageLoop::QuitClosure(),
235 TestTimeouts::action_max_timeout());
236 EXPECT_FALSE(g_good_shutdown);
237 message_loop.Run();
238 EXPECT_TRUE(g_good_shutdown);
239 return 0;
242 #else // !OS_MACOSX
244 #include <CoreFoundation/CoreFoundation.h>
246 #include "base/files/file_path.h"
247 #include "base/files/file_util.h"
248 #include "base/files/scoped_temp_dir.h"
249 #include "base/mac/mac_util.h"
250 #include "base/test/test_timeouts.h"
251 #include "base/threading/thread.h"
252 #include "chrome/common/mac/launchd.h"
253 #include "chrome/common/mac/mock_launchd.h"
254 #include "testing/gtest/include/gtest/gtest.h"
256 class ServiceProcessStateFileManipulationTest : public ::testing::Test {
257 protected:
258 ServiceProcessStateFileManipulationTest()
259 : io_thread_("ServiceProcessStateFileManipulationTest_IO") {
262 void SetUp() override {
263 base::Thread::Options options;
264 options.message_loop_type = base::MessageLoop::TYPE_IO;
265 ASSERT_TRUE(io_thread_.StartWithOptions(options));
266 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
267 ASSERT_TRUE(MockLaunchd::MakeABundle(GetTempDirPath(),
268 "Test",
269 &bundle_path_,
270 &executable_path_));
271 mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_,
272 false, false));
273 scoped_launchd_instance_.reset(
274 new Launchd::ScopedInstance(mock_launchd_.get()));
275 ASSERT_TRUE(service_process_state_.Initialize());
276 ASSERT_TRUE(service_process_state_.SignalReady(
277 io_thread_.message_loop_proxy().get(), base::Closure()));
278 loop_.PostDelayedTask(FROM_HERE,
279 base::MessageLoop::QuitClosure(),
280 TestTimeouts::action_max_timeout());
283 const MockLaunchd* mock_launchd() const { return mock_launchd_.get(); }
284 const base::FilePath& executable_path() const { return executable_path_; }
285 const base::FilePath& bundle_path() const { return bundle_path_; }
286 const base::FilePath& GetTempDirPath() const { return temp_dir_.path(); }
288 base::MessageLoopProxy* GetIOMessageLoopProxy() {
289 return io_thread_.message_loop_proxy().get();
291 void Run() { loop_.Run(); }
293 private:
294 base::ScopedTempDir temp_dir_;
295 base::MessageLoopForUI loop_;
296 base::Thread io_thread_;
297 base::FilePath executable_path_, bundle_path_;
298 scoped_ptr<MockLaunchd> mock_launchd_;
299 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_;
300 ServiceProcessState service_process_state_;
303 void DeleteFunc(const base::FilePath& file) {
304 EXPECT_TRUE(base::DeleteFile(file, true));
307 void MoveFunc(const base::FilePath& from, const base::FilePath& to) {
308 EXPECT_TRUE(base::Move(from, to));
311 void ChangeAttr(const base::FilePath& from, int mode) {
312 EXPECT_EQ(chmod(from.value().c_str(), mode), 0);
315 class ScopedAttributesRestorer {
316 public:
317 ScopedAttributesRestorer(const base::FilePath& path, int mode)
318 : path_(path), mode_(mode) {
320 ~ScopedAttributesRestorer() {
321 ChangeAttr(path_, mode_);
323 private:
324 base::FilePath path_;
325 int mode_;
328 void TrashFunc(const base::FilePath& src) {
329 FSRef path_ref;
330 FSRef new_path_ref;
331 EXPECT_TRUE(base::mac::FSRefFromPath(src.value(), &path_ref));
332 OSStatus status = FSMoveObjectToTrashSync(&path_ref,
333 &new_path_ref,
334 kFSFileOperationDefaultOptions);
335 EXPECT_EQ(status, noErr) << "FSMoveObjectToTrashSync " << status;
338 TEST_F(ServiceProcessStateFileManipulationTest, VerifyLaunchD) {
339 // There have been problems where launchd has gotten into a bad state, usually
340 // because something had deleted all the files in /tmp. launchd depends on
341 // a Unix Domain Socket that it creates at /tmp/launchd*/sock.
342 // The symptom of this problem is that the service process connect fails
343 // on Mac and "launch_msg(): Socket is not connected" appears.
344 // This test is designed to make sure that launchd is working.
345 // http://crbug/75518
346 // Note: This particular problem no longer affects launchd in 10.10+, since
347 // there is no user owned launchd process and sockets are no longer made at
348 // /tmp/launchd*/sock. This test is still useful as a sanity check to make
349 // sure that launchd appears to be working.
351 base::CommandLine cl(base::FilePath("/bin/launchctl"));
352 cl.AppendArg("limit");
354 std::string output;
355 int exit_code = -1;
356 ASSERT_TRUE(base::GetAppOutputWithExitCode(cl, &output, &exit_code)
357 && exit_code == 0)
358 << " exit_code:" << exit_code << " " << output;
361 TEST_F(ServiceProcessStateFileManipulationTest, DeleteFile) {
362 GetIOMessageLoopProxy()->PostTask(
363 FROM_HERE,
364 base::Bind(&DeleteFunc, executable_path()));
365 Run();
366 ASSERT_TRUE(mock_launchd()->remove_called());
367 ASSERT_TRUE(mock_launchd()->delete_called());
370 TEST_F(ServiceProcessStateFileManipulationTest, DeleteBundle) {
371 GetIOMessageLoopProxy()->PostTask(
372 FROM_HERE,
373 base::Bind(&DeleteFunc, bundle_path()));
374 Run();
375 ASSERT_TRUE(mock_launchd()->remove_called());
376 ASSERT_TRUE(mock_launchd()->delete_called());
379 TEST_F(ServiceProcessStateFileManipulationTest, MoveBundle) {
380 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveBundle");
381 GetIOMessageLoopProxy()->PostTask(
382 FROM_HERE,
383 base::Bind(&MoveFunc, bundle_path(), new_loc));
384 Run();
385 ASSERT_TRUE(mock_launchd()->restart_called());
386 ASSERT_TRUE(mock_launchd()->write_called());
389 TEST_F(ServiceProcessStateFileManipulationTest, MoveFile) {
390 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveFile");
391 GetIOMessageLoopProxy()->PostTask(
392 FROM_HERE,
393 base::Bind(&MoveFunc, executable_path(), new_loc));
394 Run();
395 ASSERT_TRUE(mock_launchd()->remove_called());
396 ASSERT_TRUE(mock_launchd()->delete_called());
399 TEST_F(ServiceProcessStateFileManipulationTest, TrashBundle) {
400 FSRef bundle_ref;
401 ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path().value(), &bundle_ref));
402 GetIOMessageLoopProxy()->PostTask(
403 FROM_HERE,
404 base::Bind(&TrashFunc, bundle_path()));
405 Run();
406 ASSERT_TRUE(mock_launchd()->remove_called());
407 ASSERT_TRUE(mock_launchd()->delete_called());
408 std::string path(base::mac::PathFromFSRef(bundle_ref));
409 base::FilePath file_path(path);
410 ASSERT_TRUE(base::DeleteFile(file_path, true));
413 TEST_F(ServiceProcessStateFileManipulationTest, ChangeAttr) {
414 ScopedAttributesRestorer restorer(bundle_path(), 0777);
415 GetIOMessageLoopProxy()->PostTask(
416 FROM_HERE,
417 base::Bind(&ChangeAttr, bundle_path(), 0222));
418 Run();
419 ASSERT_TRUE(mock_launchd()->remove_called());
420 ASSERT_TRUE(mock_launchd()->delete_called());
423 #endif // !OS_MACOSX