2 * Copyright 2013 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/Subprocess.h"
21 #include <glog/logging.h>
22 #include <gtest/gtest.h>
24 #include "folly/Format.h"
25 #include "folly/experimental/Gen.h"
26 #include "folly/experimental/FileGen.h"
27 #include "folly/experimental/StringGen.h"
28 #include "folly/experimental/io/FsUtil.h"
30 using namespace folly;
32 TEST(SimpleSubprocessTest, ExitsSuccessfully) {
33 Subprocess proc(std::vector<std::string>{ "/bin/true" });
34 EXPECT_EQ(0, proc.wait().exitStatus());
37 TEST(SimpleSubprocessTest, ExitsSuccessfullyChecked) {
38 Subprocess proc(std::vector<std::string>{ "/bin/true" });
42 TEST(SimpleSubprocessTest, ExitsWithError) {
43 Subprocess proc(std::vector<std::string>{ "/bin/false" });
44 EXPECT_EQ(1, proc.wait().exitStatus());
47 TEST(SimpleSubprocessTest, ExitsWithErrorChecked) {
48 Subprocess proc(std::vector<std::string>{ "/bin/false" });
49 EXPECT_THROW(proc.waitChecked(), CalledProcessError);
52 TEST(SimpleSubprocessTest, ExecFails) {
53 Subprocess proc(std::vector<std::string>{ "/no/such/file" });
54 EXPECT_EQ(127, proc.wait().exitStatus());
57 TEST(SimpleSubprocessTest, ShellExitsSuccesssfully) {
58 Subprocess proc("true");
59 EXPECT_EQ(0, proc.wait().exitStatus());
62 TEST(SimpleSubprocessTest, ShellExitsWithError) {
63 Subprocess proc("false");
64 EXPECT_EQ(1, proc.wait().exitStatus());
67 TEST(ParentDeathSubprocessTest, ParentDeathSignal) {
68 // Find out where we are.
69 static constexpr size_t pathLength = 2048;
70 char buf[pathLength + 1];
71 int r = readlink("/proc/self/exe", buf, pathLength);
76 helper.remove_filename();
77 helper /= "subprocess_test_parent_death_helper";
79 fs::path tempFile(fs::temp_directory_path() / fs::unique_path());
81 std::vector<std::string> args {helper.string(), tempFile.string()};
82 Subprocess proc(args);
83 // The helper gets killed by its child, see details in
84 // SubprocessTestParentDeathHelper.cpp
85 ASSERT_EQ(SIGKILL, proc.wait().killSignal());
87 // Now wait for the file to be created, see details in
88 // SubprocessTestParentDeathHelper.cpp
89 while (!fs::exists(tempFile)) {
90 usleep(20000); // 20ms
96 TEST(PopenSubprocessTest, PopenRead) {
97 Subprocess proc("ls /", Subprocess::pipeStdout());
99 gen::byLine(proc.stdout()) |
100 [&] (StringPiece line) {
101 if (line == "etc" || line == "bin" || line == "usr") {
109 TEST(CommunicateSubprocessTest, SimpleRead) {
110 Subprocess proc(std::vector<std::string>{ "/bin/echo", "-n", "foo", "bar"},
111 Subprocess::pipeStdout());
112 auto p = proc.communicate();
113 EXPECT_EQ("foo bar", p.first);
117 TEST(CommunicateSubprocessTest, BigWrite) {
118 const int numLines = 1 << 20;
119 std::string line("hello\n");
121 data.reserve(numLines * line.size());
122 for (int i = 0; i < numLines; ++i) {
126 Subprocess proc("wc -l", Subprocess::pipeStdin() | Subprocess::pipeStdout());
127 auto p = proc.communicate(Subprocess::writeStdin() | Subprocess::readStdout(),
129 EXPECT_EQ(folly::format("{}\n", numLines).str(), p.first);
133 TEST(CommunicateSubprocessTest, Duplex) {
134 // Take 10MB of data and pass them through a filter.
135 // One line, as tr is line-buffered
136 const int bytes = 10 << 20;
137 std::string line(bytes, 'x');
139 Subprocess proc("tr a-z A-Z",
140 Subprocess::pipeStdin() | Subprocess::pipeStdout());
141 auto p = proc.communicate(Subprocess::writeStdin() | Subprocess::readStdout(),
143 EXPECT_EQ(bytes, p.first.size());
144 EXPECT_EQ(std::string::npos, p.first.find_first_not_of('X'));