Ninja
|
00001 // Copyright 2012 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include "subprocess.h" 00016 00017 #include "test.h" 00018 00019 #ifndef _WIN32 00020 // SetWithLots need setrlimit. 00021 #include <sys/time.h> 00022 #include <sys/resource.h> 00023 #include <unistd.h> 00024 #endif 00025 00026 namespace { 00027 00028 #ifdef _WIN32 00029 const char* kSimpleCommand = "cmd /c dir \\"; 00030 #else 00031 const char* kSimpleCommand = "ls /"; 00032 #endif 00033 00034 struct SubprocessTest : public testing::Test { 00035 SubprocessSet subprocs_; 00036 }; 00037 00038 } // anonymous namespace 00039 00040 // Run a command that fails and emits to stderr. 00041 TEST_F(SubprocessTest, BadCommandStderr) { 00042 Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command"); 00043 ASSERT_NE((Subprocess *) 0, subproc); 00044 00045 while (!subproc->Done()) { 00046 // Pretend we discovered that stderr was ready for writing. 00047 subprocs_.DoWork(); 00048 } 00049 00050 EXPECT_EQ(ExitFailure, subproc->Finish()); 00051 EXPECT_NE("", subproc->GetOutput()); 00052 } 00053 00054 // Run a command that does not exist 00055 TEST_F(SubprocessTest, NoSuchCommand) { 00056 Subprocess* subproc = subprocs_.Add("ninja_no_such_command"); 00057 ASSERT_NE((Subprocess *) 0, subproc); 00058 00059 while (!subproc->Done()) { 00060 // Pretend we discovered that stderr was ready for writing. 00061 subprocs_.DoWork(); 00062 } 00063 00064 EXPECT_EQ(ExitFailure, subproc->Finish()); 00065 EXPECT_NE("", subproc->GetOutput()); 00066 #ifdef _WIN32 00067 ASSERT_EQ("CreateProcess failed: The system cannot find the file " 00068 "specified.\n", subproc->GetOutput()); 00069 #endif 00070 } 00071 00072 #ifndef _WIN32 00073 00074 TEST_F(SubprocessTest, InterruptChild) { 00075 Subprocess* subproc = subprocs_.Add("kill -INT $$"); 00076 ASSERT_NE((Subprocess *) 0, subproc); 00077 00078 while (!subproc->Done()) { 00079 subprocs_.DoWork(); 00080 } 00081 00082 EXPECT_EQ(ExitInterrupted, subproc->Finish()); 00083 } 00084 00085 TEST_F(SubprocessTest, InterruptParent) { 00086 Subprocess* subproc = subprocs_.Add("kill -INT $PPID ; sleep 1"); 00087 ASSERT_NE((Subprocess *) 0, subproc); 00088 00089 while (!subproc->Done()) { 00090 bool interrupted = subprocs_.DoWork(); 00091 if (interrupted) 00092 return; 00093 } 00094 00095 ADD_FAILURE() << "We should have been interrupted"; 00096 } 00097 00098 #endif 00099 00100 TEST_F(SubprocessTest, SetWithSingle) { 00101 Subprocess* subproc = subprocs_.Add(kSimpleCommand); 00102 ASSERT_NE((Subprocess *) 0, subproc); 00103 00104 while (!subproc->Done()) { 00105 subprocs_.DoWork(); 00106 } 00107 ASSERT_EQ(ExitSuccess, subproc->Finish()); 00108 ASSERT_NE("", subproc->GetOutput()); 00109 00110 ASSERT_EQ(1u, subprocs_.finished_.size()); 00111 } 00112 00113 TEST_F(SubprocessTest, SetWithMulti) { 00114 Subprocess* processes[3]; 00115 const char* kCommands[3] = { 00116 kSimpleCommand, 00117 #ifdef _WIN32 00118 "cmd /c echo hi", 00119 "cmd /c time /t", 00120 #else 00121 "whoami", 00122 "pwd", 00123 #endif 00124 }; 00125 00126 for (int i = 0; i < 3; ++i) { 00127 processes[i] = subprocs_.Add(kCommands[i]); 00128 ASSERT_NE((Subprocess *) 0, processes[i]); 00129 } 00130 00131 ASSERT_EQ(3u, subprocs_.running_.size()); 00132 for (int i = 0; i < 3; ++i) { 00133 ASSERT_FALSE(processes[i]->Done()); 00134 ASSERT_EQ("", processes[i]->GetOutput()); 00135 } 00136 00137 while (!processes[0]->Done() || !processes[1]->Done() || 00138 !processes[2]->Done()) { 00139 ASSERT_GT(subprocs_.running_.size(), 0u); 00140 subprocs_.DoWork(); 00141 } 00142 00143 ASSERT_EQ(0u, subprocs_.running_.size()); 00144 ASSERT_EQ(3u, subprocs_.finished_.size()); 00145 00146 for (int i = 0; i < 3; ++i) { 00147 ASSERT_EQ(ExitSuccess, processes[i]->Finish()); 00148 ASSERT_NE("", processes[i]->GetOutput()); 00149 delete processes[i]; 00150 } 00151 } 00152 00153 // OS X's process limit is less than 1025 by default 00154 // (|sysctl kern.maxprocperuid| is 709 on 10.7 and 10.8 and less prior to that). 00155 #if defined(linux) || defined(__OpenBSD__) 00156 TEST_F(SubprocessTest, SetWithLots) { 00157 // Arbitrary big number; needs to be over 1024 to confirm we're no longer 00158 // hostage to pselect. 00159 const size_t kNumProcs = 1025; 00160 00161 // Make sure [ulimit -n] isn't going to stop us from working. 00162 rlimit rlim; 00163 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim)); 00164 ASSERT_GT(rlim.rlim_cur, kNumProcs) 00165 << "Raise [ulimit -n] well above " << kNumProcs 00166 << " to make this test go"; 00167 00168 vector<Subprocess*> procs; 00169 for (size_t i = 0; i < kNumProcs; ++i) { 00170 Subprocess* subproc = subprocs_.Add("/bin/echo"); 00171 ASSERT_NE((Subprocess *) 0, subproc); 00172 procs.push_back(subproc); 00173 } 00174 while (!subprocs_.running_.empty()) 00175 subprocs_.DoWork(); 00176 for (size_t i = 0; i < procs.size(); ++i) { 00177 ASSERT_EQ(ExitSuccess, procs[i]->Finish()); 00178 ASSERT_NE("", procs[i]->GetOutput()); 00179 } 00180 ASSERT_EQ(kNumProcs, subprocs_.finished_.size()); 00181 } 00182 #endif // linux || __OpenBSD__ 00183 00184 // TODO: this test could work on Windows, just not sure how to simply 00185 // read stdin. 00186 #ifndef _WIN32 00187 // Verify that a command that attempts to read stdin correctly thinks 00188 // that stdin is closed. 00189 TEST_F(SubprocessTest, ReadStdin) { 00190 Subprocess* subproc = subprocs_.Add("cat -"); 00191 while (!subproc->Done()) { 00192 subprocs_.DoWork(); 00193 } 00194 ASSERT_EQ(ExitSuccess, subproc->Finish()); 00195 ASSERT_EQ(1u, subprocs_.finished_.size()); 00196 } 00197 #endif // _WIN32