summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorKen Martin <ken.martin@kitware.com>2007-01-25 16:16:16 (GMT)
committerKen Martin <ken.martin@kitware.com>2007-01-25 16:16:16 (GMT)
commit2f84bd17581920eb5cbfc3b41e8cf477ba6a5853 (patch)
tree1fa8c0947593a749be89f78ec053eb3ce23f14e8 /Source
parentf71ad851d81649c59a8f4724d72ba4c935cdefce (diff)
downloadCMake-2f84bd17581920eb5cbfc3b41e8cf477ba6a5853.zip
CMake-2f84bd17581920eb5cbfc3b41e8cf477ba6a5853.tar.gz
CMake-2f84bd17581920eb5cbfc3b41e8cf477ba6a5853.tar.bz2
ENH: added per test timeout support
Diffstat (limited to 'Source')
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx13
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.h1
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx579
-rw-r--r--Source/CTest/cmCTestTestHandler.h10
-rw-r--r--Source/cmCTest.cxx16
-rw-r--r--Source/cmCTest.h2
-rw-r--r--Source/cmTest.cxx9
-rw-r--r--Source/ctest.cxx4
8 files changed, 345 insertions, 289 deletions
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index d82015b..f7b7481 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -29,6 +29,7 @@ cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
this->BuildTwoConfig = false;
this->BuildNoClean = false;
this->BuildNoCMake = false;
+ this->Timeout = 0;
}
//----------------------------------------------------------------------
@@ -146,7 +147,6 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
cmSystemTools::SetErrorCallback(CMakeMessageCallback, &cmakeOutString);
cmSystemTools::SetStdoutCallback(CMakeStdoutCallback, &cmakeOutString);
cmOStringStream out;
- // What is this? double timeout = this->CTest->GetTimeOut();
// if the generator and make program are not specified then it is an error
if (!this->BuildGenerator.size() || !this->BuildMakeProgram.size())
@@ -217,7 +217,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
*outstring = out.str();
}
- // if not test was specified then we are done
+ // if no test was specified then we are done
if (!this->TestCommand.size())
{
return 0;
@@ -361,8 +361,8 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
out << this->TestCommandArgs[k] << " ";
}
out << "\n";
- // What is this? this->TimeOut = timeout;
- int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, 0);
+ int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, 0,
+ this->Timeout);
if(runTestRes != cmsysProcess_State_Exited || retval != 0)
{
out << "Failed to run test command: " << testCommand[0] << "\n";
@@ -432,6 +432,11 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
idx++;
this->ExecutableDirectory = allArgs[idx];
}
+ if(currentArg.find("--test-timeout",0) == 0 && idx < allArgs.size() - 1)
+ {
+ idx++;
+ this->Timeout = atof(allArgs[idx].c_str());
+ }
if(currentArg.find("--build-generator",0) == 0 && idx < allArgs.size() - 1)
{
idx++;
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
index 073760d..b5fd639 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.h
+++ b/Source/CTest/cmCTestBuildAndTestHandler.h
@@ -75,6 +75,7 @@ protected:
std::vector<std::string> TestCommandArgs;
std::vector<std::string> BuildTargets;
bool BuildNoCMake;
+ double Timeout;
};
#endif
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index fef7e42..527de97 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -559,6 +559,292 @@ int cmCTestTestHandler::ProcessHandler()
}
//----------------------------------------------------------------------
+void cmCTestTestHandler::ProcessOneTest(cmCTestTestProperties *it,
+ std::vector<cmStdString> &passed,
+ std::vector<cmStdString> &failed,
+ int cnt, int tmsize)
+{
+ const std::string& testname = it->Name;
+ std::vector<std::string>& args = it->Args;
+ cmCTestTestResult cres;
+ cres.Properties = &*it;
+ cres.ExecutionTime = 0;
+ cres.ReturnValue = -1;
+ cres.Status = cmCTestTestHandler::NOT_RUN;
+ cres.TestCount = cnt;
+ cres.Name = testname;
+ cres.Path = it->Directory.c_str();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << cnt << "/");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << tmsize << " ");
+ if ( this->MemCheck )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
+ }
+ else
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+ std::string outname = testname;
+ outname.resize(30, ' ');
+ *this->LogFile << cnt << "/" << tmsize << " Testing: " << testname
+ << std::endl;
+
+ if ( this->CTest->GetShowOnly() )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
+ }
+ else
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
+ }
+
+ cmCTestLog(this->CTest, DEBUG, "Testing " << args[0].c_str() << " ... ");
+ // find the test executable
+ std::string actualCommand = this->FindTheExecutable(args[1].c_str());
+ std::string testCommand
+ = cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
+
+ // continue if we did not find the executable
+ if (testCommand == "")
+ {
+ *this->LogFile << "Unable to find executable: " << args[1].c_str()
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: "
+ << args[1].c_str() << std::endl);
+ cres.Output = "Unable to find executable: " + args[1];
+ if ( !this->CTest->GetShowOnly() )
+ {
+ cres.FullCommandLine = actualCommand;
+ this->TestResults.push_back( cres );
+ failed.push_back(testname);
+ return;
+ }
+ }
+
+ // add the arguments
+ std::vector<std::string>::const_iterator j = args.begin();
+ ++j;
+ ++j;
+ std::vector<const char*> arguments;
+ this->GenerateTestCommand(arguments);
+ arguments.push_back(actualCommand.c_str());
+ for(;j != args.end(); ++j)
+ {
+ testCommand += " ";
+ testCommand += cmSystemTools::EscapeSpaces(j->c_str());
+ arguments.push_back(j->c_str());
+ }
+ arguments.push_back(0);
+
+ /**
+ * Run an executable command and put the stdout in output.
+ */
+ std::string output;
+ int retVal = 0;
+
+
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
+ << (this->MemCheck?"MemCheck":"Test")
+ << " command: " << testCommand
+ << std::endl);
+ *this->LogFile << cnt << "/" << tmsize
+ << " Test: " << testname.c_str() << std::endl;
+ *this->LogFile << "Command: ";
+ std::vector<cmStdString>::size_type ll;
+ for ( ll = 0; ll < arguments.size()-1; ll ++ )
+ {
+ *this->LogFile << "\"" << arguments[ll] << "\" ";
+ }
+ *this->LogFile
+ << std::endl
+ << "Directory: " << it->Directory << std::endl
+ << "\"" << testname.c_str() << "\" start time: "
+ << this->CTest->CurrentTime() << std::endl
+ << "Output:" << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+ int res = 0;
+ double clock_start, clock_finish;
+ clock_start = cmSystemTools::GetTime();
+
+ if ( !this->CTest->GetShowOnly() )
+ {
+ res = this->CTest->RunTest(arguments, &output, &retVal, this->LogFile,
+ it->Timeout);
+ }
+
+ clock_finish = cmSystemTools::GetTime();
+
+ if ( this->LogFile )
+ {
+ double ttime = clock_finish - clock_start;
+ int hours = static_cast<int>(ttime / (60 * 60));
+ int minutes = static_cast<int>(ttime / 60) % 60;
+ int seconds = static_cast<int>(ttime) % 60;
+ char buffer[100];
+ sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
+ *this->LogFile
+ << "----------------------------------------------------------"
+ << std::endl
+ << "\"" << testname.c_str() << "\" end time: "
+ << this->CTest->CurrentTime() << std::endl
+ << "\"" << testname.c_str() << "\" time elapsed: "
+ << buffer << std::endl
+ << "----------------------------------------------------------"
+ << std::endl << std::endl;
+ }
+
+ cres.ExecutionTime = (double)(clock_finish - clock_start);
+ cres.FullCommandLine = testCommand;
+
+ if ( !this->CTest->GetShowOnly() )
+ {
+ bool testFailed = false;
+ std::vector<cmsys::RegularExpression>::iterator passIt;
+ bool forceFail = false;
+ if ( it->RequiredRegularExpressions.size() > 0 )
+ {
+ bool found = false;
+ for ( passIt = it->RequiredRegularExpressions.begin();
+ passIt != it->RequiredRegularExpressions.end();
+ ++ passIt )
+ {
+ if ( passIt->find(output.c_str()) )
+ {
+ found = true;
+ }
+ }
+ if ( !found )
+ {
+ forceFail = true;
+ }
+ }
+ if ( it->ErrorRegularExpressions.size() > 0 )
+ {
+ for ( passIt = it->ErrorRegularExpressions.begin();
+ passIt != it->ErrorRegularExpressions.end();
+ ++ passIt )
+ {
+ if ( passIt->find(output.c_str()) )
+ {
+ forceFail = true;
+ }
+ }
+ }
+
+ if (res == cmsysProcess_State_Exited &&
+ (retVal == 0 || it->RequiredRegularExpressions.size()) &&
+ !forceFail)
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed");
+ if ( it->WillFail )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " - But it should fail!");
+ cres.Status = cmCTestTestHandler::FAILED;
+ testFailed = true;
+ }
+ else
+ {
+ cres.Status = cmCTestTestHandler::COMPLETED;
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+ }
+ else
+ {
+ testFailed = true;
+
+ cres.Status = cmCTestTestHandler::FAILED;
+ if ( res == cmsysProcess_State_Expired )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout" << std::endl);
+ cres.Status = cmCTestTestHandler::TIMEOUT;
+ }
+ else if ( res == cmsysProcess_State_Exception )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
+ switch ( retVal )
+ {
+ case cmsysProcess_Exception_Fault:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
+ cres.Status = cmCTestTestHandler::SEGFAULT;
+ break;
+ case cmsysProcess_Exception_Illegal:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal");
+ cres.Status = cmCTestTestHandler::ILLEGAL;
+ break;
+ case cmsysProcess_Exception_Interrupt:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt");
+ cres.Status = cmCTestTestHandler::INTERRUPT;
+ break;
+ case cmsysProcess_Exception_Numerical:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical");
+ cres.Status = cmCTestTestHandler::NUMERICAL;
+ break;
+ default:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other");
+ cres.Status = cmCTestTestHandler::OTHER_FAULT;
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+ }
+ else if ( res == cmsysProcess_State_Error )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res
+ << std::endl);
+ cres.Status = cmCTestTestHandler::BAD_COMMAND;
+ }
+ else
+ {
+ // Force fail will also be here?
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed");
+ if ( it->WillFail )
+ {
+ cres.Status = cmCTestTestHandler::COMPLETED;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " - supposed to fail");
+ testFailed = false;
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+ }
+ }
+ if ( testFailed )
+ {
+ failed.push_back(testname);
+ }
+ else
+ {
+ passed.push_back(testname);
+ }
+ if (!output.empty() && output.find("<DartMeasurement") != output.npos)
+ {
+ if (this->DartStuff.find(output.c_str()))
+ {
+ std::string dartString = this->DartStuff.match(1);
+ cmSystemTools::ReplaceString(output, dartString.c_str(),"");
+ cres.RegressionImages
+ = this->GenerateRegressionImages(dartString);
+ }
+ }
+ }
+
+ if ( cres.Status == cmCTestTestHandler::COMPLETED )
+ {
+ this->CleanTestOutput(output, static_cast<size_t>
+ (this->CustomMaximumPassedTestOutputSize));
+ }
+ else
+ {
+ this->CleanTestOutput(output, static_cast<size_t>
+ (this->CustomMaximumFailedTestOutputSize));
+ }
+
+ cres.Output = output;
+ cres.ReturnValue = retVal;
+ cres.CompletionStatus = "Completed";
+ this->TestResults.push_back( cres );
+}
+
+//----------------------------------------------------------------------
void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
std::vector<cmStdString> &failed)
{
@@ -612,27 +898,16 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
{
continue;
}
-
- const std::string& testname = it->Name;
- std::vector<std::string>& args = it->Args;
- cmCTestTestResult cres;
- cres.Properties = &*it;
- cres.ExecutionTime = 0;
- cres.ReturnValue = -1;
- cres.Status = cmCTestTestHandler::NOT_RUN;
- cres.TestCount = cnt;
-
+
if (!(last_directory == it->Directory))
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Changing directory into " << it->Directory.c_str() << "\n");
+ "Changing directory into " << it->Directory.c_str() << "\n");
*this->LogFile << "Changing directory into: " << it->Directory.c_str()
- << std::endl;
+ << std::endl;
last_directory = it->Directory;
cmSystemTools::ChangeDirectory(it->Directory.c_str());
}
- cres.Name = testname;
- cres.Path = it->Directory.c_str();
if (this->UseUnion)
{
@@ -649,278 +924,15 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
// is this test in the list of tests to run? If not then skip it
if ((this->TestsToRun.size() &&
std::find(this->TestsToRun.begin(),
- this->TestsToRun.end(), inREcnt)
+ this->TestsToRun.end(), inREcnt)
== this->TestsToRun.end()) || !it->IsInBasedOnREOptions)
{
continue;
}
}
-
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << cnt << "/");
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << tmsize << " ");
- if ( this->MemCheck )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
- std::string outname = testname;
- outname.resize(30, ' ');
- *this->LogFile << cnt << "/" << tmsize << " Testing: " << testname
- << std::endl;
-
- if ( this->CTest->GetShowOnly() )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
- }
-
- cmCTestLog(this->CTest, DEBUG, "Testing " << args[0].c_str() << " ... ");
- // find the test executable
- std::string actualCommand = this->FindTheExecutable(args[1].c_str());
- std::string testCommand
- = cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
-
- // continue if we did not find the executable
- if (testCommand == "")
- {
- *this->LogFile << "Unable to find executable: " << args[1].c_str()
- << std::endl;
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: "
- << args[1].c_str() << std::endl);
- cres.Output = "Unable to find executable: " + args[1];
- if ( !this->CTest->GetShowOnly() )
- {
- cres.FullCommandLine = actualCommand;
- this->TestResults.push_back( cres );
- failed.push_back(testname);
- continue;
- }
- }
-
- // add the arguments
- std::vector<std::string>::const_iterator j = args.begin();
- ++j;
- ++j;
- std::vector<const char*> arguments;
- this->GenerateTestCommand(arguments);
- arguments.push_back(actualCommand.c_str());
- for(;j != args.end(); ++j)
- {
- testCommand += " ";
- testCommand += cmSystemTools::EscapeSpaces(j->c_str());
- arguments.push_back(j->c_str());
- }
- arguments.push_back(0);
-
- /**
- * Run an executable command and put the stdout in output.
- */
- std::string output;
- int retVal = 0;
-
-
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
- << (this->MemCheck?"MemCheck":"Test") << " command: " << testCommand
- << std::endl);
- *this->LogFile << cnt << "/" << tmsize
- << " Test: " << testname.c_str() << std::endl;
- *this->LogFile << "Command: ";
- std::vector<cmStdString>::size_type ll;
- for ( ll = 0; ll < arguments.size()-1; ll ++ )
- {
- *this->LogFile << "\"" << arguments[ll] << "\" ";
- }
- *this->LogFile
- << std::endl
- << "Directory: " << it->Directory << std::endl
- << "\"" << testname.c_str() << "\" start time: "
- << this->CTest->CurrentTime() << std::endl
- << "Output:" << std::endl
- << "----------------------------------------------------------"
- << std::endl;
- int res = 0;
- double clock_start, clock_finish;
- clock_start = cmSystemTools::GetTime();
-
- if ( !this->CTest->GetShowOnly() )
- {
- res = this->CTest->RunTest(arguments, &output, &retVal, this->LogFile);
- }
-
- clock_finish = cmSystemTools::GetTime();
-
- if ( this->LogFile )
- {
- double ttime = clock_finish - clock_start;
- int hours = static_cast<int>(ttime / (60 * 60));
- int minutes = static_cast<int>(ttime / 60) % 60;
- int seconds = static_cast<int>(ttime) % 60;
- char buffer[100];
- sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
- *this->LogFile
- << "----------------------------------------------------------"
- << std::endl
- << "\"" << testname.c_str() << "\" end time: "
- << this->CTest->CurrentTime() << std::endl
- << "\"" << testname.c_str() << "\" time elapsed: "
- << buffer << std::endl
- << "----------------------------------------------------------"
- << std::endl << std::endl;
- }
-
- cres.ExecutionTime = (double)(clock_finish - clock_start);
- cres.FullCommandLine = testCommand;
-
- if ( !this->CTest->GetShowOnly() )
- {
- bool testFailed = false;
- std::vector<cmsys::RegularExpression>::iterator passIt;
- bool forceFail = false;
- if ( it->RequiredRegularExpressions.size() > 0 )
- {
- bool found = false;
- for ( passIt = it->RequiredRegularExpressions.begin();
- passIt != it->RequiredRegularExpressions.end();
- ++ passIt )
- {
- if ( passIt->find(output.c_str()) )
- {
- found = true;
- }
- }
- if ( !found )
- {
- forceFail = true;
- }
- }
- if ( it->ErrorRegularExpressions.size() > 0 )
- {
- for ( passIt = it->ErrorRegularExpressions.begin();
- passIt != it->ErrorRegularExpressions.end();
- ++ passIt )
- {
- if ( passIt->find(output.c_str()) )
- {
- forceFail = true;
- }
- }
- }
-
- if (res == cmsysProcess_State_Exited &&
- (retVal == 0 || it->RequiredRegularExpressions.size()) &&
- !forceFail)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed");
- if ( it->WillFail )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " - But it should fail!");
- cres.Status = cmCTestTestHandler::FAILED;
- testFailed = true;
- }
- else
- {
- cres.Status = cmCTestTestHandler::COMPLETED;
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
- }
- else
- {
- testFailed = true;
-
- cres.Status = cmCTestTestHandler::FAILED;
- if ( res == cmsysProcess_State_Expired )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout" << std::endl);
- cres.Status = cmCTestTestHandler::TIMEOUT;
- }
- else if ( res == cmsysProcess_State_Exception )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
- switch ( retVal )
- {
- case cmsysProcess_Exception_Fault:
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
- cres.Status = cmCTestTestHandler::SEGFAULT;
- break;
- case cmsysProcess_Exception_Illegal:
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal");
- cres.Status = cmCTestTestHandler::ILLEGAL;
- break;
- case cmsysProcess_Exception_Interrupt:
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt");
- cres.Status = cmCTestTestHandler::INTERRUPT;
- break;
- case cmsysProcess_Exception_Numerical:
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical");
- cres.Status = cmCTestTestHandler::NUMERICAL;
- break;
- default:
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other");
- cres.Status = cmCTestTestHandler::OTHER_FAULT;
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
- }
- else if ( res == cmsysProcess_State_Error )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res
- << std::endl);
- cres.Status = cmCTestTestHandler::BAD_COMMAND;
- }
- else
- {
- // Force fail will also be here?
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed");
- if ( it->WillFail )
- {
- cres.Status = cmCTestTestHandler::COMPLETED;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " - supposed to fail");
- testFailed = false;
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
- }
- }
- if ( testFailed )
- {
- failed.push_back(testname);
- }
- else
- {
- passed.push_back(testname);
- }
- if (!output.empty() && output.find("<DartMeasurement") != output.npos)
- {
- if (this->DartStuff.find(output.c_str()))
- {
- std::string dartString = this->DartStuff.match(1);
- cmSystemTools::ReplaceString(output, dartString.c_str(),"");
- cres.RegressionImages
- = this->GenerateRegressionImages(dartString);
- }
- }
- }
-
- if ( cres.Status == cmCTestTestHandler::COMPLETED )
- {
- this->CleanTestOutput(output, static_cast<size_t>(
- this->CustomMaximumPassedTestOutputSize));
- }
- else
- {
- this->CleanTestOutput(output, static_cast<size_t>(
- this->CustomMaximumFailedTestOutputSize));
- }
-
- cres.Output = output;
- cres.ReturnValue = retVal;
- cres.CompletionStatus = "Completed";
- this->TestResults.push_back( cres );
+
+ // process this one test
+ this->ProcessOneTest(&(*it), passed, failed, cnt, tmsize);
}
this->EndTest = this->CTest->CurrentTime();
@@ -1647,6 +1659,10 @@ bool cmCTestTestHandler::SetTestsProperties(
{
rtit->WillFail = cmSystemTools::IsOn(val.c_str());
}
+ if ( key == "TIMEOUT" )
+ {
+ rtit->Timeout = atof(val.c_str());
+ }
if ( key == "FAIL_REGULAR_EXPRESSION" )
{
std::vector<std::string> lval;
@@ -1751,6 +1767,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
test.IsInBasedOnREOptions = true;
test.WillFail = false;
+ test.Timeout = 0;
if (this->UseIncludeRegExpFlag &&
!this->IncludeTestsRegularExpression.find(testname.c_str()))
{
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 2fe1998..c23089f 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -85,6 +85,7 @@ public:
std::map<cmStdString, cmStdString> Measurements;
bool IsInBasedOnREOptions;
bool WillFail;
+ double Timeout;
};
struct cmCTestTestResult
@@ -145,11 +146,18 @@ private:
virtual void GenerateDartOutput(std::ostream& os);
/**
- * Run the test for a directory and any subdirectories
+ * Run the tests for a directory and any subdirectories
*/
void ProcessDirectory(std::vector<cmStdString> &passed,
std::vector<cmStdString> &failed);
+ /**
+ * Run one test
+ */
+ void ProcessOneTest(cmCTestTestProperties *props,
+ std::vector<cmStdString> &passed,
+ std::vector<cmStdString> &failed,
+ int count, int tmsize);
typedef std::vector<cmCTestTestProperties> ListOfTests;
/**
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 8ca976d..e06eaec 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -1074,7 +1074,7 @@ int cmCTest::RunMakeCommand(const char* command, std::string* output,
//----------------------------------------------------------------------
int cmCTest::RunTest(std::vector<const char*> argv,
std::string* output, int *retVal,
- std::ostream* log)
+ std::ostream* log, double testTimeOut)
{
if(cmSystemTools::SameFile(argv[0], this->CTestSelf.c_str()) &&
!this->ForceNewCTestProcess)
@@ -1087,6 +1087,14 @@ int cmCTest::RunTest(std::vector<const char*> argv,
{
if(argv[i])
{
+ // if this test has a test command make sure we pass the timeout in
+ if (strcmp(argv[i],"--test-command") == 0 && testTimeOut)
+ {
+ args.push_back("--test-timeout");
+ cmOStringStream msg;
+ msg << testTimeOut;
+ args.push_back(msg.str());
+ }
args.push_back(argv[i]);
}
}
@@ -1128,6 +1136,12 @@ int cmCTest::RunTest(std::vector<const char*> argv,
{
timeout = this->TimeOut;
}
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- timeout set to "
+ << testTimeOut << std::endl);
+ if (testTimeOut && testTimeOut < timeout)
+ {
+ timeout = testTimeOut;
+ }
// always have at least 1 second if we got to here
if (timeout <= 0)
{
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index ca2e1a9..298f5a0 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -232,7 +232,7 @@ public:
//! Run command specialized for tests. Returns process status and retVal is
// return value or exception.
int RunTest(std::vector<const char*> args, std::string* output, int *retVal,
- std::ostream* logfile);
+ std::ostream* logfile, double testTimeOut);
/**
* Execute handler and return its result. If the handler fails, it returns
diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx
index 47f8792..2e0b92b 100644
--- a/Source/cmTest.cxx
+++ b/Source/cmTest.cxx
@@ -118,6 +118,15 @@ void cmTest::DefineProperties(cmake *cm)
" regular expressions has to match, otherwise the test will fail.");
cm->DefineProperty
+ ("TIMEOUT", cmProperty::TEST,
+ "How many seconds to allow for this test.",
+ "This property if set will limit a test to nto take more than "
+ "the specified number of seconds to run. If it exceeds that the "
+ "test process will be killed and ctest will move to the next test. "
+ "This setting takes precedence over DART_TESTING_TIMEOUT and "
+ "CTEST_TESTING_TIMOUT.");
+
+ cm->DefineProperty
("WILL_FAIL", cmProperty::TEST,
"If set to true, this will invert the pass/fail flag of the test.",
"This property can be used for tests that are expected to fail and "
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index d55597f..77d9fee 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -148,7 +148,7 @@ static const cmDocumentationEntry cmDocumentationOptions[] =
"complete. Other options that affect this mode are --build-target "
"--build-nocmake, --build-run-dir, "
"--build-two-config, --build-exe-dir, --build-project,"
- "--build-noclean, --build-options"},
+ "--build-noclean, --build-options, --test-timeout"},
{"--build-target", "Specify a specific target to build.",
"This option goes with the --build-and-test option, if left out the all "
"target is built." },
@@ -168,6 +168,8 @@ static const cmDocumentationEntry cmDocumentationOptions[] =
{"--test-command", "The test to run with the --build-and-test option.", ""
},
+ {"--test-timeout", "The time limit in seconds for --test-command.", ""
+ },
{"--tomorrow-tag", "Nightly or experimental starts with next day tag.",
"This is useful if the build will not finish in one day." },
{"--ctest-config", "The configuration file used to initialize CTest state "