summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
authorZach Mullen <zach.mullen@kitware.com>2009-08-26 16:09:06 (GMT)
committerZach Mullen <zach.mullen@kitware.com>2009-08-26 16:09:06 (GMT)
commit8ffd8d0a03d68241ce4f5f8a9fd266bee1032e1d (patch)
tree744b5e713b143008ec4ddcd8670bd47082658c05 /Source/CTest
parent1171bcfc697f6196c8f31018153217e5de779e60 (diff)
downloadCMake-8ffd8d0a03d68241ce4f5f8a9fd266bee1032e1d.zip
CMake-8ffd8d0a03d68241ce4f5f8a9fd266bee1032e1d.tar.gz
CMake-8ffd8d0a03d68241ce4f5f8a9fd266bee1032e1d.tar.bz2
ENH: refactored ctest. All testing is now parallel. If no -j option is specified, defaults to a MP level of 1 (non parallel)
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx158
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.h32
-rw-r--r--Source/CTest/cmCTestRunTest.cxx481
-rw-r--r--Source/CTest/cmCTestRunTest.h46
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx103
-rw-r--r--Source/CTest/cmCTestTestHandler.h6
6 files changed, 322 insertions, 504 deletions
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 70ca4c0..328e2e5 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -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())
- {
- 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())
+ cmCTestRunTest* testRun = new cmCTestRunTest;
+ testRun->SetCTest(this->CTest);
+ testRun->SetTestHandler(this->TestHandler);
+ testRun->SetIndex(test);
+ testRun->SetTestProperties(this->Properties[test]);
+ if(testRun->StartTest())
{
- 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();
- i != finished.end(); ++i)
- {
- cmProcess* p = *i;
- this->EndTest(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)
+ for( std::vector<cmCTestRunTest*>::iterator i = finished.begin();
+ i != finished.end(); ++i)
{
- cres.Status = cmCTestTestHandler::FAILED;
- this->Failed->push_back(this->TestNames[test]);
- }
- else
+ 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)
{
- this->Passed->push_back(this->TestNames[test]);
+ j->second.erase(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;
}
- this->TestFinishMap[test] = true;
- this->TestRunningMap[test] = false;
- this->RunningTests.erase(p);
- delete p;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "finish test " << test << "\n");
+ return true;
}
-
void cmCTestMultiProcessHandler::PrintTests()
{
#undef cout
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index 75be542..413bff2 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -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
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index cd6112d..d444249 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -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 )
- {
- 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 = testname + " ";
- outname.resize(maxTestNameWidth, '.');
- *this->TestHandler->LogFile << this->TestProperties->Index << "/"
- << this->TestHandler->TotalNumberOfTests << " 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->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)
+ std::string out, err;
+ int pipe = this->TestProcess->CheckOutput(.1, out, err);
+ if(pipe == cmsysProcess_Pipe_STDOUT)
{
- testCommand += " ";
- testCommand += cmSystemTools::EscapeSpaces(j->c_str());
- arguments.push_back(j->c_str());
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->GetIndex() << ": " << out << std::endl);
+ this->ProcessOutput += out;
+ this->ProcessOutput += "\n";
}
- 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 ++ )
+ else if(pipe == cmsysProcess_Pipe_STDERR)
{
- *this->TestHandler->LogFile << "\"" << arguments[ll] << "\" ";
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->GetIndex() << ": " << err << std::endl);
+ this->ProcessOutput += err;
+ this->ProcessOutput += "\n";
}
- *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() )
+//---------------------------------------------------------
+bool cmCTestRunTest::EndTest()
+{
+ //restore the old environment
+ if (this->ModifyEnv)
{
- res = this->RunTestProcess(arguments, &output, &retVal,
- this->TestHandler->LogFile,
- this->TestProperties->Timeout,
- &this->TestProperties->Environment);
- this->ProcessOutput = output; //save process output in the object
+ cmSystemTools::RestoreEnv(this->OrigEnv);
}
-
- 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::SetTestHandler(cmCTestTestHandler * handler)
+{
+ 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 == "")
+ {
+ *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(std::string& output)
+void cmCTestRunTest::DartProcessing()
{
- if (!output.empty() && output.find("<DartMeasurement") != output.npos)
+ if (!this->ProcessOutput.empty() &&
+ this->ProcessOutput.find("<DartMeasurement") != this->ProcessOutput.npos)
{
- if (this->TestHandler->DartStuff.find(output.c_str()))
+ 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");
-
- if(cmSystemTools::SameFile(argv[0], this->CTest->CTestSelf.c_str()) &&
- !this->CTest->ForceNewCTestProcess &&
- this->OptimizeForCTest)
- {
- 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);
- }
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": "
+ << "Test timeout computed to be: " << timeout << "\n");
- return cmsysProcess_State_Exited;
- }
- std::vector<char> tempOutput;
- if ( output )
+ if (this->ModifyEnv)
{
- *output = "";
+ this->OrigEnv = cmSystemTools::AppendEnv(environment);
}
- if (modifyEnv)
+ 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 )
{
- origEnv = cmSystemTools::AppendEnv(environment);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
}
-
- cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
- cmCTestLog(this->CTest, DEBUG, "Command is: " << argv[0] << std::endl);
- if(cmSystemTools::GetRunCommandHideConsole())
+ else
{
- cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ 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, '.');
- cmsysProcess_SetTimeout(cp, timeout);
- cmsysProcess_Execute(cp);
-
- char* data;
- int length;
- while(cmsysProcess_WaitForData(cp, &data, &length, 0))
+ // 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)
{
- if ( output )
- {
- tempOutput.insert(tempOutput.end(), data, data+length);
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(data, length));
- if ( log )
- {
- log->write(data, length);
- }
+ this->TestCommand += " ";
+ this->TestCommand += cmSystemTools::EscapeSpaces(j->c_str());
+ arguments.push_back(j->c_str());
}
+ arguments.push_back(0);
+ this->TestResult.FullCommandLine = this->TestCommand;
- cmsysProcess_WaitForExit(cp, 0);
- if(output && tempOutput.begin() != tempOutput.end())
+ *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 ++ )
{
- //We are waiting for exit before finally appending to the output
- output->append(&*tempOutput.begin(), tempOutput.size());
+ *this->TestHandler->LogFile << "\"" << arguments[ll] << "\" ";
}
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
- << std::endl);
+ *this->TestHandler->LogFile << std::endl
+ << "Directory: " << this->TestProperties->Directory << std::endl
+ << "\"" << this->TestProperties->Name.c_str() << "\" start time: "
+ << this->StartTime << std::endl;
- int result = cmsysProcess_GetState(cp);
+ *this->TestHandler->LogFile
+ << "Output:" << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+ *this->TestHandler->LogFile
+ << this->ProcessOutput.c_str() << "<end of output>" << std::endl;
- 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)
+ if ( this->CTest->GetShowOnly() )
{
- 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);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
}
- cmsysProcess_Delete(cp);
-
- if (modifyEnv)
+ else
{
- cmSystemTools::RestoreEnv(origEnv);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
}
- return result;
+ cmCTestLog(this->CTest, DEBUG, "Testing "
+ << this->TestProperties->Name.c_str() << " ... ");
}
-
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 1438a60..72a108a 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -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; }
+
+ void SetCTest(cmCTest * ct) { this->CTest = ct; }
- std::string GetProcessOutput()
- { return this->ProcessOutput; }
+ int GetIndex() { return this->Index; }
- //Provides a handle to the log stream in case someone wants
- // to asynchronously process the log
- std::ostream * GetLogStream()
- { return this->TestHandler->LogFile; }
+ 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
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 62b111f..6df925c 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -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;
}
//----------------------------------------------------------------------
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 03ce285..a6b8e8e 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -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
*/