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/rand_util.h"
     10 #include "base/stringprintf.h"
     11 #include "base/test/multiprocess_test.h"
     12 #include "base/time.h"
     13 #include "chrome/common/multi_process_lock.h"
     14 #include "testing/multiprocess_func_list.h"
     15 
     16 class MultiProcessLockTest : public base::MultiProcessTest {
     17  public:
     18   static const char kLockEnviromentVarName[];
     19 
     20   class ScopedEnvironmentVariable {
     21    public:
     22     ScopedEnvironmentVariable(const std::string &name,
     23                               const std::string &value)
     24         : name_(name), environment_(base::Environment::Create()) {
     25       environment_->SetVar(name_.c_str(), value);
     26     }
     27     ~ScopedEnvironmentVariable() {
     28       environment_->UnSetVar(name_.c_str());
     29     }
     30 
     31    private:
     32     std::string name_;
     33     scoped_ptr<base::Environment> environment_;
     34     DISALLOW_COPY_AND_ASSIGN(ScopedEnvironmentVariable);
     35   };
     36 
     37   std::string GenerateLockName();
     38   void ExpectLockIsLocked(const std::string &name);
     39   void ExpectLockIsUnlocked(const std::string &name);
     40 };
     41 
     42 const char MultiProcessLockTest::kLockEnviromentVarName[]
     43     = "MULTI_PROCESS_TEST_LOCK_NAME";
     44 
     45 std::string MultiProcessLockTest::GenerateLockName() {
     46   base::Time now = base::Time::NowFromSystemTime();
     47   return base::StringPrintf("multi_process_test_lock %lf%lf",
     48                             now.ToDoubleT(), base::RandDouble());
     49 }
     50 
     51 void MultiProcessLockTest::ExpectLockIsLocked(const std::string &name) {
     52   ScopedEnvironmentVariable var(kLockEnviromentVarName, name);
     53   base::ProcessHandle handle = SpawnChild("MultiProcessLockTryFailMain", false);
     54   ASSERT_TRUE(handle);
     55   int exit_code = 0;
     56   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
     57   EXPECT_EQ(exit_code, 0);
     58 }
     59 
     60 void MultiProcessLockTest::ExpectLockIsUnlocked(
     61     const std::string &name) {
     62   ScopedEnvironmentVariable var(kLockEnviromentVarName, name);
     63   base::ProcessHandle handle = SpawnChild("MultiProcessLockTrySucceedMain",
     64                                           false);
     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   // Linux has a max path name of 108 characters.
     81   // http://lxr.linux.no/linux+v2.6.36/include/linux/un.h
     82   // This is enforced on all platforms.
     83   LOG(INFO) << "Following error log due to long name is expected";
     84   std::string name("This is a name that is longer than one hundred and eight "
     85       "characters to make sure that we fail appropriately on linux when we "
     86       "have a path that is to long for linux to handle");
     87   scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
     88   EXPECT_FALSE(test_lock->TryLock());
     89 }
     90 
     91 TEST_F(MultiProcessLockTest, SimpleLock) {
     92   std::string name = GenerateLockName();
     93   scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
     94   EXPECT_TRUE(test_lock->TryLock());
     95   ExpectLockIsLocked(name);
     96   test_lock->Unlock();
     97   ExpectLockIsUnlocked(name);
     98 }
     99 
    100 TEST_F(MultiProcessLockTest, RecursiveLock) {
    101   std::string name = GenerateLockName();
    102   scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
    103   EXPECT_TRUE(test_lock->TryLock());
    104   ExpectLockIsLocked(name);
    105   LOG(INFO) << "Following error log "
    106             << "'MultiProcessLock is already locked' is expected";
    107   EXPECT_TRUE(test_lock->TryLock());
    108   ExpectLockIsLocked(name);
    109   test_lock->Unlock();
    110   ExpectLockIsUnlocked(name);
    111   LOG(INFO) << "Following error log "
    112             << "'Over-unlocked MultiProcessLock' is expected";
    113   test_lock->Unlock();
    114   ExpectLockIsUnlocked(name);
    115   test_lock.reset();
    116 }
    117 
    118 TEST_F(MultiProcessLockTest, LockScope) {
    119   // Check to see that lock is released when it goes out of scope.
    120   std::string name = GenerateLockName();
    121   {
    122     scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
    123     EXPECT_TRUE(test_lock->TryLock());
    124     ExpectLockIsLocked(name);
    125   }
    126   ExpectLockIsUnlocked(name);
    127 }
    128 
    129 MULTIPROCESS_TEST_MAIN(MultiProcessLockTryFailMain) {
    130   std::string name;
    131   scoped_ptr<base::Environment> environment(base::Environment::Create());
    132   EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName,
    133                                   &name));
    134 #if defined(OS_MACOSX)
    135   // OS X sends out a log if a lock fails.
    136   // Hopefully this will keep people from panicking about it when they
    137   // are perusing the build logs.
    138   LOG(INFO) << "Following error log "
    139             << "\"CFMessagePort: bootstrap_register(): failed 1100 (0x44c) "
    140             << "'Permission denied'\" is expected";
    141 #endif  // defined(OS_MACOSX)
    142   scoped_ptr<MultiProcessLock> test_lock(
    143       MultiProcessLock::Create(name));
    144   EXPECT_FALSE(test_lock->TryLock());
    145   return 0;
    146 }
    147 
    148 MULTIPROCESS_TEST_MAIN(MultiProcessLockTrySucceedMain) {
    149   std::string name;
    150   scoped_ptr<base::Environment> environment(base::Environment::Create());
    151   EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName,
    152                                   &name));
    153   scoped_ptr<MultiProcessLock> test_lock(
    154       MultiProcessLock::Create(name));
    155   EXPECT_TRUE(test_lock->TryLock());
    156   return 0;
    157 }
    158