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