Checksums on CTest submit files, and retry timed out submissions.

This commit is contained in:
Zach Mullen 2010-06-03 10:34:34 -04:00
parent 7f619608d5
commit e525649a4e
7 changed files with 198 additions and 21 deletions

View File

@ -163,6 +163,11 @@ IF(BUILD_TESTING)
SET(DART_TESTING_TIMEOUT 1500 CACHE STRING
"Maximum time allowed before CTest will kill the test.")
SET(CTEST_SUBMIT_RETRY_DELAY 5 CACHE STRING
"How long to wait between timed-out CTest submissions.")
SET(CTEST_SUBMIT_RETRY_COUNT 3 CACHE STRING
"How many times to retry timed-out CTest submissions.")
FIND_PROGRAM(MEMORYCHECK_COMMAND
NAMES purify valgrind boundscheck
PATHS
@ -263,6 +268,8 @@ IF(BUILD_TESTING)
SLURM_SBATCH_COMMAND
SLURM_SRUN_COMMAND
SITE
CTEST_SUBMIT_RETRY_DELAY
CTEST_SUBMIT_RETRY_COUNT
)
# BUILDNAME
IF(NOT RUN_FROM_DART)

View File

@ -83,3 +83,7 @@ CurlOptions: @CTEST_CURL_OPTIONS@
# warning, if you add new options here that have to do with submit,
# you have to update cmCTestSubmitCommand.cxx
# For CTest submissions that timeout, these options
# specify behavior for retrying the submission
CTestRetryTime: @CTEST_SUBMIT_RETRY_DELAY@
CTestRetryCount: @CTEST_SUBMIT_RETRY_COUNT@

View File

@ -147,6 +147,11 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(this->Parts);
}
static_cast<cmCTestSubmitHandler*>(handler)->SetOption("RetryTime",
this->RetryDelay.c_str());
static_cast<cmCTestSubmitHandler*>(handler)->SetOption("RetryCount",
this->RetryCount.c_str());
return handler;
}
@ -169,6 +174,18 @@ bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
return true;
}
if(arg == "RETRY_COUNT")
{
this->ArgumentDoing = ArgumentDoingRetryCount;
return true;
}
if(arg == "RETRY_DELAY")
{
this->ArgumentDoing = ArgumentDoingRetryDelay;
return true;
}
// Look for other arguments.
return this->Superclass::CheckArgumentKeyword(arg);
}
@ -213,6 +230,16 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg)
return true;
}
if(this->ArgumentDoing == ArgumentDoingRetryCount)
{
this->RetryCount = arg;
}
if(this->ArgumentDoing == ArgumentDoingRetryDelay)
{
this->RetryDelay = arg;
}
// Look for other arguments.
return this->Superclass::CheckArgumentValue(arg);
}

View File

