Split FileTest to a smaller test and an extended test
[folly.git] / folly / test / FileLockTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/File.h>
18
19 #include <boost/thread/locks.hpp>
20
21 #include <folly/String.h>
22 #include <folly/Subprocess.h>
23 #include <folly/experimental/io/FsUtil.h>
24 #include <folly/experimental/TestUtil.h>
25
26 #include <gflags/gflags.h>
27 #include <glog/logging.h>
28 #include <gtest/gtest.h>
29
30 #include <mutex>
31
32 using namespace folly;
33 using namespace folly::test;
34
35 DEFINE_bool(s, false, "get shared lock");
36 DEFINE_bool(x, false, "get exclusive lock");
37
38 TEST(File, Locks) {
39   typedef std::unique_lock<File> Lock;
40   typedef boost::shared_lock<File> SharedLock;
41
42   // Find out where we are.
43   static constexpr size_t pathLength = 2048;
44   char buf[pathLength + 1];
45   int r = readlink("/proc/self/exe", buf, pathLength);
46   CHECK_ERR(r);
47   buf[r] = '\0';
48
49   fs::path me(buf);
50   auto helper_basename = "file_test_lock_helper";
51   fs::path helper;
52   if (fs::exists(me.parent_path() / helper_basename)) {
53     helper = me.parent_path() / helper_basename;
54   } else {
55     throw std::runtime_error(
56         folly::to<std::string>("cannot find helper ", helper_basename));
57   }
58
59   TemporaryFile tempFile;
60   File f(tempFile.fd());
61
62   enum LockMode { EXCLUSIVE, SHARED };
63   auto testLock = [&](LockMode mode, bool expectedSuccess) {
64     auto ret = Subprocess({helper.native(),
65                            mode == SHARED ? "-s" : "-x",
66                            tempFile.path().native()}).wait();
67     EXPECT_TRUE(ret.exited());
68     if (ret.exited()) {
69       EXPECT_EQ(expectedSuccess ? 0 : 42, ret.exitStatus());
70     }
71   };
72
73   // Make sure nothing breaks and things compile.
74   { Lock lock(f); }
75
76   { SharedLock lock(f); }
77
78   {
79     Lock lock(f, std::defer_lock);
80     EXPECT_TRUE(lock.try_lock());
81   }
82
83   {
84     SharedLock lock(f, boost::defer_lock);
85     EXPECT_TRUE(lock.try_lock());
86   }
87
88   // X blocks X
89   {
90     Lock lock(f);
91     testLock(EXCLUSIVE, false);
92   }
93
94   // X blocks S
95   {
96     Lock lock(f);
97     testLock(SHARED, false);
98   }
99
100   // S blocks X
101   {
102     SharedLock lock(f);
103     testLock(EXCLUSIVE, false);
104   }
105
106   // S does not block S
107   {
108     SharedLock lock(f);
109     testLock(SHARED, true);
110   }
111 }