1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Use of this source code is governed by a BSD-style license that can be 3731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// found in the LICENSE file. 4731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/service_process_util.h" 6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/basictypes.h" 8dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 9dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if !defined(OS_MACOSX) 1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/at_exit.h" 11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/command_line.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/process_util.h" 14731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/string_util.h" 1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/test/multiprocess_test.h" 1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/test/test_timeouts.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/threading/thread.h" 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/utf_string_conversions.h" 19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/common/chrome_switches.h" 20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/chrome_version_info.h" 2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "testing/multiprocess_func_list.h" 22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_WIN) 24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/win/win_util.h" 25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif 26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_LINUX) 28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <glib.h> 29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/common/auto_start_linux.h" 30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif 31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace { 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool g_good_shutdown = false; 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ShutdownTask(MessageLoop* loop) { 3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Quit the main message loop. 3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_FALSE(g_good_shutdown); 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen g_good_shutdown = true; 4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen loop->PostTask(FROM_HERE, new MessageLoop::QuitTask()); 4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} // namespace 44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 45731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTEST(ServiceProcessUtilTest, ScopedVersionedName) { 46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string test_str = "test"; 47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string scoped_name = GetServiceProcessScopedVersionedName(test_str); 48731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick chrome::VersionInfo version_info; 49731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(version_info.is_valid()); 50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(EndsWith(scoped_name, test_str, true)); 51731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_NE(std::string::npos, scoped_name.find(version_info.Version())); 52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 53731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenclass ServiceProcessStateTest : public base::MultiProcessTest { 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public: 5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ServiceProcessStateTest(); 5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ~ServiceProcessStateTest(); 5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen virtual void SetUp(); 5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::MessageLoopProxy* IOMessageLoopProxy() { 6072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return io_thread_.message_loop_proxy(); 6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 6272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen void LaunchAndWait(const std::string& name); 6372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 6421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen private: 6521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // This is used to release the ServiceProcessState singleton after each test. 6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen base::ShadowingAtExitManager at_exit_manager_; 6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Thread io_thread_; 6821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}; 6921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenServiceProcessStateTest::ServiceProcessStateTest() 7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : io_thread_("ServiceProcessStateTestThread") { 7272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenServiceProcessStateTest::~ServiceProcessStateTest() { 7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ServiceProcessStateTest::SetUp() { 7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Thread::Options options(MessageLoop::TYPE_IO, 0); 7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(io_thread_.StartWithOptions(options)); 8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 8172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ServiceProcessStateTest::LaunchAndWait(const std::string& name) { 8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::ProcessHandle handle = SpawnChild(name, false); 8472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(handle); 8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int exit_code = 0; 8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(base::WaitForExitCode(handle, &exit_code)); 8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_EQ(exit_code, 0); 8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(ServiceProcessStateTest, Singleton) { 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessState state; 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(state.Initialize()); 9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LaunchAndWait("ServiceProcessStateTestSingleton"); 94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(ServiceProcessStateTest, ReadyState) { 9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_FALSE(CheckServiceProcessReady()); 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessState state; 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(state.Initialize()); 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(state.SignalReady(IOMessageLoopProxy(), NULL)); 10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LaunchAndWait("ServiceProcessStateTestReadyTrue"); 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state.SignalStopped(); 10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LaunchAndWait("ServiceProcessStateTestReadyFalse"); 104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 106dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST_F(ServiceProcessStateTest, AutoRun) { 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessState state; 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(state.AddToAutoRun()); 109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen scoped_ptr<CommandLine> autorun_command_line; 110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_WIN) 111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::string value_name = GetServiceProcessScopedName("_service_run"); 112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen string16 value; 113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, 114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen UTF8ToWide(value_name), 115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &value)); 116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autorun_command_line.reset(new CommandLine(CommandLine::FromString(value))); 117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#elif defined(OS_LINUX) 118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(GOOGLE_CHROME_BUILD) 119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::string base_desktop_name = "google-chrome-service.desktop"; 120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#else // CHROMIUM_BUILD 121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::string base_desktop_name = "chromium-service.desktop"; 122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif 123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::string exec_value; 124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(AutoStart::GetAutostartFileValue( 125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value)); 126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GError *error = NULL; 127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gchar **argv = NULL; 128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gint argc = 0; 129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (g_shell_parse_argv(exec_value.c_str(), &argc, &argv, &error)) { 130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autorun_command_line.reset(new CommandLine(argc, argv)); 131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen g_strfreev(argv); 132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else { 133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ADD_FAILURE(); 134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen g_error_free(error); 135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif // defined(OS_WIN) 137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (autorun_command_line.get()) { 138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType), 139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::string(switches::kServiceProcess)); 140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(state.RemoveFromAutoRun()); 142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_WIN) 143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, 144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen UTF8ToWide(value_name), 145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &value)); 146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#elif defined(OS_LINUX) 147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(AutoStart::GetAutostartFileValue( 148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value)); 149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif // defined(OS_WIN) 150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(ServiceProcessStateTest, SharedMem) { 15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string version; 15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::ProcessId pid; 155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#if defined(OS_WIN) 156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // On Posix, named shared memory uses a file on disk. This file 157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // could be lying around from previous crashes which could cause 158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // GetServiceProcessPid to lie. On Windows, we use a named event so we 159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // don't have this issue. Until we have a more stable shared memory 160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // implementation on Posix, this check will only execute on Windows. 161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_FALSE(GetServiceProcessData(&version, &pid)); 162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#endif // defined(OS_WIN) 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessState state; 164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(state.Initialize()); 165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(GetServiceProcessData(&version, &pid)); 16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_EQ(base::GetCurrentProcId(), pid); 16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenTEST_F(ServiceProcessStateTest, ForceShutdown) { 17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::ProcessHandle handle = SpawnChild("ServiceProcessStateTestShutdown", 17172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen true); 17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(handle); 17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) { 17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::PlatformThread::Sleep(TestTimeouts::tiny_timeout_ms()); 17572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(CheckServiceProcessReady()); 17772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string version; 17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::ProcessId pid; 179dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(GetServiceProcessData(&version, &pid)); 18072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(ForceServiceProcessShutdown(version, pid)); 18172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int exit_code = 0; 18272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(base::WaitForExitCodeWithTimeout(handle, 183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &exit_code, TestTimeouts::action_max_timeout_ms())); 184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::CloseProcessHandle(handle); 18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_EQ(exit_code, 0); 18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 18872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenMULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) { 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessState state; 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_FALSE(state.Initialize()); 19172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenMULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) { 19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(CheckServiceProcessReady()); 19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenMULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) { 20072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_FALSE(CheckServiceProcessReady()); 20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenMULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) { 20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen MessageLoop message_loop; 20672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen message_loop.set_thread_name("ServiceProcessStateTestShutdownMainThread"); 20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread"); 20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Thread::Options options(MessageLoop::TYPE_IO, 0); 20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(io_thread_.StartWithOptions(options)); 210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessState state; 211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(state.Initialize()); 212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(state.SignalReady(io_thread_.message_loop_proxy(), 213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction(&ShutdownTask, 214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MessageLoop::current()))); 21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen message_loop.PostDelayedTask(FROM_HERE, 21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen new MessageLoop::QuitTask(), 21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TestTimeouts::action_max_timeout_ms()); 21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_FALSE(g_good_shutdown); 21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen message_loop.Run(); 22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(g_good_shutdown); 22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 223731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else // !OS_MACOSX 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <CoreFoundation/CoreFoundation.h> 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <launch.h> 229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <sys/stat.h> 230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/file_path.h" 232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/file_util.h" 233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/mac/mac_util.h" 234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/mac/scoped_cftyperef.h" 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_temp_dir.h" 236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/message_loop.h" 237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/stringprintf.h" 238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/sys_string_conversions.h" 239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/test/test_timeouts.h" 240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/threading/thread.h" 241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/launchd_mac.h" 242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "testing/gtest/include/gtest/gtest.h" 243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// TODO(dmaclach): Write this in terms of a real mock. 245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// http://crbug.com/76923 246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass MockLaunchd : public Launchd { 247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public: 248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MockLaunchd(const FilePath& file, MessageLoop* loop) 249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : file_(file), 250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen message_loop_(loop), 251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen restart_called_(false), 252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen remove_called_(false), 253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen checkin_called_(false), 254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen write_called_(false), 255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delete_called_(false) { 256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual ~MockLaunchd() { } 258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual CFDictionaryRef CopyExports() OVERRIDE { 260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ADD_FAILURE(); 261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return NULL; 262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual CFDictionaryRef CopyJobDictionary(CFStringRef label) OVERRIDE { 265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ADD_FAILURE(); 266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return NULL; 267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error) 270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen OVERRIDE { 271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen checkin_called_ = true; 272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM); 273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFStringRef program_args = CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS); 274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const void *keys[] = { program, program_args }; 275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::mac::ScopedCFTypeRef<CFStringRef> path( 276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::SysUTF8ToCFStringRef(file_.value())); 277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const void *array_values[] = { path.get() }; 278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::mac::ScopedCFTypeRef<CFArrayRef> args( 279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFArrayCreate(kCFAllocatorDefault, 280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen array_values, 281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1, 282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &kCFTypeArrayCallBacks)); 283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const void *values[] = { path, args }; 284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return CFDictionaryCreate(kCFAllocatorDefault, 285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen keys, 286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen values, 287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arraysize(keys), 288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &kCFTypeDictionaryKeyCallBacks, 289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &kCFTypeDictionaryValueCallBacks); 290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool RemoveJob(CFStringRef label, CFErrorRef* error) OVERRIDE { 293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen remove_called_ = true; 294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen message_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask); 295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool RestartJob(Domain domain, 299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Type type, 300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFStringRef name, 301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFStringRef session_type) OVERRIDE { 302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen restart_called_ = true; 303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen message_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask); 304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual CFMutableDictionaryRef CreatePlistFromFile( 308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Domain domain, 309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Type type, 310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFStringRef name) OVERRIDE { 311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::mac::ScopedCFTypeRef<CFDictionaryRef> dict( 312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CopyDictionaryByCheckingIn(NULL)); 313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); 314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool WritePlistToFile(Domain domain, 317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Type type, 318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFStringRef name, 319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFDictionaryRef dict) OVERRIDE { 320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen write_called_ = true; 321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool DeletePlist(Domain domain, 325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Type type, 326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFStringRef name) OVERRIDE { 327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delete_called_ = true; 328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool restart_called() const { return restart_called_; } 332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool remove_called() const { return remove_called_; } 333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool checkin_called() const { return checkin_called_; } 334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool write_called() const { return write_called_; } 335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool delete_called() const { return delete_called_; } 336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private: 338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath file_; 339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MessageLoop* message_loop_; 340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool restart_called_; 341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool remove_called_; 342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool checkin_called_; 343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool write_called_; 344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool delete_called_; 345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass ServiceProcessStateFileManipulationTest : public ::testing::Test { 348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen protected: 349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessStateFileManipulationTest() 350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : io_thread_("ServiceProcessStateFileManipulationTest_IO") { 351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual ~ServiceProcessStateFileManipulationTest() { } 353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void SetUp() { 355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::Thread::Options options; 356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen options.message_loop_type = MessageLoop::TYPE_IO; 357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(io_thread_.StartWithOptions(options)); 358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(MakeABundle(GetTempDirPath(), 360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "Test", 361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &bundle_path_, 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &executable_path_)); 363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_)); 364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_launchd_instance_.reset( 365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new Launchd::ScopedInstance(mock_launchd_.get())); 366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(service_process_state_.Initialize()); 367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(service_process_state_.SignalReady( 368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen io_thread_.message_loop_proxy(), 369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NULL)); 370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen loop_.PostDelayedTask(FROM_HERE, 371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new MessageLoop::QuitTask, 372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TestTimeouts::action_max_timeout_ms()); 373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool MakeABundle(const FilePath& dst, 376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::string& name, 377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath* bundle_root, 378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath* executable) { 379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *bundle_root = dst.Append(name + std::string(".app")); 380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath contents = bundle_root->AppendASCII("Contents"); 381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath mac_os = contents.AppendASCII("MacOS"); 382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *executable = mac_os.Append(name); 383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath info_plist = contents.Append("Info.plist"); 384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!file_util::CreateDirectory(mac_os)) { 386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const char *data = "#! testbundle\n"; 389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int len = strlen(data); 390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (file_util::WriteFile(*executable, data, len) != len) { 391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (chmod(executable->value().c_str(), 0555) != 0) { 394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const char* info_plist_format = 398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "<plist version=\"1.0\">\n" 401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "<dict>\n" 402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <key>CFBundleDevelopmentRegion</key>\n" 403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <string>English</string>\n" 404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <key>CFBundleIdentifier</key>\n" 405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <string>com.test.%s</string>\n" 406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <key>CFBundleInfoDictionaryVersion</key>\n" 407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <string>6.0</string>\n" 408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <key>CFBundleExecutable</key>\n" 409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <string>%s</string>\n" 410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <key>CFBundleVersion</key>\n" 411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen " <string>1</string>\n" 412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "</dict>\n" 413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "</plist>\n"; 414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string info_plist_data = base::StringPrintf(info_plist_format, 415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen name.c_str(), 416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen name.c_str()); 417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen len = info_plist_data.length(); 418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (file_util::WriteFile(info_plist, info_plist_data.c_str(), len) != len) { 419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const UInt8* bundle_root_path = 422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen reinterpret_cast<const UInt8*>(bundle_root->value().c_str()); 423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::mac::ScopedCFTypeRef<CFURLRef> url( 424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bundle_root_path, 426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bundle_root->value().length(), 427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen true)); 428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::mac::ScopedCFTypeRef<CFBundleRef> bundle( 429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CFBundleCreate(kCFAllocatorDefault, url)); 430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return bundle.get(); 431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const MockLaunchd* mock_launchd() const { return mock_launchd_.get(); } 434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const FilePath& executable_path() const { return executable_path_; } 435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const FilePath& bundle_path() const { return bundle_path_; } 436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const FilePath& GetTempDirPath() const { return temp_dir_.path(); } 437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::MessageLoopProxy* GetIOMessageLoopProxy() { 439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return io_thread_.message_loop_proxy().get(); 440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void Run() { loop_.Run(); } 442ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 443ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private: 444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ScopedTempDir temp_dir_; 445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MessageLoopForUI loop_; 446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::Thread io_thread_; 447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath executable_path_, bundle_path_; 448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<MockLaunchd> mock_launchd_; 449ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_; 450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ServiceProcessState service_process_state_; 451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DeleteFunc(const FilePath& file) { 454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(file_util::Delete(file, true)); 455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid MoveFunc(const FilePath& from, const FilePath& to) { 458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(file_util::Move(from, to)); 459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ChangeAttr(const FilePath& from, int mode) { 462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_EQ(chmod(from.value().c_str(), mode), 0); 463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass ScopedAttributesRestorer { 466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public: 467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ScopedAttributesRestorer(const FilePath& path, int mode) 468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : path_(path), mode_(mode) { 469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ~ScopedAttributesRestorer() { 471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ChangeAttr(path_, mode_); 472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 473ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private: 474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath path_; 475ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int mode_; 476ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 477ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 478ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TrashFunc(const FilePath& src) { 479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FSRef path_ref; 480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FSRef new_path_ref; 481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(base::mac::FSRefFromPath(src.value(), &path_ref)); 482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen OSStatus status = FSMoveObjectToTrashSync(&path_ref, 483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &new_path_ref, 484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen kFSFileOperationDefaultOptions); 485ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_EQ(status, noErr) << "FSMoveObjectToTrashSync " << status; 486ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 487ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 488ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(ServiceProcessStateFileManipulationTest, DeleteFile) { 489ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetIOMessageLoopProxy()->PostTask( 490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FROM_HERE, 491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction(&DeleteFunc, executable_path())); 492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Run(); 493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->remove_called()); 494ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->delete_called()); 495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(ServiceProcessStateFileManipulationTest, DeleteBundle) { 498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetIOMessageLoopProxy()->PostTask( 499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FROM_HERE, 500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction(&DeleteFunc, bundle_path())); 501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Run(); 502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->remove_called()); 503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->delete_called()); 504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(ServiceProcessStateFileManipulationTest, MoveBundle) { 507ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath new_loc = GetTempDirPath().AppendASCII("MoveBundle"); 508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetIOMessageLoopProxy()->PostTask( 509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FROM_HERE, 510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction(&MoveFunc, bundle_path(), new_loc)); 511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Run(); 512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->restart_called()); 513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->write_called()); 514ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 516ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(ServiceProcessStateFileManipulationTest, MoveFile) { 517ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath new_loc = GetTempDirPath().AppendASCII("MoveFile"); 518ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetIOMessageLoopProxy()->PostTask( 519ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FROM_HERE, 520ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction(&MoveFunc, executable_path(), new_loc)); 521ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Run(); 522ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->remove_called()); 523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->delete_called()); 524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(ServiceProcessStateFileManipulationTest, TrashBundle) { 527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FSRef bundle_ref; 528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path().value(), &bundle_ref)); 529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetIOMessageLoopProxy()->PostTask( 530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FROM_HERE, 531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction(&TrashFunc, bundle_path())); 532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Run(); 533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->remove_called()); 534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->delete_called()); 535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string path(base::mac::PathFromFSRef(bundle_ref)); 536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePath file_path(path); 537ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(file_util::Delete(file_path, true)); 538ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 539ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(ServiceProcessStateFileManipulationTest, ChangeAttr) { 541ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ScopedAttributesRestorer restorer(bundle_path(), 0777); 542ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetIOMessageLoopProxy()->PostTask( 543ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FROM_HERE, 544ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction(&ChangeAttr, bundle_path(), 0222)); 545ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Run(); 546ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->remove_called()); 547ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(mock_launchd()->delete_called()); 548ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 550dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif // !OS_MACOSX 551