Chromium Code Reviews| 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 |