d0203cabb7ebc684f1415ea5c03d927abc70a121
[folly.git] / folly / test / SubprocessTest.cpp
1 /*
2  * Copyright 2012 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/Subprocess.h"
18
19 #include <glog/logging.h>
20 #include <gtest/gtest.h>
21
22 #include "folly/Format.h"
23 #include "folly/experimental/io/Stream.h"
24
25 using namespace folly;
26
27 TEST(SimpleSubprocessTest, ExitsSuccessfully) {
28   Subprocess proc(std::vector<std::string>{ "/bin/true" });
29   EXPECT_EQ(0, proc.wait().exitStatus());
30 }
31
32 TEST(SimpleSubprocessTest, ExitsSuccessfullyChecked) {
33   Subprocess proc(std::vector<std::string>{ "/bin/true" });
34   proc.waitChecked();
35 }
36
37 TEST(SimpleSubprocessTest, ExitsWithError) {
38   Subprocess proc(std::vector<std::string>{ "/bin/false" });
39   EXPECT_EQ(1, proc.wait().exitStatus());
40 }
41
42 TEST(SimpleSubprocessTest, ExitsWithErrorChecked) {
43   Subprocess proc(std::vector<std::string>{ "/bin/false" });
44   EXPECT_THROW(proc.waitChecked(), CalledProcessError);
45 }
46
47 TEST(SimpleSubprocessTest, ShellExitsSuccesssfully) {
48   Subprocess proc("true");
49   EXPECT_EQ(0, proc.wait().exitStatus());
50 }
51
52 TEST(SimpleSubprocessTest, ShellExitsWithError) {
53   Subprocess proc("false");
54   EXPECT_EQ(1, proc.wait().exitStatus());
55 }
56
57 TEST(PopenSubprocessTest, PopenRead) {
58   Subprocess proc("ls /", Subprocess::pipeStdout());
59   int found = 0;
60   for (auto bline : byLine(proc.stdout())) {
61     StringPiece line(bline);
62     if (line == "etc" || line == "bin" || line == "usr") {
63       ++found;
64     }
65   }
66   EXPECT_EQ(3, found);
67   proc.waitChecked();
68 }
69
70 TEST(CommunicateSubprocessTest, SimpleRead) {
71   Subprocess proc(std::vector<std::string>{ "/bin/echo", "-n", "foo", "bar"},
72                   Subprocess::pipeStdout());
73   auto p = proc.communicate();
74   EXPECT_EQ("foo bar", p.first);
75   proc.waitChecked();
76 }
77
78 TEST(CommunicateSubprocessTest, BigWrite) {
79   const int numLines = 1 << 20;
80   std::string line("hello\n");
81   std::string data;
82   data.reserve(numLines * line.size());
83   for (int i = 0; i < numLines; ++i) {
84     data.append(line);
85   }
86
87   Subprocess proc("wc -l", Subprocess::pipeStdin() | Subprocess::pipeStdout());
88   auto p = proc.communicate(Subprocess::writeStdin() | Subprocess::readStdout(),
89                             data);
90   EXPECT_EQ(folly::format("{}\n", numLines).str(), p.first);
91   proc.waitChecked();
92 }
93
94 TEST(CommunicateSubprocessTest, Duplex) {
95   // Take 10MB of data and pass them through a filter.
96   // One line, as tr is line-buffered
97   const int bytes = 10 << 20;
98   std::string line(bytes, 'x');
99
100   Subprocess proc("tr a-z A-Z",
101                   Subprocess::pipeStdin() | Subprocess::pipeStdout());
102   auto p = proc.communicate(Subprocess::writeStdin() | Subprocess::readStdout(),
103                             line);
104   EXPECT_EQ(bytes, p.first.size());
105   EXPECT_EQ(std::string::npos, p.first.find_first_not_of('X'));
106   proc.waitChecked();
107 }
108