From 3e52000a07cb71172bc0ff7223dbca6f793786b6 Mon Sep 17 00:00:00 2001 From: Zach Mullen Date: Wed, 30 Jun 2010 10:39:17 -0400 Subject: [PATCH] Fix cycle detection for test dependencies --- Source/CTest/cmCTestMultiProcessHandler.cxx | 29 +++++++++------------ Tests/CMakeLists.txt | 24 ++++++++++++++++- Tests/CTestTestCycle/CMakeLists.txt | 13 +++++++++ Tests/CTestTestCycle/CTestConfig.cmake | 7 +++++ Tests/CTestTestCycle/simple.cxx | 5 ++++ Tests/CTestTestCycle/test.cmake.in | 22 ++++++++++++++++ Tests/CTestTestDepends/CMakeLists.txt | 12 +++++++++ Tests/CTestTestDepends/CTestConfig.cmake | 7 +++++ Tests/CTestTestDepends/simple.cxx | 5 ++++ Tests/CTestTestDepends/test.cmake.in | 22 ++++++++++++++++ 10 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 Tests/CTestTestCycle/CMakeLists.txt create mode 100644 Tests/CTestTestCycle/CTestConfig.cmake create mode 100644 Tests/CTestTestCycle/simple.cxx create mode 100644 Tests/CTestTestCycle/test.cmake.in create mode 100644 Tests/CTestTestDepends/CMakeLists.txt create mode 100644 Tests/CTestTestDepends/CTestConfig.cmake create mode 100644 Tests/CTestTestDepends/simple.cxx create mode 100644 Tests/CTestTestDepends/test.cmake.in diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 4d3936779..4d2a57366 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -611,7 +611,7 @@ int cmCTestMultiProcessHandler::FindMaxIndex() //Returns true if no cycles exist in the dependency graph bool cmCTestMultiProcessHandler::CheckCycles() { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Checking test dependency graph..." << std::endl); for(TestMap::iterator it = this->Tests.begin(); it != this->Tests.end(); ++it) @@ -619,34 +619,29 @@ bool cmCTestMultiProcessHandler::CheckCycles() //DFS from each element to itself std::stack s; std::vector 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::iterator v = visited.begin(); - v != visited.end(); ++v) + if(std::find(visited.begin(), visited.end(), *d) != visited.end()) { - 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; - } + //cycle exists + cmCTestLog(this->CTest, ERROR_MESSAGE, "Error: a cycle exists in " + "the test dependency graph for the test \"" + << this->Properties[it->first]->Name << "\"." << std::endl + << "Please fix the cycle and run ctest again." << std::endl); + return false; } - visited.push_back(*d); + s.push(*d); } - visited.pop_back(); + visited.push_back(test); } } return true; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 2c7056d50..e00a1ccb0 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1373,7 +1373,29 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ) SET_TESTS_PROPERTIES(CTestTestTimeout PROPERTIES PASS_REGULAR_EXPRESSION "TestTimeout *\\.+ *\\*\\*\\*Timeout.*CheckChild *\\.+ *Passed") - + + CONFIGURE_FILE( + "${CMake_SOURCE_DIR}/Tests/CTestTestDepends/test.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestTestDepends/test.cmake" + @ONLY ESCAPE_QUOTES) + ADD_TEST(CTestTestDepends ${CMAKE_CTEST_COMMAND} + -C "\${CTestTest_CONFIG}" + -S "${CMake_BINARY_DIR}/Tests/CTestTestDepends/test.cmake" -V + --output-log "${CMake_BINARY_DIR}/Tests/CTestTestDepends/testOutput.log" + ) + + CONFIGURE_FILE( + "${CMake_SOURCE_DIR}/Tests/CTestTestCycle/test.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestTestCycle/test.cmake" + @ONLY ESCAPE_QUOTES) + ADD_TEST(CTestTestCycle ${CMAKE_CTEST_COMMAND} + -C "\${CTestTest_CONFIG}" + -S "${CMake_BINARY_DIR}/Tests/CTestTestCycle/test.cmake" -V + --output-log "${CMake_BINARY_DIR}/Tests/CTestTestCycle/testOutput.log" + ) + SET_TESTS_PROPERTIES(CTestTestCycle PROPERTIES + PASS_REGULAR_EXPRESSION "a cycle exists in the test dependency graph") + CONFIGURE_FILE( "${CMake_SOURCE_DIR}/Tests/CTestTestRunScript/test.cmake.in" "${CMake_BINARY_DIR}/Tests/CTestTestRunScript/test.cmake" diff --git a/Tests/CTestTestCycle/CMakeLists.txt b/Tests/CTestTestCycle/CMakeLists.txt new file mode 100644 index 000000000..6ba6b8c95 --- /dev/null +++ b/Tests/CTestTestCycle/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 2.6) +project(CTestTestCycle) +include(CTest) + +add_executable (simple simple.cxx) +add_test (one simple) +add_test (two simple) +add_test (three simple) + +# Add cyclical test dependency +set_tests_properties(one PROPERTIES DEPENDS "two") +set_tests_properties(two PROPERTIES DEPENDS "three") +set_tests_properties(three PROPERTIES DEPENDS "one") diff --git a/Tests/CTestTestCycle/CTestConfig.cmake b/Tests/CTestTestCycle/CTestConfig.cmake new file mode 100644 index 000000000..43e99863a --- /dev/null +++ b/Tests/CTestTestCycle/CTestConfig.cmake @@ -0,0 +1,7 @@ +set (CTEST_PROJECT_NAME "CTestTestCycle") +set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT") +set (CTEST_DART_SERVER_VERSION "2") +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "www.cdash.org") +set(CTEST_DROP_LOCATION "/CDash/submit.php?project=PublicDashboard") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Tests/CTestTestCycle/simple.cxx b/Tests/CTestTestCycle/simple.cxx new file mode 100644 index 000000000..766b7751b --- /dev/null +++ b/Tests/CTestTestCycle/simple.cxx @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} diff --git a/Tests/CTestTestCycle/test.cmake.in b/Tests/CTestTestCycle/test.cmake.in new file mode 100644 index 000000000..a17adca01 --- /dev/null +++ b/Tests/CTestTestCycle/test.cmake.in @@ -0,0 +1,22 @@ +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@-Cycle") + +SET(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestCycle") +SET(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestCycle") +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) diff --git a/Tests/CTestTestDepends/CMakeLists.txt b/Tests/CTestTestDepends/CMakeLists.txt new file mode 100644 index 000000000..26367a658 --- /dev/null +++ b/Tests/CTestTestDepends/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required (VERSION 2.6) +project(CTestTestDepends) +include(CTest) + +add_executable (simple simple.cxx) +add_test (one simple) +add_test (two simple) +add_test (three simple) + +# Add redundant (but not cyclical) dependencies +set_tests_properties(two PROPERTIES DEPENDS "one") +set_tests_properties(three PROPERTIES DEPENDS "one;two") diff --git a/Tests/CTestTestDepends/CTestConfig.cmake b/Tests/CTestTestDepends/CTestConfig.cmake new file mode 100644 index 000000000..e3af7dd8d --- /dev/null +++ b/Tests/CTestTestDepends/CTestConfig.cmake @@ -0,0 +1,7 @@ +set (CTEST_PROJECT_NAME "CTestTestDepends") +set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT") +set (CTEST_DART_SERVER_VERSION "2") +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "www.cdash.org") +set(CTEST_DROP_LOCATION "/CDash/submit.php?project=PublicDashboard") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Tests/CTestTestDepends/simple.cxx b/Tests/CTestTestDepends/simple.cxx new file mode 100644 index 000000000..766b7751b --- /dev/null +++ b/Tests/CTestTestDepends/simple.cxx @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} diff --git a/Tests/CTestTestDepends/test.cmake.in b/Tests/CTestTestDepends/test.cmake.in new file mode 100644 index 000000000..ed4e18226 --- /dev/null +++ b/Tests/CTestTestDepends/test.cmake.in @@ -0,0 +1,22 @@ +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@-Depends") + +SET(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestDepends") +SET(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestDepends") +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)