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 16class 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 42const char MultiProcessLockTest::kLockEnviromentVarName[] 43 = "MULTI_PROCESS_TEST_LOCK_NAME"; 44 45std::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 51void 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 60void 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 71TEST_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 79TEST_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 91TEST_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 100TEST_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 118TEST_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 129MULTIPROCESS_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 148MULTIPROCESS_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