Added logic to check for cycles in the test dependency graph before any tests are run. Previously a cycle resulted in a segfault from stack overflow.

This commit is contained in:
Zach Mullen 2009-11-02 12:52:50 -05:00
parent 59f6f383e9
commit d47ada823a
2 changed files with 52 additions and 1 deletions

View File

@ -15,6 +15,7 @@
#include "cmCTest.h"
#include "cmSystemTools.h"
#include <stdlib.h>
#include <stack>
cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
{
@ -56,6 +57,10 @@ void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
void cmCTestMultiProcessHandler::RunTests()
{
this->CheckResume();
if(!this->CheckCycles())
{
return;
}
this->TestHandler->SetMaxIndex(this->FindMaxIndex());
this->StartNextTests();
while(this->Tests.size() != 0)
@ -340,7 +345,7 @@ void cmCTestMultiProcessHandler::PrintTestList()
this->TestHandler->SetMaxIndex(this->FindMaxIndex());
int count = 0;
for (PropertiesMap::iterator it = this->Properties.begin();
it != this->Properties.end(); it ++ )
it != this->Properties.end(); ++it)
{
count++;
cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
@ -433,3 +438,47 @@ int cmCTestMultiProcessHandler::FindMaxIndex()
}
return max;
}
//Returns true if no cycles exist in the dependency graph
bool cmCTestMultiProcessHandler::CheckCycles()
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Checking test dependency graph..." << std::endl);
for(TestMap::iterator it = this->Tests.begin();
it != this->Tests.end(); ++it)
{
//DFS from each element to itself
std::stack<int> s;
std::vector<int> visited;
s.push(it->first);
visited.push_back(it->first);
while(!s.empty())
{
int test = s.top();
s.pop();
for(TestSet::iterator d = this->Tests[test].begin();
d != this->Tests[test].end(); ++d)
{
s.push(*d);
for(std::vector<int>::iterator v = visited.begin();
v != visited.end(); ++v)
{
if(*v == *d)
{
//cycle exists
cmCTestLog(this->CTest, ERROR_MESSAGE, "Error: a cycle exists in "
"the test dependency graph for the test \""
<< this->Properties[*d]->Name << "\"." << std::endl
<< "Please fix the cycle and run ctest again." << std::endl);
return false;
}
}
visited.push_back(*d);
}
visited.pop_back();
}
}
return true;
}

View File

@ -76,6 +76,8 @@ protected:
void RemoveTest(int index);
//Check if we need to resume an interrupted test set
void CheckResume();
//Check if there are any circular dependencies
bool CheckCycles();
int FindMaxIndex();
inline size_t GetProcessorsUsed(int index);
// map from test number to set of depend tests