1695b41eeSopenharmony_ci// Copyright 2012 Google Inc. All Rights Reserved.
2695b41eeSopenharmony_ci//
3695b41eeSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4695b41eeSopenharmony_ci// you may not use this file except in compliance with the License.
5695b41eeSopenharmony_ci// You may obtain a copy of the License at
6695b41eeSopenharmony_ci//
7695b41eeSopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8695b41eeSopenharmony_ci//
9695b41eeSopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10695b41eeSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11695b41eeSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12695b41eeSopenharmony_ci// See the License for the specific language governing permissions and
13695b41eeSopenharmony_ci// limitations under the License.
14695b41eeSopenharmony_ci
15695b41eeSopenharmony_ci#include "subprocess.h"
16695b41eeSopenharmony_ci
17695b41eeSopenharmony_ci#include "test.h"
18695b41eeSopenharmony_ci
19695b41eeSopenharmony_ci#ifndef _WIN32
20695b41eeSopenharmony_ci// SetWithLots need setrlimit.
21695b41eeSopenharmony_ci#include <stdio.h>
22695b41eeSopenharmony_ci#include <sys/time.h>
23695b41eeSopenharmony_ci#include <sys/resource.h>
24695b41eeSopenharmony_ci#include <unistd.h>
25695b41eeSopenharmony_ci#endif
26695b41eeSopenharmony_ci
27695b41eeSopenharmony_ciusing namespace std;
28695b41eeSopenharmony_ci
29695b41eeSopenharmony_cinamespace {
30695b41eeSopenharmony_ci
31695b41eeSopenharmony_ci#ifdef _WIN32
32695b41eeSopenharmony_ciconst char* kSimpleCommand = "cmd /c dir \\";
33695b41eeSopenharmony_ci#else
34695b41eeSopenharmony_ciconst char* kSimpleCommand = "ls /";
35695b41eeSopenharmony_ci#endif
36695b41eeSopenharmony_ci
37695b41eeSopenharmony_cistruct SubprocessTest : public testing::Test {
38695b41eeSopenharmony_ci  SubprocessSet subprocs_;
39695b41eeSopenharmony_ci};
40695b41eeSopenharmony_ci
41695b41eeSopenharmony_ci}  // anonymous namespace
42695b41eeSopenharmony_ci
43695b41eeSopenharmony_ci// Run a command that fails and emits to stderr.
44695b41eeSopenharmony_ciTEST_F(SubprocessTest, BadCommandStderr) {
45695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command");
46695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
47695b41eeSopenharmony_ci
48695b41eeSopenharmony_ci  while (!subproc->Done()) {
49695b41eeSopenharmony_ci    // Pretend we discovered that stderr was ready for writing.
50695b41eeSopenharmony_ci    subprocs_.DoWork();
51695b41eeSopenharmony_ci  }
52695b41eeSopenharmony_ci
53695b41eeSopenharmony_ci  EXPECT_EQ(ExitFailure, subproc->Finish());
54695b41eeSopenharmony_ci  EXPECT_NE("", subproc->GetOutput());
55695b41eeSopenharmony_ci}
56695b41eeSopenharmony_ci
57695b41eeSopenharmony_ci// Run a command that does not exist
58695b41eeSopenharmony_ciTEST_F(SubprocessTest, NoSuchCommand) {
59695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("ninja_no_such_command");
60695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
61695b41eeSopenharmony_ci
62695b41eeSopenharmony_ci  while (!subproc->Done()) {
63695b41eeSopenharmony_ci    // Pretend we discovered that stderr was ready for writing.
64695b41eeSopenharmony_ci    subprocs_.DoWork();
65695b41eeSopenharmony_ci  }
66695b41eeSopenharmony_ci
67695b41eeSopenharmony_ci  EXPECT_EQ(ExitFailure, subproc->Finish());
68695b41eeSopenharmony_ci  EXPECT_NE("", subproc->GetOutput());
69695b41eeSopenharmony_ci#ifdef _WIN32
70695b41eeSopenharmony_ci  ASSERT_EQ("CreateProcess failed: The system cannot find the file "
71695b41eeSopenharmony_ci            "specified.\n", subproc->GetOutput());
72695b41eeSopenharmony_ci#endif
73695b41eeSopenharmony_ci}
74695b41eeSopenharmony_ci
75695b41eeSopenharmony_ci#ifndef _WIN32
76695b41eeSopenharmony_ci
77695b41eeSopenharmony_ciTEST_F(SubprocessTest, InterruptChild) {
78695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("kill -INT $$");
79695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
80695b41eeSopenharmony_ci
81695b41eeSopenharmony_ci  while (!subproc->Done()) {
82695b41eeSopenharmony_ci    subprocs_.DoWork();
83695b41eeSopenharmony_ci  }
84695b41eeSopenharmony_ci
85695b41eeSopenharmony_ci  EXPECT_EQ(ExitInterrupted, subproc->Finish());
86695b41eeSopenharmony_ci}
87695b41eeSopenharmony_ci
88695b41eeSopenharmony_ciTEST_F(SubprocessTest, InterruptParent) {
89695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("kill -INT $PPID ; sleep 1");
90695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
91695b41eeSopenharmony_ci
92695b41eeSopenharmony_ci  while (!subproc->Done()) {
93695b41eeSopenharmony_ci    bool interrupted = subprocs_.DoWork();
94695b41eeSopenharmony_ci    if (interrupted)
95695b41eeSopenharmony_ci      return;
96695b41eeSopenharmony_ci  }
97695b41eeSopenharmony_ci
98695b41eeSopenharmony_ci  ASSERT_FALSE("We should have been interrupted");
99695b41eeSopenharmony_ci}
100695b41eeSopenharmony_ci
101695b41eeSopenharmony_ciTEST_F(SubprocessTest, InterruptChildWithSigTerm) {
102695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("kill -TERM $$");
103695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
104695b41eeSopenharmony_ci
105695b41eeSopenharmony_ci  while (!subproc->Done()) {
106695b41eeSopenharmony_ci    subprocs_.DoWork();
107695b41eeSopenharmony_ci  }
108695b41eeSopenharmony_ci
109695b41eeSopenharmony_ci  EXPECT_EQ(ExitInterrupted, subproc->Finish());
110695b41eeSopenharmony_ci}
111695b41eeSopenharmony_ci
112695b41eeSopenharmony_ciTEST_F(SubprocessTest, InterruptParentWithSigTerm) {
113695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("kill -TERM $PPID ; sleep 1");
114695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
115695b41eeSopenharmony_ci
116695b41eeSopenharmony_ci  while (!subproc->Done()) {
117695b41eeSopenharmony_ci    bool interrupted = subprocs_.DoWork();
118695b41eeSopenharmony_ci    if (interrupted)
119695b41eeSopenharmony_ci      return;
120695b41eeSopenharmony_ci  }
121695b41eeSopenharmony_ci
122695b41eeSopenharmony_ci  ASSERT_FALSE("We should have been interrupted");
123695b41eeSopenharmony_ci}
124695b41eeSopenharmony_ci
125695b41eeSopenharmony_ciTEST_F(SubprocessTest, InterruptChildWithSigHup) {
126695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("kill -HUP $$");
127695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
128695b41eeSopenharmony_ci
129695b41eeSopenharmony_ci  while (!subproc->Done()) {
130695b41eeSopenharmony_ci    subprocs_.DoWork();
131695b41eeSopenharmony_ci  }
132695b41eeSopenharmony_ci
133695b41eeSopenharmony_ci  EXPECT_EQ(ExitInterrupted, subproc->Finish());
134695b41eeSopenharmony_ci}
135695b41eeSopenharmony_ci
136695b41eeSopenharmony_ciTEST_F(SubprocessTest, InterruptParentWithSigHup) {
137695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("kill -HUP $PPID ; sleep 1");
138695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
139695b41eeSopenharmony_ci
140695b41eeSopenharmony_ci  while (!subproc->Done()) {
141695b41eeSopenharmony_ci    bool interrupted = subprocs_.DoWork();
142695b41eeSopenharmony_ci    if (interrupted)
143695b41eeSopenharmony_ci      return;
144695b41eeSopenharmony_ci  }
145695b41eeSopenharmony_ci
146695b41eeSopenharmony_ci  ASSERT_FALSE("We should have been interrupted");
147695b41eeSopenharmony_ci}
148695b41eeSopenharmony_ci
149695b41eeSopenharmony_ciTEST_F(SubprocessTest, Console) {
150695b41eeSopenharmony_ci  // Skip test if we don't have the console ourselves.
151695b41eeSopenharmony_ci  if (isatty(0) && isatty(1) && isatty(2)) {
152695b41eeSopenharmony_ci    Subprocess* subproc =
153695b41eeSopenharmony_ci        subprocs_.Add("test -t 0 -a -t 1 -a -t 2", /*use_console=*/true);
154695b41eeSopenharmony_ci    ASSERT_NE((Subprocess*)0, subproc);
155695b41eeSopenharmony_ci
156695b41eeSopenharmony_ci    while (!subproc->Done()) {
157695b41eeSopenharmony_ci      subprocs_.DoWork();
158695b41eeSopenharmony_ci    }
159695b41eeSopenharmony_ci
160695b41eeSopenharmony_ci    EXPECT_EQ(ExitSuccess, subproc->Finish());
161695b41eeSopenharmony_ci  }
162695b41eeSopenharmony_ci}
163695b41eeSopenharmony_ci
164695b41eeSopenharmony_ci#endif
165695b41eeSopenharmony_ci
166695b41eeSopenharmony_ciTEST_F(SubprocessTest, SetWithSingle) {
167695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add(kSimpleCommand);
168695b41eeSopenharmony_ci  ASSERT_NE((Subprocess *) 0, subproc);
169695b41eeSopenharmony_ci
170695b41eeSopenharmony_ci  while (!subproc->Done()) {
171695b41eeSopenharmony_ci    subprocs_.DoWork();
172695b41eeSopenharmony_ci  }
173695b41eeSopenharmony_ci  ASSERT_EQ(ExitSuccess, subproc->Finish());
174695b41eeSopenharmony_ci  ASSERT_NE("", subproc->GetOutput());
175695b41eeSopenharmony_ci
176695b41eeSopenharmony_ci  ASSERT_EQ(1u, subprocs_.finished_.size());
177695b41eeSopenharmony_ci}
178695b41eeSopenharmony_ci
179695b41eeSopenharmony_ciTEST_F(SubprocessTest, SetWithMulti) {
180695b41eeSopenharmony_ci  Subprocess* processes[3];
181695b41eeSopenharmony_ci  const char* kCommands[3] = {
182695b41eeSopenharmony_ci    kSimpleCommand,
183695b41eeSopenharmony_ci#ifdef _WIN32
184695b41eeSopenharmony_ci    "cmd /c echo hi",
185695b41eeSopenharmony_ci    "cmd /c time /t",
186695b41eeSopenharmony_ci#else
187695b41eeSopenharmony_ci    "id -u",
188695b41eeSopenharmony_ci    "pwd",
189695b41eeSopenharmony_ci#endif
190695b41eeSopenharmony_ci  };
191695b41eeSopenharmony_ci
192695b41eeSopenharmony_ci  for (int i = 0; i < 3; ++i) {
193695b41eeSopenharmony_ci    processes[i] = subprocs_.Add(kCommands[i]);
194695b41eeSopenharmony_ci    ASSERT_NE((Subprocess *) 0, processes[i]);
195695b41eeSopenharmony_ci  }
196695b41eeSopenharmony_ci
197695b41eeSopenharmony_ci  ASSERT_EQ(3u, subprocs_.running_.size());
198695b41eeSopenharmony_ci  for (int i = 0; i < 3; ++i) {
199695b41eeSopenharmony_ci    ASSERT_FALSE(processes[i]->Done());
200695b41eeSopenharmony_ci    ASSERT_EQ("", processes[i]->GetOutput());
201695b41eeSopenharmony_ci  }
202695b41eeSopenharmony_ci
203695b41eeSopenharmony_ci  while (!processes[0]->Done() || !processes[1]->Done() ||
204695b41eeSopenharmony_ci         !processes[2]->Done()) {
205695b41eeSopenharmony_ci    ASSERT_GT(subprocs_.running_.size(), 0u);
206695b41eeSopenharmony_ci    subprocs_.DoWork();
207695b41eeSopenharmony_ci  }
208695b41eeSopenharmony_ci
209695b41eeSopenharmony_ci  ASSERT_EQ(0u, subprocs_.running_.size());
210695b41eeSopenharmony_ci  ASSERT_EQ(3u, subprocs_.finished_.size());
211695b41eeSopenharmony_ci
212695b41eeSopenharmony_ci  for (int i = 0; i < 3; ++i) {
213695b41eeSopenharmony_ci    ASSERT_EQ(ExitSuccess, processes[i]->Finish());
214695b41eeSopenharmony_ci    ASSERT_NE("", processes[i]->GetOutput());
215695b41eeSopenharmony_ci    delete processes[i];
216695b41eeSopenharmony_ci  }
217695b41eeSopenharmony_ci}
218695b41eeSopenharmony_ci
219695b41eeSopenharmony_ci#if defined(USE_PPOLL)
220695b41eeSopenharmony_ciTEST_F(SubprocessTest, SetWithLots) {
221695b41eeSopenharmony_ci  // Arbitrary big number; needs to be over 1024 to confirm we're no longer
222695b41eeSopenharmony_ci  // hostage to pselect.
223695b41eeSopenharmony_ci  const unsigned kNumProcs = 1025;
224695b41eeSopenharmony_ci
225695b41eeSopenharmony_ci  // Make sure [ulimit -n] isn't going to stop us from working.
226695b41eeSopenharmony_ci  rlimit rlim;
227695b41eeSopenharmony_ci  ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
228695b41eeSopenharmony_ci  if (rlim.rlim_cur < kNumProcs) {
229695b41eeSopenharmony_ci    printf("Raise [ulimit -n] above %u (currently %lu) to make this test go\n",
230695b41eeSopenharmony_ci           kNumProcs, rlim.rlim_cur);
231695b41eeSopenharmony_ci    return;
232695b41eeSopenharmony_ci  }
233695b41eeSopenharmony_ci
234695b41eeSopenharmony_ci  vector<Subprocess*> procs;
235695b41eeSopenharmony_ci  for (size_t i = 0; i < kNumProcs; ++i) {
236695b41eeSopenharmony_ci    Subprocess* subproc = subprocs_.Add("/bin/echo");
237695b41eeSopenharmony_ci    ASSERT_NE((Subprocess *) 0, subproc);
238695b41eeSopenharmony_ci    procs.push_back(subproc);
239695b41eeSopenharmony_ci  }
240695b41eeSopenharmony_ci  while (!subprocs_.running_.empty())
241695b41eeSopenharmony_ci    subprocs_.DoWork();
242695b41eeSopenharmony_ci  for (size_t i = 0; i < procs.size(); ++i) {
243695b41eeSopenharmony_ci    ASSERT_EQ(ExitSuccess, procs[i]->Finish());
244695b41eeSopenharmony_ci    ASSERT_NE("", procs[i]->GetOutput());
245695b41eeSopenharmony_ci  }
246695b41eeSopenharmony_ci  ASSERT_EQ(kNumProcs, subprocs_.finished_.size());
247695b41eeSopenharmony_ci}
248695b41eeSopenharmony_ci#endif  // !__APPLE__ && !_WIN32
249695b41eeSopenharmony_ci
250695b41eeSopenharmony_ci// TODO: this test could work on Windows, just not sure how to simply
251695b41eeSopenharmony_ci// read stdin.
252695b41eeSopenharmony_ci#ifndef _WIN32
253695b41eeSopenharmony_ci// Verify that a command that attempts to read stdin correctly thinks
254695b41eeSopenharmony_ci// that stdin is closed.
255695b41eeSopenharmony_ciTEST_F(SubprocessTest, ReadStdin) {
256695b41eeSopenharmony_ci  Subprocess* subproc = subprocs_.Add("cat -");
257695b41eeSopenharmony_ci  while (!subproc->Done()) {
258695b41eeSopenharmony_ci    subprocs_.DoWork();
259695b41eeSopenharmony_ci  }
260695b41eeSopenharmony_ci  ASSERT_EQ(ExitSuccess, subproc->Finish());
261695b41eeSopenharmony_ci  ASSERT_EQ(1u, subprocs_.finished_.size());
262695b41eeSopenharmony_ci}
263695b41eeSopenharmony_ci#endif  // _WIN32
264