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