Chromium Code Reviews| 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; |
| +} |