1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 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 5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <errno.h> 6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <fcntl.h> 7731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <sys/file.h> 8731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/process_singleton.h" 10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 11731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/eintr_wrapper.h" 12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/file_util.h" 13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/path_service.h" 14731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/chrome_constants.h" 15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/chrome_paths.h" 16731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/test/testing_profile.h" 17731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "testing/platform_test.h" 18731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 19731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace { 20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickclass ProcessSingletonMacTest : public PlatformTest { 22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick public: 23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick virtual void SetUp() { 24731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick PlatformTest::SetUp(); 25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Put the lock in a temporary directory. Doesn't need to be a 27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // full profile to test this code. 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 29731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick lock_path_ = temp_dir_.path().Append(chrome::kSingletonLockFilename); 30731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 31731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick virtual void TearDown() { 33731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick PlatformTest::TearDown(); 34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Verify that the lock was released. 36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 37731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Return |true| if the file exists and is locked. Forces a failure 40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // in the containing test in case of error condition. 41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick bool IsLocked() { 42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int fd = HANDLE_EINTR(open(lock_path_.value().c_str(), O_RDONLY)); 43731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (fd == -1) { 44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_EQ(ENOENT, errno) << "Unexpected error opening lockfile."; 45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 48731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_util::ScopedFD auto_close(&fd); 49731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int rc = HANDLE_EINTR(flock(fd, LOCK_EX|LOCK_NB)); 51731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Got the lock, so it wasn't already locked. Close releases. 53731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (rc != -1) 54731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Someone else has the lock. 57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (errno == EWOULDBLOCK) 58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return true; 59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_EQ(EWOULDBLOCK, errno) << "Unexpected error acquiring lock."; 61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ScopedTempDir temp_dir_; 65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick FilePath lock_path_; 66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}; 67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Test that the base case doesn't blow up. 69731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTEST_F(ProcessSingletonMacTest, Basic) { 70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ProcessSingleton ps(temp_dir_.path()); 71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(ps.Create()); 73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(IsLocked()); 74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ps.Cleanup(); 75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// The destructor should release the lock. 79731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTEST_F(ProcessSingletonMacTest, DestructorReleases) { 80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick { 82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ProcessSingleton ps(temp_dir_.path()); 83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(ps.Create()); 84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(IsLocked()); 85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 86731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Multiple singletons should interlock appropriately. 90731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTEST_F(ProcessSingletonMacTest, Interlock) { 91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ProcessSingleton ps1(temp_dir_.path()); 92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ProcessSingleton ps2(temp_dir_.path()); 93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Windows and Linux use a command-line flag to suppress this, but 95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // it is on a sub-process so the scope is contained. Rather than 96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // add additional API to process_singleton.h in an #ifdef, just tell 97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // the reader what to expect and move on. 98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick LOG(ERROR) << "Expect two failures to obtain the lock."; 99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // When |ps1| has the lock, |ps2| cannot get it. 101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(ps1.Create()); 103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(IsLocked()); 104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(ps2.Create()); 105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ps1.Cleanup(); 106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // And when |ps2| has the lock, |ps1| cannot get it. 108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(ps2.Create()); 110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(IsLocked()); 111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(ps1.Create()); 112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ps2.Cleanup(); 113731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 114731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Like |Interlock| test, but via |NotifyOtherProcessOrCreate()|. 117731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTEST_F(ProcessSingletonMacTest, NotifyOtherProcessOrCreate) { 118731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ProcessSingleton ps1(temp_dir_.path()); 119731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ProcessSingleton ps2(temp_dir_.path()); 120731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 121731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Windows and Linux use a command-line flag to suppress this, but 122731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // it is on a sub-process so the scope is contained. Rather than 123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // add additional API to process_singleton.h in an #ifdef, just tell 124731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // the reader what to expect and move on. 125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick LOG(ERROR) << "Expect two failures to obtain the lock."; 126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 127731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // When |ps1| has the lock, |ps2| cannot get it. 128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_EQ(ProcessSingleton::PROCESS_NONE, ps1.NotifyOtherProcessOrCreate()); 130731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(IsLocked()); 131731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, ps2.NotifyOtherProcessOrCreate()); 132731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ps1.Cleanup(); 133731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 134731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // And when |ps2| has the lock, |ps1| cannot get it. 135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_EQ(ProcessSingleton::PROCESS_NONE, ps2.NotifyOtherProcessOrCreate()); 137731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_TRUE(IsLocked()); 138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, ps1.NotifyOtherProcessOrCreate()); 139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ps2.Cleanup(); 140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EXPECT_FALSE(IsLocked()); 141731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 142731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 143731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// TODO(shess): Test that the lock is released when the process dies. 144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// DEATH_TEST? I don't know. If the code to communicate between 145731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// browser processes is ever written, this all would need to be tested 146731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// more like the other platforms, in which case it would be easy. 147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 148731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} // namespace 149