diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx index 0196c899b..3658ef2bf 100644 --- a/Source/CTest/cmCTestGenericHandler.cxx +++ b/Source/CTest/cmCTestGenericHandler.cxx @@ -166,12 +166,6 @@ bool cmCTestGenericHandler::StartLogFile(const char* name, ostr << "_" << this->CTest->GetCurrentTag(); } ostr << ".log"; - // if this is a parallel subprocess then add the id to the - // file so they don't clobber each other - if(this->CTest->GetParallelSubprocess()) - { - ostr << "." << this->CTest->GetParallelSubprocessId(); - } if( !this->CTest->OpenOutputFile("Temporary", ostr.str().c_str(), xofs) ) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create log file: " diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 328e2e5a2..1c8182554 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -18,7 +18,8 @@ #include "cmProcess.h" #include "cmStandardIncludes.h" #include "cmCTest.h" - +#include "cmSystemTools.h" +#include cmCTestMultiProcessHandler::cmCTestMultiProcessHandler() { @@ -39,6 +40,7 @@ cmCTestMultiProcessHandler::SetTests(TestMap& tests, this->Tests = tests; this->Properties = properties; } + // Set the max number of tests that can be run at the same time. void cmCTestMultiProcessHandler::SetParallelLevel(size_t level) { @@ -47,6 +49,7 @@ void cmCTestMultiProcessHandler::SetParallelLevel(size_t level) void cmCTestMultiProcessHandler::RunTests() { + this->CheckResume(); this->StartNextTests(); while(this->Tests.size() != 0) { @@ -57,6 +60,7 @@ void cmCTestMultiProcessHandler::RunTests() while(this->CheckOutput()) { } + this->MarkFinished(); } void cmCTestMultiProcessHandler::StartTestProcess(int test) @@ -176,7 +180,6 @@ bool cmCTestMultiProcessHandler::CheckOutput() finished.push_back(p); } } - for( std::vector::iterator i = finished.begin(); i != finished.end(); ++i) { @@ -199,12 +202,30 @@ bool cmCTestMultiProcessHandler::CheckOutput() this->TestFinishMap[test] = true; this->TestRunningMap[test] = false; this->RunningTests.erase(p); + this->WriteCheckpoint(test); delete p; } return true; } +void cmCTestMultiProcessHandler::WriteCheckpoint(int index) +{ + std::string fname = this->CTest->GetBinaryDir() + + "/Testing/Temporary/CTestCheckpoint.txt"; + std::fstream fout; + fout.open(fname.c_str(), std::ios::app); + fout << index << "\n"; + fout.close(); +} + +void cmCTestMultiProcessHandler::MarkFinished() +{ + std::string fname = this->CTest->GetBinaryDir() + + "/Testing/Temporary/CTestCheckpoint.txt"; + cmSystemTools::RemoveFile(fname.c_str()); +} + void cmCTestMultiProcessHandler::PrintTests() { #undef cout @@ -221,6 +242,48 @@ void cmCTestMultiProcessHandler::PrintTests() } } +//---------------------------------------------------------------- +void cmCTestMultiProcessHandler::CheckResume() +{ + std::string fname = this->CTest->GetBinaryDir() + + "/Testing/Temporary/CTestCheckpoint.txt"; + if(this->CTest->GetFailover()) + { + if(cmSystemTools::FileExists(fname.c_str(), true)) + { + *this->TestHandler->LogFile << "Resuming previously interrupted test set" + << std::endl + << "----------------------------------------------------------" + << std::endl; + + std::ifstream fin; + fin.open(fname.c_str()); + std::string line; + while(std::getline(fin, line)) + { + int index = atoi(line.c_str()); + this->RemoveTest(index); + } + fin.close(); + } + } + else + { + if(cmSystemTools::FileExists(fname.c_str(), true)) + { + cmSystemTools::RemoveFile(fname.c_str()); + } + } +} + +void cmCTestMultiProcessHandler::RemoveTest(int index) +{ + this->Tests.erase(index); + this->Properties.erase(index); + this->TestRunningMap[index] = false; + this->TestFinishMap[index] = true; +} + #if 0 int main() { diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 413bff2cc..3a47a36de 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -68,10 +68,16 @@ protected: void StartNextTests(); void StartTestProcess(int test); bool StartTest(int test); - //void EndTest(cmProcess*); + // Mark the checkpoint for the given test + void WriteCheckpoint(int index); + // Removes the checkpoint file + void MarkFinished(); // Return true if there are still tests running // check all running processes for output and exit case bool CheckOutput(); + void RemoveTest(int index); + //Check if we need to resume an interrupted test set + void CheckResume(); // map from test number to set of depend tests TestMap Tests; //list of test properties (indices concurrent to the test map) @@ -79,8 +85,6 @@ protected: std::map TestRunningMap; std::map TestFinishMap; std::map TestOutput; - //std::string CTestCommand; - //std::string CTestCacheFile; std::vector* Passed; std::vector* Failed; std::vector* TestResults; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index d444249e5..7b42a3d13 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -67,120 +67,118 @@ bool cmCTestRunTest::EndTest() bool passed = true; int res = this->TestProcess->GetProcessStatus(); int retVal = this->TestProcess->GetExitValue(); - if ( !this->CTest->GetShowOnly() ) + + std::vector >::iterator passIt; + bool forceFail = false; + if ( this->TestProperties->RequiredRegularExpressions.size() > 0 ) { - std::vector >::iterator passIt; - bool forceFail = false; - if ( this->TestProperties->RequiredRegularExpressions.size() > 0 ) + bool found = false; + for ( passIt = this->TestProperties->RequiredRegularExpressions.begin(); + passIt != this->TestProperties->RequiredRegularExpressions.end(); + ++ passIt ) { - bool found = false; - for ( passIt = this->TestProperties->RequiredRegularExpressions.begin(); - passIt != this->TestProperties->RequiredRegularExpressions.end(); - ++ passIt ) + if ( passIt->first.find(this->ProcessOutput.c_str()) ) { - if ( passIt->first.find(this->ProcessOutput.c_str()) ) - { - found = true; - reason = "Required regular expression found."; - } + found = true; + reason = "Required regular expression found."; } - if ( !found ) - { - reason = "Required regular expression not found."; + } + if ( !found ) + { + reason = "Required regular expression not found."; + forceFail = true; + } + reason += "Regex=["; + for ( passIt = this->TestProperties->RequiredRegularExpressions.begin(); + passIt != this->TestProperties->RequiredRegularExpressions.end(); + ++ passIt ) + { + reason += passIt->second; + reason += "\n"; + } + reason += "]"; + } + if ( this->TestProperties->ErrorRegularExpressions.size() > 0 ) + { + for ( passIt = this->TestProperties->ErrorRegularExpressions.begin(); + passIt != this->TestProperties->ErrorRegularExpressions.end(); + ++ passIt ) + { + if ( passIt->first.find(this->ProcessOutput.c_str()) ) + { + reason = "Error regular expression found in output."; + reason += " Regex=["; + reason += passIt->second; + reason += "]"; forceFail = true; } - reason += "Regex=["; - for ( passIt = this->TestProperties->RequiredRegularExpressions.begin(); - passIt != this->TestProperties->RequiredRegularExpressions.end(); - ++ passIt ) - { - reason += passIt->second; - reason += "\n"; - } - reason += "]"; } - if ( this->TestProperties->ErrorRegularExpressions.size() > 0 ) + } + if (res == cmsysProcess_State_Exited) + { + bool success = + !forceFail && (retVal == 0 || + this->TestProperties->RequiredRegularExpressions.size()); + if((success && !this->TestProperties->WillFail) + || (!success && this->TestProperties->WillFail)) { - for ( passIt = this->TestProperties->ErrorRegularExpressions.begin(); - passIt != this->TestProperties->ErrorRegularExpressions.end(); - ++ passIt ) - { - if ( passIt->first.find(this->ProcessOutput.c_str()) ) - { - reason = "Error regular expression found in output."; - reason += " Regex=["; - reason += passIt->second; - reason += "]"; - forceFail = true; - } - } + this->TestResult.Status = cmCTestTestHandler::COMPLETED; + cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed " ); } - if (res == cmsysProcess_State_Exited) + else { - bool success = - !forceFail && (retVal == 0 || - this->TestProperties->RequiredRegularExpressions.size()); - if((success && !this->TestProperties->WillFail) - || (!success && this->TestProperties->WillFail)) - { - this->TestResult.Status = cmCTestTestHandler::COMPLETED; - cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed " ); - } - else - { - this->TestResult.Status = cmCTestTestHandler::FAILED; - cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason ); - } + this->TestResult.Status = cmCTestTestHandler::FAILED; + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason ); } - else if ( res == cmsysProcess_State_Expired ) + } + else if ( res == cmsysProcess_State_Expired ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout"); + this->TestResult.Status = cmCTestTestHandler::TIMEOUT; + } + else if ( res == cmsysProcess_State_Exception ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: "); + switch ( retVal ) { - cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout"); - this->TestResult.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"); - this->TestResult.Status = cmCTestTestHandler::SEGFAULT; - break; - case cmsysProcess_Exception_Illegal: - cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal"); - this->TestResult.Status = cmCTestTestHandler::ILLEGAL; - break; - case cmsysProcess_Exception_Interrupt: - cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt"); - this->TestResult.Status = cmCTestTestHandler::INTERRUPT; - break; - case cmsysProcess_Exception_Numerical: - cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical"); - this->TestResult.Status = cmCTestTestHandler::NUMERICAL; - break; - default: - cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other"); - this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT; - } - } - else // if ( res == cmsysProcess_State_Error ) - { - cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res ); - this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND; + case cmsysProcess_Exception_Fault: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault"); + this->TestResult.Status = cmCTestTestHandler::SEGFAULT; + break; + case cmsysProcess_Exception_Illegal: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal"); + this->TestResult.Status = cmCTestTestHandler::ILLEGAL; + break; + case cmsysProcess_Exception_Interrupt: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt"); + this->TestResult.Status = cmCTestTestHandler::INTERRUPT; + break; + case cmsysProcess_Exception_Numerical: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical"); + this->TestResult.Status = cmCTestTestHandler::NUMERICAL; + break; + default: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other"); + this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT; } + } + else // if ( res == cmsysProcess_State_Error ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res ); + this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND; + } - passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED; + passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED; - char buf[1024]; - sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime()); - cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n" ); - if ( this->TestHandler->LogFile ) - { - *this->TestHandler->LogFile << "Test time = " << buf << std::endl; - } - this->DartProcessing(); - } + char buf[1024]; + sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime()); + cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n" ); + if ( this->TestHandler->LogFile ) + { + *this->TestHandler->LogFile << "Test time = " << buf << std::endl; + } + this->DartProcessing(); // if this is doing MemCheck then all the output needs to be put into // Output since that is what is parsed by cmCTestMemCheckHandler if(!this->TestHandler->MemCheck) @@ -303,14 +301,10 @@ bool cmCTestRunTest::StartTest() this->StartTime = this->CTest->CurrentTime(); - if ( !this->CTest->GetShowOnly() ) - { - return this->CreateProcess(this->ActualCommand, - this->TestProperties->Args, - this->TestProperties->Timeout, - &this->TestProperties->Environment); - } - return true; + return this->CreateProcess(this->ActualCommand, + this->TestProperties->Args, + this->TestProperties->Timeout, + &this->TestProperties->Environment); } //---------------------------------------------------------------------- @@ -449,15 +443,7 @@ void cmCTestRunTest::WriteLogOutputTop() *this->TestHandler->LogFile << this->ProcessOutput.c_str() << "" << 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, HANDLER_OUTPUT, outname.c_str()); cmCTestLog(this->CTest, DEBUG, "Testing " << this->TestProperties->Name.c_str() << " ... "); } diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 72a108a10..2609808d9 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -63,7 +63,8 @@ protected: std::vector args, double testTimeOut, std::vector* environment); -private: + void WriteLogOutputTop(); + cmCTestTestHandler::cmCTestTestProperties * TestProperties; //Pointer back to the "parent"; the handler that invoked this test run cmCTestTestHandler * TestHandler; @@ -85,7 +86,6 @@ private: std::string StartTime; std::string TestCommand; std::string ActualCommand; - void WriteLogOutputTop(); }; #endif diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 6df925cfe..b51b7c5ba 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -523,14 +523,11 @@ int cmCTestTestHandler::ProcessHandler() } this->TestResults.clear(); - // do not output startup if this is a sub-process for parallel tests - if(!this->CTest->GetParallelSubprocess()) - { - cmCTestLog(this->CTest, HANDLER_OUTPUT, - (this->MemCheck ? "Memory check" : "Test") - << " project " << cmSystemTools::GetCurrentWorkingDirectory() - << std::endl); - } + + cmCTestLog(this->CTest, HANDLER_OUTPUT, + (this->MemCheck ? "Memory check" : "Test") + << " project " << cmSystemTools::GetCurrentWorkingDirectory() + << std::endl); if ( ! this->PreProcessHandler() ) { return -1; @@ -583,57 +580,49 @@ int cmCTestTestHandler::ProcessHandler() percent = 99; } - if(!this->CTest->GetParallelSubprocess()) + cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl + << static_cast(percent + .5) << "% tests passed, " + << failed.size() << " tests failed out of " + << total << std::endl); + double totalTestTime = 0; + + for(cmCTestTestHandler::TestResultsVector::size_type cc = 0; + cc < this->TestResults.size(); cc ++ ) { - cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl - << static_cast(percent + .5) << "% tests passed, " - << failed.size() << " tests failed out of " - << total << std::endl); - double totalTestTime = 0; - - for(cmCTestTestHandler::TestResultsVector::size_type cc = 0; - cc < this->TestResults.size(); cc ++ ) - { - cmCTestTestResult *result = &this->TestResults[cc]; - totalTestTime += result->ExecutionTime; - } - - char realBuf[1024]; - sprintf(realBuf, "%6.2f sec", (double)(clock_finish - clock_start)); - cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = " - << realBuf << "\n" ); - - char totalBuf[1024]; - sprintf(totalBuf, "%6.2f sec", totalTestTime); - cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (parallel) = " - << totalBuf << "\n" ); - + cmCTestTestResult *result = &this->TestResults[cc]; + totalTestTime += result->ExecutionTime; } + + char realBuf[1024]; + sprintf(realBuf, "%6.2f sec", (double)(clock_finish - clock_start)); + cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = " + << realBuf << "\n" ); + + char totalBuf[1024]; + sprintf(totalBuf, "%6.2f sec", totalTestTime); + cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (parallel) = " + << totalBuf << "\n" ); if (failed.size()) { cmGeneratedFileStream ofs; - if(!this->CTest->GetParallelSubprocess()) + cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl + << "The following tests FAILED:" << std::endl); + this->StartLogFile("TestsFailed", ofs); + + std::vector::iterator ftit; + for(ftit = this->TestResults.begin(); + ftit != this->TestResults.end(); ++ftit) { - cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl - << "The following tests FAILED:" << std::endl); - this->StartLogFile("TestsFailed", ofs); - - std::vector::iterator ftit; - for(ftit = this->TestResults.begin(); - ftit != this->TestResults.end(); ++ftit) + if ( ftit->Status != cmCTestTestHandler::COMPLETED ) { - if ( ftit->Status != cmCTestTestHandler::COMPLETED ) - { - ofs << ftit->TestCount << ":" << ftit->Name << std::endl; - cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3) - << ftit->TestCount << " - " - << ftit->Name.c_str() << " (" - << this->GetTestStatus(ftit->Status) << ")" - << std::endl); - } + ofs << ftit->TestCount << ":" << ftit->Name << std::endl; + cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3) + << ftit->TestCount << " - " + << ftit->Name.c_str() << " (" + << this->GetTestStatus(ftit->Status) << ")" + << std::endl); } - } } } @@ -808,7 +797,6 @@ void cmCTestTestHandler::ProcessOneTest(cmCTestTestProperties *it, std::string output; int retVal = 0; - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl << (this->MemCheck?"MemCheck":"Test") << " command: " << testCommand @@ -839,9 +827,7 @@ void cmCTestTestHandler::ProcessOneTest(cmCTestTestProperties *it, it->Timeout, &it->Environment); } - clock_finish = cmSystemTools::GetTime(); - - + clock_finish = cmSystemTools::GetTime(); cres.ExecutionTime = (double)(clock_finish - clock_start); cres.FullCommandLine = testCommand; @@ -1118,15 +1104,7 @@ void cmCTestTestHandler::CheckLabelFilter(cmCTestTestProperties& it) void cmCTestTestHandler::ComputeTestList() { this->TestList.clear(); // clear list of test - if(this->CTest->GetParallelSubprocess()) - { - this->LoadTestList(); - return; - } - else - { - this->GetListOfTests(); - } + this->GetListOfTests(); cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size(); // how many tests are in based on RegExp? int inREcnt = 0; @@ -1325,225 +1303,42 @@ bool cmCTestTestHandler::GetValue(const char* tag, return ret; } - -// This should load only one test and is used in -j N mode. -// it is used by the sub-process ctest runs which should have -// only one -I N test to run. -void cmCTestTestHandler::LoadTestList() +//--------------------------------------------------------------------- +void cmCTestTestHandler::PrintTestList() { - this->TestList.clear(); - std::string fname = this->CTest->GetBinaryDir() - + "/Testing/Temporary/PCache.txt"; - std::ifstream fin(fname.c_str()); - std::string line; - if(!fin) - { - cmCTestLog(this->CTest, ERROR_MESSAGE, - "Could not load PCache.txt file: " - << fname.c_str() << std::endl); - return; - } - bool ok = true; - int numTestsToRun = 0; - ok = ok && this->GetValue("TotalNumberOfTests:", - this->TotalNumberOfTests, fin); - ok = ok && this->GetValue("NumberOfTestsToRun:", numTestsToRun, fin); - this->ExpandTestsToRunInformation(this->TotalNumberOfTests); - if(this->TestsToRun.size() != 1) - { - cmCTestLog(this->CTest, ERROR_MESSAGE, - "Error when in parallel mode only one test should be run: " - << this->TestsToRun.size() << std::endl); - } - int testIndexToRun = this->TestsToRun[0]; - this->CTest->SetParallelSubprocessId(testIndexToRun); - if(!ok) - { - return; - } - for(int i =0; i < numTestsToRun; i++) - { - cmCTestTestProperties p; - int numArgs = 0; - ok = this->GetValue("Name:", p.Name, fin); - ok = ok && this->GetValue("Directory:", p.Directory, fin); - ok = ok && this->GetValue("Args:", numArgs, fin); - for(int j =0; j < numArgs; ++j) - { - cmSystemTools::GetLineFromStream(fin, line); - p.Args.push_back(line); - } - int numDep = 0; - ok = ok && this->GetValue("Depends:", numDep, fin); - for(int j =0; j < numDep; ++j) - { - cmSystemTools::GetLineFromStream(fin, line); - p.Depends.push_back(line); - } - int numErrRegex = 0; - ok = ok && this->GetValue("ErrorRegularExpressions:", - numErrRegex, fin); - for(int j =0; j < numErrRegex; j++) - { - cmSystemTools::GetLineFromStream(fin, line); - std::pair rpair; - rpair.first.compile(line.c_str()); - rpair.second = line; - p.ErrorRegularExpressions.push_back(rpair); - } - int numReqRegex = 0; - ok = ok && this->GetValue("RequiredRegularExpressions:", - numReqRegex, fin); - for(int j =0; j < numReqRegex; j++) - { - cmSystemTools::GetLineFromStream(fin, line); - std::pair rpair; - rpair.first.compile(line.c_str()); - rpair.second = line; - p.RequiredRegularExpressions.push_back(rpair); - } - int numMeasure = 0; - ok = ok && this->GetValue("Measurements:", - numMeasure, fin); - for(int j =0; j < numMeasure; j++) - { - cmStdString m; - cmStdString v; - cmSystemTools::GetLineFromStream(fin, line); - m = line; - cmSystemTools::GetLineFromStream(fin, line); - v = line; - p.Measurements[m] = v; - } - int isinre; - ok = ok && this->GetValue("IsInBasedOnREOptions:", isinre, fin); - ok = ok && this->GetValue("WillFail:", p.WillFail, fin); - ok = ok && this->GetValue("TimeOut:", p.Timeout, fin); - ok = ok && this->GetValue("Index:", p.Index, fin); - int numEnv = 0; - ok = ok && this->GetValue("Environment:", - numEnv, fin); - for(int j =0; j < numEnv; j++) - { - cmSystemTools::GetLineFromStream(fin, line); - p.Environment.push_back(line); - } - int numLabels = 0; - ok = ok && this->GetValue("Labels:", - numLabels, fin); - for(int j =0; j < numLabels; j++) - { - cmSystemTools::GetLineFromStream(fin, line); - p.Labels.push_back(line); - } - if(!ok) - { - cmCTestLog(this->CTest, ERROR_MESSAGE, - "Internal Error reading cached test information." - << std::endl); - return; - } - if(p.Index == testIndexToRun) - { - // add the one test and stop reading - this->TestList.push_back(p); - return; - } - } -} -std::string cmCTestTestHandler::SaveTestList() -{ - std::string fname = this->CTest->GetBinaryDir() - + "/Testing/Temporary/PCache.txt"; - cmGeneratedFileStream fout(fname.c_str()); - if(!fout) - { - cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl - << "Could not open PCache.txt for write:" - << fname.c_str() - << std::endl); - } - fout << "TotalNumberOfTests:\n"; - fout << this->TotalNumberOfTests << "\n"; - fout << "NumberOfTestsToRun:\n"; - fout << this->TestList.size() << "\n"; + int total = this->TotalNumberOfTests; for (ListOfTests::iterator it = this->TestList.begin(); it != this->TestList.end(); it ++ ) - { + { cmCTestTestProperties& p = *it; - fout << "Name:\n" - << p.Name.c_str() - << "\nDirectory:\n" - << p.Directory.c_str() - << "\nArgs:\n" - << p.Args.size() << "\n"; - for(std::vector::iterator i = p.Args.begin(); - i != p.Args.end(); ++i) + cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) + << p.Index << "/"); + cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) + << total << " "); + if (this->MemCheck) { - fout << i->c_str() << "\n"; + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check"); } - fout << "Depends:\n" << p.Depends.size() << "\n"; - for(std::vector::iterator i = p.Depends.begin(); - i != p.Depends.end(); ++i) + else { - fout << i->c_str() << "\n"; - } - std::vector >::iterator regxi; - fout << "ErrorRegularExpressions:\n" << - p.ErrorRegularExpressions.size() << "\n"; - for(regxi = p.ErrorRegularExpressions.begin(); - regxi != p.ErrorRegularExpressions.end(); regxi++) - { - fout << regxi->second << "\n"; - } - fout << "RequiredRegularExpressions:\n" << - p.RequiredRegularExpressions.size() << "\n"; - for(regxi = p.RequiredRegularExpressions.begin(); - regxi != p.RequiredRegularExpressions.end(); regxi++) - { - fout << regxi->second << "\n"; - } - fout << "Measurements:\n" << - p.Measurements.size() << "\n"; - for(std::map::const_iterator m = - p.Measurements.begin(); m != p.Measurements.end(); ++m) - { - fout << m->first << "\n"; - fout << m->second << "\n"; - } - - fout << "IsInBasedOnREOptions:\n" - << p.IsInBasedOnREOptions - << "\nWillFail:\n" - << p.WillFail - << "\nTimeOut:\n" - << p.Timeout - << "\nIndex:\n" - << p.Index << "\n"; - fout << "Environment:\n" << - p.Environment.size() << "\n"; - for(std::vector::const_iterator e = - p.Environment.begin(); e != p.Environment.end(); ++e) - { - fout << *e << "\n"; - } - fout << "Labels:\n" << - p.Labels.size() << "\n"; - for(std::vector::const_iterator e = - p.Labels.begin(); e != p.Labels.end(); ++e) - { - fout << *e << "\n"; + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing"); } + cmCTestLog(this->CTest, HANDLER_OUTPUT, " "); + cmCTestLog(this->CTest, HANDLER_OUTPUT, p.Name.c_str() << std::endl); } - fout.close(); - return fname; } +//--------------------------------------------------------------------- void cmCTestTestHandler::ProcessDirectory(std::vector &passed, std::vector &failed) { this->ComputeTestList(); + + if(this->CTest->GetShowOnly()) + { + this->PrintTestList(); + return; + } cmCTestMultiProcessHandler parallel; parallel.SetCTest(this->CTest); parallel.SetParallelLevel(this->CTest->GetParallelLevel()); diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index a6b8e8ec4..9dbb52cff 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -141,6 +141,7 @@ protected: void WriteTestResultHeader(std::ostream& os, cmCTestTestResult* result); void WriteTestResultFooter(std::ostream& os, cmCTestTestResult* result); + void PrintTestList(); //! Clean test output to specified length bool CleanTestOutput(std::string& output, size_t length); @@ -203,10 +204,6 @@ private: // based on union regex and -I stuff void ComputeTestList(); - // Save the state of the test list and return the file - // name it was saved to - std::string SaveTestList(); - void LoadTestList(); bool GetValue(const char* tag, std::string& value, std::ifstream& fin); diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 759077200..f1ad1a7cb 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -208,9 +208,9 @@ std::string cmCTest::DecodeURL(const std::string& in) //---------------------------------------------------------------------- cmCTest::cmCTest() { - this->ParallelSubprocess = false; this->ParallelLevel = 1; this->SubmitIndex = 0; + this->Failover = false; this->ForceNewCTestProcess = false; this->TomorrowTag = false; this->Verbose = false; @@ -795,11 +795,7 @@ int cmCTest::ProcessTests() bool notest = true; int update_count = 0; - // do not output startup if this is a sub-process for parallel tests - if(!this->GetParallelSubprocess()) - { - cmCTestLog(this, OUTPUT, "Start processing tests" << std::endl); - } + cmCTestLog(this, OUTPUT, "Start processing tests" << std::endl); for(Part p = PartStart; notest && p != PartCount; p = Part(p+1)) { @@ -908,11 +904,8 @@ int cmCTest::ProcessTests() } if ( res != 0 ) { - if(!this->GetParallelSubprocess()) - { - cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest" + cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest" << std::endl); - } } return res; } @@ -1707,6 +1700,10 @@ void cmCTest::HandleCommandLineArguments(size_t &i, { std::string arg = args[i]; + if(this->CheckArgument(arg, "-F")) + { + this->Failover = true; + } if(this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1) { i++; @@ -1718,20 +1715,6 @@ void cmCTest::HandleCommandLineArguments(size_t &i, int plevel = atoi(arg.substr(2).c_str()); this->SetParallelLevel(plevel); } - if(this->CheckArgument(arg, "--internal-ctest-parallel") - && i < args.size() - 1) - { - i++; - int pid = atoi(args[i].c_str()); - this->SetParallelSubprocessId(pid); - this->SetParallelSubprocess(); - } - - if(this->CheckArgument(arg, "--parallel-cache") && i < args.size() - 1) - { - i++; - this->SetParallelCacheFile(args[i].c_str()); - } if(this->CheckArgument(arg, "-C", "--build-config") && i < args.size() - 1) diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 91a0fc66c..222cbe5bd 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -138,15 +138,6 @@ public: int GetParallelLevel() { return this->ParallelLevel; } void SetParallelLevel(int); - bool GetParallelSubprocess() { return this->ParallelSubprocess; } - void SetParallelSubprocess() { this->ParallelSubprocess = true; } - - void SetParallelSubprocessId(int id) { this->ParallelSubprocessId = id;} - int GetParallelSubprocessId() { return this->ParallelSubprocessId;} - const char* GetParallelCacheFile() - { return this->ParallelCacheFile.c_str();} - void SetParallelCacheFile(const char* c) { this->ParallelCacheFile = c; } - /** * Check if CTest file exists */ @@ -371,6 +362,9 @@ public: void SetSpecificTrack(const char* track); const char* GetSpecificTrack(); + void SetFailover(bool failover) { this->Failover = failover; } + bool GetFailover() { return this->Failover; } + bool GetVerbose() { return this->Verbose;} bool GetExtraVerbose() { return this->ExtraVerbose;} @@ -384,6 +378,8 @@ private: bool ExtraVerbose; bool ProduceXML; + bool Failover; + bool ForceNewCTestProcess; bool RunConfigurationScript; @@ -420,10 +416,8 @@ private: int MaxTestNameWidth; - std::string ParallelCacheFile; int ParallelLevel; - int ParallelSubprocessId; - bool ParallelSubprocess; + int CompatibilityMode; // information for the --build-and-test options diff --git a/Source/ctest.cxx b/Source/ctest.cxx index 7cf2bcd1c..9cb0aab0a 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -70,6 +70,9 @@ static const char * cmDocumentationOptions[][3] = {"--output-on-failure", "Output anything outputted by the test program " "if the test should fail. This option can also be enabled by setting " "the environment variable CTEST_OUTPUT_ON_FAILURE"}, + {"-F", "Enable failover.", "This option allows ctest to resume a test " + "set execution that was previously interrupted. If no interruption " + "occurred, the -F option will have no effect."}, {"-Q,--quiet", "Make ctest quiet.", "This option will suppress all the output. The output log file will " "still be generated if the --output-log is specified. Options such "