Index: chrome/common/multi_process_lock_unittest.cc |
diff --git a/chrome/common/multi_process_lock_unittest.cc b/chrome/common/multi_process_lock_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ef275abb7824d9304478cb53fadcfe03ebcb873f |
--- /dev/null |
+++ b/chrome/common/multi_process_lock_unittest.cc |
@@ -0,0 +1,205 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/basictypes.h" |
+#include "base/logging.h" |
+#include "base/rand_util.h" |
+#include "base/scoped_ptr.h" |
+#include "base/stringprintf.h" |
+#include "base/test/multiprocess_test.h" |
+#include "base/time.h" |
+#include "chrome/common/multi_process_lock.h" |
+#include "testing/multiprocess_func_list.h" |
+ |
+#if defined(OS_WIN) |
+#include <windows.h> |
+#else // !defined(OS_WIN) |
+#include <stdlib.h> |
+#endif // defined(OS_WIN) |
+ |
+class MultiProcessLockTest : public base::MultiProcessTest { |
+ public: |
+ static const char kLockEnviromentVarName[]; |
+ |
+ // TODO(dmaclach): Move to process_utils. |
+ class ScopedEnvironmentVariable { |
+ public: |
+ ScopedEnvironmentVariable(const std::string &name, |
+ const std::string &value) : name_(name) { |
+ setenv(name_, value); |
+ } |
+ ~ScopedEnvironmentVariable() { |
+ setenv(name_, ""); |
+ } |
+ private: |
+ std::string name_; |
+ DISALLOW_COPY_AND_ASSIGN(ScopedEnvironmentVariable); |
+ }; |
+ |
+ // TODO(dmaclach): Move setenv and getenv to process_utils. |
+ static bool setenv(const std::string &name, const std::string &value); |
+ static bool getenv(const std::string &name, std::string *value); |
+ |
+ std::string GenerateLockName(); |
+ void ExpectLockIsLocked(const std::string &name); |
+ void ExpectLockIsUnlocked(const std::string &name); |
+}; |
+ |
+const char MultiProcessLockTest::kLockEnviromentVarName[] |
+ = "MULTI_PROCESS_TEST_LOCK_NAME"; |
+ |
+bool MultiProcessLockTest::setenv(const std::string &name, |
Mark Mentovai
2010/11/16 18:55:15
Does base/environmenth.h help here?
|
+ const std::string &value) { |
+#if defined(OS_WIN) |
+ return _putenv_s(name.c_str(), value.c_str()) == 0; |
+#else // !defined(OS_WIN) |
+ if (value.length()) { |
+ return ::setenv(name.c_str(), value.c_str(), true) == 0; |
+ } else { |
+ return unsetenv(name.c_str()); |
+ } |
+#endif //defined(OS_WIN) |
+} |
+ |
+bool MultiProcessLockTest::getenv(const std::string &name, std::string *value) { |
+ bool ret = false; |
+#if defined(OS_WIN) |
+ size_t requiredSize = 0; |
+ errno_t err = getenv_s(&requiredSize, NULL, 0, name.c_str()); |
+ if (err == 0 && requiredSize > 0) { |
+ ret = true; |
+ if (value) { |
+ scoped_array<char> c_value(new char[requiredSize]); |
+ err = getenv_s(&requiredSize, c_value.get(), requiredSize, name.c_str()); |
+ if (err == 0) { |
+ *value = c_value.get(); |
+ } else { |
+ ret = false; |
+ *value = ""; |
+ } |
+ } |
+ } |
+#else // !defined(OS_WIN) |
+ const char *c_value = ::getenv(name.c_str()); |
+ if (c_value) { |
+ ret = true; |
+ if (value) { |
+ *value = c_value; |
+ } |
+ } |
+#endif //defined(OS_WIN) |
+ return ret; |
+} |
+ |
+std::string MultiProcessLockTest::GenerateLockName() { |
+ base::Time now = base::Time::NowFromSystemTime(); |
+ return base::StringPrintf("multi_process_test_lock %lf%lf", |
+ now.ToDoubleT(), base::RandDouble()); |
+} |
+ |
+void MultiProcessLockTest::ExpectLockIsLocked(const std::string &name) { |
+ ScopedEnvironmentVariable var(kLockEnviromentVarName, name); |
+ base::ProcessHandle handle = SpawnChild("MultiProcessLockTryFailMain", false); |
+ ASSERT_TRUE(handle); |
+ int exit_code = 0; |
+ EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); |
+ EXPECT_EQ(exit_code, 0); |
+} |
+ |
+void MultiProcessLockTest::ExpectLockIsUnlocked( |
+ const std::string &name) { |
+ ScopedEnvironmentVariable var(kLockEnviromentVarName, name); |
+ base::ProcessHandle handle = SpawnChild("MultiProcessLockTrySucceedMain", |
+ false); |
+ ASSERT_TRUE(handle); |
+ int exit_code = 0; |
+ EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); |
+ EXPECT_EQ(exit_code, 0); |
+} |
+ |
+TEST_F(MultiProcessLockTest, BasicCreationTest) { |
+ // Test basic creation/destruction with no lock taken |
+ std::string name = GenerateLockName(); |
+ scoped_ptr<MultiProcessLock> scoped(MultiProcessLock::Create(name)); |
+ ExpectLockIsUnlocked(name); |
+ scoped.reset(NULL); |
+} |
+ |
+TEST_F(MultiProcessLockTest, LongNameTest) { |
+ // Linux has a max path name of 108 characters. |
+ // http://lxr.linux.no/linux+v2.6.36/include/linux/un.h |
+ // This is enforced on all platforms. |
+ LOG(INFO) << "Following error log due to long name is expected"; |
+ std::string name("This is a name that is longer than one hundred and eight " |
+ "characters to make sure that we fail appropriately on linux when we " |
+ "have a path that is to long for linux to handle"); |
+ scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); |
+ EXPECT_FALSE(test_lock->TryLock()); |
+} |
+ |
+TEST_F(MultiProcessLockTest, SimpleLock) { |
+ std::string name = GenerateLockName(); |
+ scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); |
+ EXPECT_TRUE(test_lock->TryLock()); |
+ ExpectLockIsLocked(name); |
+ test_lock->Unlock(); |
+ ExpectLockIsUnlocked(name); |
+} |
+ |
+TEST_F(MultiProcessLockTest, RecursiveLock) { |
+ std::string name = GenerateLockName(); |
+ scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); |
+ EXPECT_TRUE(test_lock->TryLock()); |
+ ExpectLockIsLocked(name); |
+ LOG(INFO) << "Following error log " |
+ << "'MultiProcessLock is already locked' is expected"; |
+ EXPECT_TRUE(test_lock->TryLock()); |
+ ExpectLockIsLocked(name); |
+ test_lock->Unlock(); |
+ ExpectLockIsUnlocked(name); |
+ LOG(INFO) << "Following error log " |
+ << "'Over-unlocked MultiProcessLock' is expected"; |
+ test_lock->Unlock(); |
+ ExpectLockIsUnlocked(name); |
+ test_lock.reset(); |
+} |
+ |
+TEST_F(MultiProcessLockTest, LockScope) { |
+ // Check to see that lock is released when it goes out of scope. |
+ std::string name = GenerateLockName(); |
+ { |
+ scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); |
+ EXPECT_TRUE(test_lock->TryLock()); |
+ ExpectLockIsLocked(name); |
+ } |
+ ExpectLockIsUnlocked(name); |
+} |
+ |
+MULTIPROCESS_TEST_MAIN(MultiProcessLockTryFailMain) { |
+ std::string name; |
+ EXPECT_TRUE(MultiProcessLockTest::getenv( |
+ MultiProcessLockTest::kLockEnviromentVarName, &name)); |
+#if defined(OS_MACOSX) |
+ // OS X sends out a log if a lock fails. |
+ // Hopefully this will keep people from panicking about it when they |
+ // are perusing thge build logs. |
avi_google.com
2010/11/16 22:07:30
drive-by typo: thge
|
+ LOG(INFO) << "Following error log " |
+ << "\"CFMessagePort: bootstrap_register(): failed 1100 (0x44c) " |
+ << "'Permission denied'\" is expected"; |
+#endif // defined(OS_MACOSX) |
+ scoped_ptr<MultiProcessLock> test_lock( |
+ MultiProcessLock::Create(name)); |
+ EXPECT_FALSE(test_lock->TryLock()); |
+ return 0; |
+} |
+ |
+MULTIPROCESS_TEST_MAIN(MultiProcessLockTrySucceedMain) { |
+ std::string name; |
+ EXPECT_TRUE(MultiProcessLockTest::getenv( |
+ MultiProcessLockTest::kLockEnviromentVarName, &name)); |
+ scoped_ptr<MultiProcessLock> test_lock( |
+ MultiProcessLock::Create(name)); |
+ EXPECT_TRUE(test_lock->TryLock()); |
+ return 0; |
+} |