proxygen
SubprocessTest.cpp File Reference
#include <folly/Subprocess.h>
#include <sys/types.h>
#include <chrono>
#include <boost/container/flat_set.hpp>
#include <glog/logging.h>
#include <folly/Exception.h>
#include <folly/FileUtil.h>
#include <folly/Format.h>
#include <folly/String.h>
#include <folly/experimental/TestUtil.h>
#include <folly/experimental/io/FsUtil.h>
#include <folly/gen/Base.h>
#include <folly/gen/File.h>
#include <folly/gen/String.h>
#include <folly/portability/GTest.h>
#include <folly/portability/Unistd.h>

Go to the source code of this file.

Classes

struct  WriteFileAfterFork
 

Macros

#define EXPECT_SPAWN_OPT_ERROR(err, errMsg, options, cmd, ...)
 
#define EXPECT_SPAWN_ERROR(err, errMsg, cmd, ...)   EXPECT_SPAWN_OPT_ERROR(err, errMsg, Subprocess::Options(), cmd, ##__VA_ARGS__)
 

Functions

 TEST (SimpleSubprocessTest, ExitsSuccessfully)
 
 TEST (SimpleSubprocessTest, ExitsSuccessfullyChecked)
 
 TEST (SimpleSubprocessTest, CloneFlagsWithVfork)
 
 TEST (SimpleSubprocessTest, CloneFlagsWithFork)
 
 TEST (SimpleSubprocessTest, CloneFlagsSubprocessCtorExitsAfterExec)
 
 TEST (SimpleSubprocessTest, ExitsWithError)
 
 TEST (SimpleSubprocessTest, ExitsWithErrorChecked)
 
 TEST (SimpleSubprocessTest, DefaultConstructibleProcessReturnCode)
 
 TEST (SimpleSubprocessTest, MoveSubprocess)
 
 TEST (SimpleSubprocessTest, DefaultConstructor)
 
 TEST (SimpleSubprocessTest, ExecFails)
 
 TEST (SimpleSubprocessTest, ShellExitsSuccesssfully)
 
 TEST (SimpleSubprocessTest, ShellExitsWithError)
 
 TEST (SimpleSubprocessTest, ChangeChildDirectorySuccessfully)
 
 TEST (SimpleSubprocessTest, ChangeChildDirectoryWithError)
 
 TEST (SimpleSubprocessTest, FdLeakTest)
 
 TEST (SimpleSubprocessTest, Detach)
 
 TEST (SimpleSubprocessTest, DetachExecFails)
 
 TEST (ParentDeathSubprocessTest, ParentDeathSignal)
 
 TEST (PopenSubprocessTest, PopenRead)
 
 TEST (AfterForkCallbackSubprocessTest, TestAfterForkCallbackSuccess)
 
 TEST (AfterForkCallbackSubprocessTest, TestAfterForkCallbackError)
 
 TEST (CommunicateSubprocessTest, SimpleRead)
 
 TEST (CommunicateSubprocessTest, BigWrite)
 
 TEST (CommunicateSubprocessTest, Duplex)
 
 TEST (CommunicateSubprocessTest, ProcessGroupLeader)
 
 TEST (CommunicateSubprocessTest, Duplex2)
 
 TEST (CommunicateSubprocessTest, Chatty)
 
 TEST (CommunicateSubprocessTest, TakeOwnershipOfPipes)
 

Macro Definition Documentation

