Ninja
subprocess_test.cc
Go to the documentation of this file.
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