OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/common/service_process_util.h" | |
6 | |
5 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
6 | 8 |
7 #if !defined(OS_MACOSX) | 9 #if !defined(OS_MACOSX) |
8 // TODO(dmaclach): Figure out tests that will work with launchd on Mac OS. | |
9 | |
10 #include "base/at_exit.h" | 10 #include "base/at_exit.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/process_util.h" | 12 #include "base/process_util.h" |
13 #include "base/scoped_ptr.h" | 13 #include "base/scoped_ptr.h" |
14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
15 #include "base/test/multiprocess_test.h" | 15 #include "base/test/multiprocess_test.h" |
16 #include "base/test/test_timeouts.h" | 16 #include "base/test/test_timeouts.h" |
17 #include "base/threading/thread.h" | 17 #include "base/threading/thread.h" |
18 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
19 #include "chrome/common/chrome_switches.h" | 19 #include "chrome/common/chrome_switches.h" |
20 #include "chrome/common/chrome_version_info.h" | 20 #include "chrome/common/chrome_version_info.h" |
21 #include "chrome/common/service_process_util.h" | |
22 #include "testing/multiprocess_func_list.h" | 21 #include "testing/multiprocess_func_list.h" |
23 | 22 |
24 #if defined(OS_WIN) | 23 #if defined(OS_WIN) |
25 #include "base/win/win_util.h" | 24 #include "base/win/win_util.h" |
26 #endif | 25 #endif |
27 | 26 |
28 #if defined(OS_LINUX) | 27 #if defined(OS_LINUX) |
29 #include <glib.h> | 28 #include <glib.h> |
30 #include "chrome/common/auto_start_linux.h" | 29 #include "chrome/common/auto_start_linux.h" |
31 #endif | 30 #endif |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
82 | 81 |
83 void ServiceProcessStateTest::LaunchAndWait(const std::string& name) { | 82 void ServiceProcessStateTest::LaunchAndWait(const std::string& name) { |
84 base::ProcessHandle handle = SpawnChild(name, false); | 83 base::ProcessHandle handle = SpawnChild(name, false); |
85 ASSERT_TRUE(handle); | 84 ASSERT_TRUE(handle); |
86 int exit_code = 0; | 85 int exit_code = 0; |
87 ASSERT_TRUE(base::WaitForExitCode(handle, &exit_code)); | 86 ASSERT_TRUE(base::WaitForExitCode(handle, &exit_code)); |
88 ASSERT_EQ(exit_code, 0); | 87 ASSERT_EQ(exit_code, 0); |
89 } | 88 } |
90 | 89 |
91 TEST_F(ServiceProcessStateTest, Singleton) { | 90 TEST_F(ServiceProcessStateTest, Singleton) { |
92 ServiceProcessState* state = ServiceProcessState::GetInstance(); | 91 ServiceProcessState state; |
93 ASSERT_TRUE(state->Initialize()); | 92 ASSERT_TRUE(state.Initialize()); |
94 LaunchAndWait("ServiceProcessStateTestSingleton"); | 93 LaunchAndWait("ServiceProcessStateTestSingleton"); |
95 } | 94 } |
96 | 95 |
97 TEST_F(ServiceProcessStateTest, ReadyState) { | 96 TEST_F(ServiceProcessStateTest, ReadyState) { |
98 ASSERT_FALSE(CheckServiceProcessReady()); | 97 ASSERT_FALSE(CheckServiceProcessReady()); |
99 ServiceProcessState* state = ServiceProcessState::GetInstance(); | 98 ServiceProcessState state; |
100 ASSERT_TRUE(state->Initialize()); | 99 ASSERT_TRUE(state.Initialize()); |
101 ASSERT_TRUE(state->SignalReady(IOMessageLoopProxy(), NULL)); | 100 ASSERT_TRUE(state.SignalReady(IOMessageLoopProxy(), NULL)); |
102 LaunchAndWait("ServiceProcessStateTestReadyTrue"); | 101 LaunchAndWait("ServiceProcessStateTestReadyTrue"); |
103 state->SignalStopped(); | 102 state.SignalStopped(); |
104 LaunchAndWait("ServiceProcessStateTestReadyFalse"); | 103 LaunchAndWait("ServiceProcessStateTestReadyFalse"); |
105 } | 104 } |
106 | 105 |
107 TEST_F(ServiceProcessStateTest, AutoRun) { | 106 TEST_F(ServiceProcessStateTest, AutoRun) { |
108 ServiceProcessState* state = ServiceProcessState::GetInstance(); | 107 ServiceProcessState state; |
109 ASSERT_TRUE(state->AddToAutoRun()); | 108 ASSERT_TRUE(state.AddToAutoRun()); |
110 scoped_ptr<CommandLine> autorun_command_line; | 109 scoped_ptr<CommandLine> autorun_command_line; |
111 #if defined(OS_WIN) | 110 #if defined(OS_WIN) |
112 std::string value_name = GetServiceProcessScopedName("_service_run"); | 111 std::string value_name = GetServiceProcessScopedName("_service_run"); |
113 string16 value; | 112 string16 value; |
114 EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, | 113 EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, |
115 UTF8ToWide(value_name), | 114 UTF8ToWide(value_name), |
116 &value)); | 115 &value)); |
117 autorun_command_line.reset(new CommandLine(CommandLine::FromString(value))); | 116 autorun_command_line.reset(new CommandLine(CommandLine::FromString(value))); |
118 #elif defined(OS_LINUX) | 117 #elif defined(OS_LINUX) |
119 #if defined(GOOGLE_CHROME_BUILD) | 118 #if defined(GOOGLE_CHROME_BUILD) |
(...skipping 12 matching lines...) Expand all Loading... | |
132 g_strfreev(argv); | 131 g_strfreev(argv); |
133 } else { | 132 } else { |
134 ADD_FAILURE(); | 133 ADD_FAILURE(); |
135 g_error_free(error); | 134 g_error_free(error); |
136 } | 135 } |
137 #endif // defined(OS_WIN) | 136 #endif // defined(OS_WIN) |
138 if (autorun_command_line.get()) { | 137 if (autorun_command_line.get()) { |
139 EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType), | 138 EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType), |
140 std::string(switches::kServiceProcess)); | 139 std::string(switches::kServiceProcess)); |
141 } | 140 } |
142 ASSERT_TRUE(state->RemoveFromAutoRun()); | 141 ASSERT_TRUE(state.RemoveFromAutoRun()); |
143 #if defined(OS_WIN) | 142 #if defined(OS_WIN) |
144 EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, | 143 EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, |
145 UTF8ToWide(value_name), | 144 UTF8ToWide(value_name), |
146 &value)); | 145 &value)); |
147 #elif defined(OS_LINUX) | 146 #elif defined(OS_LINUX) |
148 EXPECT_FALSE(AutoStart::GetAutostartFileValue( | 147 EXPECT_FALSE(AutoStart::GetAutostartFileValue( |
149 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value)); | 148 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value)); |
150 #endif // defined(OS_WIN) | 149 #endif // defined(OS_WIN) |
151 } | 150 } |
152 | 151 |
153 TEST_F(ServiceProcessStateTest, SharedMem) { | 152 TEST_F(ServiceProcessStateTest, SharedMem) { |
154 std::string version; | 153 std::string version; |
155 base::ProcessId pid; | 154 base::ProcessId pid; |
156 #if defined(OS_WIN) | 155 #if defined(OS_WIN) |
157 // On Posix, named shared memory uses a file on disk. This file | 156 // On Posix, named shared memory uses a file on disk. This file |
158 // could be lying around from previous crashes which could cause | 157 // could be lying around from previous crashes which could cause |
159 // GetServiceProcessPid to lie. On Windows, we use a named event so we | 158 // GetServiceProcessPid to lie. On Windows, we use a named event so we |
160 // don't have this issue. Until we have a more stable shared memory | 159 // don't have this issue. Until we have a more stable shared memory |
161 // implementation on Posix, this check will only execute on Windows. | 160 // implementation on Posix, this check will only execute on Windows. |
162 ASSERT_FALSE(GetServiceProcessData(&version, &pid)); | 161 ASSERT_FALSE(GetServiceProcessData(&version, &pid)); |
163 #endif // defined(OS_WIN) | 162 #endif // defined(OS_WIN) |
164 ServiceProcessState* state = ServiceProcessState::GetInstance(); | 163 ServiceProcessState state; |
165 ASSERT_TRUE(state->Initialize()); | 164 ASSERT_TRUE(state.Initialize()); |
166 ASSERT_TRUE(GetServiceProcessData(&version, &pid)); | 165 ASSERT_TRUE(GetServiceProcessData(&version, &pid)); |
167 ASSERT_EQ(base::GetCurrentProcId(), pid); | 166 ASSERT_EQ(base::GetCurrentProcId(), pid); |
168 } | 167 } |
169 | 168 |
170 TEST_F(ServiceProcessStateTest, ForceShutdown) { | 169 TEST_F(ServiceProcessStateTest, ForceShutdown) { |
171 base::ProcessHandle handle = SpawnChild("ServiceProcessStateTestShutdown", | 170 base::ProcessHandle handle = SpawnChild("ServiceProcessStateTestShutdown", |
172 true); | 171 true); |
173 ASSERT_TRUE(handle); | 172 ASSERT_TRUE(handle); |
174 for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) { | 173 for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) { |
175 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout_ms()); | 174 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout_ms()); |
176 } | 175 } |
177 ASSERT_TRUE(CheckServiceProcessReady()); | 176 ASSERT_TRUE(CheckServiceProcessReady()); |
178 std::string version; | 177 std::string version; |
179 base::ProcessId pid; | 178 base::ProcessId pid; |
180 ASSERT_TRUE(GetServiceProcessData(&version, &pid)); | 179 ASSERT_TRUE(GetServiceProcessData(&version, &pid)); |
181 ASSERT_TRUE(ForceServiceProcessShutdown(version, pid)); | 180 ASSERT_TRUE(ForceServiceProcessShutdown(version, pid)); |
182 int exit_code = 0; | 181 int exit_code = 0; |
183 ASSERT_TRUE(base::WaitForExitCodeWithTimeout(handle, | 182 ASSERT_TRUE(base::WaitForExitCodeWithTimeout(handle, |
184 &exit_code, TestTimeouts::action_timeout_ms() * 2)); | 183 &exit_code, TestTimeouts::action_timeout_ms() * 2)); |
185 ASSERT_EQ(exit_code, 0); | 184 ASSERT_EQ(exit_code, 0); |
186 } | 185 } |
187 | 186 |
188 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) { | 187 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) { |
189 ServiceProcessState* state = ServiceProcessState::GetInstance(); | 188 ServiceProcessState state; |
190 EXPECT_FALSE(state->Initialize()); | 189 EXPECT_FALSE(state.Initialize()); |
191 return 0; | 190 return 0; |
192 } | 191 } |
193 | 192 |
194 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) { | 193 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) { |
195 EXPECT_TRUE(CheckServiceProcessReady()); | 194 EXPECT_TRUE(CheckServiceProcessReady()); |
196 return 0; | 195 return 0; |
197 } | 196 } |
198 | 197 |
199 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) { | 198 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) { |
200 EXPECT_FALSE(CheckServiceProcessReady()); | 199 EXPECT_FALSE(CheckServiceProcessReady()); |
201 return 0; | 200 return 0; |
202 } | 201 } |
203 | 202 |
204 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) { | 203 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) { |
205 MessageLoop message_loop; | 204 MessageLoop message_loop; |
206 message_loop.set_thread_name("ServiceProcessStateTestShutdownMainThread"); | 205 message_loop.set_thread_name("ServiceProcessStateTestShutdownMainThread"); |
207 base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread"); | 206 base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread"); |
208 base::Thread::Options options(MessageLoop::TYPE_IO, 0); | 207 base::Thread::Options options(MessageLoop::TYPE_IO, 0); |
209 EXPECT_TRUE(io_thread_.StartWithOptions(options)); | 208 EXPECT_TRUE(io_thread_.StartWithOptions(options)); |
210 ServiceProcessState* state = ServiceProcessState::GetInstance(); | 209 ServiceProcessState state; |
211 EXPECT_TRUE(state->Initialize()); | 210 EXPECT_TRUE(state.Initialize()); |
212 EXPECT_TRUE(state->SignalReady(io_thread_.message_loop_proxy(), | 211 EXPECT_TRUE(state.SignalReady(io_thread_.message_loop_proxy(), |
213 NewRunnableFunction(&ShutdownTask, | 212 NewRunnableFunction(&ShutdownTask, |
214 MessageLoop::current()))); | 213 MessageLoop::current()))); |
215 message_loop.PostDelayedTask(FROM_HERE, | 214 message_loop.PostDelayedTask(FROM_HERE, |
216 new MessageLoop::QuitTask(), | 215 new MessageLoop::QuitTask(), |
217 TestTimeouts::action_max_timeout_ms()); | 216 TestTimeouts::action_max_timeout_ms()); |
218 EXPECT_FALSE(g_good_shutdown); | 217 EXPECT_FALSE(g_good_shutdown); |
219 message_loop.Run(); | 218 message_loop.Run(); |
220 EXPECT_TRUE(g_good_shutdown); | 219 EXPECT_TRUE(g_good_shutdown); |
221 return 0; | 220 return 0; |
222 } | 221 } |
223 | 222 |
223 #else // !OS_MACOSX | |
224 | |
225 #include <CoreFoundation/CoreFoundation.h> | |
226 | |
227 #include <launch.h> | |
228 #include <sys/stat.h> | |
229 | |
230 #include "base/file_path.h" | |
231 #include "base/file_util.h" | |
232 #include "base/mac/mac_util.h" | |
233 #include "base/mac/scoped_cftyperef.h" | |
234 #include "base/message_loop.h" | |
235 #include "base/scoped_temp_dir.h" | |
236 #include "base/stringprintf.h" | |
237 #include "base/sys_string_conversions.h" | |
238 #include "base/test/test_timeouts.h" | |
239 #include "base/threading/thread.h" | |
240 #include "chrome/common/launchd_mac.h" | |
241 #include "testing/gtest/include/gtest/gtest.h" | |
242 | |
243 // TODO(dmaclach): Write this in terms of a real mock. | |
244 // http://crbug.com/76923 | |
245 class MockLaunchd : public Launchd { | |
246 public: | |
247 MockLaunchd(const FilePath& file, MessageLoop* loop) | |
248 : file_(file), | |
249 message_loop_(loop), | |
250 restart_called_(false), | |
251 remove_called_(false), | |
252 checkin_called_(false), | |
253 write_called_(false), | |
254 delete_called_(false) | |
Mark Mentovai
2011/03/22 00:48:24
Nit: { goes on this line.
dmac
2011/03/22 03:13:32
Done.
| |
255 { } | |
256 virtual ~MockLaunchd() { } | |
257 | |
258 virtual CFDictionaryRef CopyExports() OVERRIDE { | |
259 ADD_FAILURE(); | |
260 return NULL; | |
261 } | |
262 | |
263 virtual CFDictionaryRef CopyJobDictionary(CFStringRef label) OVERRIDE { | |
264 ADD_FAILURE(); | |
265 return NULL; | |
266 } | |
267 | |
268 virtual CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error) | |
269 OVERRIDE { | |
270 checkin_called_ = true; | |
271 CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM); | |
272 CFStringRef program_args = CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS); | |
273 const void *keys[] = { program, program_args }; | |
274 base::mac::ScopedCFTypeRef<CFStringRef> path( | |
275 base::SysUTF8ToCFStringRef(file_.value())); | |
276 const void *array_values[] = { path.get() }; | |
277 base::mac::ScopedCFTypeRef<CFArrayRef> args( | |
278 CFArrayCreate(kCFAllocatorDefault, | |
279 array_values, | |
280 1, | |
281 &kCFTypeArrayCallBacks)); | |
282 const void *values[] = { path, args }; | |
283 return CFDictionaryCreate(kCFAllocatorDefault, | |
284 keys, | |
285 values, | |
286 arraysize(keys), | |
287 &kCFTypeDictionaryKeyCallBacks, | |
288 &kCFTypeDictionaryValueCallBacks); | |
289 } | |
290 | |
291 virtual bool RemoveJob(CFStringRef label, CFErrorRef* error) OVERRIDE { | |
292 remove_called_ = true; | |
293 message_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask); | |
294 return true; | |
295 } | |
296 | |
297 virtual bool RestartJob(Domain domain, | |
298 Type type, | |
299 CFStringRef name, | |
300 CFStringRef session_type) OVERRIDE { | |
301 restart_called_ = true; | |
302 message_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask); | |
303 return true; | |
304 } | |
305 | |
306 virtual CFMutableDictionaryRef CreatePlistFromFile( | |
307 Domain domain, | |
308 Type type, | |
309 CFStringRef name) OVERRIDE { | |
310 base::mac::ScopedCFTypeRef<CFDictionaryRef> dict( | |
311 CopyDictionaryByCheckingIn(NULL)); | |
312 return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); | |
313 } | |
314 | |
315 virtual bool WritePlistToFile(Domain domain, | |
316 Type type, | |
317 CFStringRef name, | |
318 CFDictionaryRef dict) OVERRIDE { | |
319 write_called_ = true; | |
320 return true; | |
321 } | |
322 | |
323 virtual bool DeletePlist(Domain domain, | |
324 Type type, | |
325 CFStringRef name) OVERRIDE { | |
326 delete_called_ = true; | |
327 return true; | |
328 } | |
329 | |
330 FilePath file_; | |
Mark Mentovai
2011/03/22 00:48:24
OK for now, but the data should really be in a pri
dmac
2011/03/22 03:13:32
Done.
| |
331 MessageLoop* message_loop_; | |
332 bool restart_called_; | |
333 bool remove_called_; | |
334 bool checkin_called_; | |
335 bool write_called_; | |
336 bool delete_called_; | |
337 }; | |
338 | |
339 class ServiceProcessStateFileManipulationTest : public ::testing::Test { | |
340 protected: | |
341 ServiceProcessStateFileManipulationTest() | |
342 : io_thread_("ServiceProcessStateFileManipulationTest_IO") { | |
343 } | |
344 virtual ~ServiceProcessStateFileManipulationTest() { } | |
345 | |
346 virtual void SetUp() { | |
347 base::Thread::Options options; | |
348 options.message_loop_type = MessageLoop::TYPE_IO; | |
349 ASSERT_TRUE(io_thread_.StartWithOptions(options)); | |
350 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
351 ASSERT_TRUE(MakeABundle(temp_dir_.path(), | |
352 "Test", | |
353 &bundle_path_, | |
354 &executable_path_)); | |
355 mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_)); | |
356 scoped_launchd_instance_.reset( | |
357 new Launchd::ScopedInstance(mock_launchd_.get())); | |
358 ASSERT_TRUE(service_process_state_.Initialize()); | |
359 ASSERT_TRUE(service_process_state_.SignalReady( | |
360 io_thread_.message_loop_proxy(), | |
361 NULL)); | |
362 loop_.PostDelayedTask(FROM_HERE, | |
363 new MessageLoop::QuitTask, | |
364 TestTimeouts::large_test_timeout_ms()); | |
365 } | |
366 | |
367 bool MakeABundle(const FilePath& dst, | |
368 const std::string& name, | |
369 FilePath* bundle_root, | |
370 FilePath* executable) { | |
371 *bundle_root = dst.Append(name + std::string(".app")); | |
372 FilePath contents = bundle_root->AppendASCII("Contents"); | |
373 FilePath mac_os = contents.AppendASCII("MacOS"); | |
374 *executable = mac_os.Append(name); | |
375 FilePath info_plist = contents.Append("Info.plist"); | |
376 | |
377 if (!file_util::CreateDirectory(mac_os)) { | |
378 return false; | |
379 } | |
380 const char *data = "#! testbundle"; | |
Mark Mentovai
2011/03/22 00:48:24
Put a \n at the end of this string.
dmac
2011/03/22 03:13:32
Done.
| |
381 int len = strlen(data); | |
382 if (file_util::WriteFile(*executable, data, len) != len) { | |
383 return false; | |
384 } | |
385 if (chmod(executable->value().c_str(), 0555) != 0) { | |
386 return false; | |
387 } | |
388 | |
389 const char* info_plist_format = | |
390 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r" | |
Mark Mentovai
2011/03/22 00:48:24
Your lines should end with \n throughout this stri
dmac
2011/03/22 03:13:32
I'm a classy kind of guy. Done.
| |
391 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple .com/DTDs/PropertyList-1.0.dtd\">\r" | |
392 "<plist version=\"1.0\">\r" | |
393 "<dict>\r" | |
394 " <key>CFBundleDevelopmentRegion</key>\r" | |
395 " <string>English</string>\r" | |
396 " <key>CFBundleIdentifier</key>\r" | |
397 " <string>com.test.%s</string>\r" | |
398 " <key>CFBundleInfoDictionaryVersion</key>\r" | |
399 " <string>6.0</string>\r" | |
400 " <key>CFBundleExecutable</key>\r" | |
401 " <string>%s</string>\r" | |
402 " <key>CFBundleVersion</key>\r" | |
403 " <string>1</string>\r" | |
404 "</dict>\r" | |
405 "</plist>\r"; | |
406 std::string info_plist_data = base::StringPrintf(info_plist_format, | |
407 name.c_str(), | |
408 name.c_str()); | |
409 len = info_plist_data.length(); | |
410 if (file_util::WriteFile(info_plist, info_plist_data.c_str(), len) != len) { | |
411 return false; | |
412 } | |
413 const UInt8* bundle_root_path = | |
414 reinterpret_cast<const UInt8*>(bundle_root->value().c_str()); | |
415 base::mac::ScopedCFTypeRef<CFURLRef> url( | |
416 CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, | |
417 bundle_root_path, | |
418 bundle_root->value().length(), | |
419 true)); | |
420 base::mac::ScopedCFTypeRef<CFBundleRef> bundle( | |
421 CFBundleCreate(kCFAllocatorDefault, url)); | |
422 return bundle.get(); | |
423 } | |
424 | |
425 ScopedTempDir temp_dir_; | |
Mark Mentovai
2011/03/22 00:48:24
Make private when able, as in the class above.
dmac
2011/03/22 03:13:32
Done.
| |
426 MessageLoopForUI loop_; | |
427 base::Thread io_thread_; | |
428 FilePath executable_path_, bundle_path_; | |
429 scoped_ptr<MockLaunchd> mock_launchd_; | |
430 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_; | |
431 ServiceProcessState service_process_state_; | |
432 }; | |
433 | |
434 void DeleteFunc(const FilePath& file) { | |
435 EXPECT_TRUE(file_util::Delete(file, true)); | |
436 } | |
437 | |
438 void MoveFunc(const FilePath& from, const FilePath& to) { | |
439 EXPECT_TRUE(file_util::Move(from, to)); | |
440 } | |
441 | |
442 void ChangeAttr(const FilePath& from, int mode) { | |
443 EXPECT_EQ(chmod(from.value().c_str(), mode), 0); | |
444 } | |
445 | |
446 class ScopedAttributesRestorer { | |
447 public: | |
448 ScopedAttributesRestorer(const FilePath& path, int mode) | |
449 : path_(path), mode_(mode) { | |
450 } | |
451 ~ScopedAttributesRestorer() { | |
452 ChangeAttr(path_, mode_); | |
453 } | |
454 private: | |
455 FilePath path_; | |
456 int mode_; | |
457 }; | |
458 | |
459 void TrashFunc(const FilePath& src) { | |
460 FSRef path_ref; | |
461 FSRef new_path_ref; | |
462 EXPECT_TRUE(base::mac::FSRefFromPath(src.value(), &path_ref)); | |
463 OSStatus status = FSMoveObjectToTrashSync(&path_ref, | |
464 &new_path_ref, | |
465 kFSFileOperationDefaultOptions); | |
466 EXPECT_EQ(status, noErr) << "FSMoveObjectToTrashSync " << status; | |
467 } | |
468 | |
469 TEST_F(ServiceProcessStateFileManipulationTest, DeleteFile) { | |
470 io_thread_.message_loop_proxy()->PostTask( | |
471 FROM_HERE, | |
472 NewRunnableFunction(&DeleteFunc, executable_path_)); | |
473 loop_.Run(); | |
474 ASSERT_TRUE(mock_launchd_->remove_called_); | |
475 ASSERT_TRUE(mock_launchd_->delete_called_); | |
476 } | |
477 | |
478 TEST_F(ServiceProcessStateFileManipulationTest, DeleteBundle) { | |
479 io_thread_.message_loop_proxy()->PostTask( | |
480 FROM_HERE, | |
481 NewRunnableFunction(&DeleteFunc, bundle_path_)); | |
482 loop_.Run(); | |
483 ASSERT_TRUE(mock_launchd_->remove_called_); | |
484 ASSERT_TRUE(mock_launchd_->delete_called_); | |
485 } | |
486 | |
487 TEST_F(ServiceProcessStateFileManipulationTest, MoveBundle) { | |
488 FilePath new_loc = temp_dir_.path().AppendASCII("MoveBundle"); | |
489 io_thread_.message_loop_proxy()->PostTask( | |
490 FROM_HERE, | |
491 NewRunnableFunction(&MoveFunc, bundle_path_, new_loc)); | |
492 loop_.Run(); | |
493 ASSERT_TRUE(mock_launchd_->restart_called_); | |
494 ASSERT_TRUE(mock_launchd_->write_called_); | |
495 } | |
496 | |
497 TEST_F(ServiceProcessStateFileManipulationTest, MoveFile) { | |
498 FilePath new_loc = temp_dir_.path().AppendASCII("MoveFile"); | |
499 io_thread_.message_loop_proxy()->PostTask( | |
500 FROM_HERE, | |
501 NewRunnableFunction(&MoveFunc, executable_path_, new_loc)); | |
502 loop_.Run(); | |
503 ASSERT_TRUE(mock_launchd_->remove_called_); | |
504 ASSERT_TRUE(mock_launchd_->delete_called_); | |
505 } | |
506 | |
507 TEST_F(ServiceProcessStateFileManipulationTest, TrashBundle) { | |
508 FSRef bundle_ref; | |
509 ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path_.value(), &bundle_ref)); | |
510 io_thread_.message_loop_proxy()->PostTask( | |
511 FROM_HERE, | |
512 NewRunnableFunction(&TrashFunc, bundle_path_)); | |
513 loop_.Run(); | |
514 ASSERT_TRUE(mock_launchd_->remove_called_); | |
515 ASSERT_TRUE(mock_launchd_->delete_called_); | |
516 std::string path(base::mac::PathFromFSRef(bundle_ref)); | |
517 FilePath file_path(path); | |
518 ASSERT_TRUE(file_util::Delete(file_path, true)); | |
519 } | |
520 | |
521 TEST_F(ServiceProcessStateFileManipulationTest, ChangeAttr) { | |
522 ScopedAttributesRestorer restorer(bundle_path_, 0777); | |
523 io_thread_.message_loop_proxy()->PostTask( | |
524 FROM_HERE, | |
525 NewRunnableFunction(&ChangeAttr, bundle_path_, 0222)); | |
526 loop_.Run(); | |
527 ASSERT_TRUE(mock_launchd_->remove_called_); | |
528 ASSERT_TRUE(mock_launchd_->delete_called_); | |
529 } | |
530 | |
224 #endif // !OS_MACOSX | 531 #endif // !OS_MACOSX |
OLD | NEW |