Home | History | Annotate | Download | only in common
      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
      3 // found in the LICENSE file.
      4 
      5 #include "base/basictypes.h"
      6 #include "base/environment.h"
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/process/kill.h"
     10 #include "base/rand_util.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/test/multiprocess_test.h"
     13 #include "base/time/time.h"
     14 #include "chrome/common/multi_process_lock.h"
     15 #include "testing/multiprocess_func_list.h"
     16 
     17 class MultiProcessLockTest : public base::MultiProcessTest {
     18  public:
     19   static const char kLockEnviromentVarName[];
     20 
     21   class ScopedEnvironmentVariable {
     22    public:
     23     ScopedEnvironmentVariable(const std::string &name,
     24                               const std::string &value)
     25         : name_(name), environment_(base::Environment::Create()) {
     26       environment_->SetVar(name_.c_str(), value);
     27     }
     28     ~ScopedEnvironmentVariable() {
     29       environment_->UnSetVar(name_.c_str());
     30     }
     31 
     32    private:
     33     std::string name_;
     34     scoped_ptr<base::Environment> environment_;
     35     DISALLOW_COPY_AND_ASSIGN(ScopedEnvironmentVariable);
     36   };
     37 
     38   std::string GenerateLockName();
     39   void ExpectLockIsLocked(const std::string &name);
     40   void ExpectLockIsUnlocked(const std::string &name);
     41 };
     42 
     43 const char MultiProcessLockTest::kLockEnviromentVarName[]
     44     = "MULTI_PROCESS_TEST_LOCK_NAME";
     45 
     46 std::string MultiProcessLockTest::GenerateLockName() {
     47   base::Time now = base::Time::NowFromSystemTime();
     48   return base::StringPrintf("multi_process_test_lock %lf%lf",
     49                             now.ToDoubleT(), base::RandDouble());
     50 }
     51 
     52 void MultiProcessLockTest::ExpectLockIsLocked(const std::string &name) {
     53   ScopedEnvironmentVariable var(kLockEnviromentVarName, name);
     54   base::ProcessHandle handle = SpawnChild("MultiProcessLockTryFailMain");
     55   ASSERT_TRUE(handle);
     56   int exit_code = 0;
     57   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
     58   EXPECT_EQ(exit_code, 0);
     59 }
     60 
     61 void MultiProcessLockTest::ExpectLockIsUnlocked(
     62     const std::string &name) {
     63   ScopedEnvironmentVariable var(kLockEnviromentVarName, name);
     64   base::ProcessHandle handle = SpawnChild("MultiProcessLockTrySucceedMain");
     65   ASSERT_TRUE(handle);
     66   int exit_code = 0;
     67   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
     68   EXPECT_EQ(exit_code, 0);
     69 }
     70 
     71 TEST_F(MultiProcessLockTest, BasicCreationTest) {
     72   // Test basic creation/destruction with no lock taken
     73   std::string name = GenerateLockName();
     74   scoped_ptr<MultiProcessLock> scoped(MultiProcessLock::Create(name));
     75   ExpectLockIsUnlocked(name);
     76   scoped.reset(NULL);
     77 }
     78 
     79 TEST_F(MultiProcessLockTest, LongNameTest) {
     80   // Every platform has has it's own max path name size,
     81   // so different checks are needed for them.
     82   // POSIX: sizeof(address.sun_path) - 2
     83   // Mac OS X: BOOTSTRAP_MAX_NAME_LEN
     84   // Windows: MAX_PATH
     85   LOG(INFO) << "Following error log due to long name is expected";
     86 #if defined(OS_MACOSX)
     87   std::string name("This is a name that is longer than one hundred and "
     88       "twenty-eight characters to make sure that we fail appropriately on "
     89       "Mac OS X when we have a path that is too long for Mac OS X to handle");
     90 #elif defined(OS_POSIX)
     91   std::string name("This is a name that is longer than one hundred and eight "
     92       "characters to make sure that we fail appropriately on POSIX systems "
     93       "when we have a path that is too long for the system to handle");
     94 #elif defined(OS_WIN)
     95   std::string name("This is a name that is longer than two hundred and sixty "
     96       "characters to make sure that we fail appropriately on Windows when we "
     97       "have a path that is too long for Windows to handle "
     98       "This limitation comes from the MAX_PATH definition which is obviously "
     99       "defined to be a maximum of two hundred and sixty characters ");
    100 #endif
    101   scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
    102   EXPECT_FALSE(test_lock->TryLock());
    103 }
    104 
    105 TEST_F(MultiProcessLockTest, SimpleLock) {
    106   std::string name = GenerateLockName();
    107   scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
    108   EXPECT_TRUE(test_lock->TryLock());
    109   ExpectLockIsLocked(name);
    110   test_lock->Unlock();
    111   ExpectLockIsUnlocked(name);
    112 }
    113 
    114 TEST_F(MultiProcessLockTest, RecursiveLock) {
    115   std::string name = GenerateLockName();
    116   scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
    117   EXPECT_TRUE(test_lock->TryLock());
    118   ExpectLockIsLocked(name);
    119   LOG(INFO) << "Following error log "
    120             << "'MultiProcessLock is already locked' is expected";
    121   EXPECT_TRUE(test_lock->TryLock());
    122   ExpectLockIsLocked(name);
    123   test_lock->Unlock();
    124   ExpectLockIsUnlocked(name);
    125   LOG(INFO) << "Following error log "
    126             << "'Over-unlocked MultiProcessLock' is expected";
    127   test_lock->Unlock();
    128   ExpectLockIsUnlocked(name);
    129   test_lock.reset();
    130 }
    131 
    132 TEST_F(MultiProcessLockTest, LockScope) {
    133   // Check to see that lock is released when it goes out of scope.
    134   std::string name = GenerateLockName();
    135   {
    136     scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
    137     EXPECT_TRUE(test_lock->TryLock());
    138     ExpectLockIsLocked(name);
    139   }
    140   ExpectLockIsUnlocked(name);
    141 }
    142 
    143 MULTIPROCESS_TEST_MAIN(MultiProcessLockTryFailMain) {
    144   std::string name;
    145   scoped_ptr<base::Environment> environment(base::Environment::Create());
    146   EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName,
    147                                   &name));
    148 #if defined(OS_MACOSX)
    149   // OS X sends out a log if a lock fails.
    150   // Hopefully this will keep people from panicking about it when they
    151   // are perusing the build logs.
    152   LOG(INFO) << "Following error log "
    153             << "\"CFMessagePort: bootstrap_register(): failed 1100 (0x44c) "
    154             << "'Permission denied'\" is expected";
    155 #endif  // defined(OS_MACOSX)
    156   scoped_ptr<MultiProcessLock> test_lock(
    157       MultiProcessLock::Create(name));
    158   EXPECT_FALSE(test_lock->TryLock());
    159   return 0;
    160 }
    161 
    162 MULTIPROCESS_TEST_MAIN(MultiProcessLockTrySucceedMain) {
    163   std::string name;
    164   scoped_ptr<base::Environment> environment(base::Environment::Create());
    165   EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName,
    166                                   &name));
    167   scoped_ptr<MultiProcessLock> test_lock(
    168       MultiProcessLock::Create(name));
    169   EXPECT_TRUE(test_lock->TryLock());
    170   return 0;
    171 }
    172