|
|
@@ -14,12 +14,14 @@
|
|
|
#include <utility>
|
|
|
|
|
|
#include <cm/memory>
|
|
|
+#include <cm/optional>
|
|
|
|
|
|
#include "cmsys/RegularExpression.hxx"
|
|
|
|
|
|
#include "cmCTest.h"
|
|
|
#include "cmCTestMemCheckHandler.h"
|
|
|
#include "cmCTestMultiProcessHandler.h"
|
|
|
+#include "cmDuration.h"
|
|
|
#include "cmProcess.h"
|
|
|
#include "cmStringAlgorithms.h"
|
|
|
#include "cmSystemTools.h"
|
|
|
@@ -30,11 +32,6 @@ cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler)
|
|
|
{
|
|
|
this->CTest = multiHandler.CTest;
|
|
|
this->TestHandler = multiHandler.TestHandler;
|
|
|
- this->TestResult.ExecutionTime = cmDuration::zero();
|
|
|
- this->TestResult.ReturnValue = 0;
|
|
|
- this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
|
|
|
- this->TestResult.TestCount = 0;
|
|
|
- this->TestResult.Properties = nullptr;
|
|
|
}
|
|
|
|
|
|
void cmCTestRunTest::CheckOutput(std::string const& line)
|
|
|
@@ -623,28 +620,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
|
|
|
}
|
|
|
this->StartTime = this->CTest->CurrentTime();
|
|
|
|
|
|
- auto timeout = this->TestProperties->Timeout;
|
|
|
-
|
|
|
- this->TimeoutIsForStopTime = 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) {
|
|
|
- this->TimeoutIsForStopTime = true;
|
|
|
- timeout = stop_timeout;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
|
|
|
- &this->TestProperties->Environment,
|
|
|
- &this->TestProperties->EnvironmentModification,
|
|
|
- &this->TestProperties->Affinity);
|
|
|
+ return this->ForkProcess();
|
|
|
}
|
|
|
|
|
|
void cmCTestRunTest::ComputeArguments()
|
|
|
@@ -742,46 +718,80 @@ void cmCTestRunTest::ParseOutputForMeasurements()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-bool cmCTestRunTest::ForkProcess(
|
|
|
- cmDuration testTimeOut, bool explicitTimeout,
|
|
|
- std::vector<std::string>* environment,
|
|
|
- std::vector<std::string>* environment_modification,
|
|
|
- std::vector<size_t>* affinity)
|
|
|
+bool cmCTestRunTest::ForkProcess()
|
|
|
{
|
|
|
this->TestProcess->SetId(this->Index);
|
|
|
this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
|
|
|
this->TestProcess->SetCommand(this->ActualCommand);
|
|
|
this->TestProcess->SetCommandArguments(this->Arguments);
|
|
|
|
|
|
- // determine how much time we have
|
|
|
- cmDuration timeout = this->CTest->GetRemainingTimeAllowed();
|
|
|
- if (timeout != cmCTest::MaxDuration()) {
|
|
|
- timeout -= std::chrono::minutes(2);
|
|
|
+ cm::optional<cmDuration> timeout;
|
|
|
+
|
|
|
+ // Check TIMEOUT test property.
|
|
|
+ if (this->TestProperties->Timeout &&
|
|
|
+ *this->TestProperties->Timeout >= cmDuration::zero()) {
|
|
|
+ timeout = this->TestProperties->Timeout;
|
|
|
+ }
|
|
|
+
|
|
|
+ // An explicit TIMEOUT=0 test property means "no timeout".
|
|
|
+ if (timeout && *timeout == std::chrono::duration<double>::zero()) {
|
|
|
+ timeout = cm::nullopt;
|
|
|
+ } else {
|
|
|
+ // Check --timeout.
|
|
|
+ if (!timeout && this->CTest->GetGlobalTimeout() > cmDuration::zero()) {
|
|
|
+ timeout = this->CTest->GetGlobalTimeout();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check CTEST_TEST_TIMEOUT.
|
|
|
+ cmDuration ctestTestTimeout = this->CTest->GetTimeOut();
|
|
|
+ if (ctestTestTimeout > cmDuration::zero() &&
|
|
|
+ (!timeout || ctestTestTimeout < *timeout)) {
|
|
|
+ timeout = ctestTestTimeout;
|
|
|
+ }
|
|
|
}
|
|
|
- if (this->CTest->GetTimeOut() > cmDuration::zero() &&
|
|
|
- this->CTest->GetTimeOut() < timeout) {
|
|
|
- timeout = this->CTest->GetTimeOut();
|
|
|
+
|
|
|
+ // Check CTEST_TIME_LIMIT.
|
|
|
+ cmDuration timeRemaining = this->CTest->GetRemainingTimeAllowed();
|
|
|
+ if (timeRemaining != cmCTest::MaxDuration()) {
|
|
|
+ // This two minute buffer is historical.
|
|
|
+ timeRemaining -= std::chrono::minutes(2);
|
|
|
}
|
|
|
- if (testTimeOut > cmDuration::zero() &&
|
|
|
- testTimeOut < this->CTest->GetRemainingTimeAllowed()) {
|
|
|
- timeout = testTimeOut;
|
|
|
+
|
|
|
+ // Check --stop-time.
|
|
|
+ std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
|
|
|
+ if (stop_time != std::chrono::system_clock::time_point()) {
|
|
|
+ cmDuration timeUntilStop =
|
|
|
+ (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
|
|
|
+ if (timeUntilStop < timeRemaining) {
|
|
|
+ timeRemaining = timeUntilStop;
|
|
|
+ }
|
|
|
}
|
|
|
- // always have at least 1 second if we got to here
|
|
|
- if (timeout <= cmDuration::zero()) {
|
|
|
- timeout = std::chrono::seconds(1);
|
|
|
+
|
|
|
+ // Enforce remaining time even over explicit TIMEOUT=0.
|
|
|
+ if (timeRemaining <= cmDuration::zero()) {
|
|
|
+ timeRemaining = cmDuration::zero();
|
|
|
}
|
|
|
- // handle timeout explicitly set to 0
|
|
|
- if (testTimeOut == cmDuration::zero() && explicitTimeout) {
|
|
|
- timeout = cmDuration::zero();
|
|
|
+ if (!timeout || timeRemaining < *timeout) {
|
|
|
+ this->TimeoutIsForStopTime = true;
|
|
|
+ timeout = timeRemaining;
|
|
|
}
|
|
|
- cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
|
|
- this->Index << ": "
|
|
|
- << "Test timeout computed to be: "
|
|
|
- << cmDurationTo<unsigned int>(timeout)
|
|
|
- << "\n",
|
|
|
- this->TestHandler->GetQuiet());
|
|
|
|
|
|
- this->TestProcess->SetTimeout(timeout);
|
|
|
+ if (timeout) {
|
|
|
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
|
|
+ this->Index << ": "
|
|
|
+ << "Test timeout computed to be: "
|
|
|
+ << cmDurationTo<unsigned int>(*timeout)
|
|
|
+ << "\n",
|
|
|
+ this->TestHandler->GetQuiet());
|
|
|
+
|
|
|
+ this->TestProcess->SetTimeout(*timeout);
|
|
|
+ } else {
|
|
|
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
|
|
+ this->Index
|
|
|
+ << ": "
|
|
|
+ << "Test timeout suppressed by TIMEOUT property.\n",
|
|
|
+ this->TestHandler->GetQuiet());
|
|
|
+ }
|
|
|
|
|
|
cmSystemTools::SaveRestoreEnvironment sre;
|
|
|
std::ostringstream envMeasurement;
|
|
|
@@ -789,17 +799,17 @@ bool cmCTestRunTest::ForkProcess(
|
|
|
// We split processing ENVIRONMENT and ENVIRONMENT_MODIFICATION into two
|
|
|
// phases to ensure that MYVAR=reset: in the latter phase resets to the
|
|
|
// former phase's settings, rather than to the original environment.
|
|
|
- if (environment && !environment->empty()) {
|
|
|
+ if (!this->TestProperties->Environment.empty()) {
|
|
|
cmSystemTools::EnvDiff diff;
|
|
|
- diff.AppendEnv(*environment);
|
|
|
+ diff.AppendEnv(this->TestProperties->Environment);
|
|
|
diff.ApplyToCurrentEnv(&envMeasurement);
|
|
|
}
|
|
|
|
|
|
- if (environment_modification && !environment_modification->empty()) {
|
|
|
+ if (!this->TestProperties->EnvironmentModification.empty()) {
|
|
|
cmSystemTools::EnvDiff diff;
|
|
|
bool env_ok = true;
|
|
|
|
|
|
- for (auto const& envmod : *environment_modification) {
|
|
|
+ for (auto const& envmod : this->TestProperties->EnvironmentModification) {
|
|
|
env_ok &= diff.ParseOperation(envmod);
|
|
|
}
|
|
|
|
|
|
@@ -828,7 +838,7 @@ bool cmCTestRunTest::ForkProcess(
|
|
|
1);
|
|
|
|
|
|
return this->TestProcess->StartProcess(this->MultiTestHandler.Loop,
|
|
|
- affinity);
|
|
|
+ &this->TestProperties->Affinity);
|
|
|
}
|
|
|
|
|
|
void cmCTestRunTest::SetupResourcesEnvironment(std::vector<std::string>* log)
|