flock locks in folly::File, FileUtil, Exception.h fixes and tests
[folly.git] / folly / test / FileTest.cpp
index 4f47f0fec2b2e6328e9d29941acdb657165b8258..3b5acaaa8008f2f4a880e40fb1495f2a8aaf9b7e 100644 (file)
 
 #include "folly/File.h"
 
+#include <mutex>
+
+#include <boost/thread/locks.hpp>
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
 #include "folly/Benchmark.h"
 #include "folly/String.h"
+#include "folly/Subprocess.h"
+#include "folly/experimental/io/FsUtil.h"
+#include "folly/experimental/TestUtil.h"
 
 using namespace folly;
+using namespace folly::test;
 
 namespace {
 void expectWouldBlock(ssize_t r) {
@@ -122,3 +129,78 @@ TEST(File, Truthy) {
     EXPECT_TRUE(false);
   }
 }
+
+TEST(File, Locks) {
+  typedef std::unique_lock<File> Lock;
+  typedef boost::shared_lock<File> SharedLock;
+
+  // Find out where we are.
+  static constexpr size_t pathLength = 2048;
+  char buf[pathLength + 1];
+  int r = readlink("/proc/self/exe", buf, pathLength);
+  CHECK_ERR(r);
+  buf[r] = '\0';
+
+  fs::path helper(buf);
+  helper.remove_filename();
+  helper /= "file_test_lock_helper";
+
+  TemporaryFile tempFile;
+  File f(tempFile.fd());
+
+  enum LockMode { EXCLUSIVE, SHARED };
+  auto testLock = [&] (LockMode mode, bool expectedSuccess) {
+    auto ret =
+      Subprocess({helper.native(),
+                  mode == SHARED ? "-s" : "-x",
+                  tempFile.path().native()}).wait();
+    EXPECT_TRUE(ret.exited());
+    if (ret.exited()) {
+      EXPECT_EQ(expectedSuccess ? 0 : 42, ret.exitStatus());
+    }
+  };
+
+  // Make sure nothing breaks and things compile.
+  {
+    Lock lock(f);
+  }
+
+  {
+    SharedLock lock(f);
+  }
+
+  {
+    Lock lock(f, std::defer_lock);
+    EXPECT_TRUE(lock.try_lock());
+  }
+
+  {
+    SharedLock lock(f, boost::defer_lock);
+    EXPECT_TRUE(lock.try_lock());
+  }
+
+  // X blocks X
+  {
+    Lock lock(f);
+    testLock(EXCLUSIVE, false);
+  }
+
+  // X blocks S
+  {
+    Lock lock(f);
+    testLock(SHARED, false);
+  }
+
+  // S blocks X
+  {
+    SharedLock lock(f);
+    testLock(EXCLUSIVE, false);
+  }
+
+  // S does not block S
+  {
+    SharedLock lock(f);
+    testLock(SHARED, true);
+  }
+}
+