|
@@ -20,7 +20,6 @@
|
|
|
|
|
|
struct ExpectedStatus
|
|
struct ExpectedStatus
|
|
{
|
|
{
|
|
- bool Finished;
|
|
|
|
bool MatchExitStatus;
|
|
bool MatchExitStatus;
|
|
bool MatchTermSignal;
|
|
bool MatchTermSignal;
|
|
cmUVProcessChain::Status Status;
|
|
cmUVProcessChain::Status Status;
|
|
@@ -28,38 +27,6 @@ struct ExpectedStatus
|
|
std::string ExceptionString;
|
|
std::string ExceptionString;
|
|
};
|
|
};
|
|
|
|
|
|
-static const std::vector<ExpectedStatus> status1 = {
|
|
|
|
- { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
- { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
- { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static const std::vector<ExpectedStatus> status2 = {
|
|
|
|
- { true, true, true, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
- { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
- { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static const std::vector<ExpectedStatus> status3 = {
|
|
|
|
- { true, true, true, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
- { true, true, true, { 1, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
|
|
|
|
-#ifdef _WIN32
|
|
|
|
- { true,
|
|
|
|
- true,
|
|
|
|
- true,
|
|
|
|
- { STATUS_ACCESS_VIOLATION, 0 },
|
|
|
|
- cmUVProcessChain::ExceptionCode::Fault,
|
|
|
|
- "Access violation" },
|
|
|
|
-#else
|
|
|
|
- { true,
|
|
|
|
- false,
|
|
|
|
- true,
|
|
|
|
- { 0, SIGABRT },
|
|
|
|
- cmUVProcessChain::ExceptionCode::Other,
|
|
|
|
- "Subprocess aborted" },
|
|
|
|
-#endif
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
static const char* ExceptionCodeToString(cmUVProcessChain::ExceptionCode code)
|
|
static const char* ExceptionCodeToString(cmUVProcessChain::ExceptionCode code)
|
|
{
|
|
{
|
|
switch (code) {
|
|
switch (code) {
|
|
@@ -73,6 +40,8 @@ static const char* ExceptionCodeToString(cmUVProcessChain::ExceptionCode code)
|
|
return "Interrupt";
|
|
return "Interrupt";
|
|
case cmUVProcessChain::ExceptionCode::Numerical:
|
|
case cmUVProcessChain::ExceptionCode::Numerical:
|
|
return "Numerical";
|
|
return "Numerical";
|
|
|
|
+ case cmUVProcessChain::ExceptionCode::Spawn:
|
|
|
|
+ return "Spawn";
|
|
case cmUVProcessChain::ExceptionCode::Other:
|
|
case cmUVProcessChain::ExceptionCode::Other:
|
|
return "Other";
|
|
return "Other";
|
|
default:
|
|
default:
|
|
@@ -83,9 +52,10 @@ static const char* ExceptionCodeToString(cmUVProcessChain::ExceptionCode code)
|
|
bool operator==(const cmUVProcessChain::Status* actual,
|
|
bool operator==(const cmUVProcessChain::Status* actual,
|
|
const ExpectedStatus& expected)
|
|
const ExpectedStatus& expected)
|
|
{
|
|
{
|
|
- if (!expected.Finished) {
|
|
|
|
- return !actual;
|
|
|
|
- } else if (!actual) {
|
|
|
|
|
|
+ if (expected.Status.SpawnResult != actual->SpawnResult) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (expected.Status.Finished != actual->Finished) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
if (expected.MatchExitStatus &&
|
|
if (expected.MatchExitStatus &&
|
|
@@ -96,7 +66,7 @@ bool operator==(const cmUVProcessChain::Status* actual,
|
|
expected.Status.TermSignal != actual->TermSignal) {
|
|
expected.Status.TermSignal != actual->TermSignal) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- if (expected.Finished &&
|
|
|
|
|
|
+ if (expected.Status.Finished &&
|
|
std::make_pair(expected.ExceptionCode, expected.ExceptionString) !=
|
|
std::make_pair(expected.ExceptionCode, expected.ExceptionString) !=
|
|
actual->GetException()) {
|
|
actual->GetException()) {
|
|
return false;
|
|
return false;
|
|
@@ -150,39 +120,96 @@ static void printResults(
|
|
{
|
|
{
|
|
std::cout << "Expected: " << std::endl;
|
|
std::cout << "Expected: " << std::endl;
|
|
for (auto const& e : expected) {
|
|
for (auto const& e : expected) {
|
|
- if (e.Finished) {
|
|
|
|
- std::cout << " ExitStatus: "
|
|
|
|
- << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
|
|
|
|
- << ", TermSignal: "
|
|
|
|
- << printExpected(e.MatchTermSignal, e.Status.TermSignal)
|
|
|
|
- << ", ExceptionCode: "
|
|
|
|
- << printExpected(e.Finished,
|
|
|
|
- ExceptionCodeToString(e.ExceptionCode))
|
|
|
|
- << ", ExceptionString: \""
|
|
|
|
- << printExpected(e.Finished, e.ExceptionString) << '"'
|
|
|
|
- << std::endl;
|
|
|
|
- } else {
|
|
|
|
- std::cout << " null" << std::endl;
|
|
|
|
- }
|
|
|
|
|
|
+ std::cout << " SpawnResult: " << e.Status.SpawnResult
|
|
|
|
+ << ", Finished: " << e.Status.Finished << ", ExitStatus: "
|
|
|
|
+ << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
|
|
|
|
+ << ", TermSignal: "
|
|
|
|
+ << printExpected(e.MatchTermSignal, e.Status.TermSignal)
|
|
|
|
+ << ", ExceptionCode: "
|
|
|
|
+ << printExpected(e.Status.Finished,
|
|
|
|
+ ExceptionCodeToString(e.ExceptionCode))
|
|
|
|
+ << ", ExceptionString: \""
|
|
|
|
+ << printExpected(e.Status.Finished, e.ExceptionString) << '"'
|
|
|
|
+ << std::endl;
|
|
}
|
|
}
|
|
std::cout << "Actual:" << std::endl;
|
|
std::cout << "Actual:" << std::endl;
|
|
for (auto const& a : actual) {
|
|
for (auto const& a : actual) {
|
|
- if (a) {
|
|
|
|
- auto exception = a->GetException();
|
|
|
|
- std::cout << " ExitStatus: " << a->ExitStatus
|
|
|
|
- << ", TermSignal: " << a->TermSignal << ", ExceptionCode: "
|
|
|
|
- << ExceptionCodeToString(exception.first)
|
|
|
|
- << ", ExceptionString: \"" << exception.second << '"'
|
|
|
|
- << std::endl;
|
|
|
|
- } else {
|
|
|
|
- std::cout << " null" << std::endl;
|
|
|
|
- }
|
|
|
|
|
|
+ auto exception = a->GetException();
|
|
|
|
+ std::cout << " SpawnResult: " << a->SpawnResult
|
|
|
|
+ << ", Finished: " << a->Finished
|
|
|
|
+ << ", ExitStatus: " << a->ExitStatus
|
|
|
|
+ << ", TermSignal: " << a->TermSignal
|
|
|
|
+ << ", ExceptionCode: " << ExceptionCodeToString(exception.first)
|
|
|
|
+ << ", ExceptionString: \"" << exception.second << '"'
|
|
|
|
+ << std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static bool checkExecution(cmUVProcessChainBuilder& builder,
|
|
static bool checkExecution(cmUVProcessChainBuilder& builder,
|
|
std::unique_ptr<cmUVProcessChain>& chain)
|
|
std::unique_ptr<cmUVProcessChain>& chain)
|
|
{
|
|
{
|
|
|
|
+ static const std::vector<ExpectedStatus> status1 = {
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { 0, false, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { 0, false, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { 0, false, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ static const std::vector<ExpectedStatus> status2 = {
|
|
|
|
+ { true,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { 0, false, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { 0, false, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ static const std::vector<ExpectedStatus> status3 = {
|
|
|
|
+ { true,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ { true,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 1, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+#ifdef _WIN32
|
|
|
|
+ { true,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, STATUS_ACCESS_VIOLATION, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Fault,
|
|
|
|
+ "Access violation" },
|
|
|
|
+#else
|
|
|
|
+ { false,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 0, SIGABRT },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Other,
|
|
|
|
+ "Subprocess aborted" },
|
|
|
|
+#endif
|
|
|
|
+ };
|
|
|
|
+
|
|
std::vector<const cmUVProcessChain::Status*> status;
|
|
std::vector<const cmUVProcessChain::Status*> status;
|
|
|
|
|
|
chain = cm::make_unique<cmUVProcessChain>(builder.Start());
|
|
chain = cm::make_unique<cmUVProcessChain>(builder.Start());
|
|
@@ -201,7 +228,7 @@ static bool checkExecution(cmUVProcessChainBuilder& builder,
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- if (chain->Wait(6000)) {
|
|
|
|
|
|
+ if (chain->Wait(9000)) {
|
|
std::cout << "Wait() returned true, should be false" << std::endl;
|
|
std::cout << "Wait() returned true, should be false" << std::endl;
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
@@ -481,6 +508,113 @@ bool testUVProcessChainCwdChanged(const char* helperCommand)
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+bool testUVProcessChainSpawnFail(const char* helperCommand)
|
|
|
|
+{
|
|
|
|
+ static const std::vector<ExpectedStatus> status1 = {
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { 0, false, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { UV_ENOENT, true, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Spawn,
|
|
|
|
+ uv_strerror(UV_ENOENT) },
|
|
|
|
+#ifdef _WIN32
|
|
|
|
+ { true,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, STATUS_ACCESS_VIOLATION, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Fault,
|
|
|
|
+ "Access violation" },
|
|
|
|
+#else
|
|
|
|
+ { false,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 0, SIGABRT },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Other,
|
|
|
|
+ "Subprocess aborted" },
|
|
|
|
+#endif
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ static const std::vector<ExpectedStatus> status2 = {
|
|
|
|
+#ifdef _WIN32
|
|
|
|
+ { true,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::None,
|
|
|
|
+ "" },
|
|
|
|
+#else
|
|
|
|
+ { false,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 0, SIGPIPE },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Other,
|
|
|
|
+ "SIGPIPE" },
|
|
|
|
+#endif
|
|
|
|
+ { false,
|
|
|
|
+ false,
|
|
|
|
+ { UV_ENOENT, true, 0, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Spawn,
|
|
|
|
+ uv_strerror(UV_ENOENT) },
|
|
|
|
+#ifdef _WIN32
|
|
|
|
+ { true,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, STATUS_ACCESS_VIOLATION, 0 },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Fault,
|
|
|
|
+ "Access violation" },
|
|
|
|
+#else
|
|
|
|
+ { false,
|
|
|
|
+ true,
|
|
|
|
+ { 0, true, 0, SIGABRT },
|
|
|
|
+ cmUVProcessChain::ExceptionCode::Other,
|
|
|
|
+ "Subprocess aborted" },
|
|
|
|
+#endif
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ std::vector<const cmUVProcessChain::Status*> status;
|
|
|
|
+
|
|
|
|
+ cmUVProcessChainBuilder builder;
|
|
|
|
+ builder.AddCommand({ helperCommand, "echo" })
|
|
|
|
+ .AddCommand({ "this_command_is_for_cmake_and_should_never_exist" })
|
|
|
|
+ .AddCommand({ helperCommand, "dedup" })
|
|
|
|
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
|
|
|
|
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
|
|
|
|
+
|
|
|
|
+ auto chain = builder.Start();
|
|
|
|
+ if (!chain.Valid()) {
|
|
|
|
+ std::cout << "Valid() returned false, should be true" << std::endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Some platforms, like Solaris 10, take a long time to report a trapped
|
|
|
|
+ // subprocess to the parent process (about 1.7 seconds in the case of
|
|
|
|
+ // Solaris 10.) Wait 3 seconds to give it enough time.
|
|
|
|
+ if (chain.Wait(3000)) {
|
|
|
|
+ std::cout << "Wait() did not time out" << std::endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ status = chain.GetStatus();
|
|
|
|
+ if (!resultsMatch(status, status1)) {
|
|
|
|
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
|
|
|
|
+ printResults(status, status1);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!chain.Wait()) {
|
|
|
|
+ std::cout << "Wait() timed out" << std::endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ status = chain.GetStatus();
|
|
|
|
+ if (!resultsMatch(status, status2)) {
|
|
|
|
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
|
|
|
|
+ printResults(status, status2);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
int testUVProcessChain(int argc, char** const argv)
|
|
int testUVProcessChain(int argc, char** const argv)
|
|
{
|
|
{
|
|
if (argc < 2) {
|
|
if (argc < 2) {
|
|
@@ -518,5 +652,10 @@ int testUVProcessChain(int argc, char** const argv)
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!testUVProcessChainSpawnFail(argv[1])) {
|
|
|
|
+ std::cout << "While executing testUVProcessChainSpawnFail().\n";
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|