Ninja
subprocess_test.cc
Go to the documentation of this file.
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.
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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)
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.
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
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
Definition: subprocess.h:82
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
Subprocess wraps a single async subprocess.
Definition: subprocess.h:42
#define EXPECT_EQ(a, b)
Definition: test.h:64
#define ASSERT_GT(a, b)
Definition: test.h:85
#define ASSERT_FALSE(a)
Definition: test.h:95
TEST_F(SubprocessTest, BadCommandStderr)
#define ASSERT_EQ(a, b)
Definition: test.h:81
#define ASSERT_NE(a, b)
Definition: test.h:83
const std::string & GetOutput() const
bool Done() const
#define EXPECT_NE(a, b)
Definition: test.h:66