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 namespace {
28 
29 #ifdef _WIN32
30 const char* kSimpleCommand = "cmd /c dir \\";
31 #else
32 const char* kSimpleCommand = "ls /";
33 #endif
34 
35 struct SubprocessTest : public testing::Test {
36  SubprocessSet subprocs_;
37 };
38 
39 } // anonymous namespace
40 
41 // Run a command that fails and emits to stderr.
42 TEST_F(SubprocessTest, BadCommandStderr) {
43  Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command");
44  ASSERT_NE((Subprocess *) 0, subproc);
45 
46  while (!subproc->Done()) {
47  // Pretend we discovered that stderr was ready for writing.
48  subprocs_.DoWork();
49  }
50 
51  EXPECT_EQ(ExitFailure, subproc->Finish());
52  EXPECT_NE("", subproc->GetOutput());
53 }
54 
55 // Run a command that does not exist
56 TEST_F(SubprocessTest, NoSuchCommand) {
57  Subprocess* subproc = subprocs_.Add("ninja_no_such_command");
58  ASSERT_NE((Subprocess *) 0, subproc);
59 
60  while (!subproc->Done()) {
61  // Pretend we discovered that stderr was ready for writing.
62  subprocs_.DoWork();
63  }
64 
65  EXPECT_EQ(ExitFailure, subproc->Finish());
66  EXPECT_NE("", subproc->GetOutput());
67 #ifdef _WIN32
68  ASSERT_EQ("CreateProcess failed: The system cannot find the file "
69  "specified.\n", subproc->GetOutput());
70 #endif
71 }
72 
73 #ifndef _WIN32
74 
75 TEST_F(SubprocessTest, InterruptChild) {
76  Subprocess* subproc = subprocs_.Add("kill -INT $$");
77  ASSERT_NE((Subprocess *) 0, subproc);
78 
79  while (!subproc->Done()) {
80  subprocs_.DoWork();
81  }
82 
83  EXPECT_EQ(ExitInterrupted, subproc->Finish());
84 }
85 
86 TEST_F(SubprocessTest, InterruptParent) {
87  Subprocess* subproc = subprocs_.Add("kill -INT $PPID ; sleep 1");
88  ASSERT_NE((Subprocess *) 0, subproc);
89 
90  while (!subproc->Done()) {
91  bool interrupted = subprocs_.DoWork();
92  if (interrupted)
93  return;
94  }
95 
96  ASSERT_FALSE("We should have been interrupted");
97 }
98 
99 TEST_F(SubprocessTest, InterruptChildWithSigTerm) {
100  Subprocess* subproc = subprocs_.Add("kill -TERM $$");
101  ASSERT_NE((Subprocess *) 0, subproc);
102 
103  while (!subproc->Done()) {
104  subprocs_.DoWork();
105  }
106 
107  EXPECT_EQ(ExitInterrupted, subproc->Finish());
108 }
109 
110 TEST_F(SubprocessTest, InterruptParentWithSigTerm) {
111  Subprocess* subproc = subprocs_.Add("kill -TERM $PPID ; sleep 1");
112  ASSERT_NE((Subprocess *) 0, subproc);
113 
114  while (!subproc->Done()) {
115  bool interrupted = subprocs_.DoWork();
116  if (interrupted)
117  return;
118  }
119 
120  ASSERT_FALSE("We should have been interrupted");
121 }
122 
123 TEST_F(SubprocessTest, InterruptChildWithSigHup) {
124  Subprocess* subproc = subprocs_.Add("kill -HUP $$");
125  ASSERT_NE((Subprocess *) 0, subproc);
126 
127  while (!subproc->Done()) {
128  subprocs_.DoWork();
129  }
130 
131  EXPECT_EQ(ExitInterrupted, subproc->Finish());
132 }
133 
134 TEST_F(SubprocessTest, InterruptParentWithSigHup) {
135  Subprocess* subproc = subprocs_.Add("kill -HUP $PPID ; sleep 1");
136  ASSERT_NE((Subprocess *) 0, subproc);
137 
138  while (!subproc->Done()) {
139  bool interrupted = subprocs_.DoWork();
140  if (interrupted)
141  return;
142  }
143 
144  ASSERT_FALSE("We should have been interrupted");
145 }
146 
147 TEST_F(SubprocessTest, Console) {
148  // Skip test if we don't have the console ourselves.
149  if (isatty(0) && isatty(1) && isatty(2)) {
150  Subprocess* subproc =
151  subprocs_.Add("test -t 0 -a -t 1 -a -t 2", /*use_console=*/true);
152  ASSERT_NE((Subprocess*)0, subproc);
153 
154  while (!subproc->Done()) {
155  subprocs_.DoWork();
156  }
157 
158  EXPECT_EQ(ExitSuccess, subproc->Finish());
159  }
160 }
161 
162 #endif
163 
164 TEST_F(SubprocessTest, SetWithSingle) {
165  Subprocess* subproc = subprocs_.Add(kSimpleCommand);
166  ASSERT_NE((Subprocess *) 0, subproc);
167 
168  while (!subproc->Done()) {
169  subprocs_.DoWork();
170  }
171  ASSERT_EQ(ExitSuccess, subproc->Finish());
172  ASSERT_NE("", subproc->GetOutput());
173 
174  ASSERT_EQ(1u, subprocs_.finished_.size());
175 }
176 
177 TEST_F(SubprocessTest, SetWithMulti) {
178  Subprocess* processes[3];
179  const char* kCommands[3] = {
180  kSimpleCommand,
181 #ifdef _WIN32
182  "cmd /c echo hi",
183  "cmd /c time /t",
184 #else
185  "id -u",
186  "pwd",
187 #endif
188  };
189 
190  for (int i = 0; i < 3; ++i) {
191  processes[i] = subprocs_.Add(kCommands[i]);
192  ASSERT_NE((Subprocess *) 0, processes[i]);
193  }
194 
195  ASSERT_EQ(3u, subprocs_.running_.size());
196  for (int i = 0; i < 3; ++i) {
197  ASSERT_FALSE(processes[i]->Done());
198  ASSERT_EQ("", processes[i]->GetOutput());
199  }
200 
201  while (!processes[0]->Done() || !processes[1]->Done() ||
202  !processes[2]->Done()) {
203  ASSERT_GT(subprocs_.running_.size(), 0u);
204  subprocs_.DoWork();
205  }
206 
207  ASSERT_EQ(0u, subprocs_.running_.size());
208  ASSERT_EQ(3u, subprocs_.finished_.size());
209 
210  for (int i = 0; i < 3; ++i) {
211  ASSERT_EQ(ExitSuccess, processes[i]->Finish());
212  ASSERT_NE("", processes[i]->GetOutput());
213  delete processes[i];
214  }
215 }
216 
217 #if defined(USE_PPOLL)
218 TEST_F(SubprocessTest, SetWithLots) {
219  // Arbitrary big number; needs to be over 1024 to confirm we're no longer
220  // hostage to pselect.
221  const unsigned kNumProcs = 1025;
222 
223  // Make sure [ulimit -n] isn't going to stop us from working.
224  rlimit rlim;
225  ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
226  if (rlim.rlim_cur < kNumProcs) {
227  printf("Raise [ulimit -n] above %u (currently %lu) to make this test go\n",
228  kNumProcs, rlim.rlim_cur);
229  return;
230  }
231 
232  vector<Subprocess*> procs;
233  for (size_t i = 0; i < kNumProcs; ++i) {
234  Subprocess* subproc = subprocs_.Add("/bin/echo");
235  ASSERT_NE((Subprocess *) 0, subproc);
236  procs.push_back(subproc);
237  }
238  while (!subprocs_.running_.empty())
239  subprocs_.DoWork();
240  for (size_t i = 0; i < procs.size(); ++i) {
241  ASSERT_EQ(ExitSuccess, procs[i]->Finish());
242  ASSERT_NE("", procs[i]->GetOutput());
243  }
244  ASSERT_EQ(kNumProcs, subprocs_.finished_.size());
245 }
246 #endif // !__APPLE__ && !_WIN32
247 
248 // TODO: this test could work on Windows, just not sure how to simply
249 // read stdin.
250 #ifndef _WIN32
251 // Verify that a command that attempts to read stdin correctly thinks
252 // that stdin is closed.
253 TEST_F(SubprocessTest, ReadStdin) {
254  Subprocess* subproc = subprocs_.Add("cat -");
255  while (!subproc->Done()) {
256  subprocs_.DoWork();
257  }
258  ASSERT_EQ(ExitSuccess, subproc->Finish());
259  ASSERT_EQ(1u, subprocs_.finished_.size());
260 }
261 #endif // _WIN32
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
Definition: subprocess.h:83
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
Subprocess wraps a single async subprocess.
Definition: subprocess.h:43
#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 string & GetOutput() const
bool Done() const
#define EXPECT_NE(a, b)
Definition: test.h:66