1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "subprocess.h"
16
17 #include "test.h"
18
19 #ifndef _WIN32
20 // SetWithLots need setrlimit.
21 #include <stdio.h>
22 #include <sys/time.h>
23 #include <sys/resource.h>
24 #include <unistd.h>
25 #endif
26
27 using namespace std;
28
29 namespace {
30
31 #ifdef _WIN32
32 const char* kSimpleCommand = "cmd /c dir \\";
33 #else
34 const char* kSimpleCommand = "ls /";
35 #endif
36
37 struct SubprocessTest : public testing::Test {
38 SubprocessSet subprocs_;
39 };
40
41 } // anonymous namespace
42
43 // Run a command that fails and emits to stderr.
TEST_F(SubprocessTest,BadCommandStderr)44 TEST_F(SubprocessTest, BadCommandStderr) {
45 Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command");
46 ASSERT_NE((Subprocess *) 0, subproc);
47
48 while (!subproc->Done()) {
49 // Pretend we discovered that stderr was ready for writing.
50 subprocs_.DoWork();
51 }
52
53 EXPECT_EQ(ExitFailure, subproc->Finish());
54 EXPECT_NE("", subproc->GetOutput());
55 }
56
57 // Run a command that does not exist
TEST_F(SubprocessTest,NoSuchCommand)58 TEST_F(SubprocessTest, NoSuchCommand) {
59 Subprocess* subproc = subprocs_.Add("ninja_no_such_command");
60 ASSERT_NE((Subprocess *) 0, subproc);
61
62 while (!subproc->Done()) {
63 // Pretend we discovered that stderr was ready for writing.
64 subprocs_.DoWork();
65 }
66
67 EXPECT_EQ(ExitFailure, subproc->Finish());
68 EXPECT_NE("", subproc->GetOutput());
69 #ifdef _WIN32
70 ASSERT_EQ("CreateProcess failed: The system cannot find the file "
71 "specified.\n", subproc->GetOutput());
72 #endif
73 }
74
75 #ifndef _WIN32
76
TEST_F(SubprocessTest,InterruptChild)77 TEST_F(SubprocessTest, InterruptChild) {
78 Subprocess* subproc = subprocs_.Add("kill -INT $$");
79 ASSERT_NE((Subprocess *) 0, subproc);
80
81 while (!subproc->Done()) {
82 subprocs_.DoWork();
83 }
84
85 EXPECT_EQ(ExitInterrupted, subproc->Finish());
86 }
87
TEST_F(SubprocessTest,InterruptParent)88 TEST_F(SubprocessTest, InterruptParent) {
89 Subprocess* subproc = subprocs_.Add("kill -INT $PPID ; sleep 1");
90 ASSERT_NE((Subprocess *) 0, subproc);
91
92 while (!subproc->Done()) {
93 bool interrupted = subprocs_.DoWork();
94 if (interrupted)
95 return;
96 }
97
98 ASSERT_FALSE("We should have been interrupted");
99 }
100
TEST_F(SubprocessTest,InterruptChildWithSigTerm)101 TEST_F(SubprocessTest, InterruptChildWithSigTerm) {
102 Subprocess* subproc = subprocs_.Add("kill -TERM $$");
103 ASSERT_NE((Subprocess *) 0, subproc);
104
105 while (!subproc->Done()) {
106 subprocs_.DoWork();
107 }
108
109 EXPECT_EQ(ExitInterrupted, subproc->Finish());
110 }
111
TEST_F(SubprocessTest,InterruptParentWithSigTerm)112 TEST_F(SubprocessTest, InterruptParentWithSigTerm) {
113 Subprocess* subproc = subprocs_.Add("kill -TERM $PPID ; sleep 1");
114 ASSERT_NE((Subprocess *) 0, subproc);
115
116 while (!subproc->Done()) {
117 bool interrupted = subprocs_.DoWork();
118 if (interrupted)
119 return;
120 }
121
122 ASSERT_FALSE("We should have been interrupted");
123 }
124
TEST_F(SubprocessTest,InterruptChildWithSigHup)125 TEST_F(SubprocessTest, InterruptChildWithSigHup) {
126 Subprocess* subproc = subprocs_.Add("kill -HUP $$");
127 ASSERT_NE((Subprocess *) 0, subproc);
128
129 while (!subproc->Done()) {
130 subprocs_.DoWork();
131 }
132
133 EXPECT_EQ(ExitInterrupted, subproc->Finish());
134 }
135
TEST_F(SubprocessTest,InterruptParentWithSigHup)136 TEST_F(SubprocessTest, InterruptParentWithSigHup) {
137 Subprocess* subproc = subprocs_.Add("kill -HUP $PPID ; sleep 1");
138 ASSERT_NE((Subprocess *) 0, subproc);
139
140 while (!subproc->Done()) {
141 bool interrupted = subprocs_.DoWork();
142 if (interrupted)
143 return;
144 }
145
146 ASSERT_FALSE("We should have been interrupted");
147 }
148
TEST_F(SubprocessTest,Console)149 TEST_F(SubprocessTest, Console) {
150 // Skip test if we don't have the console ourselves.
151 if (isatty(0) && isatty(1) && isatty(2)) {
152 Subprocess* subproc =
153 subprocs_.Add("test -t 0 -a -t 1 -a -t 2", /*use_console=*/true);
154 ASSERT_NE((Subprocess*)0, subproc);
155
156 while (!subproc->Done()) {
157 subprocs_.DoWork();
158 }
159
160 EXPECT_EQ(ExitSuccess, subproc->Finish());
161 }
162 }
163
164 #endif
165
TEST_F(SubprocessTest,SetWithSingle)166 TEST_F(SubprocessTest, SetWithSingle) {
167 Subprocess* subproc = subprocs_.Add(kSimpleCommand);
168 ASSERT_NE((Subprocess *) 0, subproc);
169
170 while (!subproc->Done()) {
171 subprocs_.DoWork();
172 }
173 ASSERT_EQ(ExitSuccess, subproc->Finish());
174 ASSERT_NE("", subproc->GetOutput());
175
176 ASSERT_EQ(1u, subprocs_.finished_.size());
177 }
178
TEST_F(SubprocessTest,SetWithMulti)179 TEST_F(SubprocessTest, SetWithMulti) {
180 Subprocess* processes[3];
181 const char* kCommands[3] = {
182 kSimpleCommand,
183 #ifdef _WIN32
184 "cmd /c echo hi",
185 "cmd /c time /t",
186 #else
187 "id -u",
188 "pwd",
189 #endif
190 };
191
192 for (int i = 0; i < 3; ++i) {
193 processes[i] = subprocs_.Add(kCommands[i]);
194 ASSERT_NE((Subprocess *) 0, processes[i]);
195 }
196
197 ASSERT_EQ(3u, subprocs_.running_.size());
198 for (int i = 0; i < 3; ++i) {
199 ASSERT_FALSE(processes[i]->Done());
200 ASSERT_EQ("", processes[i]->GetOutput());
201 }
202
203 while (!processes[0]->Done() || !processes[1]->Done() ||
204 !processes[2]->Done()) {
205 ASSERT_GT(subprocs_.running_.size(), 0u);
206 subprocs_.DoWork();
207 }
208
209 ASSERT_EQ(0u, subprocs_.running_.size());
210 ASSERT_EQ(3u, subprocs_.finished_.size());
211
212 for (int i = 0; i < 3; ++i) {
213 ASSERT_EQ(ExitSuccess, processes[i]->Finish());
214 ASSERT_NE("", processes[i]->GetOutput());
215 delete processes[i];
216 }
217 }
218
219 #if defined(USE_PPOLL)
TEST_F(SubprocessTest,SetWithLots)220 TEST_F(SubprocessTest, SetWithLots) {
221 // Arbitrary big number; needs to be over 1024 to confirm we're no longer
222 // hostage to pselect.
223 const unsigned kNumProcs = 1025;
224
225 // Make sure [ulimit -n] isn't going to stop us from working.
226 rlimit rlim;
227 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
228 if (rlim.rlim_cur < kNumProcs) {
229 printf("Raise [ulimit -n] above %u (currently %lu) to make this test go\n",
230 kNumProcs, rlim.rlim_cur);
231 return;
232 }
233
234 vector<Subprocess*> procs;
235 for (size_t i = 0; i < kNumProcs; ++i) {
236 Subprocess* subproc = subprocs_.Add("/bin/echo");
237 ASSERT_NE((Subprocess *) 0, subproc);
238 procs.push_back(subproc);
239 }
240 while (!subprocs_.running_.empty())
241 subprocs_.DoWork();
242 for (size_t i = 0; i < procs.size(); ++i) {
243 ASSERT_EQ(ExitSuccess, procs[i]->Finish());
244 ASSERT_NE("", procs[i]->GetOutput());
245 }
246 ASSERT_EQ(kNumProcs, subprocs_.finished_.size());
247 }
248 #endif // !__APPLE__ && !_WIN32
249
250 // TODO: this test could work on Windows, just not sure how to simply
251 // read stdin.
252 #ifndef _WIN32
253 // Verify that a command that attempts to read stdin correctly thinks
254 // that stdin is closed.
TEST_F(SubprocessTest,ReadStdin)255 TEST_F(SubprocessTest, ReadStdin) {
256 Subprocess* subproc = subprocs_.Add("cat -");
257 while (!subproc->Done()) {
258 subprocs_.DoWork();
259 }
260 ASSERT_EQ(ExitSuccess, subproc->Finish());
261 ASSERT_EQ(1u, subprocs_.finished_.size());
262 }
263 #endif // _WIN32
264