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