Преглед изворни кода

Fixed ctest -N segfault issue. Further refactored ctest. Enabled failover for ctest

Zach Mullen пре 16 година
родитељ
комит
177edc5ed1

+ 0 - 6
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: "

+ 65 - 2
Source/CTest/cmCTestMultiProcessHandler.cxx

@@ -18,7 +18,8 @@
 #include "cmProcess.h"
 #include "cmStandardIncludes.h"
 #include "cmCTest.h"
-
+#include "cmSystemTools.h"
+#include <stdlib.h>
 
 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<cmCTestRunTest*>::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()
 {

+ 7 - 3
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<int, bool> TestRunningMap;
   std::map<int, bool> TestFinishMap;
   std::map<int, cmStdString> TestOutput;
-  //std::string CTestCommand;
-  //std::string CTestCacheFile;
   std::vector<cmStdString>* Passed;
   std::vector<cmStdString>* Failed;
   std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;

+ 98 - 112
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<std::pair<cmsys::RegularExpression,
+    std::string> >::iterator passIt;
+  bool forceFail = false;
+  if ( this->TestProperties->RequiredRegularExpressions.size() > 0 )
     {
-    std::vector<std::pair<cmsys::RegularExpression,
-      std::string> >::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()) )
-          {
-          found = true;
-          reason = "Required regular expression 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 )
+      if ( passIt->first.find(this->ProcessOutput.c_str()) )
         {
-        reason += passIt->second;
-        reason += "\n";
+        found = true;
+        reason = "Required regular expression found.";
         }
-      reason += "]";
       }
-    if ( this->TestProperties->ErrorRegularExpressions.size() > 0 )
+    if ( !found )
+      { 
+      reason = "Required regular expression not found.";
+      forceFail = true;
+      }
+    reason +=  "Regex=["; 
+    for ( passIt = this->TestProperties->RequiredRegularExpressions.begin();
+          passIt != this->TestProperties->RequiredRegularExpressions.end();
+          ++ passIt )
       {
-      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 += passIt->second;
+      reason += "\n";
       }
-    if (res == cmsysProcess_State_Exited)
+    reason += "]";
+    }
+  if ( this->TestProperties->ErrorRegularExpressions.size() > 0 )
+    {
+    for ( passIt = this->TestProperties->ErrorRegularExpressions.begin();
+          passIt != this->TestProperties->ErrorRegularExpressions.end();
+          ++ passIt )
       {
-      bool success = 
-        !forceFail &&  (retVal == 0 || 
-        this->TestProperties->RequiredRegularExpressions.size());
-      if((success && !this->TestProperties->WillFail) 
-        || (!success && this->TestProperties->WillFail))
+      if ( passIt->first.find(this->ProcessOutput.c_str()) )
         {
-        this->TestResult.Status = cmCTestTestHandler::COMPLETED;
-        cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Passed  " );
-        }
-      else
-        {
-        this->TestResult.Status = cmCTestTestHandler::FAILED;
-        cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed  " << reason );
+        reason = "Error regular expression found in output.";
+        reason += " Regex=[";
+        reason += passIt->second;
+        reason += "]";
+        forceFail = true;
         }
       }
-    else if ( res == cmsysProcess_State_Expired )
+    }
+  if (res == cmsysProcess_State_Exited)
+    {
+    bool success = 
+      !forceFail &&  (retVal == 0 || 
+      this->TestProperties->RequiredRegularExpressions.size());
+    if((success && !this->TestProperties->WillFail) 
+      || (!success && this->TestProperties->WillFail))
       {
-      cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout");
-      this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
+      this->TestResult.Status = cmCTestTestHandler::COMPLETED;
+      cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Passed  " );
       }
-    else if ( res == cmsysProcess_State_Exception )
+    else
       {
-      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;
-        }
+      this->TestResult.Status = cmCTestTestHandler::FAILED;
+      cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed  " << reason );
       }
-    else // if ( res == cmsysProcess_State_Error )
+    }
+  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, "***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() << "<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, HANDLER_OUTPUT, outname.c_str());
   cmCTestLog(this->CTest, DEBUG, "Testing " 
              << this->TestProperties->Name.c_str() << " ... ");
 }

+ 2 - 2
Source/CTest/cmCTestRunTest.h

@@ -63,7 +63,8 @@ protected:
                      std::vector<std::string> args,
                      double testTimeOut,
                      std::vector<std::string>* 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

+ 62 - 267
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<int>(percent + .5) << "% tests passed, "
-                 << failed.size() << " tests failed out of " 
-                 << total << std::endl); 
-      double totalTestTime = 0;
+    cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
+               << static_cast<int>(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" );
-      
+    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" );
 
     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<cmCTestTestHandler::cmCTestTestResult>::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<cmCTestTestHandler::cmCTestTestResult>::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<cmsys::RegularExpression, std::string> 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<cmsys::RegularExpression, std::string> 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<std::string>::iterator i = p.Args.begin();
-        i != p.Args.end(); ++i)
-      {
-      fout << i->c_str() << "\n";
-      }
-    fout << "Depends:\n" << p.Depends.size() << "\n";
-    for(std::vector<std::string>::iterator i = p.Depends.begin();
-        i != p.Depends.end(); ++i)
-      {
-      fout << i->c_str() << "\n";
-      }
-    std::vector<std::pair<cmsys::RegularExpression,
-      std::string> >::iterator regxi;
-    fout << "ErrorRegularExpressions:\n" << 
-      p.ErrorRegularExpressions.size() << "\n";
-    for(regxi  = p.ErrorRegularExpressions.begin(); 
-        regxi != p.ErrorRegularExpressions.end(); regxi++)
+    cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) 
+             << p.Index << "/");
+    cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) 
+             << total << " ");
+    if (this->MemCheck)
       {
-      fout << regxi->second << "\n";
+      cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
       }
-    fout << "RequiredRegularExpressions:\n" << 
-      p.RequiredRegularExpressions.size() << "\n";
-    for(regxi  = p.RequiredRegularExpressions.begin(); 
-        regxi != p.RequiredRegularExpressions.end(); regxi++)
+     else
       {
-      fout << regxi->second << "\n";
-      }
-    fout << "Measurements:\n" << 
-      p.Measurements.size() << "\n";
-    for(std::map<cmStdString, cmStdString>::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<std::string>::const_iterator e =
-          p.Environment.begin(); e != p.Environment.end(); ++e)
-      {
-      fout << *e << "\n";
-      }
-    fout << "Labels:\n" <<
-      p.Labels.size() << "\n";
-    for(std::vector<std::string>::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<cmStdString> &passed,
                                          std::vector<cmStdString> &failed)
 {
   this->ComputeTestList();
+
+  if(this->CTest->GetShowOnly())
+    {
+    this->PrintTestList();
+    return;
+    }
   cmCTestMultiProcessHandler parallel;
   parallel.SetCTest(this->CTest);
   parallel.SetParallelLevel(this->CTest->GetParallelLevel());

+ 1 - 4
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);

+ 7 - 24
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)

+ 6 - 12
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

+ 3 - 0
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 "