/*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#include "folly/File.h"
+#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/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) {
}
}
+TEST(File, SimpleStringPiece) {
+ char buf = 'x';
+ File f(StringPiece("/etc/hosts"));
+ EXPECT_NE(-1, f.fd());
+ EXPECT_EQ(1, ::read(f.fd(), &buf, 1));
+ f.close();
+ EXPECT_EQ(-1, f.fd());
+}
+
TEST(File, OwnsFd) {
// Wrap a file descriptor, make sure that ownsFd works
// We'll test that the file descriptor is closed by closing the writing
::close(p[0]);
}
+TEST(File, Release) {
+ File in(STDOUT_FILENO, false);
+ CHECK_EQ(STDOUT_FILENO, in.release());
+ CHECK_EQ(-1, in.release());
+}
+
#define EXPECT_CONTAINS(haystack, needle) \
EXPECT_NE(::std::string::npos, ::folly::StringPiece(haystack).find(needle)) \
<< "Haystack: '" << haystack << "'\nNeedle: '" << needle << "'";
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';
+
+ // NOTE(agallagher): Our various internal build systems layout built
+ // binaries differently, so the two layouts below.
+ fs::path me(buf);
+ auto helper_basename = "file_test_lock_helper";
+ fs::path helper;
+ if (fs::exists(me.parent_path() / helper_basename)) {
+ helper = me.parent_path() / helper_basename;
+ } else if (fs::exists(
+ me.parent_path().parent_path() / helper_basename / helper_basename)) {
+ helper = me.parent_path().parent_path()
+ / helper_basename / helper_basename;
+ } else {
+ throw std::runtime_error(
+ folly::to<std::string>("cannot find helper ", helper_basename));
+ }
+
+ 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);
+ }
+}