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