From e525649a4e9f2578c41593b56f9af4b4b7719984 Mon Sep 17 00:00:00 2001 From: Zach Mullen <zach.mullen@kitware.com> Date: Thu, 3 Jun 2010 10:34:34 -0400 Subject: Checksums on CTest submit files, and retry timed out submissions. --- Modules/CTest.cmake | 9 +- Modules/DartConfiguration.tcl.in | 4 + Source/CTest/cmCTestSubmitCommand.cxx | 27 ++++++ Source/CTest/cmCTestSubmitCommand.h | 6 ++ Source/CTest/cmCTestSubmitHandler.cxx | 170 ++++++++++++++++++++++++++++++---- Source/CTest/cmCTestSubmitHandler.h | 1 + Tests/CTestTest3/test.cmake.in | 2 +- 7 files changed, 198 insertions(+), 21 deletions(-) diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake index 2d0702e..bdaf911 100644 --- a/Modules/CTest.cmake +++ b/Modules/CTest.cmake @@ -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 @@ -262,7 +267,9 @@ IF(BUILD_TESTING) SCPCOMMAND SLURM_SBATCH_COMMAND SLURM_SRUN_COMMAND - SITE + SITE + CTEST_SUBMIT_RETRY_DELAY + CTEST_SUBMIT_RETRY_COUNT ) # BUILDNAME IF(NOT RUN_FROM_DART) diff --git a/Modules/DartConfiguration.tcl.in b/Modules/DartConfiguration.tcl.in index 85b4138..799ff79 100644 --- a/Modules/DartConfiguration.tcl.in +++ b/Modules/DartConfiguration.tcl.in @@ -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@ diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index d1226da..6a45d58 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -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); } diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index ccaef7e..14dfa37 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -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; }; diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 7b4f38b..fca05ac 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -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) - { - output += *i; - } - output = cmSystemTools::UpperCase(output); - - if(output.find("WARNING") != std::string::npos) - { - this->HasWarnings = true; - } - if(output.find("ERROR") != std::string::npos) + if(output.find("<cdash") != output.npos) { - this->HasErrors = true; + ResponseParser parser; + parser.Parse(output.c_str()); + + if(parser.Status != ResponseParser::STATUS_OK) + { + this->HasErrors = true; + cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission failed: " << + parser.Message << std::endl); + return; + } } - - if(this->HasWarnings || this->HasErrors) + else { - cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n" << - cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n"); + 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"); + } } - } //---------------------------------------------------------------------------- diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index 8b011ea..e7755b1 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -79,6 +79,7 @@ private: std::string GetSubmitResultsPrefix(); + class ResponseParser; cmStdString HTTPProxy; int HTTPProxyType; cmStdString HTTPProxyAuth; diff --git a/Tests/CTestTest3/test.cmake.in b/Tests/CTestTest3/test.cmake.in index 1e8ea50..9819235 100644 --- a/Tests/CTestTest3/test.cmake.in +++ b/Tests/CTestTest3/test.cmake.in @@ -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}") -- cgit v0.12 From 082c87e5287e75e65a75d7588c40508f12e18632 Mon Sep 17 00:00:00 2001 From: Zach Mullen <zach.mullen@kitware.com> Date: Thu, 3 Jun 2010 13:27:26 -0400 Subject: Cross-platform fixes for checksum/retry code --- Modules/DartConfiguration.tcl.in | 4 ++-- Source/CTest/cmCTestSubmitCommand.h | 9 +++++++-- Source/CTest/cmCTestSubmitHandler.cxx | 34 ++++++++++++++++++++-------------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Modules/DartConfiguration.tcl.in b/Modules/DartConfiguration.tcl.in index 799ff79..cbb9a32 100644 --- a/Modules/DartConfiguration.tcl.in +++ b/Modules/DartConfiguration.tcl.in @@ -85,5 +85,5 @@ CurlOptions: @CTEST_CURL_OPTIONS@ # For CTest submissions that timeout, these options # specify behavior for retrying the submission -CTestRetryTime: @CTEST_SUBMIT_RETRY_DELAY@ -CTestRetryCount: @CTEST_SUBMIT_RETRY_COUNT@ +CTestSubmitRetryDelay: @CTEST_SUBMIT_RETRY_DELAY@ +CTestSubmitRetryCount: @CTEST_SUBMIT_RETRY_COUNT@ diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index 14dfa37..5a80b45 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -63,7 +63,8 @@ public: virtual const char* GetFullDocumentation() { return - " ctest_submit([PARTS ...] [FILES ...] [RETURN_VALUE res])\n" + " ctest_submit([PARTS ...] [FILES ...] [RETRY_COUNT count] " + " [RETRY_DELAY delay][RETURN_VALUE res])\n" "By default all available parts are submitted if no PARTS or FILES " "are specified. " "The PARTS option lists a subset of parts to be submitted. " @@ -79,7 +80,11 @@ public: " ExtraFiles = Files listed by CTEST_EXTRA_SUBMIT_FILES\n" " Submit = nothing\n" "The FILES option explicitly lists specific files to be submitted. " - "Each individual file must exist at the time of the call.\n"; + "Each individual file must exist at the time of the call.\n" + "The RETRY_DELAY option specifies how long in seconds to wait after " + "a timed-out submission before attempting to re-submit.\n" + "The RETRY_COUNT option specifies how many times to retry a timed-out " + "submission.\n"; } cmTypeMacro(cmCTestSubmitCommand, cmCTestHandlerCommand); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index fca05ac..fe00a82 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -55,12 +55,19 @@ public: std::string Message; private: - std::string CurrentValue; - std::string CurrentTag; + + std::vector<char> CurrentValue; + + std::string GetCurrentValue() + { + std::string val; + val.assign(&this->CurrentValue[0], this->CurrentValue.size()); + return val; + } virtual void StartElement(const char* name, const char** atts) { - this->CurrentValue = ""; + this->CurrentValue.clear(); if(strcmp(name, "cdash") == 0) { this->CDashVersion = this->FindAttribute(atts, "version"); @@ -76,12 +83,12 @@ private: { if(strcmp(name, "status") == 0) { - this->CurrentValue = cmSystemTools::UpperCase(this->CurrentValue); - if(this->CurrentValue == "OK" || this->CurrentValue == "SUCCESS") + std::string status = cmSystemTools::UpperCase(this->GetCurrentValue()); + if(status == "OK" || status == "SUCCESS") { this->Status = STATUS_OK; } - else if(this->CurrentValue == "WARNING") + else if(status == "WARNING") { this->Status = STATUS_WARNING; } @@ -92,15 +99,15 @@ private: } else if(strcmp(name, "filename") == 0) { - this->Filename = this->CurrentValue; + this->Filename = this->GetCurrentValue(); } else if(strcmp(name, "md5") == 0) { - this->MD5 = this->CurrentValue; + this->MD5 = this->GetCurrentValue(); } else if(strcmp(name, "message") == 0) { - this->Message = this->CurrentValue; + this->Message = this->GetCurrentValue(); } } }; @@ -445,9 +452,8 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, char md5[33]; cmSystemTools::ComputeFileMD5(local_file.c_str(), md5); md5[32] = 0; - std::stringstream md5string; - md5string << "&MD5=" << md5; - upload_as += md5string.str(); + upload_as += "&MD5="; + upload_as += md5; struct stat st; if ( ::stat(local_file.c_str(), &st) ) @@ -501,9 +507,9 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, "" : this->GetOption("RetryCount"); int time = retryTime == "" ? atoi(this->CTest->GetCTestConfiguration( - "CTestRetryTime").c_str()) : atoi(retryTime.c_str()); + "CTestSubmitRetryDelay").c_str()) : atoi(retryTime.c_str()); int count = retryCount == "" ? atoi(this->CTest->GetCTestConfiguration( - "CTestRetryCount").c_str()) : atoi(retryCount.c_str()); + "CTestSubmitRetryCount").c_str()) : atoi(retryCount.c_str()); for(int i = 0; i < count; i++) { -- cgit v0.12 From d6b71078da1bf75ab3031bae5c2952a6f0bd9d45 Mon Sep 17 00:00:00 2001 From: Zach Mullen <zach.mullen@kitware.com> Date: Thu, 3 Jun 2010 13:52:48 -0400 Subject: Fix subscript out of range crash --- Source/CTest/cmCTestSubmitHandler.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index fe00a82..9bbb2e6 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -61,7 +61,10 @@ private: std::string GetCurrentValue() { std::string val; - val.assign(&this->CurrentValue[0], this->CurrentValue.size()); + if(this->CurrentValue.size()) + { + val.assign(&this->CurrentValue[0], this->CurrentValue.size()); + } return val; } -- cgit v0.12 From 86e81b53c196bfd29aa7d877d2fb9e71a6392cc1 Mon Sep 17 00:00:00 2001 From: Zach Mullen <zach.mullen@kitware.com> Date: Sat, 5 Jun 2010 10:36:23 -0400 Subject: CTest should resubmit in the checksum failed case --- Source/CTest/cmCTestSubmitHandler.cxx | 43 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 9bbb2e6..21c005d 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -501,8 +501,22 @@ 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) + if ( chunk.size() > 0 ) + { + cmCTestLog(this->CTest, DEBUG, "CURL output: [" + << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" + << std::endl); + this->ParseResponse(chunk); + } + if ( chunkDebug.size() > 0 ) + { + cmCTestLog(this->CTest, DEBUG, "CURL debug output: [" + << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]" + << std::endl); + } + + // If we time out or checksum fails, wait and retry + if(res == CURLE_OPERATION_TIMEDOUT || this->HasErrors) { std::string retryTime = this->GetOption("RetryTime") == NULL ? "" : this->GetOption("RetryTime"); @@ -532,30 +546,25 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, chunk.clear(); chunkDebug.clear(); + this->HasErrors = false; res = ::curl_easy_perform(curl); - if(res != CURLE_OPERATION_TIMEDOUT) + if ( chunk.size() > 0 ) + { + cmCTestLog(this->CTest, DEBUG, "CURL output: [" + << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" + << std::endl); + this->ParseResponse(chunk); + } + + if(res != CURLE_OPERATION_TIMEDOUT && !this->HasErrors) { break; } } } - if ( chunk.size() > 0 ) - { - cmCTestLog(this->CTest, DEBUG, "CURL output: [" - << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" - << std::endl); - this->ParseResponse(chunk); - } - if ( chunkDebug.size() > 0 ) - { - cmCTestLog(this->CTest, DEBUG, "CURL debug output: [" - << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]" - << std::endl); - } - fclose(ftpfile); if ( res ) { -- cgit v0.12 From af5ef0c96982be431791ea35d6de8798ffe70254 Mon Sep 17 00:00:00 2001 From: Zach Mullen <zach.mullen@kitware.com> Date: Thu, 10 Jun 2010 12:25:49 -0400 Subject: Testing for CTest checksum --- Source/CTest/cmCTestSubmitCommand.cxx | 12 ++++++- Source/CTest/cmCTestSubmitCommand.h | 2 ++ Source/CTest/cmCTestSubmitHandler.cxx | 60 ++++++++++++++++++++--------------- Tests/CMakeLists.txt | 11 +++++++ Tests/CTestTest3/test.cmake.in | 2 +- Tests/CTestTestChecksum/test.cmake.in | 23 ++++++++++++++ 6 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 Tests/CTestTestChecksum/test.cmake.in diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 6a45d58..24974e3 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -147,10 +147,12 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(this->Parts); } - static_cast<cmCTestSubmitHandler*>(handler)->SetOption("RetryTime", + static_cast<cmCTestSubmitHandler*>(handler)->SetOption("RetryDelay", this->RetryDelay.c_str()); static_cast<cmCTestSubmitHandler*>(handler)->SetOption("RetryCount", this->RetryCount.c_str()); + static_cast<cmCTestSubmitHandler*>(handler)->SetOption("InternalTest", + this->InternalTest ? "ON" : "OFF"); return handler; } @@ -186,6 +188,12 @@ bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg) return true; } + if(arg == "INTERNAL_TEST_CHECKSUM") + { + this->InternalTest = true; + return true; + } + // Look for other arguments. return this->Superclass::CheckArgumentKeyword(arg); } @@ -233,11 +241,13 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg) if(this->ArgumentDoing == ArgumentDoingRetryCount) { this->RetryCount = arg; + return true; } if(this->ArgumentDoing == ArgumentDoingRetryDelay) { this->RetryDelay = arg; + return true; } // Look for other arguments. diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index 5a80b45..edc9c65 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -29,6 +29,7 @@ public: { this->PartsMentioned = false; this->FilesMentioned = false; + this->InternalTest = false; this->RetryCount = ""; this->RetryDelay = ""; } @@ -107,6 +108,7 @@ protected: bool PartsMentioned; std::set<cmCTest::Part> Parts; bool FilesMentioned; + bool InternalTest; cmCTest::SetOfStrings Files; std::string RetryCount; std::string RetryDelay; diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 21c005d..4ca382c 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -452,11 +452,19 @@ 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; upload_as += "&MD5="; - upload_as += md5; + + if(cmSystemTools::IsOn(this->GetOption("InternalTest"))) + { + upload_as += "bad_md5sum"; + } + else + { + char md5[33]; + cmSystemTools::ComputeFileMD5(local_file.c_str(), md5); + md5[32] = 0; + upload_as += md5; + } struct stat st; if ( ::stat(local_file.c_str(), &st) ) @@ -518,23 +526,26 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, // If we time out or checksum fails, wait and retry if(res == CURLE_OPERATION_TIMEDOUT || this->HasErrors) { - std::string retryTime = this->GetOption("RetryTime") == NULL ? - "" : this->GetOption("RetryTime"); + std::string retryDelay = this->GetOption("RetryDelay") == NULL ? + "" : this->GetOption("RetryDelay"); std::string retryCount = this->GetOption("RetryCount") == NULL ? "" : this->GetOption("RetryCount"); - int time = retryTime == "" ? atoi(this->CTest->GetCTestConfiguration( - "CTestSubmitRetryDelay").c_str()) : atoi(retryTime.c_str()); + int delay = retryDelay == "" ? atoi(this->CTest->GetCTestConfiguration( + "CTestSubmitRetryDelay").c_str()) : atoi(retryDelay.c_str()); int count = retryCount == "" ? atoi(this->CTest->GetCTestConfiguration( "CTestSubmitRetryCount").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"); + " Connection timed out, waiting " << delay << " seconds...\n"); - double stop = cmSystemTools::GetTime() + time; - while(cmSystemTools::GetTime() < stop) {} //wait <time> seconds + double stop = cmSystemTools::GetTime() + delay; + while(cmSystemTools::GetTime() < stop) + { + cmSystemTools::Delay(100); + } cmCTestLog(this->CTest, HANDLER_OUTPUT, " Retry submission: Attempt " << (i + 1) << " of " @@ -622,23 +633,20 @@ void cmCTestSubmitHandler return; } } - else + output = cmSystemTools::UpperCase(output); + if(output.find("WARNING") != std::string::npos) { - output = cmSystemTools::UpperCase(output); - if(output.find("WARNING") != std::string::npos) - { - this->HasWarnings = true; - } - if(output.find("ERROR") != std::string::npos) - { - this->HasErrors = true; - } + 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"); } } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 330cf9f..c1cc8b8 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1449,6 +1449,17 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ --output-log "${CMake_BINARY_DIR}/Tests/CTestTest3/testOutput.log" ) + CONFIGURE_FILE("${CMake_SOURCE_DIR}/Tests/CTestTestChecksum/test.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestTestChecksum/test.cmake" @ONLY + ESCAPE_QUOTES) + ADD_TEST(CTestTestChecksum ${CMAKE_CTEST_COMMAND} + -S "${CMake_BINARY_DIR}/Tests/CTestTestChecksum/test.cmake" -V + --output-log + "${CMake_BINARY_DIR}/Tests/CTestTestChecksum/testOutput.log" + ) + SET_TESTS_PROPERTIES(CTestTestChecksum PROPERTIES PASS_REGULAR_EXPRESSION + "Submission failed: Checksum failed for file") + # these tests take a long time, make sure they have it # if timeouts have not already been set GET_TEST_PROPERTY(CTestTest TIMEOUT PREVIOUS_TIMEOUT) diff --git a/Tests/CTestTest3/test.cmake.in b/Tests/CTestTest3/test.cmake.in index 9819235..1e8ea50 100644 --- a/Tests/CTestTest3/test.cmake.in +++ b/Tests/CTestTest3/test.cmake.in @@ -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(RETRY_COUNT 4 RETRY_DELAY 10 RETURN_VALUE res) + CTEST_SUBMIT(RETURN_VALUE res) ELSE(svncommand) MESSAGE("Cannot find SVN command: ${svncommand}") diff --git a/Tests/CTestTestChecksum/test.cmake.in b/Tests/CTestTestChecksum/test.cmake.in new file mode 100644 index 0000000..7ef8ab2 --- /dev/null +++ b/Tests/CTestTestChecksum/test.cmake.in @@ -0,0 +1,23 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.1) + +# Settings: +SET(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest") +SET(CTEST_SITE "@SITE@") +SET(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Checksum") + +SET(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestParallel") +SET(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestParallel") +SET(CTEST_CVS_COMMAND "@CVSCOMMAND@") +SET(CTEST_CMAKE_GENERATOR "@CMAKE_TEST_GENERATOR@") +SET(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}") +SET(CTEST_MEMORYCHECK_COMMAND "@MEMORYCHECK_COMMAND@") +SET(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE "@MEMORYCHECK_SUPPRESSIONS_FILE@") +SET(CTEST_MEMORYCHECK_COMMAND_OPTIONS "@MEMORYCHECK_COMMAND_OPTIONS@") +SET(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@") +SET(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") + +CTEST_START(Experimental) +CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res) +CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res) +CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 4) +CTEST_SUBMIT(RETRY_DELAY 3 RETRY_COUNT 2 INTERNAL_TEST_CHECKSUM RETURN_VALUE res) -- cgit v0.12 From d0d1cdd71bb85b821be9b65be94819f3575b49ad Mon Sep 17 00:00:00 2001 From: Zach Mullen <zach.mullen@kitware.com> Date: Thu, 10 Jun 2010 15:02:24 -0400 Subject: Mock checksum failure output for old CDash versions --- Source/CTest/cmCTestSubmitHandler.cxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 4ca382c..bfe515d 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -509,6 +509,19 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, // Now run off and do what you've been told! res = ::curl_easy_perform(curl); + if(cmSystemTools::IsOn(this->GetOption("InternalTest")) && + cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, + this->CTest->GetCDashVersion().c_str(), "1.7")) + { + // mock failure output for internal test case + std::string mock_output = "<cdash version=\"1.7.0\">\n" + " <status>ERROR</status>\n" + " <message>Checksum failed for file.</message>\n" + "</cdash>\n"; + chunk.clear(); + chunk.assign(mock_output.begin(), mock_output.end()); + } + if ( chunk.size() > 0 ) { cmCTestLog(this->CTest, DEBUG, "CURL output: [" -- cgit v0.12 From 87054972a703efac5137ab3d83f7f0dc9c10b9b3 Mon Sep 17 00:00:00 2001 From: Zach Mullen <zach.mullen@kitware.com> Date: Tue, 22 Jun 2010 11:13:48 -0400 Subject: Checksum test should use CMAKE_TESTS_CDASH_SERVER --- Tests/CTestTestChecksum/test.cmake.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tests/CTestTestChecksum/test.cmake.in b/Tests/CTestTestChecksum/test.cmake.in index 7ef8ab2..c3c41a5 100644 --- a/Tests/CTestTestChecksum/test.cmake.in +++ b/Tests/CTestTestChecksum/test.cmake.in @@ -20,4 +20,9 @@ CTEST_START(Experimental) CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res) CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res) CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 4) + +SET(CTEST_DROP_METHOD "@protocol@") +SET(CTEST_DROP_SITE "@server@") +SET(CTEST_DROP_LOCATION "@path@/submit.php?project=PublicDashboard") + CTEST_SUBMIT(RETRY_DELAY 3 RETRY_COUNT 2 INTERNAL_TEST_CHECKSUM RETURN_VALUE res) -- cgit v0.12 From 46df0b44ac97859ab40dd0aa03ceca297a455587 Mon Sep 17 00:00:00 2001 From: David Cole <david.cole@kitware.com> Date: Mon, 12 Jul 2010 16:48:38 -0400 Subject: Activate retry code on any curl submit failure. Previously, we were only going into the retry block for time out conditions. But a "could not connect" response, or really any sort of curl failure, is also a condition where we should retry the submit if the user has requested a retry. --- Source/CTest/cmCTestSubmitHandler.cxx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index bfe515d..1e18259 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -536,8 +536,9 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, << std::endl); } - // If we time out or checksum fails, wait and retry - if(res == CURLE_OPERATION_TIMEDOUT || this->HasErrors) + // If curl failed for any reason, or checksum fails, wait and retry + // + if(res != CURLE_OK || this->HasErrors) { std::string retryDelay = this->GetOption("RetryDelay") == NULL ? "" : this->GetOption("RetryDelay"); @@ -552,7 +553,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, for(int i = 0; i < count; i++) { cmCTestLog(this->CTest, HANDLER_OUTPUT, - " Connection timed out, waiting " << delay << " seconds...\n"); + " Submit failed, waiting " << delay << " seconds...\n"); double stop = cmSystemTools::GetTime() + delay; while(cmSystemTools::GetTime() < stop) @@ -582,7 +583,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, this->ParseResponse(chunk); } - if(res != CURLE_OPERATION_TIMEDOUT && !this->HasErrors) + if(res == CURLE_OK && !this->HasErrors) { break; } -- cgit v0.12