ENH: refactored ctest. All testing is now parallel. If no -j option is specified, defaults to a MP level of 1 (non parallel)
This commit is contained in:
parent
1171bcfc69
commit
8ffd8d0a03
|
@ -23,12 +23,11 @@
|
|||
cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
|
||||
{
|
||||
this->ParallelLevel = 1;
|
||||
this->ProcessId = 0;
|
||||
}
|
||||
// Set the tests
|
||||
void
|
||||
cmCTestMultiProcessHandler::SetTests(TestMap& tests,
|
||||
std::map<int,cmStdString>& testNames)
|
||||
PropertiesMap& properties)
|
||||
{
|
||||
// set test run map to false for all
|
||||
for(TestMap::iterator i = this->Tests.begin();
|
||||
|
@ -38,15 +37,14 @@ cmCTestMultiProcessHandler::SetTests(TestMap& tests,
|
|||
this->TestFinishMap[i->first] = false;
|
||||
}
|
||||
this->Tests = tests;
|
||||
this->TestNames = testNames;
|
||||
this->Properties = properties;
|
||||
}
|
||||
// Set the max number of tests that can be run at the same time.
|
||||
void cmCTestMultiProcessHandler::SetParallelLevel(size_t l)
|
||||
void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
|
||||
{
|
||||
this->ParallelLevel = l;
|
||||
this->ParallelLevel = level < 1 ? 1 : level;
|
||||
}
|
||||
|
||||
|
||||
void cmCTestMultiProcessHandler::RunTests()
|
||||
{
|
||||
this->StartNextTests();
|
||||
|
@ -59,65 +57,28 @@ void cmCTestMultiProcessHandler::RunTests()
|
|||
while(this->CheckOutput())
|
||||
{
|
||||
}
|
||||
|
||||
for(std::map<int, cmStdString>::iterator i =
|
||||
this->TestOutput.begin();
|
||||
i != this->TestOutput.end(); ++i)
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
i->second << std::endl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cmCTestMultiProcessHandler::StartTestProcess(int test)
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
" test " << test << "\n");
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, test << ": "
|
||||
<< " test " << test << "\n");
|
||||
this->TestRunningMap[test] = true; // mark the test as running
|
||||
// now remove the test itself
|
||||
this->Tests.erase(test);
|
||||
// now run the test
|
||||
cmProcess* newp = new cmProcess;
|
||||
newp->SetId(this->ProcessId);
|
||||
newp->SetId(test);
|
||||
newp->SetCommand(this->CTestCommand.c_str());
|
||||
std::vector<std::string> args;
|
||||
cmOStringStream width;
|
||||
if(this->CTest->GetMaxTestNameWidth())
|
||||
cmCTestRunTest* testRun = new cmCTestRunTest;
|
||||
testRun->SetCTest(this->CTest);
|
||||
testRun->SetTestHandler(this->TestHandler);
|
||||
testRun->SetIndex(test);
|
||||
testRun->SetTestProperties(this->Properties[test]);
|
||||
if(testRun->StartTest())
|
||||
{
|
||||
args.push_back("-W");
|
||||
width << this->CTest->GetMaxTestNameWidth();
|
||||
args.push_back(width.str().c_str());
|
||||
}
|
||||
args.push_back("-I");
|
||||
cmOStringStream strm;
|
||||
strm << test << "," << test;
|
||||
args.push_back(strm.str());
|
||||
args.push_back("--parallel-cache");
|
||||
args.push_back(this->CTestCacheFile.c_str());
|
||||
args.push_back("--internal-ctest-parallel");
|
||||
cmOStringStream strm2;
|
||||
strm2 << test;
|
||||
args.push_back(strm2.str());
|
||||
if(this->CTest->GetExtraVerbose())
|
||||
{
|
||||
args.push_back("-VV");
|
||||
}
|
||||
newp->SetCommandArguments(args);
|
||||
if(!newp->StartProcess())
|
||||
{
|
||||
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
||||
"Error starting " << newp->GetCommand() << "\n");
|
||||
this->EndTest(newp);
|
||||
this->RunningTests.insert(testRun);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->RunningTests.insert(newp);
|
||||
testRun->EndTest();
|
||||
}
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
"ctest -I " << test << "\n");
|
||||
this->ProcessId++;
|
||||
}
|
||||
|
||||
bool cmCTestMultiProcessHandler::StartTest(int test)
|
||||
|
@ -160,7 +121,7 @@ bool cmCTestMultiProcessHandler::StartTest(int test)
|
|||
}
|
||||
// This test was not able to start because it is waiting
|
||||
// on depends to run
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void cmCTestMultiProcessHandler::StartNextTests()
|
||||
|
@ -195,7 +156,6 @@ void cmCTestMultiProcessHandler::StartNextTests()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool cmCTestMultiProcessHandler::CheckOutput()
|
||||
{
|
||||
// no more output we are done
|
||||
|
@ -203,82 +163,48 @@ bool cmCTestMultiProcessHandler::CheckOutput()
|
|||
{
|
||||
return false;
|
||||
}
|
||||
std::vector<cmProcess*> finished;
|
||||
std::vector<cmCTestRunTest*> finished;
|
||||
std::string out, err;
|
||||
for(std::set<cmProcess*>::const_iterator i = this->RunningTests.begin();
|
||||
for(std::set<cmCTestRunTest*>::const_iterator i = this->RunningTests.begin();
|
||||
i != this->RunningTests.end(); ++i)
|
||||
{
|
||||
cmProcess* p = *i;
|
||||
int pipe = p->CheckOutput(.1, out, err);
|
||||
if(pipe == cmsysProcess_Pipe_STDOUT)
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT,
|
||||
p->GetId() << ": " << out << std::endl);
|
||||
this->TestOutput[ p->GetId() ] += out;
|
||||
this->TestOutput[ p->GetId() ] += "\n";
|
||||
}
|
||||
else if(pipe == cmsysProcess_Pipe_STDERR)
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT,
|
||||
p->GetId() << ": " << err << std::endl);
|
||||
this->TestOutput[ p->GetId() ] += err;
|
||||
this->TestOutput[ p->GetId() ] += "\n";
|
||||
}
|
||||
cmCTestRunTest* p = *i;
|
||||
p->CheckOutput(); //reads and stores the process output
|
||||
|
||||
if(!p->IsRunning())
|
||||
{
|
||||
finished.push_back(p);
|
||||
}
|
||||
}
|
||||
for( std::vector<cmProcess*>::iterator i = finished.begin();
|
||||
|
||||
for( std::vector<cmCTestRunTest*>::iterator i = finished.begin();
|
||||
i != finished.end(); ++i)
|
||||
{
|
||||
cmProcess* p = *i;
|
||||
this->EndTest(p);
|
||||
cmCTestRunTest* p = *i;
|
||||
int test = p->GetIndex();
|
||||
|
||||
if(p->EndTest())
|
||||
{
|
||||
this->Passed->push_back(p->GetTestProperties()->Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Failed->push_back(p->GetTestProperties()->Name);
|
||||
}
|
||||
for(TestMap::iterator j = this->Tests.begin();
|
||||
j!= this->Tests.end(); ++j)
|
||||
{
|
||||
j->second.erase(test);
|
||||
}
|
||||
this->TestFinishMap[test] = true;
|
||||
this->TestRunningMap[test] = false;
|
||||
this->RunningTests.erase(p);
|
||||
|
||||
delete p;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmCTestMultiProcessHandler::EndTest(cmProcess* p)
|
||||
{
|
||||
// Should have a way of getting this stuff from the
|
||||
// launched ctest, maybe a temp file or some extra xml
|
||||
// stuff in the stdout
|
||||
// Need things like Reason and ExecutionTime, Path, etc.
|
||||
int test = p->GetId();
|
||||
int exitVal = p->GetExitValue();
|
||||
cmCTestTestHandler::cmCTestTestResult cres;
|
||||
cres.Properties = 0;
|
||||
cres.ExecutionTime = p->GetTotalTime();
|
||||
cres.ReturnValue = exitVal;
|
||||
cres.Status = cmCTestTestHandler::COMPLETED;
|
||||
cres.TestCount = test;
|
||||
cres.Name = this->TestNames[test];
|
||||
cres.Path = "";
|
||||
if(exitVal)
|
||||
{
|
||||
cres.Status = cmCTestTestHandler::FAILED;
|
||||
this->Failed->push_back(this->TestNames[test]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Passed->push_back(this->TestNames[test]);
|
||||
}
|
||||
this->TestResults->push_back(cres);
|
||||
// remove test from depend of all other tests
|
||||
for(TestMap::iterator i = this->Tests.begin();
|
||||
i!= this->Tests.end(); ++i)
|
||||
{
|
||||
i->second.erase(test);
|
||||
}
|
||||
this->TestFinishMap[test] = true;
|
||||
this->TestRunningMap[test] = false;
|
||||
this->RunningTests.erase(p);
|
||||
delete p;
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
"finish test " << test << "\n");
|
||||
}
|
||||
|
||||
|
||||
void cmCTestMultiProcessHandler::PrintTests()
|
||||
{
|
||||
#undef cout
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#ifndef cmCTestMultiProcessHandler_h
|
||||
#define cmCTestMultiProcessHandler_h
|
||||
|
||||
class cmProcess;
|
||||
#include <cmStandardIncludes.h>
|
||||
#include <cmCTestTestHandler.h>
|
||||
#include <cmCTestRunTest.h>
|
||||
|
||||
/** \class cmCTestMultiProcessHandler
|
||||
* \brief run parallel ctest
|
||||
|
@ -31,16 +31,18 @@ class cmCTestMultiProcessHandler
|
|||
public:
|
||||
struct TestSet : public std::set<int> {};
|
||||
struct TestMap : public std::map<int, TestSet> {};
|
||||
struct PropertiesMap : public
|
||||
std::map<int, cmCTestTestHandler::cmCTestTestProperties*> {};
|
||||
|
||||
cmCTestMultiProcessHandler();
|
||||
// Set the tests
|
||||
void SetTests(TestMap& tests,
|
||||
std::map<int, cmStdString>& testNames);
|
||||
void SetTests(TestMap& tests, PropertiesMap& properties);
|
||||
// Set the max number of tests that can be run at the same time.
|
||||
void SetParallelLevel(size_t);
|
||||
void RunTests();
|
||||
void PrintTests();
|
||||
void SetCTestCommand(const char* c) { this->CTestCommand = c;}
|
||||
void SetTestCacheFile(const char* c) { this->CTestCacheFile = c;}
|
||||
//void SetCTestCommand(const char* c) { this->CTestCommand = c;}
|
||||
//void SetTestCacheFile(const char* c) { this->CTestCacheFile = c;}
|
||||
void SetPassFailVectors(std::vector<cmStdString>* passed,
|
||||
std::vector<cmStdString>* failed)
|
||||
{
|
||||
|
@ -51,7 +53,14 @@ public:
|
|||
{
|
||||
this->TestResults = r;
|
||||
}
|
||||
|
||||
void SetCTest(cmCTest* ctest) { this->CTest = ctest;}
|
||||
|
||||
void SetTestHandler(cmCTestTestHandler * handler)
|
||||
{ this->TestHandler = handler; }
|
||||
|
||||
cmCTestTestHandler * GetTestHandler()
|
||||
{ return this->TestHandler; }
|
||||
protected:
|
||||
cmCTest* CTest;
|
||||
// Start the next test or tests as many as are allowed by
|
||||
|
@ -59,24 +68,25 @@ protected:
|
|||
void StartNextTests();
|
||||
void StartTestProcess(int test);
|
||||
bool StartTest(int test);
|
||||
void EndTest(cmProcess*);
|
||||
//void EndTest(cmProcess*);
|
||||
// Return true if there are still tests running
|
||||
// check all running processes for output and exit case
|
||||
bool CheckOutput();
|
||||
// map from test number to set of depend tests
|
||||
TestMap Tests;
|
||||
std::map<int, cmStdString> TestNames;
|
||||
//list of test properties (indices concurrent to the test map)
|
||||
PropertiesMap Properties;
|
||||
std::map<int, bool> TestRunningMap;
|
||||
std::map<int, bool> TestFinishMap;
|
||||
std::map<int, cmStdString> TestOutput;
|
||||
std::string CTestCommand;
|
||||
std::string CTestCacheFile;
|
||||
//std::string CTestCommand;
|
||||
//std::string CTestCacheFile;
|
||||
std::vector<cmStdString>* Passed;
|
||||
std::vector<cmStdString>* Failed;
|
||||
std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
|
||||
int ProcessId;
|
||||
size_t ParallelLevel; // max number of process that can be run at once
|
||||
std::set<cmProcess*> RunningTests; // current running tests
|
||||
std::set<cmCTestRunTest*> RunningTests; // current running tests
|
||||
cmCTestTestHandler * TestHandler;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,150 +21,52 @@
|
|||
|
||||
cmCTestRunTest::cmCTestRunTest()
|
||||
{
|
||||
this->OptimizeForCTest = true;
|
||||
cmCTestTestHandler::cmCTestTestResult result;
|
||||
this->TestResult = result;
|
||||
}
|
||||
|
||||
cmCTestRunTest::~cmCTestRunTest()
|
||||
{
|
||||
}
|
||||
|
||||
void cmCTestRunTest::SetTestHandler(cmCTestTestHandler * handler)
|
||||
bool cmCTestRunTest::IsRunning()
|
||||
{
|
||||
this->TestHandler = handler;
|
||||
this->CTest = handler->CTest;
|
||||
return this->TestProcess->IsRunning();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Executes a test. Returns whether it passed or failed
|
||||
bool cmCTestRunTest::Execute()
|
||||
//---------------------------------------------------------
|
||||
//waits .1 sec for output from this process.
|
||||
void cmCTestRunTest::CheckOutput()
|
||||
{
|
||||
const std::string& testname = this->TestProperties->Name;
|
||||
std::vector<std::string>& args = this->TestProperties->Args;
|
||||
this->TestResult.Properties = this->TestProperties;
|
||||
this->TestResult.ExecutionTime = 0;
|
||||
this->TestResult.ReturnValue = -1;
|
||||
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
|
||||
this->TestResult.TestCount = this->TestProperties->Index;
|
||||
this->TestResult.Name = testname;
|
||||
this->TestResult.Path = this->TestProperties->Directory.c_str();
|
||||
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3)
|
||||
<< this->TestProperties->Index << "/");
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3)
|
||||
<< this->TestHandler->TotalNumberOfTests << " ");
|
||||
if ( this->TestHandler->MemCheck )
|
||||
std::string out, err;
|
||||
int pipe = this->TestProcess->CheckOutput(.1, out, err);
|
||||
if(pipe == cmsysProcess_Pipe_STDOUT)
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
this->GetIndex() << ": " << out << std::endl);
|
||||
this->ProcessOutput += out;
|
||||
this->ProcessOutput += "\n";
|
||||
}
|
||||
else
|
||||
else if(pipe == cmsysProcess_Pipe_STDERR)
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
this->GetIndex() << ": " << err << std::endl);
|
||||
this->ProcessOutput += err;
|
||||
this->ProcessOutput += "\n";
|
||||
}
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
|
||||
const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
|
||||
std::string outname = testname + " ";
|
||||
outname.resize(maxTestNameWidth, '.');
|
||||
*this->TestHandler->LogFile << this->TestProperties->Index << "/"
|
||||
<< this->TestHandler->TotalNumberOfTests << " Testing: "
|
||||
<< testname << std::endl;
|
||||
}
|
||||
|
||||
if ( this->CTest->GetShowOnly() )
|
||||
//---------------------------------------------------------
|
||||
bool cmCTestRunTest::EndTest()
|
||||
{
|
||||
//restore the old environment
|
||||
if (this->ModifyEnv)
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
|
||||
cmSystemTools::RestoreEnv(this->OrigEnv);
|
||||
}
|
||||
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->TestHandler->FindTheExecutable(args[1].c_str());
|
||||
std::string testCommand
|
||||
= cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
|
||||
|
||||
// continue if we did not find the executable
|
||||
if (testCommand == "")
|
||||
{
|
||||
*this->TestHandler->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);
|
||||
this->TestResult.Output = "Unable to find executable: " + args[1];
|
||||
if ( !this->CTest->GetShowOnly() )
|
||||
{
|
||||
this->TestResult.FullCommandLine = actualCommand;
|
||||
this->TestHandler->TestResults.push_back( this->TestResult );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// add the arguments
|
||||
std::vector<std::string>::const_iterator j = args.begin();
|
||||
++j; // skip test name
|
||||
++j; // skip command as it is in actualCommand
|
||||
std::vector<const char*> arguments;
|
||||
this->TestHandler->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->TestHandler->MemCheck?"MemCheck":"Test")
|
||||
<< " command: " << testCommand
|
||||
<< std::endl);
|
||||
*this->TestHandler->LogFile << this->TestProperties->Index << "/"
|
||||
<< this->TestHandler->TotalNumberOfTests
|
||||
<< " Test: " << testname.c_str() << std::endl;
|
||||
*this->TestHandler->LogFile << "Command: ";
|
||||
std::vector<cmStdString>::size_type ll;
|
||||
for ( ll = 0; ll < arguments.size()-1; ll ++ )
|
||||
{
|
||||
*this->TestHandler->LogFile << "\"" << arguments[ll] << "\" ";
|
||||
}
|
||||
*this->TestHandler->LogFile
|
||||
<< std::endl
|
||||
<< "Directory: " << this->TestProperties->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->RunTestProcess(arguments, &output, &retVal,
|
||||
this->TestHandler->LogFile,
|
||||
this->TestProperties->Timeout,
|
||||
&this->TestProperties->Environment);
|
||||
this->ProcessOutput = output; //save process output in the object
|
||||
}
|
||||
|
||||
clock_finish = cmSystemTools::GetTime();
|
||||
|
||||
this->TestResult.ExecutionTime = (double)(clock_finish - clock_start);
|
||||
this->TestResult.FullCommandLine = testCommand;
|
||||
this->WriteLogOutputTop();
|
||||
std::string reason;
|
||||
|
||||
bool passed = true;
|
||||
|
||||
int res = this->TestProcess->GetProcessStatus();
|
||||
int retVal = this->TestProcess->GetExitValue();
|
||||
if ( !this->CTest->GetShowOnly() )
|
||||
{
|
||||
std::vector<std::pair<cmsys::RegularExpression,
|
||||
|
@ -177,7 +79,7 @@ bool cmCTestRunTest::Execute()
|
|||
passIt != this->TestProperties->RequiredRegularExpressions.end();
|
||||
++ passIt )
|
||||
{
|
||||
if ( passIt->first.find(output.c_str()) )
|
||||
if ( passIt->first.find(this->ProcessOutput.c_str()) )
|
||||
{
|
||||
found = true;
|
||||
reason = "Required regular expression found.";
|
||||
|
@ -204,7 +106,7 @@ bool cmCTestRunTest::Execute()
|
|||
passIt != this->TestProperties->ErrorRegularExpressions.end();
|
||||
++ passIt )
|
||||
{
|
||||
if ( passIt->first.find(output.c_str()) )
|
||||
if ( passIt->first.find(this->ProcessOutput.c_str()) )
|
||||
{
|
||||
reason = "Error regular expression found in output.";
|
||||
reason += " Regex=[";
|
||||
|
@ -214,7 +116,6 @@ bool cmCTestRunTest::Execute()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res == cmsysProcess_State_Exited)
|
||||
{
|
||||
bool success =
|
||||
|
@ -224,13 +125,12 @@ bool cmCTestRunTest::Execute()
|
|||
|| (!success && this->TestProperties->WillFail))
|
||||
{
|
||||
this->TestResult.Status = cmCTestTestHandler::COMPLETED;
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed " );
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed " );
|
||||
}
|
||||
else
|
||||
{
|
||||
this->TestResult.Status = cmCTestTestHandler::FAILED;
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT,
|
||||
"***Failed " << reason );
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason );
|
||||
}
|
||||
}
|
||||
else if ( res == cmsysProcess_State_Expired )
|
||||
|
@ -273,28 +173,29 @@ bool cmCTestRunTest::Execute()
|
|||
passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED;
|
||||
|
||||
char buf[1024];
|
||||
sprintf(buf, "%6.2f sec", this->TestResult.ExecutionTime);
|
||||
sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime());
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n" );
|
||||
if ( this->TestHandler->LogFile )
|
||||
{
|
||||
*this->TestHandler->LogFile << "\nTest time = " << buf << std::endl;
|
||||
*this->TestHandler->LogFile << "Test time = " << buf << std::endl;
|
||||
}
|
||||
this->DartProcessing(output);
|
||||
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)
|
||||
{
|
||||
if ( this->TestResult.Status == cmCTestTestHandler::COMPLETED )
|
||||
{
|
||||
this->TestHandler->CleanTestOutput(output, static_cast<size_t>
|
||||
(this->TestHandler->CustomMaximumPassedTestOutputSize));
|
||||
this->TestHandler->CleanTestOutput(this->ProcessOutput,
|
||||
static_cast<size_t>
|
||||
(this->TestHandler->CustomMaximumPassedTestOutputSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->TestHandler->CleanTestOutput(output, static_cast<size_t>
|
||||
(this->TestHandler->CustomMaximumFailedTestOutputSize));
|
||||
this->TestHandler->CleanTestOutput(this->ProcessOutput,
|
||||
static_cast<size_t>
|
||||
(this->TestHandler->CustomMaximumFailedTestOutputSize));
|
||||
}
|
||||
}
|
||||
this->TestResult.Reason = reason;
|
||||
|
@ -308,7 +209,7 @@ bool cmCTestRunTest::Execute()
|
|||
reasonType = "Test Fail Reason";
|
||||
pass = false;
|
||||
}
|
||||
double ttime = clock_finish - clock_start;
|
||||
double ttime = this->TestProcess->GetTotalTime();
|
||||
int hours = static_cast<int>(ttime / (60 * 60));
|
||||
int minutes = static_cast<int>(ttime / 60) % 60;
|
||||
int seconds = static_cast<int>(ttime) % 60;
|
||||
|
@ -333,34 +234,99 @@ bool cmCTestRunTest::Execute()
|
|||
*this->TestHandler->LogFile << "Test Failed.\n";
|
||||
}
|
||||
}
|
||||
*this->TestHandler->LogFile << "\"" << testname.c_str() << "\" end time: "
|
||||
<< this->CTest->CurrentTime() << std::endl
|
||||
<< "\"" << testname.c_str() << "\" time elapsed: "
|
||||
*this->TestHandler->LogFile << "\"" << this->TestProperties->Name.c_str()
|
||||
<< "\" end time: " << this->CTest->CurrentTime() << std::endl
|
||||
<< "\"" << this->TestProperties->Name.c_str() << "\" time elapsed: "
|
||||
<< buffer << std::endl
|
||||
<< "----------------------------------------------------------"
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
this->TestResult.Output = output;
|
||||
this->TestResult.ReturnValue = retVal;
|
||||
this->TestResult.Output = this->ProcessOutput;
|
||||
this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
|
||||
this->TestResult.CompletionStatus = "Completed";
|
||||
this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime();
|
||||
this->TestHandler->TestResults.push_back( this->TestResult );
|
||||
|
||||
delete this->TestProcess;
|
||||
return passed;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void cmCTestRunTest::DartProcessing(std::string& output)
|
||||
void cmCTestRunTest::SetTestHandler(cmCTestTestHandler * handler)
|
||||
{
|
||||
if (!output.empty() && output.find("<DartMeasurement") != output.npos)
|
||||
this->TestHandler = handler;
|
||||
this->CTest = handler->CTest;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Starts the execution of a test. Returns once it has started
|
||||
bool cmCTestRunTest::StartTest()
|
||||
{
|
||||
std::vector<std::string>& args = this->TestProperties->Args;
|
||||
this->TestResult.Properties = this->TestProperties;
|
||||
this->TestResult.ExecutionTime = 0;
|
||||
this->TestResult.ReturnValue = -1;
|
||||
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
|
||||
this->TestResult.TestCount = this->TestProperties->Index;
|
||||
this->TestResult.Name = this->TestProperties->Name;
|
||||
this->TestResult.Path = this->TestProperties->Directory.c_str();
|
||||
|
||||
// find the test executable
|
||||
this->ActualCommand
|
||||
= this->TestHandler->FindTheExecutable(args[1].c_str());
|
||||
this->TestCommand
|
||||
= cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str());
|
||||
|
||||
// continue if we did not find the executable
|
||||
if (this->TestCommand == "")
|
||||
{
|
||||
if (this->TestHandler->DartStuff.find(output.c_str()))
|
||||
*this->TestHandler->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);
|
||||
this->TestResult.Output = "Unable to find executable: " + args[1];
|
||||
if ( !this->CTest->GetShowOnly() )
|
||||
{
|
||||
this->TestResult.FullCommandLine = this->ActualCommand;
|
||||
this->TestHandler->TestResults.push_back( this->TestResult );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an executable command and put the stdout in output.
|
||||
*/
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
|
||||
<< this->Index << ": "
|
||||
<< (this->TestHandler->MemCheck?"MemCheck":"Test")
|
||||
<< " command: " << this->TestCommand
|
||||
<< std::endl);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void cmCTestRunTest::DartProcessing()
|
||||
{
|
||||
if (!this->ProcessOutput.empty() &&
|
||||
this->ProcessOutput.find("<DartMeasurement") != this->ProcessOutput.npos)
|
||||
{
|
||||
if (this->TestHandler->DartStuff.find(this->ProcessOutput.c_str()))
|
||||
{
|
||||
std::string dartString = this->TestHandler->DartStuff.match(1);
|
||||
// keep searching and replacing until none are left
|
||||
while (this->TestHandler->DartStuff1.find(output.c_str()))
|
||||
while (this->TestHandler->DartStuff1.find(this->ProcessOutput.c_str()))
|
||||
{
|
||||
// replace the exact match for the string
|
||||
cmSystemTools::ReplaceString(output,
|
||||
cmSystemTools::ReplaceString(this->ProcessOutput,
|
||||
this->TestHandler->DartStuff1.match(1).c_str(), "");
|
||||
}
|
||||
this->TestResult.RegressionImages
|
||||
|
@ -370,13 +336,27 @@ void cmCTestRunTest::DartProcessing(std::string& output)
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int cmCTestRunTest::RunTestProcess(std::vector<const char*> argv,
|
||||
std::string* output, int *retVal,
|
||||
std::ostream* log, double testTimeOut,
|
||||
bool cmCTestRunTest::CreateProcess(std::string command,
|
||||
std::vector<std::string> args,
|
||||
double testTimeOut,
|
||||
std::vector<std::string>* environment)
|
||||
{
|
||||
std::vector<std::string> commandArgs;
|
||||
std::vector<std::string>::iterator i = args.begin();
|
||||
|
||||
++i; //skip test name
|
||||
++i; //skip executable name
|
||||
for(; i != args.end(); ++i)
|
||||
{
|
||||
commandArgs.push_back(*i);
|
||||
}
|
||||
this->TestProcess = new cmProcess;
|
||||
this->TestProcess->SetId(this->Index);
|
||||
this->TestProcess->SetCommand(command.c_str());
|
||||
this->TestProcess->SetCommandArguments(commandArgs);
|
||||
|
||||
std::vector<std::string> origEnv;
|
||||
bool modifyEnv = (environment && environment->size()>0);
|
||||
this->ModifyEnv = (environment && environment->size()>0);
|
||||
|
||||
// determine how much time we have
|
||||
double timeout = this->CTest->GetRemainingTimeAllowed() - 120;
|
||||
|
@ -395,154 +375,89 @@ int cmCTestRunTest::RunTestProcess(std::vector<const char*> argv,
|
|||
{
|
||||
timeout = 1;
|
||||
}
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
"Test timeout computed to be: " << timeout << "\n");
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": "
|
||||
<< "Test timeout computed to be: " << timeout << "\n");
|
||||
|
||||
if(cmSystemTools::SameFile(argv[0], this->CTest->CTestSelf.c_str()) &&
|
||||
!this->CTest->ForceNewCTestProcess &&
|
||||
this->OptimizeForCTest)
|
||||
if (this->ModifyEnv)
|
||||
{
|
||||
cmCTest inst;
|
||||
inst.ConfigType = this->CTest->ConfigType;
|
||||
inst.TimeOut = timeout;
|
||||
|
||||
// Capture output of the child ctest.
|
||||
cmOStringStream oss;
|
||||
inst.SetStreams(&oss, &oss);
|
||||
|
||||
std::vector<std::string> args;
|
||||
for(unsigned int i =0; i < argv.size(); ++i)
|
||||
{
|
||||
if(argv[i])
|
||||
{
|
||||
// make sure we pass the timeout in for any build and test
|
||||
// invocations. Since --build-generator is required this is a
|
||||
// good place to check for it, and to add the arguments in
|
||||
if (strcmp(argv[i],"--build-generator") == 0 && timeout)
|
||||
{
|
||||
args.push_back("--test-timeout");
|
||||
cmOStringStream msg;
|
||||
msg << timeout;
|
||||
args.push_back(msg.str());
|
||||
}
|
||||
args.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
if ( log )
|
||||
{
|
||||
*log << "* Run internal CTest" << std::endl;
|
||||
}
|
||||
std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
|
||||
|
||||
if (modifyEnv)
|
||||
{
|
||||
origEnv = cmSystemTools::AppendEnv(environment);
|
||||
}
|
||||
|
||||
*retVal = inst.Run(args, output);
|
||||
*output += oss.str();
|
||||
if ( log )
|
||||
{
|
||||
*log << output->c_str();
|
||||
}
|
||||
cmSystemTools::ChangeDirectory(oldpath.c_str());
|
||||
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
"Internal cmCTest object used to run test." << std::endl
|
||||
<< *output << std::endl);
|
||||
|
||||
if (modifyEnv)
|
||||
{
|
||||
cmSystemTools::RestoreEnv(origEnv);
|
||||
}
|
||||
|
||||
return cmsysProcess_State_Exited;
|
||||
}
|
||||
std::vector<char> tempOutput;
|
||||
if ( output )
|
||||
{
|
||||
*output = "";
|
||||
this->OrigEnv = cmSystemTools::AppendEnv(environment);
|
||||
}
|
||||
|
||||
if (modifyEnv)
|
||||
{
|
||||
origEnv = cmSystemTools::AppendEnv(environment);
|
||||
}
|
||||
|
||||
cmsysProcess* cp = cmsysProcess_New();
|
||||
cmsysProcess_SetCommand(cp, &*argv.begin());
|
||||
cmCTestLog(this->CTest, DEBUG, "Command is: " << argv[0] << std::endl);
|
||||
if(cmSystemTools::GetRunCommandHideConsole())
|
||||
{
|
||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
||||
}
|
||||
|
||||
cmsysProcess_SetTimeout(cp, timeout);
|
||||
cmsysProcess_Execute(cp);
|
||||
|
||||
char* data;
|
||||
int length;
|
||||
while(cmsysProcess_WaitForData(cp, &data, &length, 0))
|
||||
{
|
||||
if ( output )
|
||||
{
|
||||
tempOutput.insert(tempOutput.end(), data, data+length);
|
||||
}
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
cmCTestLogWrite(data, length));
|
||||
if ( log )
|
||||
{
|
||||
log->write(data, length);
|
||||
}
|
||||
}
|
||||
|
||||
cmsysProcess_WaitForExit(cp, 0);
|
||||
if(output && tempOutput.begin() != tempOutput.end())
|
||||
{
|
||||
//We are waiting for exit before finally appending to the output
|
||||
output->append(&*tempOutput.begin(), tempOutput.size());
|
||||
}
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
|
||||
<< std::endl);
|
||||
|
||||
int result = cmsysProcess_GetState(cp);
|
||||
|
||||
if(result == cmsysProcess_State_Exited)
|
||||
{
|
||||
*retVal = cmsysProcess_GetExitValue(cp);
|
||||
if(*retVal != 0 && this->CTest->OutputTestOutputOnTestFailure)
|
||||
{
|
||||
this->CTest->OutputTestErrors(tempOutput);
|
||||
}
|
||||
}
|
||||
else if(result == cmsysProcess_State_Exception)
|
||||
{
|
||||
if(this->CTest->OutputTestOutputOnTestFailure)
|
||||
{
|
||||
this->CTest->OutputTestErrors(tempOutput);
|
||||
}
|
||||
*retVal = cmsysProcess_GetExitException(cp);
|
||||
std::string outerr = "\n*** Exception executing: ";
|
||||
outerr += cmsysProcess_GetExceptionString(cp);
|
||||
*output += outerr;
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, outerr.c_str()
|
||||
<< std::endl << std::flush);
|
||||
}
|
||||
else if(result == cmsysProcess_State_Error)
|
||||
{
|
||||
std::string outerr = "\n*** ERROR executing: ";
|
||||
outerr += cmsysProcess_GetErrorString(cp);
|
||||
*output += outerr;
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, outerr.c_str()
|
||||
<< std::endl << std::flush);
|
||||
}
|
||||
cmsysProcess_Delete(cp);
|
||||
|
||||
if (modifyEnv)
|
||||
{
|
||||
cmSystemTools::RestoreEnv(origEnv);
|
||||
}
|
||||
|
||||
return result;
|
||||
return this->TestProcess->StartProcess();
|
||||
}
|
||||
|
||||
void cmCTestRunTest::WriteLogOutputTop()
|
||||
{
|
||||
/* Not sure whether we want to prepend the test index anymore
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3)
|
||||
<< this->Index << ": ");*/
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3)
|
||||
<< this->TestProperties->Index << "/");
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3)
|
||||
<< this->TestHandler->TotalNumberOfTests << " ");
|
||||
if ( this->TestHandler->MemCheck )
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
|
||||
}
|
||||
else
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
|
||||
}
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
|
||||
const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
|
||||
std::string outname = this->TestProperties->Name + " ";
|
||||
outname.resize(maxTestNameWidth, '.');
|
||||
|
||||
// add the arguments
|
||||
std::vector<std::string>::const_iterator j =
|
||||
this->TestProperties->Args.begin();
|
||||
++j; // skip test name
|
||||
++j; // skip command as it is in actualCommand
|
||||
std::vector<const char*> arguments;
|
||||
this->TestHandler->GenerateTestCommand(arguments);
|
||||
arguments.push_back(this->ActualCommand.c_str());
|
||||
for(;j != this->TestProperties->Args.end(); ++j)
|
||||
{
|
||||
this->TestCommand += " ";
|
||||
this->TestCommand += cmSystemTools::EscapeSpaces(j->c_str());
|
||||
arguments.push_back(j->c_str());
|
||||
}
|
||||
arguments.push_back(0);
|
||||
this->TestResult.FullCommandLine = this->TestCommand;
|
||||
|
||||
*this->TestHandler->LogFile << this->TestProperties->Index << "/"
|
||||
<< this->TestHandler->TotalNumberOfTests << " Testing: "
|
||||
<< this->TestProperties->Name << std::endl;
|
||||
*this->TestHandler->LogFile << this->TestProperties->Index << "/"
|
||||
<< this->TestHandler->TotalNumberOfTests
|
||||
<< " Test: " << this->TestProperties->Name.c_str() << std::endl;
|
||||
*this->TestHandler->LogFile << "Command: ";
|
||||
std::vector<cmStdString>::size_type ll;
|
||||
for ( ll = 0; ll < arguments.size()-1; ll ++ )
|
||||
{
|
||||
*this->TestHandler->LogFile << "\"" << arguments[ll] << "\" ";
|
||||
}
|
||||
*this->TestHandler->LogFile << std::endl
|
||||
<< "Directory: " << this->TestProperties->Directory << std::endl
|
||||
<< "\"" << this->TestProperties->Name.c_str() << "\" start time: "
|
||||
<< this->StartTime << std::endl;
|
||||
|
||||
*this->TestHandler->LogFile
|
||||
<< "Output:" << std::endl
|
||||
<< "----------------------------------------------------------"
|
||||
<< std::endl;
|
||||
*this->TestHandler->LogFile
|
||||
<< this->ProcessOutput.c_str() << "<end of output>" << 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 "
|
||||
<< this->TestProperties->Name.c_str() << " ... ");
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <cmStandardIncludes.h>
|
||||
#include <cmCTestTestHandler.h>
|
||||
#include <cmProcess.h>
|
||||
|
||||
/** \class cmRunTest
|
||||
* \brief represents a single test to be run
|
||||
|
@ -38,44 +39,53 @@ public:
|
|||
{ return this->TestProperties; }
|
||||
|
||||
void SetTestHandler(cmCTestTestHandler * handler);
|
||||
|
||||
void SetOptimizeForCTest(bool optimize)
|
||||
{ this->OptimizeForCTest = optimize; }
|
||||
|
||||
bool GetOptimizeForCTest()
|
||||
{ return this->OptimizeForCTest; }
|
||||
void SetIndex(int i) { this->Index = i; }
|
||||
|
||||
std::string GetProcessOutput()
|
||||
{ return this->ProcessOutput; }
|
||||
void SetCTest(cmCTest * ct) { this->CTest = ct; }
|
||||
|
||||
//Provides a handle to the log stream in case someone wants
|
||||
// to asynchronously process the log
|
||||
std::ostream * GetLogStream()
|
||||
{ return this->TestHandler->LogFile; }
|
||||
int GetIndex() { return this->Index; }
|
||||
|
||||
std::string GetProcessOutput() { return this->ProcessOutput; }
|
||||
|
||||
cmCTestTestHandler::cmCTestTestResult GetTestResults()
|
||||
{ return this->TestResult; }
|
||||
|
||||
//Runs the test
|
||||
bool Execute();
|
||||
bool IsRunning();
|
||||
void CheckOutput();
|
||||
//launch the test process, return whether it started correctly
|
||||
bool StartTest();
|
||||
//capture the test results and send them back to the test handler
|
||||
bool EndTest();
|
||||
protected:
|
||||
void DartProcessing(std::string& output);
|
||||
int RunTestProcess(std::vector<const char*> argv,
|
||||
std::string* output, int *retVal,
|
||||
std::ostream* log, double testTimeOut,
|
||||
void DartProcessing();
|
||||
bool CreateProcess(std::string executable,
|
||||
std::vector<std::string> args,
|
||||
double testTimeOut,
|
||||
std::vector<std::string>* environment);
|
||||
private:
|
||||
cmCTestTestHandler::cmCTestTestProperties * TestProperties;
|
||||
//Pointer back to the "parent"; the handler that invoked this test run
|
||||
cmCTestTestHandler * TestHandler;
|
||||
cmCTest * CTest;
|
||||
cmProcess * TestProcess;
|
||||
//If the executable to run is ctest, don't create a new process;
|
||||
//just instantiate a new cmTest. (Can be disabled for a single test
|
||||
//if this option is set to false.)
|
||||
bool OptimizeForCTest;
|
||||
//bool OptimizeForCTest;
|
||||
|
||||
//flag for whether the env was modified for this run
|
||||
bool ModifyEnv;
|
||||
//stores the original environment if we are modifying it
|
||||
std::vector<std::string> OrigEnv;
|
||||
std::string ProcessOutput;
|
||||
//The test results
|
||||
cmCTestTestHandler::cmCTestTestResult TestResult;
|
||||
int Index;
|
||||
std::string StartTime;
|
||||
std::string TestCommand;
|
||||
std::string ActualCommand;
|
||||
void WriteLogOutputTop();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -543,8 +543,15 @@ int cmCTestTestHandler::ProcessHandler()
|
|||
std::vector<cmStdString> passed;
|
||||
std::vector<cmStdString> failed;
|
||||
int total;
|
||||
|
||||
//start the real time clock
|
||||
double clock_start, clock_finish;
|
||||
clock_start = cmSystemTools::GetTime();
|
||||
|
||||
this->ProcessDirectory(passed, failed);
|
||||
|
||||
clock_finish = cmSystemTools::GetTime();
|
||||
|
||||
total = int(passed.size()) + int(failed.size());
|
||||
|
||||
if (total == 0)
|
||||
|
@ -591,10 +598,15 @@ int cmCTestTestHandler::ProcessHandler()
|
|||
totalTestTime += result->ExecutionTime;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
sprintf(buf, "%6.2f sec", totalTestTime);
|
||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time = "
|
||||
<< buf << "\n" );
|
||||
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" );
|
||||
|
||||
}
|
||||
|
||||
|
@ -1528,21 +1540,28 @@ std::string cmCTestTestHandler::SaveTestList()
|
|||
return fname;
|
||||
}
|
||||
|
||||
void cmCTestTestHandler::ProcessParallel(std::vector<cmStdString> &passed,
|
||||
void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
|
||||
std::vector<cmStdString> &failed)
|
||||
{
|
||||
this->ComputeTestList();
|
||||
cmCTestMultiProcessHandler parallel;
|
||||
parallel.SetCTest(this->CTest);
|
||||
parallel.SetParallelLevel(this->CTest->GetParallelLevel());
|
||||
parallel.SetParallelLevel(this->CTest->GetParallelLevel());
|
||||
parallel.SetTestHandler(this);
|
||||
|
||||
*this->LogFile << "Start testing: "
|
||||
<< this->CTest->CurrentTime() << std::endl
|
||||
<< "----------------------------------------------------------"
|
||||
<< std::endl;
|
||||
|
||||
cmCTestMultiProcessHandler::TestSet depends;
|
||||
cmCTestMultiProcessHandler::TestMap tests;
|
||||
std::map<int, cmStdString> testnames;
|
||||
cmCTestMultiProcessHandler::PropertiesMap properties;
|
||||
for (ListOfTests::iterator it = this->TestList.begin();
|
||||
it != this->TestList.end(); it ++ )
|
||||
{
|
||||
cmCTestTestProperties& p = *it;
|
||||
testnames[p.Index] = p.Name;
|
||||
|
||||
if(p.Depends.size())
|
||||
{
|
||||
for(std::vector<std::string>::iterator i = p.Depends.begin();
|
||||
|
@ -1560,76 +1579,16 @@ void cmCTestTestHandler::ProcessParallel(std::vector<cmStdString> &passed,
|
|||
}
|
||||
}
|
||||
tests[it->Index] = depends;
|
||||
properties[it->Index] = &*it;
|
||||
}
|
||||
parallel.SetCTestCommand(this->CTest->GetCTestExecutable());
|
||||
parallel.SetTests(tests, testnames);
|
||||
std::string fname = this->SaveTestList();
|
||||
parallel.SetTestCacheFile(fname.c_str());
|
||||
parallel.SetTests(tests, properties);
|
||||
parallel.SetPassFailVectors(&passed, &failed);
|
||||
this->TestResults.clear();
|
||||
parallel.SetTestResults(&this->TestResults);
|
||||
parallel.RunTests();
|
||||
cmSystemTools::RemoveFile(fname.c_str());
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
|
||||
std::vector<cmStdString> &failed)
|
||||
{
|
||||
if(this->CTest->GetParallelLevel() > 0)
|
||||
{
|
||||
this->ProcessParallel(passed, failed);
|
||||
return;
|
||||
}
|
||||
// save the current working directory
|
||||
std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
|
||||
// compute the list of tests to run
|
||||
this->ComputeTestList();
|
||||
this->StartTest = this->CTest->CurrentTime();
|
||||
this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
|
||||
double elapsed_time_start = cmSystemTools::GetTime();
|
||||
*this->LogFile << "Start testing: " << this->StartTest << std::endl
|
||||
<< "----------------------------------------------------------"
|
||||
<< std::endl;
|
||||
std::string last_directory = "";
|
||||
|
||||
// run each test
|
||||
for (ListOfTests::iterator it = this->TestList.begin();
|
||||
it != this->TestList.end(); it ++ )
|
||||
{
|
||||
if (!(last_directory == it->Directory))
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
"Changing directory into " << it->Directory.c_str() << "\n");
|
||||
*this->LogFile << "Changing directory into: " << it->Directory.c_str()
|
||||
<< std::endl;
|
||||
last_directory = it->Directory;
|
||||
cmSystemTools::ChangeDirectory(it->Directory.c_str());
|
||||
}
|
||||
// process this one test
|
||||
cmCTestRunTest testRun;
|
||||
testRun.SetTestProperties(&(*it));
|
||||
testRun.SetTestHandler(this);
|
||||
|
||||
bool testPassed = testRun.Execute(); //run the test
|
||||
if(testPassed && !this->CTest->GetShowOnly())
|
||||
{
|
||||
passed.push_back(it->Name);
|
||||
}
|
||||
else if(!testPassed)
|
||||
{
|
||||
failed.push_back(it->Name);
|
||||
}
|
||||
}
|
||||
this->EndTest = this->CTest->CurrentTime();
|
||||
this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
|
||||
this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
|
||||
if ( this->LogFile )
|
||||
{
|
||||
*this->LogFile << "End testing: " << this->EndTest << std::endl;
|
||||
}
|
||||
cmSystemTools::ChangeDirectory(current_dir.c_str());
|
||||
*this->LogFile << "End testing: "
|
||||
<< this->CTest->CurrentTime() << std::endl;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -31,6 +31,7 @@ class cmMakefile;
|
|||
class cmCTestTestHandler : public cmCTestGenericHandler
|
||||
{
|
||||
friend class cmCTestRunTest;
|
||||
friend class cmCTestMultiProcessHandler;
|
||||
public:
|
||||
cmTypeMacro(cmCTestTestHandler, cmCTestGenericHandler);
|
||||
|
||||
|
@ -129,6 +130,7 @@ public:
|
|||
std::vector<std::string> &extraPaths,
|
||||
std::vector<std::string> &failed);
|
||||
|
||||
typedef std::vector<cmCTestTestProperties> ListOfTests;
|
||||
protected:
|
||||
// comput a final test list
|
||||
virtual int PreProcessHandler();
|
||||
|
@ -193,7 +195,6 @@ private:
|
|||
void ProcessDirectory(std::vector<cmStdString> &passed,
|
||||
std::vector<cmStdString> &failed);
|
||||
|
||||
typedef std::vector<cmCTestTestProperties> ListOfTests;
|
||||
/**
|
||||
* Get the list of tests in directory and subdirectories.
|
||||
*/
|
||||
|
@ -221,9 +222,6 @@ private:
|
|||
bool GetValue(const char* tag,
|
||||
double& value,
|
||||
std::ifstream& fin);
|
||||
// run in -j N mode
|
||||
void ProcessParallel(std::vector<cmStdString> &passed,
|
||||
std::vector<cmStdString> &failed);
|
||||
/**
|
||||
* Find the executable for a test
|
||||
*/
|
||||
|
|
|
@ -209,7 +209,7 @@ std::string cmCTest::DecodeURL(const std::string& in)
|
|||
cmCTest::cmCTest()
|
||||
{
|
||||
this->ParallelSubprocess = false;
|
||||
this->ParallelLevel = 0;
|
||||
this->ParallelLevel = 1;
|
||||
this->SubmitIndex = 0;
|
||||
this->ForceNewCTestProcess = false;
|
||||
this->TomorrowTag = false;
|
||||
|
@ -292,6 +292,11 @@ cmCTest::~cmCTest()
|
|||
this->SetOutputLogFileName(0);
|
||||
}
|
||||
|
||||
void cmCTest::SetParallelLevel(int level)
|
||||
{
|
||||
this->ParallelLevel = level < 1 ? 1 : level;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
cmCTest::Part cmCTest::GetPartFromName(const char* name)
|
||||
{
|
||||
|
|
|
@ -136,7 +136,7 @@ public:
|
|||
void SetTimeOut(double t) { this->TimeOut = t; }
|
||||
// how many test to run at the same time
|
||||
int GetParallelLevel() { return this->ParallelLevel; }
|
||||
void SetParallelLevel(int t) { this->ParallelLevel = t; }
|
||||
void SetParallelLevel(int);
|
||||
|
||||
bool GetParallelSubprocess() { return this->ParallelSubprocess; }
|
||||
void SetParallelSubprocess() { this->ParallelSubprocess = true; }
|
||||
|
|
Loading…
Reference in New Issue