diff options
Diffstat (limited to 'Source/CTest/cmCTestRunTest.cxx')
-rw-r--r-- | Source/CTest/cmCTestRunTest.cxx | 201 |
1 files changed, 66 insertions, 135 deletions
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index dbdefae..baf894e 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -4,28 +4,27 @@ #include "cmCTest.h" #include "cmCTestMemCheckHandler.h" -#include "cmCTestTestHandler.h" +#include "cmCTestMultiProcessHandler.h" #include "cmProcess.h" #include "cmSystemTools.h" #include "cmWorkingDirectory.h" -#include "cm_curl.h" #include "cm_zlib.h" #include "cmsys/Base64.h" -#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include <chrono> +#include <cmAlgorithms.h> #include <iomanip> +#include <ratio> #include <sstream> #include <stdio.h> -#include <time.h> #include <utility> -cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) +cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler) + : MultiTestHandler(multiHandler) { - this->CTest = handler->CTest; - this->TestHandler = handler; - this->TestProcess = nullptr; + this->CTest = multiHandler.CTest; + this->TestHandler = multiHandler.TestHandler; this->TestResult.ExecutionTime = std::chrono::duration<double>::zero(); this->TestResult.ReturnValue = 0; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; @@ -34,60 +33,37 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) this->ProcessOutput.clear(); this->CompressedOutput.clear(); this->CompressionRatio = 2; - this->StopTimePassed = false; this->NumberOfRunsLeft = 1; // default to 1 run of the test this->RunUntilFail = false; // default to run the test once this->RunAgain = false; // default to not having to run again } -cmCTestRunTest::~cmCTestRunTest() +void cmCTestRunTest::CheckOutput(std::string const& line) { -} - -bool cmCTestRunTest::CheckOutput() -{ - // Read lines for up to 0.1 seconds of total time. - std::chrono::duration<double> timeout = std::chrono::milliseconds(100); - auto timeEnd = std::chrono::steady_clock::now() + timeout; - std::string line; - while ((timeout = timeEnd - std::chrono::steady_clock::now(), - timeout > std::chrono::seconds(0))) { - int p = this->TestProcess->GetNextOutputLine(line, timeout); - if (p == cmsysProcess_Pipe_None) { - // Process has terminated and all output read. - return false; - } - if (p == cmsysProcess_Pipe_STDOUT) { - // Store this line of output. - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() - << ": " << line << std::endl); - this->ProcessOutput += line; - this->ProcessOutput += "\n"; - - // Check for TIMEOUT_AFTER_MATCH property. - if (!this->TestProperties->TimeoutRegularExpressions.empty()) { - for (auto& reg : this->TestProperties->TimeoutRegularExpressions) { - if (reg.first.find(this->ProcessOutput.c_str())) { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() - << ": " - << "Test timeout changed to " - << std::chrono::duration_cast<std::chrono::seconds>( - this->TestProperties->AlternateTimeout) - .count() - << std::endl); - this->TestProcess->ResetStartTime(); - this->TestProcess->ChangeTimeout( - this->TestProperties->AlternateTimeout); - this->TestProperties->TimeoutRegularExpressions.clear(); - break; - } - } + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() + << ": " << line << std::endl); + this->ProcessOutput += line; + this->ProcessOutput += "\n"; + + // Check for TIMEOUT_AFTER_MATCH property. + if (!this->TestProperties->TimeoutRegularExpressions.empty()) { + for (auto& reg : this->TestProperties->TimeoutRegularExpressions) { + if (reg.first.find(this->ProcessOutput.c_str())) { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() + << ": " + << "Test timeout changed to " + << std::chrono::duration_cast<std::chrono::seconds>( + this->TestProperties->AlternateTimeout) + .count() + << std::endl); + this->TestProcess->ResetStartTime(); + this->TestProcess->ChangeTimeout( + this->TestProperties->AlternateTimeout); + this->TestProperties->TimeoutRegularExpressions.clear(); + break; } - } else { // if(p == cmsysProcess_Pipe_Timeout) - break; } } - return true; } // Streamed compression of test output. The compressed data @@ -160,8 +136,8 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) this->WriteLogOutputTop(completed, total); std::string reason; bool passed = true; - int res = - started ? this->TestProcess->GetProcessStatus() : cmsysProcess_State_Error; + cmProcess::State res = + started ? this->TestProcess->GetProcessStatus() : cmProcess::State::Error; int retVal = this->TestProcess->GetExitValue(); bool forceFail = false; bool skipped = false; @@ -200,7 +176,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } } } - if (res == cmsysProcess_State_Exited) { + if (res == cmProcess::State::Exited) { bool success = !forceFail && (retVal == 0 || !this->TestProperties->RequiredRegularExpressions.empty()); @@ -221,29 +197,29 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason); outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; } - } else if (res == cmsysProcess_State_Expired) { + } else if (res == cmProcess::State::Expired) { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout "); this->TestResult.Status = cmCTestTestHandler::TIMEOUT; outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; - } else if (res == cmsysProcess_State_Exception) { + } else if (res == cmProcess::State::Exception) { outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: "); this->TestResult.ExceptionStatus = this->TestProcess->GetExitExceptionString(); switch (this->TestProcess->GetExitException()) { - case cmsysProcess_Exception_Fault: + case cmProcess::Exception::Fault: cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault"); this->TestResult.Status = cmCTestTestHandler::SEGFAULT; break; - case cmsysProcess_Exception_Illegal: + case cmProcess::Exception::Illegal: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal"); this->TestResult.Status = cmCTestTestHandler::ILLEGAL; break; - case cmsysProcess_Exception_Interrupt: + case cmProcess::Exception::Interrupt: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt"); this->TestResult.Status = cmCTestTestHandler::INTERRUPT; break; - case cmsysProcess_Exception_Numerical: + case cmProcess::Exception::Numerical: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical"); this->TestResult.Status = cmCTestTestHandler::NUMERICAL; break; @@ -254,7 +230,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } } else if ("Disabled" == this->TestResult.CompletionStatus) { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run (Disabled) "); - } else // cmsysProcess_State_Error + } else // cmProcess::State::Error { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run "); } @@ -350,7 +326,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) if (!this->NeedsToRerun()) { this->TestHandler->TestResults.push_back(this->TestResult); } - delete this->TestProcess; + this->TestProcess.reset(); return passed || skipped; } @@ -432,7 +408,7 @@ bool cmCTestRunTest::StartTest(size_t total) this->TestResult.TestCount = this->TestProperties->Index; this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory; - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestResult.Output = "Disabled"; this->TestResult.FullCommandLine.clear(); return false; @@ -453,7 +429,7 @@ bool cmCTestRunTest::StartTest(size_t total) // its arguments are irrelevant. This matters for the case where a fixture // dependency might be creating the executable we want to run. if (!this->FailedDependencies.empty()) { - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg = "Failed test dependencies:"; for (std::string const& failedDep : this->FailedDependencies) { msg += " " + failedDep; @@ -470,7 +446,7 @@ bool cmCTestRunTest::StartTest(size_t total) this->ComputeArguments(); std::vector<std::string>& args = this->TestProperties->Args; if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") { - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg; if (this->CTest->GetConfigType().empty()) { msg = "Test not available without configuration."; @@ -493,7 +469,7 @@ bool cmCTestRunTest::StartTest(size_t total) for (std::string const& file : this->TestProperties->RequiredFiles) { if (!cmSystemTools::FileExists(file.c_str())) { // Required file was not found - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find required file: " << file << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -509,7 +485,7 @@ bool cmCTestRunTest::StartTest(size_t total) if (this->ActualCommand.empty()) { // if the command was not found create a TestResult object // that has that information - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find executable: " << args[1] << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -522,11 +498,22 @@ bool cmCTestRunTest::StartTest(size_t total) } this->StartTime = this->CTest->CurrentTime(); - auto timeout = this->ResolveTimeout(); + auto timeout = this->TestProperties->Timeout; - if (this->StopTimePassed) { - return false; + std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime(); + if (stop_time != std::chrono::system_clock::time_point()) { + std::chrono::duration<double> stop_timeout = + (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24); + + if (stop_timeout <= std::chrono::duration<double>::zero()) { + stop_timeout = std::chrono::duration<double>::zero(); + } + if (timeout == std::chrono::duration<double>::zero() || + stop_timeout < timeout) { + timeout = stop_timeout; + } } + return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, &this->TestProperties->Environment); } @@ -603,72 +590,11 @@ void cmCTestRunTest::DartProcessing() } } -std::chrono::duration<double> cmCTestRunTest::ResolveTimeout() -{ - auto timeout = this->TestProperties->Timeout; - - if (this->CTest->GetStopTime().empty()) { - return timeout; - } - struct tm* lctime; - time_t current_time = time(nullptr); - lctime = gmtime(¤t_time); - int gm_hour = lctime->tm_hour; - time_t gm_time = mktime(lctime); - lctime = localtime(¤t_time); - int local_hour = lctime->tm_hour; - - int tzone_offset = local_hour - gm_hour; - if (gm_time > current_time && gm_hour < local_hour) { - // this means gm_time is on the next day - tzone_offset -= 24; - } else if (gm_time < current_time && gm_hour > local_hour) { - // this means gm_time is on the previous day - tzone_offset += 24; - } - - tzone_offset *= 100; - char buf[1024]; - // add todays year day and month to the time in str because - // curl_getdate no longer assumes the day is today - sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, - lctime->tm_mon + 1, lctime->tm_mday, - this->CTest->GetStopTime().c_str(), tzone_offset); - - time_t stop_time_t = curl_getdate(buf, ¤t_time); - if (stop_time_t == -1) { - return timeout; - } - - auto stop_time = std::chrono::system_clock::from_time_t(stop_time_t); - - // the stop time refers to the next day - if (this->CTest->NextDayStopTime) { - stop_time += std::chrono::hours(24); - } - auto stop_timeout = - (stop_time - std::chrono::system_clock::from_time_t(current_time)) % - std::chrono::hours(24); - this->CTest->LastStopTimeout = stop_timeout; - - if (stop_timeout <= std::chrono::duration<double>::zero() || - stop_timeout > this->CTest->LastStopTimeout) { - cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. " - "Stopping all tests." - << std::endl); - this->StopTimePassed = true; - return std::chrono::duration<double>::zero(); - } - return timeout == std::chrono::duration<double>::zero() - ? stop_timeout - : (timeout < stop_timeout ? timeout : stop_timeout); -} - bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut, bool explicitTimeout, std::vector<std::string>* environment) { - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); this->TestProcess->SetWorkingDirectory( this->TestProperties->Directory.c_str()); @@ -720,7 +646,7 @@ bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut, cmSystemTools::AppendEnv(*environment); } - return this->TestProcess->StartProcess(); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop); } void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) @@ -794,3 +720,8 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) cmCTestLog(this->CTest, DEBUG, "Testing " << this->TestProperties->Name << " ... "); } + +void cmCTestRunTest::FinalizeTest() +{ + this->MultiTestHandler.FinishTestProcess(this, true); +} |