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