| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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" | 5 #include "chrome/common/service_process_util.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 base::Bind(&ShutdownTask, &run_loop))); | 240 base::Bind(&ShutdownTask, &run_loop))); |
| 241 message_loop.task_runner()->PostDelayedTask( | 241 message_loop.task_runner()->PostDelayedTask( |
| 242 FROM_HERE, run_loop.QuitWhenIdleClosure(), | 242 FROM_HERE, run_loop.QuitWhenIdleClosure(), |
| 243 TestTimeouts::action_max_timeout()); | 243 TestTimeouts::action_max_timeout()); |
| 244 EXPECT_FALSE(g_good_shutdown); | 244 EXPECT_FALSE(g_good_shutdown); |
| 245 run_loop.Run(); | 245 run_loop.Run(); |
| 246 EXPECT_TRUE(g_good_shutdown); | 246 EXPECT_TRUE(g_good_shutdown); |
| 247 return 0; | 247 return 0; |
| 248 } | 248 } |
| 249 | 249 |
| 250 #else // !OS_MACOSX | |
| 251 | |
| 252 #include <CoreFoundation/CoreFoundation.h> | |
| 253 | |
| 254 #include "base/files/file_path.h" | |
| 255 #include "base/files/file_util.h" | |
| 256 #include "base/files/scoped_temp_dir.h" | |
| 257 #include "base/mac/mac_util.h" | |
| 258 #include "base/test/test_timeouts.h" | |
| 259 #include "base/threading/thread.h" | |
| 260 #include "chrome/common/mac/launchd.h" | |
| 261 #include "chrome/common/mac/mock_launchd.h" | |
| 262 #include "testing/gtest/include/gtest/gtest.h" | |
| 263 | |
| 264 class ServiceProcessStateFileManipulationTest : public ::testing::Test { | |
| 265 protected: | |
| 266 ServiceProcessStateFileManipulationTest() | |
| 267 : io_thread_("ServiceProcessStateFileManipulationTest_IO") { | |
| 268 } | |
| 269 | |
| 270 void SetUp() override { | |
| 271 base::Thread::Options options; | |
| 272 options.message_loop_type = base::MessageLoop::TYPE_IO; | |
| 273 ASSERT_TRUE(io_thread_.StartWithOptions(options)); | |
| 274 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| 275 ASSERT_TRUE(MockLaunchd::MakeABundle(GetTempDirPath(), | |
| 276 "Test", | |
| 277 &bundle_path_, | |
| 278 &executable_path_)); | |
| 279 mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_, | |
| 280 false, false)); | |
| 281 scoped_launchd_instance_.reset( | |
| 282 new Launchd::ScopedInstance(mock_launchd_.get())); | |
| 283 ASSERT_TRUE(service_process_state_.Initialize()); | |
| 284 ASSERT_TRUE(service_process_state_.SignalReady( | |
| 285 io_thread_.task_runner().get(), base::Closure())); | |
| 286 loop_.task_runner()->PostDelayedTask(FROM_HERE, | |
| 287 run_loop_.QuitWhenIdleClosure(), | |
| 288 TestTimeouts::action_max_timeout()); | |
| 289 } | |
| 290 | |
| 291 const MockLaunchd* mock_launchd() const { return mock_launchd_.get(); } | |
| 292 const base::FilePath& executable_path() const { return executable_path_; } | |
| 293 const base::FilePath& bundle_path() const { return bundle_path_; } | |
| 294 const base::FilePath& GetTempDirPath() const { return temp_dir_.GetPath(); } | |
| 295 | |
| 296 base::SingleThreadTaskRunner* GetIOTaskRunner() { | |
| 297 return io_thread_.task_runner().get(); | |
| 298 } | |
| 299 void Run() { run_loop_.Run(); } | |
| 300 | |
| 301 private: | |
| 302 base::ScopedTempDir temp_dir_; | |
| 303 base::MessageLoopForUI loop_; | |
| 304 base::RunLoop run_loop_; | |
| 305 base::Thread io_thread_; | |
| 306 base::FilePath executable_path_, bundle_path_; | |
| 307 std::unique_ptr<MockLaunchd> mock_launchd_; | |
| 308 std::unique_ptr<Launchd::ScopedInstance> scoped_launchd_instance_; | |
| 309 ServiceProcessState service_process_state_; | |
| 310 }; | |
| 311 | |
| 312 void DeleteFunc(const base::FilePath& file) { | |
| 313 EXPECT_TRUE(base::DeleteFile(file, true)); | |
| 314 } | |
| 315 | |
| 316 void MoveFunc(const base::FilePath& from, const base::FilePath& to) { | |
| 317 EXPECT_TRUE(base::Move(from, to)); | |
| 318 } | |
| 319 | |
| 320 void ChangeAttr(const base::FilePath& from, int mode) { | |
| 321 EXPECT_EQ(chmod(from.value().c_str(), mode), 0); | |
| 322 } | |
| 323 | |
| 324 class ScopedAttributesRestorer { | |
| 325 public: | |
| 326 ScopedAttributesRestorer(const base::FilePath& path, int mode) | |
| 327 : path_(path), mode_(mode) { | |
| 328 } | |
| 329 ~ScopedAttributesRestorer() { | |
| 330 ChangeAttr(path_, mode_); | |
| 331 } | |
| 332 private: | |
| 333 base::FilePath path_; | |
| 334 int mode_; | |
| 335 }; | |
| 336 | |
| 337 void TrashFunc(const base::FilePath& src) { | |
| 338 FSRef path_ref; | |
| 339 FSRef new_path_ref; | |
| 340 EXPECT_TRUE(base::mac::FSRefFromPath(src.value(), &path_ref)); | |
| 341 OSStatus status = FSMoveObjectToTrashSync(&path_ref, | |
| 342 &new_path_ref, | |
| 343 kFSFileOperationDefaultOptions); | |
| 344 EXPECT_EQ(status, noErr) << "FSMoveObjectToTrashSync " << status; | |
| 345 } | |
| 346 | |
| 347 TEST_F(ServiceProcessStateFileManipulationTest, VerifyLaunchD) { | |
| 348 // There have been problems where launchd has gotten into a bad state, usually | |
| 349 // because something had deleted all the files in /tmp. launchd depends on | |
| 350 // a Unix Domain Socket that it creates at /tmp/launchd*/sock. | |
| 351 // The symptom of this problem is that the service process connect fails | |
| 352 // on Mac and "launch_msg(): Socket is not connected" appears. | |
| 353 // This test is designed to make sure that launchd is working. | |
| 354 // http://crbug/75518 | |
| 355 // Note: This particular problem no longer affects launchd in 10.10+, since | |
| 356 // there is no user owned launchd process and sockets are no longer made at | |
| 357 // /tmp/launchd*/sock. This test is still useful as a sanity check to make | |
| 358 // sure that launchd appears to be working. | |
| 359 | |
| 360 base::CommandLine cl(base::FilePath("/bin/launchctl")); | |
| 361 cl.AppendArg("limit"); | |
| 362 | |
| 363 std::string output; | |
| 364 int exit_code = -1; | |
| 365 ASSERT_TRUE(base::GetAppOutputWithExitCode(cl, &output, &exit_code) | |
| 366 && exit_code == 0) | |
| 367 << " exit_code:" << exit_code << " " << output; | |
| 368 } | |
| 369 | |
| 370 TEST_F(ServiceProcessStateFileManipulationTest, DeleteFile) { | |
| 371 GetIOTaskRunner()->PostTask(FROM_HERE, | |
| 372 base::Bind(&DeleteFunc, executable_path())); | |
| 373 Run(); | |
| 374 ASSERT_TRUE(mock_launchd()->remove_called()); | |
| 375 ASSERT_TRUE(mock_launchd()->delete_called()); | |
| 376 } | |
| 377 | |
| 378 TEST_F(ServiceProcessStateFileManipulationTest, DeleteBundle) { | |
| 379 GetIOTaskRunner()->PostTask(FROM_HERE, | |
| 380 base::Bind(&DeleteFunc, bundle_path())); | |
| 381 Run(); | |
| 382 ASSERT_TRUE(mock_launchd()->remove_called()); | |
| 383 ASSERT_TRUE(mock_launchd()->delete_called()); | |
| 384 } | |
| 385 | |
| 386 TEST_F(ServiceProcessStateFileManipulationTest, MoveBundle) { | |
| 387 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveBundle"); | |
| 388 GetIOTaskRunner()->PostTask(FROM_HERE, | |
| 389 base::Bind(&MoveFunc, bundle_path(), new_loc)); | |
| 390 Run(); | |
| 391 ASSERT_TRUE(mock_launchd()->restart_called()); | |
| 392 ASSERT_TRUE(mock_launchd()->write_called()); | |
| 393 } | |
| 394 | |
| 395 TEST_F(ServiceProcessStateFileManipulationTest, MoveFile) { | |
| 396 base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveFile"); | |
| 397 GetIOTaskRunner()->PostTask( | |
| 398 FROM_HERE, base::Bind(&MoveFunc, executable_path(), new_loc)); | |
| 399 Run(); | |
| 400 ASSERT_TRUE(mock_launchd()->remove_called()); | |
| 401 ASSERT_TRUE(mock_launchd()->delete_called()); | |
| 402 } | |
| 403 | |
| 404 TEST_F(ServiceProcessStateFileManipulationTest, TrashBundle) { | |
| 405 FSRef bundle_ref; | |
| 406 ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path().value(), &bundle_ref)); | |
| 407 GetIOTaskRunner()->PostTask(FROM_HERE, base::Bind(&TrashFunc, bundle_path())); | |
| 408 Run(); | |
| 409 ASSERT_TRUE(mock_launchd()->remove_called()); | |
| 410 ASSERT_TRUE(mock_launchd()->delete_called()); | |
| 411 std::string path(base::mac::PathFromFSRef(bundle_ref)); | |
| 412 base::FilePath file_path(path); | |
| 413 ASSERT_TRUE(base::DeleteFile(file_path, true)); | |
| 414 } | |
| 415 | |
| 416 TEST_F(ServiceProcessStateFileManipulationTest, ChangeAttr) { | |
| 417 ScopedAttributesRestorer restorer(bundle_path(), 0777); | |
| 418 GetIOTaskRunner()->PostTask(FROM_HERE, | |
| 419 base::Bind(&ChangeAttr, bundle_path(), 0222)); | |
| 420 Run(); | |
| 421 ASSERT_TRUE(mock_launchd()->remove_called()); | |
| 422 ASSERT_TRUE(mock_launchd()->delete_called()); | |
| 423 } | |
| 424 | |
| 425 #endif // !OS_MACOSX | 250 #endif // !OS_MACOSX |
| OLD | NEW |