Add non-blocking Wait() for launched processes
[oota-llvm.git] / unittests / Support / ProgramTest.cpp
1 //===- unittest/Support/ProgramTest.cpp -----------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/Support/CommandLine.h"
11 #include "llvm/Support/FileSystem.h"
12 #include "llvm/Support/Path.h"
13 #include "llvm/Support/Program.h"
14 #include "gtest/gtest.h"
15
16 #include <stdlib.h>
17 #if defined(__APPLE__)
18 # include <crt_externs.h>
19 #elif !defined(_MSC_VER)
20 // Forward declare environ in case it's not provided by stdlib.h.
21 extern char **environ;
22 #endif
23
24 #if defined(LLVM_ON_UNIX)
25 #include <unistd.h>
26 void sleep_for(unsigned int seconds) {
27   sleep(seconds);
28 }
29 #elif defined(LLVM_ON_WIN32)
30 #include <windows.h>
31 void sleep_for(unsigned int seconds) {
32   Sleep(seconds * 1000);
33 }
34 #else
35 #error sleep_for is not implemented on your platform.
36 #endif
37
38 // From TestMain.cpp.
39 extern const char *TestMainArgv0;
40
41 namespace {
42
43 using namespace llvm;
44 using namespace sys;
45
46 static cl::opt<std::string>
47 ProgramTestStringArg1("program-test-string-arg1");
48 static cl::opt<std::string>
49 ProgramTestStringArg2("program-test-string-arg2");
50
51 static void CopyEnvironment(std::vector<const char *> &out) {
52 #ifdef __APPLE__
53   char **envp = *_NSGetEnviron();
54 #else
55   // environ seems to work for Windows and most other Unices.
56   char **envp = environ;
57 #endif
58   while (*envp != 0) {
59     out.push_back(*envp);
60     ++envp;
61   }
62 }
63
64 TEST(ProgramTest, CreateProcessTrailingSlash) {
65   if (getenv("LLVM_PROGRAM_TEST_CHILD")) {
66     if (ProgramTestStringArg1 == "has\\\\ trailing\\" &&
67         ProgramTestStringArg2 == "has\\\\ trailing\\") {
68       exit(0);  // Success!  The arguments were passed and parsed.
69     }
70     exit(1);
71   }
72
73   std::string my_exe =
74       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
75   const char *argv[] = {
76     my_exe.c_str(),
77     "--gtest_filter=ProgramTest.CreateProcessTrailingSlash",
78     "-program-test-string-arg1", "has\\\\ trailing\\",
79     "-program-test-string-arg2", "has\\\\ trailing\\",
80     0
81   };
82
83   // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child.
84   std::vector<const char *> envp;
85   CopyEnvironment(envp);
86   envp.push_back("LLVM_PROGRAM_TEST_CHILD=1");
87   envp.push_back(0);
88
89   std::string error;
90   bool ExecutionFailed;
91   // Redirect stdout and stdin to NUL, but let stderr through.
92 #ifdef LLVM_ON_WIN32
93   StringRef nul("NUL");
94 #else
95   StringRef nul("/dev/null");
96 #endif
97   const StringRef *redirects[] = { &nul, &nul, 0 };
98   int rc = ExecuteAndWait(my_exe, argv, &envp[0], redirects,
99                           /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
100                           &ExecutionFailed);
101   EXPECT_FALSE(ExecutionFailed) << error;
102   EXPECT_EQ(0, rc);
103 }
104
105 TEST(ProgramTest, TestExecuteNoWait) {
106   using namespace llvm::sys;
107
108   if (getenv("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT")) {
109     sleep_for(/*seconds*/ 1);
110     exit(0);
111   }
112
113   std::string Executable =
114       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
115   const char *argv[] = {
116     Executable.c_str(),
117     "--gtest_filter=ProgramTest.TestExecuteNoWait",
118     0
119   };
120
121   // Add LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT to the environment of the child.
122   std::vector<const char *> envp;
123   CopyEnvironment(envp);
124   envp.push_back("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT=1");
125   envp.push_back(0);
126
127   std::string Error;
128   bool ExecutionFailed;
129   ProcessInfo PI1 =
130       ExecuteNoWait(Executable, argv, &envp[0], 0, 0, &Error, &ExecutionFailed);
131   ASSERT_FALSE(ExecutionFailed) << Error;
132   ASSERT_NE(PI1.Pid, 0) << "Invalid process id";
133
134   unsigned LoopCount = 0;
135
136   // Test that Wait() with WaitUntilTerminates=true works. In this case,
137   // LoopCount should only be incremented once.
138   while (true) {
139     ++LoopCount;
140     ProcessInfo WaitResult = Wait(PI1, 0, true, &Error);
141     ASSERT_TRUE(Error.empty());
142     if (WaitResult.Pid == PI1.Pid)
143       break;
144   }
145
146   EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1";
147
148   ProcessInfo PI2 =
149       ExecuteNoWait(Executable, argv, &envp[0], 0, 0, &Error, &ExecutionFailed);
150   ASSERT_FALSE(ExecutionFailed) << Error;
151   ASSERT_NE(PI2.Pid, 0) << "Invalid process id";
152
153   // Test that Wait() with SecondsToWait=0 performs a non-blocking wait. In this
154   // cse, LoopCount should be greater than 1 (more than one increment occurs).
155   while (true) {
156     ++LoopCount;
157     ProcessInfo WaitResult = Wait(PI2, 0, false, &Error);
158     ASSERT_TRUE(Error.empty());
159     if (WaitResult.Pid == PI2.Pid)
160       break;
161   }
162
163   ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1";
164 }
165
166 TEST(ProgramTest, TestExecuteNegative) {
167   std::string Executable = "i_dont_exist";
168   const char *argv[] = { Executable.c_str(), 0 };
169
170   {
171     std::string Error;
172     bool ExecutionFailed;
173     int RetCode =
174         ExecuteAndWait(Executable, argv, 0, 0, 0, 0, &Error, &ExecutionFailed);
175     ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or "
176                                 "positive value indicating the result code";
177     ASSERT_TRUE(ExecutionFailed);
178     ASSERT_FALSE(Error.empty());
179   }
180
181   {
182     std::string Error;
183     bool ExecutionFailed;
184     ProcessInfo PI =
185         ExecuteNoWait(Executable, argv, 0, 0, 0, &Error, &ExecutionFailed);
186     ASSERT_EQ(PI.Pid, 0)
187         << "On error ExecuteNoWait should return an invalid ProcessInfo";
188     ASSERT_TRUE(ExecutionFailed);
189     ASSERT_FALSE(Error.empty());
190   }
191
192 }
193
194 } // end anonymous namespace