@ -29,6 +29,8 @@ public:
{
this->PartsMentioned = false;
this->FilesMentioned = false;
this->RetryCount = "";
this->RetryDelay = "";
}
/**
@ -92,6 +94,8 @@ protected:
{
ArgumentDoingParts = Superclass::ArgumentDoingLast1,
ArgumentDoingFiles,
ArgumentDoingRetryDelay,
ArgumentDoingRetryCount,
ArgumentDoingLast2
};
@ -99,6 +103,8 @@ protected:
std::set<cmCTest::Part> Parts;
bool FilesMentioned;
cmCTest::SetOfStrings Files;
std::string RetryCount;
std::string RetryDelay;
};

View File

@ -15,6 +15,7 @@
#include "cmVersion.h"
#include "cmGeneratedFileStream.h"
#include "cmCTest.h"
#include "cmXMLParser.h"
#include <cmsys/Process.h>
#include <cmsys/Base64.h>
@ -31,6 +32,80 @@
typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
//----------------------------------------------------------------------------
class cmCTestSubmitHandler::ResponseParser: public cmXMLParser
{
public:
ResponseParser() { this->Status = STATUS_OK; }
~ResponseParser() {}
public:
enum StatusType
{
STATUS_OK,
STATUS_WARNING,
STATUS_ERROR
};
StatusType Status;
std::string CDashVersion;
std::string Filename;
std::string MD5;
std::string Message;
private:
std::string CurrentValue;
std::string CurrentTag;
virtual void StartElement(const char* name, const char** atts)
{
this->CurrentValue = "";
if(strcmp(name, "cdash") == 0)
{
this->CDashVersion = this->FindAttribute(atts, "version");
}
}
virtual void CharacterDataHandler(const char* data, int length)
{
this->CurrentValue.insert(this->CurrentValue.end(), data, data+length);
}
virtual void EndElement(const char* name)
{
if(strcmp(name, "status") == 0)
{
this->CurrentValue = cmSystemTools::UpperCase(this->CurrentValue);
if(this->CurrentValue == "OK" || this->CurrentValue == "SUCCESS")
{
this->Status = STATUS_OK;
}
else if(this->CurrentValue == "WARNING")
{
this->Status = STATUS_WARNING;
}
else
{
this->Status = STATUS_ERROR;
}
}
else if(strcmp(name, "filename") == 0)
{
this->Filename = this->CurrentValue;
}
else if(strcmp(name, "md5") == 0)
{
this->MD5 = this->CurrentValue;
}
else if(strcmp(name, "message") == 0)
{
this->Message = this->CurrentValue;
}
}
};
static size_t
cmCTestSubmitHandlerWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
void *data)
@ -367,6 +442,13 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
= url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
+ "FileName=" + ofile;
char md5[33];
cmSystemTools::ComputeFileMD5(local_file.c_str(), md5);
md5[32] = 0;
std::stringstream md5string;
md5string << "&MD5=" << md5;
upload_as += md5string.str();
struct stat st;
if ( ::stat(local_file.c_str(), &st) )
{
@ -382,7 +464,6 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
<< local_file.c_str() << " to "
<< upload_as.c_str() << " Size: " << st.st_size << std::endl);
// specify target
::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
@ -411,6 +492,47 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
// Now run off and do what you've been told!
res = ::curl_easy_perform(curl);
// If we time out or operation is too slow, wait and retry
if(res == CURLE_OPERATION_TIMEOUTED)
{
std::string retryTime = this->GetOption("RetryTime") == NULL ?
"" : this->GetOption("RetryTime");
std::string retryCount = this->GetOption("RetryCount") == NULL ?
"" : this->GetOption("RetryCount");
int time = retryTime == "" ? atoi(this->CTest->GetCTestConfiguration(
"CTestRetryTime").c_str()) : atoi(retryTime.c_str());
int count = retryCount == "" ? atoi(this->CTest->GetCTestConfiguration(
"CTestRetryCount").c_str()) : atoi(retryCount.c_str());
for(int i = 0; i < count; i++)
{
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Connection timed out, waiting " << time << " seconds...\n");
double stop = cmSystemTools::GetTime() + time;
while(cmSystemTools::GetTime() < stop) {} //wait <time> seconds
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Retry submission: Attempt " << (i + 1) << " of "
<< count << std::endl);
::fclose(ftpfile);
ftpfile = ::fopen(local_file.c_str(), "rb");
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
chunk.clear();
chunkDebug.clear();
res = ::curl_easy_perform(curl);
if(res != CURLE_OPERATION_TIMEDOUT)
{
break;
}
}
}
if ( chunk.size() > 0 )
{
cmCTestLog(this->CTest, DEBUG, "CURL output: ["
@ -467,29 +589,39 @@ void cmCTestSubmitHandler
::ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk)
{
std::string output = "";
output.append(chunk.begin(), chunk.end());
for(cmCTestSubmitHandlerVectorOfChar::iterator i = chunk.begin();
i != chunk.end(); ++i)
if(output.find("<cdash") != output.npos)
{
output += *i;
}
output = cmSystemTools::UpperCase(output);
ResponseParser parser;
parser.Parse(output.c_str());
if(output.find("WARNING") != std::string::npos)
{
this->HasWarnings = true;
if(parser.Status != ResponseParser::STATUS_OK)
{
this->HasErrors = true;
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission failed: " <<
parser.Message << std::endl);
return;
}
}
if(output.find("ERROR") != std::string::npos)
else
{
this->HasErrors = true;
}
output = cmSystemTools::UpperCase(output);
if(output.find("WARNING") != std::string::npos)
{
this->HasWarnings = true;
}
if(output.find("ERROR") != std::string::npos)
{
this->HasErrors = true;
}
if(this->HasWarnings || this->HasErrors)
{
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n" <<
cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
if(this->HasWarnings || this->HasErrors)
{
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n" <<
cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
}
}
}
//----------------------------------------------------------------------------

View File

@ -79,6 +79,7 @@ private:
std::string GetSubmitResultsPrefix();
class ResponseParser;
cmStdString HTTPProxy;
int HTTPProxyType;
cmStdString HTTPProxyAuth;

View File

@ -113,7 +113,7 @@ IF(svncommand)
CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 5 SCHEDULE_RANDOM ON)
CTEST_MEMCHECK(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 5)
CTEST_COVERAGE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
CTEST_SUBMIT(RETURN_VALUE res)
CTEST_SUBMIT(RETRY_COUNT 4 RETRY_DELAY 10 RETURN_VALUE res)
ELSE(svncommand)
MESSAGE("Cannot find SVN command: ${svncommand}")