From 0ba9d041174f593509c44f84e0e70fafc6c0edc0 Mon Sep 17 00:00:00 2001 From: Zach Mullen Date: Tue, 16 Mar 2010 15:33:55 -0400 Subject: Add the --stop-time argument Unit test and script hook for STOP_TIME --- Source/CTest/cmCTestRunTest.cxx | 54 +++++++- Source/CTest/cmCTestRunTest.h | 4 +- Source/CTest/cmCTestTestCommand.cxx | 5 + Source/CTest/cmCTestTestCommand.h | 7 +- Source/cmCTest.cxx | 42 ++++++ Source/cmCTest.h | 7 + Source/ctest.cxx | 4 + Tests/CMakeLists.txt | 17 ++- Tests/CTestTestStopTime/CMakeLists.txt | 11 ++ Tests/CTestTestStopTime/CTestConfig.cmake | 7 + Tests/CTestTestStopTime/GetDate.cmake | 219 ++++++++++++++++++++++++++++++ Tests/CTestTestStopTime/sleep.c | 21 +++ Tests/CTestTestStopTime/test.cmake.in | 30 ++++ 13 files changed, 422 insertions(+), 6 deletions(-) create mode 100644 Tests/CTestTestStopTime/CMakeLists.txt create mode 100644 Tests/CTestTestStopTime/CTestConfig.cmake create mode 100644 Tests/CTestTestStopTime/GetDate.cmake create mode 100644 Tests/CTestTestStopTime/sleep.c create mode 100644 Tests/CTestTestStopTime/test.cmake.in diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 659cb73..94ccffe 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -14,6 +14,7 @@ #include "cmCTestMemCheckHandler.h" #include "cmCTest.h" #include "cmSystemTools.h" +#include "cm_curl.h" #include #include @@ -441,7 +442,7 @@ bool cmCTestRunTest::StartTest(size_t total) } this->StartTime = this->CTest->CurrentTime(); - return this->CreateProcess(this->TestProperties->Timeout, + return this->ForkProcess(this->ResolveTimeout(), &this->TestProperties->Environment); } @@ -518,7 +519,56 @@ void cmCTestRunTest::DartProcessing() } //---------------------------------------------------------------------- -bool cmCTestRunTest::CreateProcess(double testTimeOut, +double cmCTestRunTest::ResolveTimeout() +{ + double timeout = this->TestProperties->Timeout; + + if(this->CTest->GetStopTime() == "") + { + return timeout; + } + struct tm* lctime; + time_t current_time = time(0); + lctime = gmtime(¤t_time); + int gm_hour = lctime->tm_hour; + lctime = localtime(¤t_time); + int local_hour = lctime->tm_hour; + + int timezone = (local_hour - gm_hour) * 100; + char buf[1024]; + // add todays year day and month to the time in str because + // curl_getdate no longer assumes the day is today + sprintf(buf, "%d%02d%02d %s %+05i", + lctime->tm_year + 1900, + lctime->tm_mon + 1, + lctime->tm_mday, + this->CTest->GetStopTime().c_str(), + timezone); + + time_t stop_time = curl_getdate(buf, ¤t_time); + if(stop_time == -1) + { + return timeout; + } + + //the stop time refers to the next day + if(this->CTest->NextDayStopTime) + { + stop_time += 24*60*60; + } + double stop_timeout = stop_time - current_time; + + if(stop_timeout <= 0) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. " + "Exiting ctest." << std::endl); + exit(-1); + } + return timeout == 0 ? stop_timeout : min(timeout, stop_timeout); +} + +//---------------------------------------------------------------------- +bool cmCTestRunTest::ForkProcess(double testTimeOut, std::vector* environment) { this->TestProcess = new cmProcess; diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 1e4c1cc..14fa2e5 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -59,7 +59,9 @@ public: private: void DartProcessing(); void ExeNotFound(std::string exe); - bool CreateProcess(double testTimeOut, + // Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT) + double ResolveTimeout(); + bool ForkProcess(double testTimeOut, std::vector* environment); void WriteLogOutputTop(size_t completed, size_t total); //Run post processing of the process output for MemCheck diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index b0adf22..5aee035 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -25,6 +25,7 @@ cmCTestTestCommand::cmCTestTestCommand() this->Arguments[ctt_INCLUDE_LABEL] = "INCLUDE_LABEL"; this->Arguments[ctt_PARALLEL_LEVEL] = "PARALLEL_LEVEL"; this->Arguments[ctt_SCHEDULE_RANDOM] = "SCHEDULE_RANDOM"; + this->Arguments[ctt_STOP_TIME] = "STOP_TIME"; this->Arguments[ctt_LAST] = 0; this->Last = ctt_LAST; } @@ -98,6 +99,10 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() handler->SetOption("ScheduleRandom", this->Values[ctt_SCHEDULE_RANDOM]); } + if(this->Values[ctt_STOP_TIME]) + { + this->CTest->SetStopTime(this->Values[ctt_STOP_TIME]); + } return handler; } diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index 12314df..c6fd631 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -62,7 +62,8 @@ public: " [EXCLUDE_LABEL exclude regex] \n" " [INCLUDE_LABEL label regex] \n" " [PARALLEL_LEVEL level] \n" - " [SCHEDULE_RANDOM on]) \n" + " [SCHEDULE_RANDOM on] \n" + " [STOP_TIME time of day]) \n" "Tests the given build directory and stores results in Test.xml. The " "second argument is a variable that will hold value. Optionally, " "you can specify the starting test number START, the ending test number " @@ -73,7 +74,8 @@ public: "property LABEL. PARALLEL_LEVEL should be set to a positive number " "representing the number of tests to be run in parallel. " "SCHEDULE_RANDOM will launch tests in a random order, and is " - "typically used to detect implicit test dependencies." + "typically used to detect implicit test dependencies. STOP_TIME is the " + "time of day at which the tests should all stop running." "\n" CTEST_COMMAND_APPEND_OPTION_DOCS; } @@ -96,6 +98,7 @@ protected: ctt_INCLUDE_LABEL, ctt_PARALLEL_LEVEL, ctt_SCHEDULE_RANDOM, + ctt_STOP_TIME, ctt_LAST }; }; diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index e417e1b..c6a3849 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -314,6 +314,8 @@ cmCTest::cmCTest() this->CompressXMLFiles = false; this->CTestConfigFile = ""; this->ScheduleType = ""; + this->StopTime = ""; + this->NextDayStopTime = false; this->OutputLogFile = 0; this->OutputLogFileLastTag = -1; this->SuppressUpdatingCTestConfiguration = false; @@ -1881,6 +1883,12 @@ void cmCTest::HandleCommandLineArguments(size_t &i, double timeout = (double)atof(args[i].c_str()); this->GlobalTimeout = timeout; } + + if(this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) + { + i++; + this->SetStopTime(args[i]); + } if(this->CheckArgument(arg, "-C", "--build-config") && i < args.size() - 1) @@ -2335,6 +2343,13 @@ void cmCTest::SetNotesFiles(const char* notes) } //---------------------------------------------------------------------- +void cmCTest::SetStopTime(std::string time) +{ + this->StopTime = time; + this->DetermineNextDayStop(); +} + +//---------------------------------------------------------------------- int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf) { bool found = false; @@ -2536,6 +2551,33 @@ void cmCTest::EmptyCTestConfiguration() } //---------------------------------------------------------------------- +void cmCTest::DetermineNextDayStop() +{ + struct tm* lctime; + time_t current_time = time(0); + lctime = gmtime(¤t_time); + int gm_hour = lctime->tm_hour; + lctime = localtime(¤t_time); + int local_hour = lctime->tm_hour; + + int timezone = (local_hour - gm_hour) * 100; + char buf[1024]; + sprintf(buf, "%d%02d%02d %s %+05i", + lctime->tm_year + 1900, + lctime->tm_mon + 1, + lctime->tm_mday, + this->StopTime.c_str(), + timezone); + + time_t stop_time = curl_getdate(buf, ¤t_time); + + if(stop_time < current_time) + { + this->NextDayStopTime = true; + } +} + +//---------------------------------------------------------------------- void cmCTest::SetCTestConfiguration(const char *name, const char* value) { cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "SetCTestConfiguration:" diff --git a/Source/cmCTest.h b/Source/cmCTest.h index adf359c..4b66985 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -214,6 +214,9 @@ public: std::string GetCDashVersion(); + std::string GetStopTime() { return this->StopTime; } + void SetStopTime(std::string time); + //Used for parallel ctest job scheduling std::string GetScheduleType() { return this->ScheduleType; } void SetScheduleType(std::string type) { this->ScheduleType = type; } @@ -403,6 +406,8 @@ public: private: std::string ConfigType; std::string ScheduleType; + std::string StopTime; + bool NextDayStopTime; bool Verbose; bool ExtraVerbose; bool ProduceXML; @@ -420,6 +425,8 @@ private: int GenerateNotesFile(const char* files); + void DetermineNextDayStop(); + // these are helper classes typedef std::map t_TestingHandlers; t_TestingHandlers TestingHandlers; diff --git a/Source/ctest.cxx b/Source/ctest.cxx index c9b875d..24921c4 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -218,6 +218,10 @@ static const char * cmDocumentationOptions[][3] = {"--timeout ", "Set a global timeout on all tests.", "This option will set a global timeout on all tests that do not already " "have a timeout set on them."}, + {"--stop-time