1 | /* |
2 | * Copyright 2012-present 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/experimental/TestUtil.h> |
18 | |
19 | #include <system_error> |
20 | |
21 | #include <boost/algorithm/string.hpp> |
22 | #include <glog/logging.h> |
23 | |
24 | #include <folly/Memory.h> |
25 | #include <folly/portability/Fcntl.h> |
26 | #include <folly/portability/GTest.h> |
27 | #include <folly/portability/Stdlib.h> |
28 | |
29 | using namespace folly; |
30 | using namespace folly::test; |
31 | |
32 | TEST(TemporaryFile, Simple) { |
33 | int fd = -1; |
34 | char c = 'x'; |
35 | { |
36 | TemporaryFile f; |
37 | EXPECT_FALSE(f.path().empty()); |
38 | EXPECT_TRUE(f.path().is_absolute()); |
39 | fd = f.fd(); |
40 | EXPECT_LE(0, fd); |
41 | ssize_t r = write(fd, &c, 1); |
42 | EXPECT_EQ(1, r); |
43 | } |
44 | |
45 | msvcSuppressAbortOnInvalidParams([&] { |
46 | // The file must have been closed. This assumes that no other thread |
47 | // has opened another file in the meanwhile, which is a sane assumption |
48 | // to make in this test. |
49 | ssize_t r = write(fd, &c, 1); |
50 | int savedErrno = errno; |
51 | EXPECT_EQ(-1, r); |
52 | EXPECT_EQ(EBADF, savedErrno); |
53 | }); |
54 | } |
55 | |
56 | TEST(TemporaryFile, EarlyClose) { |
57 | fs::path p; |
58 | { |
59 | TemporaryFile f; |
60 | p = f.path(); |
61 | EXPECT_TRUE(fs::exists(p)); |
62 | f.close(); |
63 | EXPECT_EQ(-1, f.fd()); |
64 | EXPECT_TRUE(fs::exists(p)); |
65 | } |
66 | EXPECT_FALSE(fs::exists(p)); |
67 | } |
68 | |
69 | TEST(TemporaryFile, Prefix) { |
70 | TemporaryFile f("Foo" ); |
71 | EXPECT_TRUE(f.path().is_absolute()); |
72 | EXPECT_TRUE( |
73 | boost::algorithm::starts_with(f.path().filename().native(), "Foo" )); |
74 | } |
75 | |
76 | TEST(TemporaryFile, PathPrefix) { |
77 | TemporaryFile f("Foo" , "." ); |
78 | EXPECT_EQ(fs::path("." ), f.path().parent_path()); |
79 | EXPECT_TRUE( |
80 | boost::algorithm::starts_with(f.path().filename().native(), "Foo" )); |
81 | } |
82 | |
83 | TEST(TemporaryFile, NoSuchPath) { |
84 | EXPECT_THROW({ TemporaryFile f("" , "/no/such/path" ); }, std::system_error); |
85 | } |
86 | |
87 | TEST(TemporaryFile, moveAssignment) { |
88 | TemporaryFile f; |
89 | int fd; |
90 | |
91 | EXPECT_TRUE(f.path().is_absolute()); |
92 | { |
93 | TemporaryFile g("Foo" , "." ); |
94 | EXPECT_NE(g.fd(), -1); |
95 | fd = g.fd(); |
96 | f = std::move(g); |
97 | } |
98 | EXPECT_EQ(fs::path("." ), f.path().parent_path()); |
99 | EXPECT_EQ(f.fd(), fd); |
100 | |
101 | TemporaryFile h = TemporaryFile("FooBar" , "." ); |
102 | EXPECT_NE(h.fd(), -1); |
103 | } |
104 | |
105 | TEST(TemporaryFile, moveCtor) { |
106 | struct FooBar { |
107 | TemporaryFile f_; |
108 | explicit FooBar(TemporaryFile&& f) : f_(std::move(f)) {} |
109 | }; |
110 | TemporaryFile g("Foo" ); |
111 | FooBar fb(std::move(g)); |
112 | EXPECT_EQ(g.fd(), -1); |
113 | EXPECT_NE(fb.f_.fd(), -1); |
114 | } |
115 | |
116 | void testTemporaryDirectory(TemporaryDirectory::Scope scope) { |
117 | fs::path path; |
118 | { |
119 | TemporaryDirectory d("" , "" , scope); |
120 | path = d.path(); |
121 | EXPECT_FALSE(path.empty()); |
122 | EXPECT_TRUE(path.is_absolute()); |
123 | EXPECT_TRUE(fs::exists(path)); |
124 | EXPECT_TRUE(fs::is_directory(path)); |
125 | |
126 | fs::path fp = path / "bar" ; |
127 | int fd = open(fp.string().c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666); |
128 | EXPECT_NE(fd, -1); |
129 | close(fd); |
130 | |
131 | TemporaryFile f("Foo" , d.path()); |
132 | EXPECT_EQ(d.path(), f.path().parent_path()); |
133 | } |
134 | bool exists = (scope == TemporaryDirectory::Scope::PERMANENT); |
135 | EXPECT_EQ(exists, fs::exists(path)); |
136 | } |
137 | |
138 | TEST(TemporaryDirectory, Permanent) { |
139 | testTemporaryDirectory(TemporaryDirectory::Scope::PERMANENT); |
140 | } |
141 | |
142 | TEST(TemporaryDirectory, DeleteOnDestruction) { |
143 | testTemporaryDirectory(TemporaryDirectory::Scope::DELETE_ON_DESTRUCTION); |
144 | } |
145 | |
146 | void expectTempdirExists(const TemporaryDirectory& d) { |
147 | EXPECT_FALSE(d.path().empty()); |
148 | EXPECT_TRUE(fs::exists(d.path())); |
149 | EXPECT_TRUE(fs::is_directory(d.path())); |
150 | } |
151 | |
152 | TEST(TemporaryDirectory, SafelyMove) { |
153 | std::unique_ptr<TemporaryDirectory> dir; |
154 | TemporaryDirectory dir2; |
155 | { |
156 | auto scope = TemporaryDirectory::Scope::DELETE_ON_DESTRUCTION; |
157 | TemporaryDirectory d("" , "" , scope); |
158 | TemporaryDirectory d2("" , "" , scope); |
159 | expectTempdirExists(d); |
160 | expectTempdirExists(d2); |
161 | |
162 | dir = std::make_unique<TemporaryDirectory>(std::move(d)); |
163 | dir2 = std::move(d2); |
164 | } |
165 | |
166 | expectTempdirExists(*dir); |
167 | expectTempdirExists(dir2); |
168 | } |
169 | |
170 | TEST(ChangeToTempDir, ChangeDir) { |
171 | auto pwd1 = fs::current_path(); |
172 | { |
173 | ChangeToTempDir d; |
174 | EXPECT_NE(pwd1, fs::current_path()); |
175 | } |
176 | EXPECT_EQ(pwd1, fs::current_path()); |
177 | } |
178 | |
179 | TEST(PCREPatternMatch, Simple) { |
180 | EXPECT_PCRE_MATCH(".*a.c.*" , "gabca" ); |
181 | EXPECT_NO_PCRE_MATCH("a.c" , "gabca" ); |
182 | EXPECT_NO_PCRE_MATCH(".*ac.*" , "gabca" ); |
183 | } |
184 | |
185 | TEST(CaptureFD, GlogPatterns) { |
186 | CaptureFD err(fileno(stderr)); |
187 | LOG(INFO) << "All is well" ; |
188 | EXPECT_NO_PCRE_MATCH(glogErrOrWarnPattern(), err.readIncremental()); |
189 | { |
190 | LOG(ERROR) << "Uh-oh" ; |
191 | auto s = err.readIncremental(); |
192 | EXPECT_PCRE_MATCH(glogErrorPattern(), s); |
193 | EXPECT_NO_PCRE_MATCH(glogWarningPattern(), s); |
194 | EXPECT_PCRE_MATCH(glogErrOrWarnPattern(), s); |
195 | } |
196 | { |
197 | LOG(WARNING) << "Oops" ; |
198 | auto s = err.readIncremental(); |
199 | EXPECT_NO_PCRE_MATCH(glogErrorPattern(), s); |
200 | EXPECT_PCRE_MATCH(glogWarningPattern(), s); |
201 | EXPECT_PCRE_MATCH(glogErrOrWarnPattern(), s); |
202 | } |
203 | } |
204 | |
205 | TEST(CaptureFD, ChunkCob) { |
206 | std::vector<std::string> chunks; |
207 | { |
208 | CaptureFD err(fileno(stderr), [&](StringPiece p) { |
209 | chunks.emplace_back(p.str()); |
210 | switch (chunks.size()) { |
211 | case 1: |
212 | EXPECT_PCRE_MATCH(".*foo.*bar.*" , p); |
213 | break; |
214 | case 2: |
215 | EXPECT_PCRE_MATCH("[^\n]*baz.*" , p); |
216 | break; |
217 | default: |
218 | FAIL() << "Got too many chunks: " << chunks.size(); |
219 | } |
220 | }); |
221 | LOG(INFO) << "foo" ; |
222 | LOG(INFO) << "bar" ; |
223 | EXPECT_PCRE_MATCH(".*foo.*bar.*" , err.read()); |
224 | auto chunk = err.readIncremental(); |
225 | EXPECT_EQ(chunks.at(0), chunk); |
226 | LOG(INFO) << "baz" ; |
227 | EXPECT_PCRE_MATCH(".*foo.*bar.*baz.*" , err.read()); |
228 | } |
229 | EXPECT_EQ(2, chunks.size()); |
230 | } |
231 | |