#define EXPECT_SPAWN_ERROR (   err,
  errMsg,
  cmd,
  ... 
)    EXPECT_SPAWN_OPT_ERROR(err, errMsg, Subprocess::Options(), cmd, ##__VA_ARGS__)

Definition at line 128 of file SubprocessTest.cpp.

Referenced by TEST().

#define EXPECT_SPAWN_OPT_ERROR (   err,
  errMsg,
  options,
  cmd,
  ... 
)
Value:
do { \
try { \
Subprocess proc( \
std::vector<std::string>{(cmd), ##__VA_ARGS__}, (options)); \
ADD_FAILURE() << "expected an error when running " << (cmd); \
} catch (const SubprocessSpawnError& ex) { \
EXPECT_EQ((err), ex.errnoValue()); \
if (StringPiece(ex.what()).find(errMsg) == StringPiece::npos) { \
ADD_FAILURE() << "failed to find \"" << (errMsg) \
<< "\" in exception: \"" << ex.what() << "\""; \
} \
} \
} while (0)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
if(FOLLY_USE_SYMBOLIZER) add_library(folly_exception_tracer_base ExceptionTracer.cpp StackTrace.cpp) apply_folly_compile_options_to_target(folly_exception_tracer_base) target_link_libraries(folly_exception_tracer_base PUBLIC folly) add_library(folly_exception_tracer ExceptionStackTraceLib.cpp ExceptionTracerLib.cpp) apply_folly_compile_options_to_target(folly_exception_tracer) target_link_libraries(folly_exception_tracer PUBLIC folly_exception_tracer_base) add_library(folly_exception_counter ExceptionCounterLib.cpp) apply_folly_compile_options_to_target(folly_exception_counter) target_link_libraries(folly_exception_counter PUBLIC folly_exception_tracer) install(FILES ExceptionAbi.h ExceptionCounterLib.h ExceptionTracer.h ExceptionTracerLib.h StackTrace.h DESTINATION $
Definition: CMakeLists.txt:1
cmd
Definition: gtest-cfgcmd.txt:1
Range< const char * > StringPiece
#define ADD_FAILURE()
Definition: gtest.h:1808

Definition at line 113 of file SubprocessTest.cpp.

Referenced by TEST().

Function Documentation

TEST ( SimpleSubprocessTest  ,
ExitsSuccessfully   
)

Definition at line 42 of file SubprocessTest.cpp.

References EXPECT_EQ.

42  {
43  Subprocess proc(std::vector<std::string>{"/bin/true"});
44  EXPECT_EQ(0, proc.wait().exitStatus());
45 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
TEST ( SimpleSubprocessTest  ,
ExitsSuccessfullyChecked   
)

Definition at line 47 of file SubprocessTest.cpp.

References folly::Subprocess::waitChecked().

47  {
48  Subprocess proc(std::vector<std::string>{"/bin/true"});
49  proc.waitChecked();
50 }
TEST ( SimpleSubprocessTest  ,
CloneFlagsWithVfork   
)

Definition at line 52 of file SubprocessTest.cpp.

References EXPECT_EQ.

52  {
53  Subprocess proc(
54  std::vector<std::string>{"/bin/true"},
55  Subprocess::Options().useCloneWithFlags(SIGCHLD | CLONE_VFORK));
56  EXPECT_EQ(0, proc.wait().exitStatus());
57 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
TEST ( SimpleSubprocessTest  ,
CloneFlagsWithFork   
)

Definition at line 59 of file SubprocessTest.cpp.

References EXPECT_EQ.

59  {
60  Subprocess proc(
61  std::vector<std::string>{"/bin/true"},
62  Subprocess::Options().useCloneWithFlags(SIGCHLD));
63  EXPECT_EQ(0, proc.wait().exitStatus());
64 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
TEST ( SimpleSubprocessTest  ,
CloneFlagsSubprocessCtorExitsAfterExec   
)

Definition at line 66 of file SubprocessTest.cpp.

References folly::checkUnixError(), and EXPECT_TRUE.

66  {
67  Subprocess proc(
68  std::vector<std::string>{"/bin/sleep", "3600"},
69  Subprocess::Options().useCloneWithFlags(SIGCHLD));
70  checkUnixError(::kill(proc.pid(), SIGKILL), "kill");
71  auto retCode = proc.wait();
72  EXPECT_TRUE(retCode.killed());
73 }
void checkUnixError(ssize_t ret, Args &&...args)
Definition: Exception.h:101
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST ( SimpleSubprocessTest  ,
ExitsWithError   
)

Definition at line 75 of file SubprocessTest.cpp.

References EXPECT_EQ.

75  {
76  Subprocess proc(std::vector<std::string>{"/bin/false"});
77  EXPECT_EQ(1, proc.wait().exitStatus());
78 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
TEST ( SimpleSubprocessTest  ,
ExitsWithErrorChecked   
)

Definition at line 80 of file SubprocessTest.cpp.

References EXPECT_THROW.

80  {
81  Subprocess proc(std::vector<std::string>{"/bin/false"});
82  EXPECT_THROW(proc.waitChecked(), CalledProcessError);
83 }
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
TEST ( SimpleSubprocessTest  ,
DefaultConstructibleProcessReturnCode   
)

Definition at line 85 of file SubprocessTest.cpp.

References EXPECT_TRUE, and folly::ProcessReturnCode::notStarted().

85  {
86  ProcessReturnCode retcode;
87  EXPECT_TRUE(retcode.notStarted());
88 }
bool notStarted() const
Definition: Subprocess.h:174
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST ( SimpleSubprocessTest  ,
MoveSubprocess   
)

Definition at line 90 of file SubprocessTest.cpp.

References EXPECT_EQ, EXPECT_TRUE, and folly::gen::move.

90  {
91  Subprocess old_proc(std::vector<std::string>{"/bin/true"});
92  EXPECT_TRUE(old_proc.returnCode().running());
93  auto new_proc = std::move(old_proc);
94  EXPECT_TRUE(old_proc.returnCode().notStarted());
95  EXPECT_TRUE(new_proc.returnCode().running());
96  EXPECT_EQ(0, new_proc.wait().exitStatus());
97  // Now old_proc is destroyed, but we don't crash.
98 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST ( SimpleSubprocessTest  ,
DefaultConstructor   
)

Definition at line 100 of file SubprocessTest.cpp.

References folly::ProcessReturnCode::exitStatus(), EXPECT_EQ, EXPECT_TRUE, folly::gen::move, folly::ProcessReturnCode::notStarted(), folly::Subprocess::returnCode(), folly::ProcessReturnCode::running(), gmock_test_utils::Subprocess, and folly::Subprocess::wait().

100  {
101  Subprocess proc;
103 
104  {
105  auto p1 = Subprocess(std::vector<std::string>{"/bin/true"});
106  proc = std::move(p1);
107  }
108 
109  EXPECT_TRUE(proc.returnCode().running());
110  EXPECT_EQ(0, proc.wait().exitStatus());
111 }
bool notStarted() const
Definition: Subprocess.h:174
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
bool running() const
Definition: Subprocess.h:177
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
ProcessReturnCode returnCode() const
Definition: Subprocess.h:569
ProcessReturnCode wait()
Definition: Subprocess.cpp:644
TEST ( SimpleSubprocessTest  ,
ExecFails   
)

Definition at line 131 of file SubprocessTest.cpp.

References EXPECT_SPAWN_ERROR.

131  {
133  ENOENT, "failed to execute /no/such/file:", "/no/such/file");
134  EXPECT_SPAWN_ERROR(EACCES, "failed to execute /etc/passwd:", "/etc/passwd");
136  ENOTDIR,
137  "failed to execute /etc/passwd/not/a/file:",
138  "/etc/passwd/not/a/file");
139 }
#define EXPECT_SPAWN_ERROR(err, errMsg, cmd,...)
TEST ( SimpleSubprocessTest  ,
ShellExitsSuccesssfully   
)

Definition at line 141 of file SubprocessTest.cpp.

References folly::ProcessReturnCode::exitStatus(), EXPECT_EQ, and folly::Subprocess::wait().

141  {
142  Subprocess proc("true");
143  EXPECT_EQ(0, proc.wait().exitStatus());
144 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
TEST ( SimpleSubprocessTest  ,
ShellExitsWithError   
)

Definition at line 146 of file SubprocessTest.cpp.

References folly::ProcessReturnCode::exitStatus(), EXPECT_EQ, and folly::Subprocess::wait().

146  {
147  Subprocess proc("false");
148  EXPECT_EQ(1, proc.wait().exitStatus());
149 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
TEST ( SimpleSubprocessTest  ,
ChangeChildDirectorySuccessfully   
)

Definition at line 151 of file SubprocessTest.cpp.

References folly::ProcessReturnCode::exitStatus(), EXPECT_EQ, EXPECT_SPAWN_ERROR, and folly::Subprocess::wait().

151  {
152  // The filesystem root normally lacks a 'true' binary
153  EXPECT_EQ(0, chdir("/"));
154  EXPECT_SPAWN_ERROR(ENOENT, "failed to execute ./true", "./true");
155  // The child can fix that by moving to /bin before exec().
156  Subprocess proc("./true", Subprocess::Options().chdir("/bin"));
157  EXPECT_EQ(0, proc.wait().exitStatus());
158 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
#define EXPECT_SPAWN_ERROR(err, errMsg, cmd,...)
TEST ( SimpleSubprocessTest  ,
ChangeChildDirectoryWithError   
)

Definition at line 160 of file SubprocessTest.cpp.

References ADD_FAILURE, folly::Subprocess::Options::chdir(), folly::SubprocessSpawnError::errnoValue(), EXPECT_EQ, and string.

160  {
161  try {
162  Subprocess proc(
163  std::vector<std::string>{"/bin/true"},
164  Subprocess::Options().chdir("/usually/this/is/not/a/valid/directory/"));
165  ADD_FAILURE() << "expected to fail when changing the child's directory";
166  } catch (const SubprocessSpawnError& ex) {
167  EXPECT_EQ(ENOENT, ex.errnoValue());
168  const std::string expectedError =
169  "error preparing to execute /bin/true: No such file or directory";
170  if (StringPiece(ex.what()).find(expectedError) == StringPiece::npos) {
171  ADD_FAILURE() << "failed to find \"" << expectedError
172  << "\" in exception: \"" << ex.what() << "\"";
173  }
174  }
175 }
Options & chdir(const std::string &dir)
Definition: Subprocess.h:384
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
const char * string
Definition: Conv.cpp:212
Range< const char * > StringPiece
#define ADD_FAILURE()
Definition: gtest.h:1808
TEST ( SimpleSubprocessTest  ,
FdLeakTest   
)

Definition at line 206 of file SubprocessTest.cpp.

References ADD_FAILURE, folly::Subprocess::communicate(), folly::SubprocessSpawnError::errnoValue(), folly::ProcessReturnCode::exitStatus(), EXPECT_EQ, EXPECT_SPAWN_ERROR, folly::Subprocess::wait(), and folly::Subprocess::waitChecked().

206  {
207  // Normal execution
208  checkFdLeak([] {
209  Subprocess proc("true");
210  EXPECT_EQ(0, proc.wait().exitStatus());
211  });
212  // Normal execution with pipes
213  checkFdLeak([] {
214  Subprocess proc(
215  "echo foo; echo bar >&2",
216  Subprocess::Options().pipeStdout().pipeStderr());
217  auto p = proc.communicate();
218  EXPECT_EQ("foo\n", p.first);
219  EXPECT_EQ("bar\n", p.second);
220  proc.waitChecked();
221  });
222 
223  // Test where the exec call fails()
224  checkFdLeak(
225  [] { EXPECT_SPAWN_ERROR(ENOENT, "failed to execute", "/no/such/file"); });
226  // Test where the exec call fails() with pipes
227  checkFdLeak([] {
228  try {
229  Subprocess proc(
230  std::vector<std::string>({"/no/such/file"}),
231  Subprocess::Options().pipeStdout().stderrFd(Subprocess::PIPE));
232  ADD_FAILURE() << "expected an error when running /no/such/file";
233  } catch (const SubprocessSpawnError& ex) {
234  EXPECT_EQ(ENOENT, ex.errnoValue());
235  }
236  });
237 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
#define EXPECT_SPAWN_ERROR(err, errMsg, cmd,...)
#define ADD_FAILURE()
Definition: gtest.h:1808
TEST ( SimpleSubprocessTest  ,
Detach   
)

Definition at line 239 of file SubprocessTest.cpp.

References folly::Subprocess::Options::detach(), folly::test::end(), EXPECT_EQ, EXPECT_LE, now(), s, and start.

239  {
241  {
242  Subprocess proc(
243  std::vector<std::string>{"/bin/sleep", "10"},
245  EXPECT_EQ(-1, proc.pid());
246  }
248  // We should be able to create and destroy the Subprocess object quickly,
249  // without waiting for the sleep process to finish. This should usually
250  // happen in a matter of milliseconds, but we allow up to 5 seconds just to
251  // provide lots of leeway on heavily loaded continuous build machines.
252  EXPECT_LE(end - start, 5s);
253 }
#define EXPECT_LE(val1, val2)
Definition: gtest.h:1928
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::chrono::steady_clock::time_point now()
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
auto start
static set< string > s
TEST ( SimpleSubprocessTest  ,
DetachExecFails   
)

Definition at line 255 of file SubprocessTest.cpp.

References EXPECT_SPAWN_OPT_ERROR.

255  {
256  // Errors executing the process should be propagated from the grandchild
257  // process back to the original parent process.
259  ENOENT,
260  "failed to execute /no/such/file:",
261  Subprocess::Options().detach(),
262  "/no/such/file");
263 }
#define EXPECT_SPAWN_OPT_ERROR(err, errMsg, options, cmd,...)
TEST ( ParentDeathSubprocessTest  ,
ParentDeathSignal   
)

Definition at line 265 of file SubprocessTest.cpp.

References ASSERT_EQ, folly::fs::executable_path(), folly::ProcessReturnCode::killSignal(), and folly::Subprocess::wait().

265  {
266  // Find out where we are.
267  const auto basename = "subprocess_test_parent_death_helper";
268  auto helper = fs::executable_path();
269  helper.remove_filename() /= basename;
270  if (!fs::exists(helper)) {
271  helper = helper.parent_path().parent_path() / basename / basename;
272  }
273 
274  fs::path tempFile(fs::temp_directory_path() / fs::unique_path());
275 
276  std::vector<std::string> args{helper.string(), tempFile.string()};
277  Subprocess proc(args);
278  // The helper gets killed by its child, see details in
279  // SubprocessTestParentDeathHelper.cpp
280  ASSERT_EQ(SIGKILL, proc.wait().killSignal());
281 
282  // Now wait for the file to be created, see details in
283  // SubprocessTestParentDeathHelper.cpp
284  while (!fs::exists(tempFile)) {
285  usleep(20000); // 20ms
286  }
287 
288  fs::remove(tempFile);
289 }
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
path executable_path()
Definition: FsUtil.cpp:72
TEST ( PopenSubprocessTest  ,
PopenRead   
)

Definition at line 291 of file SubprocessTest.cpp.

References folly::gen::byLine(), EXPECT_EQ, folly::Subprocess::stdoutFd(), and folly::Subprocess::waitChecked().

291  {
292  Subprocess proc("ls /", Subprocess::Options().pipeStdout());
293  int found = 0;
294  gen::byLine(File(proc.stdoutFd())) | [&](StringPiece line) {
295  if (line == "etc" || line == "bin" || line == "usr") {
296  ++found;
297  }
298  };
299  EXPECT_EQ(3, found);
300  proc.waitChecked();
301 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
auto byLine(File file, char delim= '\n')
Definition: File-inl.h:148
TEST ( AfterForkCallbackSubprocessTest  ,
TestAfterForkCallbackSuccess   
)

Definition at line 320 of file SubprocessTest.cpp.

References folly::Subprocess::Options::dangerousPostForkPreExecCallback(), EXPECT_EQ, EXPECT_TRUE, WriteFileAfterFork::filename_, folly::readFile(), s, and string.

320  {
322  // Trigger a file write from the child.
323  WriteFileAfterFork write_cob("good_file");
324  Subprocess proc(
325  std::vector<std::string>{"/bin/echo"},
327  // The file gets written immediately.
328  std::string s;
329  EXPECT_TRUE(readFile(write_cob.filename_.c_str(), s));
330  EXPECT_EQ("ok", s);
331  proc.waitChecked();
332 }
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
Definition: FileUtil.h:125
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
static set< string > s
Options & dangerousPostForkPreExecCallback(DangerousPostForkPreExecCallback *cob)
Definition: Subprocess.h:457
TEST ( AfterForkCallbackSubprocessTest  ,
TestAfterForkCallbackError   
)

Definition at line 334 of file SubprocessTest.cpp.

References folly::Subprocess::Options::dangerousPostForkPreExecCallback(), EXPECT_FALSE, EXPECT_THROW, and WriteFileAfterFork::filename_.

334  {
336  // The child will try to write to a file, whose directory does not exist.
337  WriteFileAfterFork write_cob("bad/file");
338  EXPECT_THROW(
339  Subprocess proc(
340  std::vector<std::string>{"/bin/echo"},
343  EXPECT_FALSE(fs::exists(write_cob.filename_));
344 }
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
Options & dangerousPostForkPreExecCallback(DangerousPostForkPreExecCallback *cob)
Definition: Subprocess.h:457
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
TEST ( CommunicateSubprocessTest  ,
SimpleRead   
)

Definition at line 346 of file SubprocessTest.cpp.

References folly::Subprocess::communicate(), EXPECT_EQ, and folly::Subprocess::Options::pipeStdout().

346  {
347  Subprocess proc(
348  std::vector<std::string>{"/bin/echo", "-n", "foo", "bar"},
350  auto p = proc.communicate();
351  EXPECT_EQ("foo bar", p.first);
352  proc.waitChecked();
353 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::pair< std::string, std::string > communicate(StringPiece input=StringPiece())
Definition: Subprocess.cpp:740
TEST ( CommunicateSubprocessTest  ,
BigWrite   
)

Definition at line 355 of file SubprocessTest.cpp.

References folly::Subprocess::communicate(), data, EXPECT_EQ, folly::format(), i, string, and folly::Subprocess::waitChecked().

355  {
356  const int numLines = 1 << 20;
357  std::string line("hello\n");
359  data.reserve(numLines * line.size());
360  for (int i = 0; i < numLines; ++i) {
361  data.append(line);
362  }
363 
364  Subprocess proc("wc -l", Subprocess::Options().pipeStdin().pipeStdout());
365  auto p = proc.communicate(data);
366  EXPECT_EQ(folly::format("{}\n", numLines).str(), p.first);
367  proc.waitChecked();
368 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
const char * string
Definition: Conv.cpp:212
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
TEST ( CommunicateSubprocessTest  ,
Duplex   
)

Definition at line 370 of file SubprocessTest.cpp.

References folly::Subprocess::communicate(), EXPECT_EQ, string, and folly::Subprocess::waitChecked().

370  {
371  // Take 10MB of data and pass them through a filter.
372  // One line, as tr is line-buffered
373  const int bytes = 10 << 20;
374  std::string line(bytes, 'x');
375 
376  Subprocess proc("tr a-z A-Z", Subprocess::Options().pipeStdin().pipeStdout());
377  auto p = proc.communicate(line);
378  EXPECT_EQ(bytes, p.first.size());
379  EXPECT_EQ(std::string::npos, p.first.find_first_not_of('X'));
380  proc.waitChecked();
381 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
const char * string
Definition: Conv.cpp:212
TEST ( CommunicateSubprocessTest  ,
ProcessGroupLeader   
)

Definition at line 383 of file SubprocessTest.cpp.

References EXPECT_THROW, and folly::Subprocess::waitChecked().

383  {
384  const auto testIsLeader = "test $(cut -d ' ' -f 5 /proc/$$/stat) = $$";
385  Subprocess nonLeader(testIsLeader);
386  EXPECT_THROW(nonLeader.waitChecked(), CalledProcessError);
387  Subprocess leader(testIsLeader, Subprocess::Options().processGroupLeader());
388  leader.waitChecked();
389 }
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
TEST ( CommunicateSubprocessTest  ,
Duplex2   
)

Definition at line 391 of file SubprocessTest.cpp.

References folly::IOBufQueue::append(), cmd, folly::Subprocess::communicateIOBuf(), fizz::test::copyBuffer(), upload::dest, EXPECT_EQ, folly::gen::move, folly::Subprocess::Options::pipeStderr(), folly::Subprocess::Options::pipeStdin(), folly::Subprocess::Options::pipeStdout(), fizz::detail::read(), folly::gen::split(), string, folly::Subprocess::Options::usePath(), and folly::Subprocess::waitChecked().

391  {
392  checkFdLeak([] {
393  // Pipe 200,000 lines through sed
394  const size_t numCopies = 100000;
395  auto iobuf = IOBuf::copyBuffer("this is a test\nanother line\n");
396  IOBufQueue input;
397  for (size_t n = 0; n < numCopies; ++n) {
398  input.append(iobuf->clone());
399  }
400 
401  std::vector<std::string> cmd({
402  "sed",
403  "-u",
404  "-e",
405  "s/a test/a successful test/",
406  "-e",
407  "/^another line/w/dev/stderr",
408  });
409  auto options =
411  Subprocess proc(cmd, options);
412  auto out = proc.communicateIOBuf(std::move(input));
413  proc.waitChecked();
414 
415  // Convert stdout and stderr to strings so we can call split() on them.
416  fbstring stdoutStr;
417  if (out.first.front()) {
418  stdoutStr = out.first.move()->moveToFbString();
419  }
420  fbstring stderrStr;
421  if (out.second.front()) {
422  stderrStr = out.second.move()->moveToFbString();
423  }
424 
425  // stdout should be a copy of stdin, with "a test" replaced by
426  // "a successful test"
427  std::vector<StringPiece> stdoutLines;
428  split('\n', stdoutStr, stdoutLines);
429  EXPECT_EQ(numCopies * 2 + 1, stdoutLines.size());
430  // Strip off the trailing empty line
431  if (!stdoutLines.empty()) {
432  EXPECT_EQ("", stdoutLines.back());
433  stdoutLines.pop_back();
434  }
435  size_t linenum = 0;
436  for (const auto& line : stdoutLines) {
437  if ((linenum & 1) == 0) {
438  EXPECT_EQ("this is a successful test", line);
439  } else {
440  EXPECT_EQ("another line", line);
441  }
442  ++linenum;
443  }
444 
445  // stderr should only contain the lines containing "another line"
446  std::vector<StringPiece> stderrLines;
447  split('\n', stderrStr, stderrLines);
448  EXPECT_EQ(numCopies + 1, stderrLines.size());
449  // Strip off the trailing empty line
450  if (!stderrLines.empty()) {
451  EXPECT_EQ("", stderrLines.back());
452  stderrLines.pop_back();
453  }
454  for (const auto& line : stderrLines) {
455  EXPECT_EQ("another line", line);
456  }
457  });
458 }
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
S split(const StringPiece source, char delimiter)
Definition: String.h:61
std::unique_ptr< IOBuf > copyBuffer(const folly::IOBuf &buf)
cmd
Definition: gtest-cfgcmd.txt:1
TEST ( CommunicateSubprocessTest  ,
Chatty   
)

Definition at line 491 of file SubprocessTest.cpp.

References cmd, folly::Subprocess::communicate(), folly::Subprocess::enableNotifications(), folly::ProcessReturnCode::exitStatus(), EXPECT_EQ, EXPECT_FALSE, EXPECT_TRUE, folly::Subprocess::Options::pipeStderr(), folly::Subprocess::Options::pipeStdin(), folly::Subprocess::Options::pipeStdout(), string, folly::Subprocess::Options::usePath(), folly::Subprocess::wait(), and folly::writeFull().

491  {
492  checkFdLeak([] {
493  const int lineCount = 1000;
494 
495  int wcount = 0;
496  int rcount = 0;
497 
498  auto options =
500  std::vector<std::string> cmd{
501  "sed",
502  "-u",
503  "-e",
504  "s/a test/a successful test/",
505  };
506 
507  Subprocess proc(cmd, options);
508 
509  auto writeCallback = [&](int pfd, int cfd) -> bool {
510  EXPECT_EQ(0, cfd); // child stdin
511  EXPECT_EQ(rcount, wcount); // chatty, one read for every write
512 
513  auto msg = folly::to<std::string>("a test ", wcount, "\n");
514 
515  // Not entirely kosher, we should handle partial writes, but this is
516  // fine for writes <= PIPE_BUF
517  EXPECT_EQ(msg.size(), writeFull(pfd, msg.data(), msg.size()));
518 
519  ++wcount;
520  proc.enableNotifications(0, false);
521 
522  return (wcount == lineCount);
523  };
524 
525  bool eofSeen = false;
526 
527  auto readCallback = [&](int pfd, int cfd) -> bool {
528  std::string lineBuf;
529 
530  if (cfd != 1) {
531  EXPECT_EQ(2, cfd);
532  EXPECT_TRUE(readToString(pfd, lineBuf, 1));
533  EXPECT_EQ(0, lineBuf.size());
534  return true;
535  }
536 
537  EXPECT_FALSE(eofSeen);
538 
539  std::string expected;
540 
541  if (rcount < lineCount) {
542  expected = folly::to<std::string>("a successful test ", rcount++, "\n");
543  }
544 
545  EXPECT_EQ(wcount, rcount);
546 
547  // Not entirely kosher, we should handle partial reads, but this is
548  // fine for reads <= PIPE_BUF
549  bool atEof = readToString(pfd, lineBuf, expected.size() + 1);
550  if (atEof) {
551  // EOF only expected after we finished reading
552  EXPECT_EQ(lineCount, rcount);
553  eofSeen = true;
554  }
555 
556  EXPECT_EQ(expected, lineBuf);
557 
558  if (wcount != lineCount) { // still more to write...
559  proc.enableNotifications(0, true);
560  }
561 
562  return eofSeen;
563  };
564 
565  proc.communicate(readCallback, writeCallback);
566 
567  EXPECT_EQ(lineCount, wcount);
568  EXPECT_EQ(lineCount, rcount);
569  EXPECT_TRUE(eofSeen);
570 
571  EXPECT_EQ(0, proc.wait().exitStatus());
572  });
573 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
ssize_t writeFull(int fd, const void *buf, size_t count)
Definition: FileUtil.cpp:134
cmd
Definition: gtest-cfgcmd.txt:1
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
TEST ( CommunicateSubprocessTest  ,
TakeOwnershipOfPipes   
)

Definition at line 575 of file SubprocessTest.cpp.

References EXPECT_EQ, pipe(), folly::readFull(), string, folly::Subprocess::takeOwnershipOfPipes(), and folly::Subprocess::waitChecked().

575  {
576  std::vector<Subprocess::ChildPipe> pipes;
577  {
578  Subprocess proc(
579  "echo $'oh\\nmy\\ncat' | wc -l &", Subprocess::Options().pipeStdout());
580  pipes = proc.takeOwnershipOfPipes();
581  proc.waitChecked();
582  }
583  EXPECT_EQ(1, pipes.size());
584  EXPECT_EQ(1, pipes[0].childFd);
585 
586  char buf[10];
587  EXPECT_EQ(2, readFull(pipes[0].pipe.fd(), buf, 10));
588  buf[2] = 0;
589  EXPECT_EQ("3\n", std::string(buf));
590 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
ssize_t readFull(int fd, void *buf, size_t count)
Definition: FileUtil.cpp:126
const char * string
Definition: Conv.cpp:212
void pipe(CPUExecutor cpu, IOExecutor io)