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 |
264 | |