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, ShellExitsSuccesssfully) {
53 Subprocess proc("true");
54 EXPECT_EQ(0, proc.wait().exitStatus());
57 TEST(SimpleSubprocessTest, ShellExitsWithError) {
58 Subprocess proc("false");
59 EXPECT_EQ(1, proc.wait().exitStatus());
62 TEST(ParentDeathSubprocessTest, ParentDeathSignal) {
63 // Find out where we are.
64 static constexpr size_t pathLength = 2048;
66 int r = readlink("/proc/self/exe", buf, pathLength);
71 helper.remove_filename();
72 helper /= "subprocess_test_parent_death_helper";
74 fs::path tempFile(fs::temp_directory_path() / fs::unique_path());
76 std::vector<std::string> args {helper.string(), tempFile.string()};
77 Subprocess proc(args);
78 // The helper gets killed by its child, see details in
79 // SubprocessTestParentDeathHelper.cpp
80 ASSERT_EQ(SIGKILL, proc.wait().killSignal());
82 // Now wait for the file to be created, see details in
83 // SubprocessTestParentDeathHelper.cpp
84 while (!fs::exists(tempFile)) {
85 usleep(20000); // 20ms
91 TEST(PopenSubprocessTest, PopenRead) {
92 Subprocess proc("ls /", Subprocess::pipeStdout());
94 gen::byLine(proc.stdout()) |
95 [&] (StringPiece line) {
96 if (line == "etc" || line == "bin" || line == "usr") {
104 TEST(CommunicateSubprocessTest, SimpleRead) {
105 Subprocess proc(std::vector<std::string>{ "/bin/echo", "-n", "foo", "bar"},
106 Subprocess::pipeStdout());
107 auto p = proc.communicate();
108 EXPECT_EQ("foo bar", p.first);
112 TEST(CommunicateSubprocessTest, BigWrite) {
113 const int numLines = 1 << 20;
114 std::string line("hello\n");
116 data.reserve(numLines * line.size());
117 for (int i = 0; i < numLines; ++i) {
121 Subprocess proc("wc -l", Subprocess::pipeStdin() | Subprocess::pipeStdout());
122 auto p = proc.communicate(Subprocess::writeStdin() | Subprocess::readStdout(),
124 EXPECT_EQ(folly::format("{}\n", numLines).str(), p.first);
128 TEST(CommunicateSubprocessTest, Duplex) {
129 // Take 10MB of data and pass them through a filter.
130 // One line, as tr is line-buffered
131 const int bytes = 10 << 20;
132 std::string line(bytes, 'x');
134 Subprocess proc("tr a-z A-Z",
135 Subprocess::pipeStdin() | Subprocess::pipeStdout());
136 auto p = proc.communicate(Subprocess::writeStdin() | Subprocess::readStdout(),
138 EXPECT_EQ(bytes, p.first.size());
139 EXPECT_EQ(std::string::npos, p.first.find_first_not_of('X'));