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) { |
| 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 bool restart_called() const { return restart_called_; } |
| 331 bool remove_called() const { return remove_called_; } |
| 332 bool checkin_called() const { return checkin_called_; } |
| 333 bool write_called() const { return write_called_; } |
| 334 bool delete_called() const { return delete_called_; } |
| 335 |
| 336 private: |
| 337 FilePath file_; |
| 338 MessageLoop* message_loop_; |
| 339 bool restart_called_; |
| 340 bool remove_called_; |
| 341 bool checkin_called_; |
| 342 bool write_called_; |
| 343 bool delete_called_; |
| 344 }; |
| 345 |
| 346 class ServiceProcessStateFileManipulationTest : public ::testing::Test { |
| 347 protected: |
| 348 ServiceProcessStateFileManipulationTest() |
| 349 : io_thread_("ServiceProcessStateFileManipulationTest_IO") { |
| 350 } |
| 351 virtual ~ServiceProcessStateFileManipulationTest() { } |
| 352 |
| 353 virtual void SetUp() { |
| 354 base::Thread::Options options; |
| 355 options.message_loop_type = MessageLoop::TYPE_IO; |
| 356 ASSERT_TRUE(io_thread_.StartWithOptions(options)); |
| 357 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 358 ASSERT_TRUE(MakeABundle(GetTempDirPath(), |
| 359 "Test", |
| 360 &bundle_path_, |
| 361 &executable_path_)); |
| 362 mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_)); |
| 363 scoped_launchd_instance_.reset( |
| 364 new Launchd::ScopedInstance(mock_launchd_.get())); |
| 365 ASSERT_TRUE(service_process_state_.Initialize()); |
| 366 ASSERT_TRUE(service_process_state_.SignalReady( |
| 367 io_thread_.message_loop_proxy(), |
| 368 NULL)); |
| 369 loop_.PostDelayedTask(FROM_HERE, |
| 370 new MessageLoop::QuitTask, |
| 371 TestTimeouts::large_test_timeout_ms()); |
| 372 } |
| 373 |
| 374 bool MakeABundle(const FilePath& dst, |
| 375 const std::string& name, |
| 376 FilePath* bundle_root, |
| 377 FilePath* executable) { |
| 378 *bundle_root = dst.Append(name + std::string(".app")); |
| 379 FilePath contents = bundle_root->AppendASCII("Contents"); |
| 380 FilePath mac_os = contents.AppendASCII("MacOS"); |
| 381 *executable = mac_os.Append(name); |
| 382 FilePath info_plist = contents.Append("Info.plist"); |
| 383 |
| 384 if (!file_util::CreateDirectory(mac_os)) { |
| 385 return false; |
| 386 } |
| 387 const char *data = "#! testbundle\n"; |
| 388 int len = strlen(data); |
| 389 if (file_util::WriteFile(*executable, data, len) != len) { |
| 390 return false; |
| 391 } |
| 392 if (chmod(executable->value().c_str(), 0555) != 0) { |
| 393 return false; |
| 394 } |
| 395 |
| 396 const char* info_plist_format = |
| 397 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
| 398 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple
.com/DTDs/PropertyList-1.0.dtd\">\n" |
| 399 "<plist version=\"1.0\">\n" |
| 400 "<dict>\n" |
| 401 " <key>CFBundleDevelopmentRegion</key>\n" |
| 402 " <string>English</string>\n" |
| 403 " <key>CFBundleIdentifier</key>\n" |
| 404 " <string>com.test.%s</string>\n" |
| 405 " <key>CFBundleInfoDictionaryVersion</key>\n" |
| 406 " <string>6.0</string>\n" |
| 407 " <key>CFBundleExecutable</key>\n" |
| 408 " <string>%s</string>\n" |
| 409 " <key>CFBundleVersion</key>\n" |
| 410 " <string>1</string>\n" |
| 411 "</dict>\n" |
| 412 "</plist>\n"; |
| 413 std::string info_plist_data = base::StringPrintf(info_plist_format, |
| 414 name.c_str(), |
| 415 name.c_str()); |
| 416 len = info_plist_data.length(); |
| 417 if (file_util::WriteFile(info_plist, info_plist_data.c_str(), len) != len) { |
| 418 return false; |
| 419 } |
| 420 const UInt8* bundle_root_path = |
| 421 reinterpret_cast<const UInt8*>(bundle_root->value().c_str()); |
| 422 base::mac::ScopedCFTypeRef<CFURLRef> url( |
| 423 CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, |
| 424 bundle_root_path, |
| 425 bundle_root->value().length(), |
| 426 true)); |
| 427 base::mac::ScopedCFTypeRef<CFBundleRef> bundle( |
| 428 CFBundleCreate(kCFAllocatorDefault, url)); |
| 429 return bundle.get(); |
| 430 } |
| 431 |
| 432 const MockLaunchd* mock_launchd() const { return mock_launchd_.get(); } |
| 433 const FilePath& executable_path() const { return executable_path_; } |
| 434 const FilePath& bundle_path() const { return bundle_path_; } |
| 435 const FilePath& GetTempDirPath() const { return temp_dir_.path(); } |
| 436 |
| 437 base::MessageLoopProxy* GetIOMessageLoopProxy() { |
| 438 return io_thread_.message_loop_proxy().get(); |
| 439 } |
| 440 void Run() { loop_.Run(); } |
| 441 |
| 442 private: |
| 443 ScopedTempDir temp_dir_; |
| 444 MessageLoopForUI loop_; |
| 445 base::Thread io_thread_; |
| 446 FilePath executable_path_, bundle_path_; |
| 447 scoped_ptr<MockLaunchd> mock_launchd_; |
| 448 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_; |
| 449 ServiceProcessState service_process_state_; |
| 450 }; |
| 451 |
| 452 void DeleteFunc(const FilePath& file) { |
| 453 EXPECT_TRUE(file_util::Delete(file, true)); |
| 454 } |
| 455 |
| 456 void MoveFunc(const FilePath& from, const FilePath& to) { |
| 457 EXPECT_TRUE(file_util::Move(from, to)); |
| 458 } |
| 459 |
| 460 void ChangeAttr(const FilePath& from, int mode) { |
| 461 EXPECT_EQ(chmod(from.value().c_str(), mode), 0); |
| 462 } |
| 463 |
| 464 class ScopedAttributesRestorer { |
| 465 public: |
| 466 ScopedAttributesRestorer(const FilePath& path, int mode) |
| 467 : path_(path), mode_(mode) { |
| 468 } |
| 469 ~ScopedAttributesRestorer() { |
| 470 ChangeAttr(path_, mode_); |
| 471 } |
| 472 private: |
| 473 FilePath path_; |
| 474 int mode_; |
| 475 }; |
| 476 |
| 477 void TrashFunc(const FilePath& src) { |
| 478 FSRef path_ref; |
| 479 FSRef new_path_ref; |
| 480 EXPECT_TRUE(base::mac::FSRefFromPath(src.value(), &path_ref)); |
| 481 OSStatus status = FSMoveObjectToTrashSync(&path_ref, |
| 482 &new_path_ref, |
| 483 kFSFileOperationDefaultOptions); |
| 484 EXPECT_EQ(status, noErr) << "FSMoveObjectToTrashSync " << status; |
| 485 } |
| 486 |
| 487 TEST_F(ServiceProcessStateFileManipulationTest, DISABLED_DeleteFile) { |
| 488 GetIOMessageLoopProxy()->PostTask( |
| 489 FROM_HERE, |
| 490 NewRunnableFunction(&DeleteFunc, executable_path())); |
| 491 Run(); |
| 492 ASSERT_TRUE(mock_launchd()->remove_called()); |
| 493 ASSERT_TRUE(mock_launchd()->delete_called()); |
| 494 } |
| 495 |
| 496 TEST_F(ServiceProcessStateFileManipulationTest, DISABLED_DeleteBundle) { |
| 497 GetIOMessageLoopProxy()->PostTask( |
| 498 FROM_HERE, |
| 499 NewRunnableFunction(&DeleteFunc, bundle_path())); |
| 500 Run(); |
| 501 ASSERT_TRUE(mock_launchd()->remove_called()); |
| 502 ASSERT_TRUE(mock_launchd()->delete_called()); |
| 503 } |
| 504 |
| 505 TEST_F(ServiceProcessStateFileManipulationTest, DISABLED_MoveBundle) { |
| 506 FilePath new_loc = GetTempDirPath().AppendASCII("MoveBundle"); |
| 507 GetIOMessageLoopProxy()->PostTask( |
| 508 FROM_HERE, |
| 509 NewRunnableFunction(&MoveFunc, bundle_path(), new_loc)); |
| 510 Run(); |
| 511 ASSERT_TRUE(mock_launchd()->restart_called()); |
| 512 ASSERT_TRUE(mock_launchd()->write_called()); |
| 513 } |
| 514 |
| 515 TEST_F(ServiceProcessStateFileManipulationTest, DISABLED_MoveFile) { |
| 516 FilePath new_loc = GetTempDirPath().AppendASCII("MoveFile"); |
| 517 GetIOMessageLoopProxy()->PostTask( |
| 518 FROM_HERE, |
| 519 NewRunnableFunction(&MoveFunc, executable_path(), new_loc)); |
| 520 Run(); |
| 521 ASSERT_TRUE(mock_launchd()->remove_called()); |
| 522 ASSERT_TRUE(mock_launchd()->delete_called()); |
| 523 } |
| 524 |
| 525 TEST_F(ServiceProcessStateFileManipulationTest, DISABLED_TrashBundle) { |
| 526 FSRef bundle_ref; |
| 527 ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path().value(), &bundle_ref)); |
| 528 GetIOMessageLoopProxy()->PostTask( |
| 529 FROM_HERE, |
| 530 NewRunnableFunction(&TrashFunc, bundle_path())); |
| 531 Run(); |
| 532 ASSERT_TRUE(mock_launchd()->remove_called()); |
| 533 ASSERT_TRUE(mock_launchd()->delete_called()); |
| 534 std::string path(base::mac::PathFromFSRef(bundle_ref)); |
| 535 FilePath file_path(path); |
| 536 ASSERT_TRUE(file_util::Delete(file_path, true)); |
| 537 } |
| 538 |
| 539 TEST_F(ServiceProcessStateFileManipulationTest, DISABLED_ChangeAttr) { |
| 540 ScopedAttributesRestorer restorer(bundle_path(), 0777); |
| 541 GetIOMessageLoopProxy()->PostTask( |
| 542 FROM_HERE, |
| 543 NewRunnableFunction(&ChangeAttr, bundle_path(), 0222)); |
| 544 Run(); |
| 545 ASSERT_TRUE(mock_launchd()->remove_called()); |
| 546 ASSERT_TRUE(mock_launchd()->delete_called()); |
| 547 } |
| 548 |
224 #endif // !OS_MACOSX | 549 #endif // !OS_MACOSX |
OLD | NEW |