2 * Copyright 2015 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/File.h>
21 #include <boost/thread/locks.hpp>
22 #include <glog/logging.h>
23 #include <gtest/gtest.h>
25 #include <folly/Benchmark.h>
26 #include <folly/String.h>
27 #include <folly/Subprocess.h>
28 #include <folly/experimental/io/FsUtil.h>
29 #include <folly/experimental/TestUtil.h>
31 using namespace folly;
32 using namespace folly::test;
35 void expectWouldBlock(ssize_t r) {
36 int savedErrno = errno;
38 EXPECT_EQ(EAGAIN, savedErrno) << errnoStr(savedErrno);
40 void expectOK(ssize_t r) {
41 int savedErrno = errno;
42 EXPECT_LE(0, r) << ": errno=" << errnoStr(savedErrno);
47 // Open a file, ensure it's indeed open for reading
51 EXPECT_NE(-1, f.fd());
52 EXPECT_EQ(1, ::read(f.fd(), &buf, 1));
54 EXPECT_EQ(-1, f.fd());
58 TEST(File, SimpleStringPiece) {
60 File f(StringPiece("/etc/hosts"));
61 EXPECT_NE(-1, f.fd());
62 EXPECT_EQ(1, ::read(f.fd(), &buf, 1));
64 EXPECT_EQ(-1, f.fd());
68 // Wrap a file descriptor, make sure that ownsFd works
69 // We'll test that the file descriptor is closed by closing the writing
70 // end of a pipe and making sure that a non-blocking read from the reading
76 int flags = ::fcntl(p[0], F_GETFL);
78 expectOK(::fcntl(p[0], F_SETFL, flags | O_NONBLOCK));
79 expectWouldBlock(::read(p[0], &buf, 1));
82 EXPECT_EQ(p[1], f.fd());
84 // Ensure that moving the file doesn't close it
87 EXPECT_EQ(p[1], f.fd());
88 File f1(std::move(f));
89 EXPECT_EQ(-1, f.fd());
90 EXPECT_EQ(p[1], f1.fd());
92 expectWouldBlock(::read(p[0], &buf, 1)); // not closed
95 EXPECT_EQ(p[1], f.fd());
97 ssize_t r = ::read(p[0], &buf, 1); // eof
103 TEST(File, Release) {
104 File in(STDOUT_FILENO, false);
105 CHECK_EQ(STDOUT_FILENO, in.release());
106 CHECK_EQ(-1, in.release());
109 #define EXPECT_CONTAINS(haystack, needle) \
110 EXPECT_NE(::std::string::npos, ::folly::StringPiece(haystack).find(needle)) \
111 << "Haystack: '" << haystack << "'\nNeedle: '" << needle << "'";
113 TEST(File, UsefulError) {
115 File("does_not_exist.txt", 0, 0666);
116 } catch (const std::runtime_error& e) {
117 EXPECT_CONTAINS(e.what(), "does_not_exist.txt");
118 EXPECT_CONTAINS(e.what(), "0666");
123 File temp = File::temporary();
125 EXPECT_TRUE(bool(temp));
133 if (File file = File::temporary()) {
139 EXPECT_FALSE(bool(File()));
143 if (File notOpened = File()) {
149 typedef std::unique_lock<File> Lock;
150 typedef boost::shared_lock<File> SharedLock;
152 // Find out where we are.
153 static constexpr size_t pathLength = 2048;
154 char buf[pathLength + 1];
155 int r = readlink("/proc/self/exe", buf, pathLength);
159 // NOTE(agallagher): Our various internal build systems layout built
160 // binaries differently, so the two layouts below.
162 auto helper_basename = "file_test_lock_helper";
164 if (fs::exists(me.parent_path() / helper_basename)) {
165 helper = me.parent_path() / helper_basename;
166 } else if (fs::exists(
167 me.parent_path().parent_path() / helper_basename / helper_basename)) {
168 helper = me.parent_path().parent_path()
169 / helper_basename / helper_basename;
171 throw std::runtime_error(
172 folly::to<std::string>("cannot find helper ", helper_basename));
175 TemporaryFile tempFile;
176 File f(tempFile.fd());
178 enum LockMode { EXCLUSIVE, SHARED };
179 auto testLock = [&] (LockMode mode, bool expectedSuccess) {
181 Subprocess({helper.native(),
182 mode == SHARED ? "-s" : "-x",
183 tempFile.path().native()}).wait();
184 EXPECT_TRUE(ret.exited());
186 EXPECT_EQ(expectedSuccess ? 0 : 42, ret.exitStatus());
190 // Make sure nothing breaks and things compile.
200 Lock lock(f, std::defer_lock);
201 EXPECT_TRUE(lock.try_lock());
205 SharedLock lock(f, boost::defer_lock);
206 EXPECT_TRUE(lock.try_lock());
212 testLock(EXCLUSIVE, false);
218 testLock(SHARED, false);
224 testLock(EXCLUSIVE, false);
227 // S does not block S
230 testLock(SHARED, true);