1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
24a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
34a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// found in the LICENSE file.
44a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
54a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/basictypes.h"
64a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/environment.h"
74a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/logging.h"
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/rand_util.h"
104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/stringprintf.h"
114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/test/multiprocess_test.h"
124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/time.h"
134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/multi_process_lock.h"
144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "testing/multiprocess_func_list.h"
154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass MultiProcessLockTest : public base::MultiProcessTest {
174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch public:
184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  static const char kLockEnviromentVarName[];
194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  class ScopedEnvironmentVariable {
214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch   public:
224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    ScopedEnvironmentVariable(const std::string &name,
234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                              const std::string &value)
244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        : name_(name), environment_(base::Environment::Create()) {
254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      environment_->SetVar(name_.c_str(), value);
264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    ~ScopedEnvironmentVariable() {
284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      environment_->UnSetVar(name_.c_str());
294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch   private:
324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    std::string name_;
334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    scoped_ptr<base::Environment> environment_;
344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    DISALLOW_COPY_AND_ASSIGN(ScopedEnvironmentVariable);
354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  };
364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string GenerateLockName();
384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  void ExpectLockIsLocked(const std::string &name);
394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  void ExpectLockIsUnlocked(const std::string &name);
404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch};
414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char MultiProcessLockTest::kLockEnviromentVarName[]
434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    = "MULTI_PROCESS_TEST_LOCK_NAME";
444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochstd::string MultiProcessLockTest::GenerateLockName() {
464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::Time now = base::Time::NowFromSystemTime();
474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return base::StringPrintf("multi_process_test_lock %lf%lf",
484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                            now.ToDoubleT(), base::RandDouble());
494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid MultiProcessLockTest::ExpectLockIsLocked(const std::string &name) {
524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ScopedEnvironmentVariable var(kLockEnviromentVarName, name);
534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::ProcessHandle handle = SpawnChild("MultiProcessLockTryFailMain", false);
544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ASSERT_TRUE(handle);
554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int exit_code = 0;
564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(exit_code, 0);
584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid MultiProcessLockTest::ExpectLockIsUnlocked(
614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const std::string &name) {
624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ScopedEnvironmentVariable var(kLockEnviromentVarName, name);
634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::ProcessHandle handle = SpawnChild("MultiProcessLockTrySucceedMain",
644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                          false);
654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ASSERT_TRUE(handle);
664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int exit_code = 0;
674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(exit_code, 0);
694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(MultiProcessLockTest, BasicCreationTest) {
724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Test basic creation/destruction with no lock taken
734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name = GenerateLockName();
744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<MultiProcessLock> scoped(MultiProcessLock::Create(name));
754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsUnlocked(name);
764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped.reset(NULL);
774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(MultiProcessLockTest, LongNameTest) {
804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Linux has a max path name of 108 characters.
814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // http://lxr.linux.no/linux+v2.6.36/include/linux/un.h
824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // This is enforced on all platforms.
834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  LOG(INFO) << "Following error log due to long name is expected";
844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name("This is a name that is longer than one hundred and eight "
854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      "characters to make sure that we fail appropriately on linux when we "
864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      "have a path that is to long for linux to handle");
874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_FALSE(test_lock->TryLock());
894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(MultiProcessLockTest, SimpleLock) {
924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name = GenerateLockName();
934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(test_lock->TryLock());
954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsLocked(name);
964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  test_lock->Unlock();
974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsUnlocked(name);
984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(MultiProcessLockTest, RecursiveLock) {
1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name = GenerateLockName();
1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
1034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(test_lock->TryLock());
1044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsLocked(name);
1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  LOG(INFO) << "Following error log "
1064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch            << "'MultiProcessLock is already locked' is expected";
1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(test_lock->TryLock());
1084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsLocked(name);
1094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  test_lock->Unlock();
1104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsUnlocked(name);
1114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  LOG(INFO) << "Following error log "
1124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch            << "'Over-unlocked MultiProcessLock' is expected";
1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  test_lock->Unlock();
1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsUnlocked(name);
1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  test_lock.reset();
1164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(MultiProcessLockTest, LockScope) {
1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Check to see that lock is released when it goes out of scope.
1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name = GenerateLockName();
1214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  {
1224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name));
1234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    EXPECT_TRUE(test_lock->TryLock());
1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    ExpectLockIsLocked(name);
1254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
1264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ExpectLockIsUnlocked(name);
1274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochMULTIPROCESS_TEST_MAIN(MultiProcessLockTryFailMain) {
1304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name;
1314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<base::Environment> environment(base::Environment::Create());
1324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName,
1334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  &name));
1344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(OS_MACOSX)
1354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // OS X sends out a log if a lock fails.
1364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Hopefully this will keep people from panicking about it when they
1374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // are perusing the build logs.
1384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  LOG(INFO) << "Following error log "
1394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch            << "\"CFMessagePort: bootstrap_register(): failed 1100 (0x44c) "
1404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch            << "'Permission denied'\" is expected";
1414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif  // defined(OS_MACOSX)
1424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<MultiProcessLock> test_lock(
1434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      MultiProcessLock::Create(name));
1444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_FALSE(test_lock->TryLock());
1454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return 0;
1464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochMULTIPROCESS_TEST_MAIN(MultiProcessLockTrySucceedMain) {
1494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name;
1504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<base::Environment> environment(base::Environment::Create());
1514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName,
1524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  &name));
1534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<MultiProcessLock> test_lock(
1544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      MultiProcessLock::Create(name));
1554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(test_lock->TryLock());
1564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return 0;
1574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
158