summaryrefslogtreecommitdiffstats
path: root/Tests/RunCMake/CTestResourceAllocation
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/RunCMake/CTestResourceAllocation')
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/CMakeLists.txt.in9
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake23
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/RunCMakeTest.cmake167
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree1.cmake7
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree2-ctest-s-res-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree2.cmake8
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3.log3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4.log3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good1.log14
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good2.log0
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin.log0
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nolog-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-noproc-count-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badcount-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badres-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets1-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets2-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets3-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets4-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets5-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets6-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets7-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good1-check.cmake20
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good2-check.cmake6
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nocount-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nores-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nowidgets-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx399
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ensure_parallel-ctest-s-res-check.cmake16
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ensure_parallel.cmake11
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/lotsoftests-ctest-s-res-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/lotsoftests.cmake16
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt4
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt4
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/process_count-ctest-s-res-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/process_count.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/resspec.json55
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/test.cmake.in23
66 files changed, 855 insertions, 0 deletions
diff --git a/Tests/RunCMake/CTestResourceAllocation/CMakeLists.txt.in b/Tests/RunCMake/CTestResourceAllocation/CMakeLists.txt.in
new file mode 100644
index 0000000..9984421
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/CMakeLists.txt.in
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.15)
+set(CASE_NAME "@CASE_NAME@")
+if(CASE_NAME MATCHES "^(.*)-ctest-s")
+ set(projname "${CMAKE_MATCH_1}")
+ project(${projname} NONE)
+ include(CTest)
+ include("@RunCMake_SOURCE_DIR@/ResourceCommon.cmake")
+ include("@RunCMake_SOURCE_DIR@/${projname}.cmake")
+endif()
diff --git a/Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake b/Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake
new file mode 100644
index 0000000..7d63299
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake
@@ -0,0 +1,23 @@
+function(setup_resource_tests)
+ if(CTEST_RESOURCE_ALLOC_ENABLED)
+ add_test(NAME ResourceSetup COMMAND "${CMAKE_COMMAND}" -E remove -f "${CMAKE_BINARY_DIR}/ctresalloc.log")
+ endif()
+endfunction()
+
+function(add_resource_test name sleep_time proc)
+ if(CTEST_RESOURCE_ALLOC_ENABLED)
+ add_test(NAME "${name}" COMMAND "${CTRESALLOC_COMMAND}" write "${CMAKE_BINARY_DIR}/ctresalloc.log" "${name}" "${sleep_time}" "${proc}")
+ set_property(TEST "${name}" PROPERTY DEPENDS ResourceSetup)
+ else()
+ add_test(NAME "${name}" COMMAND "${CTRESALLOC_COMMAND}" write "${CMAKE_BINARY_DIR}/ctresalloc.log" "${name}" "${sleep_time}")
+ endif()
+ set_property(TEST "${name}" PROPERTY RESOURCE_GROUPS "${proc}")
+ list(APPEND RESOURCE_TESTS "${name}")
+ set(RESOURCE_TESTS "${RESOURCE_TESTS}" PARENT_SCOPE)
+endfunction()
+
+function(cleanup_resource_tests)
+ if(CTEST_RESOURCE_ALLOC_ENABLED)
+ file(WRITE "${CMAKE_BINARY_DIR}/restests.txt" "${RESOURCE_TESTS}")
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CTestResourceAllocation/RunCMakeTest.cmake b/Tests/RunCMake/CTestResourceAllocation/RunCMakeTest.cmake
new file mode 100644
index 0000000..d52a63e
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/RunCMakeTest.cmake
@@ -0,0 +1,167 @@
+include(RunCMake)
+include(RunCTest)
+
+###############################################################################
+# Test ctresalloc itself - we want to make sure it's not just rubber-stamping
+# the test results
+###############################################################################
+
+function(ctresalloc_verify_log expected_contents)
+ if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/ctresalloc.log")
+ string(APPEND RunCMake_TEST_FAILED "Log file was not written\n")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ return()
+ endif()
+ file(READ "${RunCMake_TEST_BINARY_DIR}/ctresalloc.log" actual_contents)
+ if(NOT actual_contents STREQUAL expected_contents)
+ string(APPEND RunCMake_TEST_FAILED "Actual log did not match expected log\n")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(run_ctresalloc_write_proc name proc)
+ file(REMOVE "${RunCMake_BINARY_DIR}/${name}-build/ctresalloc.log")
+ run_ctresalloc_write_proc_nodel("${name}" "${proc}" "${ARGN}")
+endfunction()
+
+function(run_ctresalloc_write_proc_nodel name proc)
+ string(REPLACE ";" "\\;" proc "${proc}")
+ run_cmake_command(${name} "${CMAKE_COMMAND}" -E env "${ARGN}" "${CTRESALLOC_COMMAND}" write "${RunCMake_BINARY_DIR}/${name}-build/ctresalloc.log" "${name}" 0 "${proc}")
+endfunction()
+
+function(run_ctresalloc_write_noproc name)
+ run_cmake_command(${name} "${CMAKE_COMMAND}" -E env "${ARGN}" "${CTRESALLOC_COMMAND}" write "${RunCMake_BINARY_DIR}/${name}-build/ctresalloc.log" "${name}" 0)
+endfunction()
+
+function(run_ctresalloc_verify name tests)
+ string(REPLACE ";" "\\;" tests "${tests}")
+ run_cmake_command(${name} "${CTRESALLOC_COMMAND}" verify "${RunCMake_SOURCE_DIR}/${name}.log" "${CMAKE_CURRENT_LIST_DIR}/resspec.json" "${tests}")
+endfunction()
+
+unset(ENV{CTEST_RESOURCE_GROUP_COUNT})
+set(RunCMake_TEST_NO_CLEAN 1)
+file(REMOVE_RECURSE "${RunCMake_BINARY_DIR}/ctresalloc-write-proc-good1-build")
+file(MAKE_DIRECTORY "${RunCMake_BINARY_DIR}/ctresalloc-write-proc-good1-build")
+file(WRITE "${RunCMake_BINARY_DIR}/ctresalloc-write-proc-good1-build/ctresalloc.log"
+[[begin test1
+alloc widgets 0 1
+dealloc widgets 0 1
+end test1
+]])
+run_ctresalloc_write_proc_nodel(ctresalloc-write-proc-good1 "1,widgets:2,transmogrifiers:1;2,widgets:1,widgets:2"
+ CTEST_RESOURCE_GROUP_COUNT=3
+ CTEST_RESOURCE_GROUP_0=widgets,transmogrifiers
+ CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2
+ CTEST_RESOURCE_GROUP_0_TRANSMOGRIFIERS=id:calvin,slots:1
+ CTEST_RESOURCE_GROUP_1=widgets
+ "CTEST_RESOURCE_GROUP_1_WIDGETS=id:0,slots:1\\;id:2,slots:2"
+ CTEST_RESOURCE_GROUP_2=widgets
+ "CTEST_RESOURCE_GROUP_2_WIDGETS=id:0,slots:1\\;id:2,slots:2"
+ )
+set(RunCMake_TEST_NO_CLEAN 0)
+run_ctresalloc_write_proc(ctresalloc-write-proc-good2 "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ CTEST_RESOURCE_GROUP_0_WIDGETS=id:3,slots:8
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-nocount "widgets:8")
+run_ctresalloc_write_proc(ctresalloc-write-proc-badcount "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=2
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-nores "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badres "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets,transmogrifiers
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-nowidgets "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badwidgets1 "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ CTEST_RESOURCE_GROUP_0_WIDGETS=
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badwidgets2 "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ "CTEST_RESOURCE_GROUP_0_WIDGETS=id:3,slots:8\\;id:0,slots:1"
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badwidgets3 "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ CTEST_RESOURCE_GROUP_0_WIDGETS=id:3,slots:7
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badwidgets4 "widgets:8"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ CTEST_RESOURCE_GROUP_0_WIDGETS=invalid
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badwidgets5 "widgets:2,widgets:2"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ "CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2\\;id:0,slots:1"
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badwidgets6 "widgets:2"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ "CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2\\;id:0,slots:1"
+ )
+run_ctresalloc_write_proc(ctresalloc-write-proc-badwidgets7 "widgets:2,widgets:2"
+ CTEST_RESOURCE_GROUP_COUNT=1
+ CTEST_RESOURCE_GROUP_0=widgets
+ CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2
+ )
+
+run_ctresalloc_write_noproc(ctresalloc-write-noproc-good1)
+run_ctresalloc_write_noproc(ctresalloc-write-noproc-count
+ CTEST_RESOURCE_GROUP_COUNT=1
+ )
+
+run_ctresalloc_verify(ctresalloc-verify-good1 "test1;test2")
+run_ctresalloc_verify(ctresalloc-verify-good2 "")
+run_ctresalloc_verify(ctresalloc-verify-nolog "")
+run_ctresalloc_verify(ctresalloc-verify-nores "")
+run_ctresalloc_verify(ctresalloc-verify-noid "")
+run_ctresalloc_verify(ctresalloc-verify-notenough "")
+run_ctresalloc_verify(ctresalloc-verify-baddealloc "")
+run_ctresalloc_verify(ctresalloc-verify-leak "")
+run_ctresalloc_verify(ctresalloc-verify-badtest1 "")
+run_ctresalloc_verify(ctresalloc-verify-badtest2 "test1")
+run_ctresalloc_verify(ctresalloc-verify-badtest3 "test1")
+run_ctresalloc_verify(ctresalloc-verify-badtest4 "test1")
+run_ctresalloc_verify(ctresalloc-verify-badtest5 "test1")
+run_ctresalloc_verify(ctresalloc-verify-nobegin "test1")
+run_ctresalloc_verify(ctresalloc-verify-noend "test1")
+
+###############################################################################
+# Now test the resource allocation feature of CTest
+###############################################################################
+
+function(run_ctest_resource name parallel random)
+ run_ctest("${name}-ctest-s-res" "-DCTEST_RESOURCE_ALLOC_ENABLED=1" "-DCTRESALLOC_COMMAND=${CTRESALLOC_COMMAND}" "-DCTEST_PARALLEL=${parallel}" "-DCTEST_RANDOM=${random}")
+ run_ctest("${name}-ctest-s-nores" "-DCTEST_RESOURCE_ALLOC_ENABLED=0" "-DCTRESALLOC_COMMAND=${CTRESALLOC_COMMAND}" "-DCTEST_PARALLEL=${parallel}" "-DCTEST_RANDOM=${random}")
+endfunction()
+
+function(verify_ctest_resources)
+ file(READ "${RunCMake_TEST_BINARY_DIR}/restests.txt" restests)
+ execute_process(COMMAND "${CTRESALLOC_COMMAND}" verify "${RunCMake_TEST_BINARY_DIR}/ctresalloc.log" "${CMAKE_CURRENT_LIST_DIR}/resspec.json" "${restests}"
+ OUTPUT_VARIABLE output ERROR_QUIET RESULT_VARIABLE result)
+ if(result)
+ string(APPEND RunCMake_TEST_FAILED "${output}")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+run_ctest_resource(lotsoftests 10 1)
+run_ctest_resource(checkfree1 2 0)
+run_ctest_resource(checkfree2 1 0)
+run_ctest_resource(notenough1 1 0)
+run_ctest_resource(notenough2 1 0)
+run_ctest_resource(ensure_parallel 2 0)
+
+set(ENV{CTEST_RESOURCE_GROUP_COUNT} 2)
+run_ctest_resource(process_count 1 0)
+unset(ENV{CTEST_RESOURCE_GROUP_COUNT})
diff --git a/Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-check.cmake b/Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-check.cmake
new file mode 100644
index 0000000..ceda72e
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-check.cmake
@@ -0,0 +1 @@
+verify_ctest_resources()
diff --git a/Tests/RunCMake/CTestResourceAllocation/checkfree1.cmake b/Tests/RunCMake/CTestResourceAllocation/checkfree1.cmake
new file mode 100644
index 0000000..45cbf20
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/checkfree1.cmake
@@ -0,0 +1,7 @@
+setup_resource_tests()
+
+add_resource_test(Test1 1 "widgets:8")
+add_resource_test(Test2 1 "fluxcapacitors:50;fluxcapacitors:50,widgets:8")
+add_resource_test(Test3 1 "fluxcapacitors:121")
+
+cleanup_resource_tests()
diff --git a/Tests/RunCMake/CTestResourceAllocation/checkfree2-ctest-s-res-check.cmake b/Tests/RunCMake/CTestResourceAllocation/checkfree2-ctest-s-res-check.cmake
new file mode 100644
index 0000000..ceda72e
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/checkfree2-ctest-s-res-check.cmake
@@ -0,0 +1 @@
+verify_ctest_resources()
diff --git a/Tests/RunCMake/CTestResourceAllocation/checkfree2.cmake b/Tests/RunCMake/CTestResourceAllocation/checkfree2.cmake
new file mode 100644
index 0000000..03b737c
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/checkfree2.cmake
@@ -0,0 +1,8 @@
+setup_resource_tests()
+
+# This test is an attack on the resource scheduling algorithm. It has been
+# carefully crafted to fool the algorithm into thinking there aren't sufficient
+# resources for it.
+add_resource_test(Test1 1 "widgets:2;4,widgets:4")
+
+cleanup_resource_tests()
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc.log
new file mode 100644
index 0000000..abd6bad
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc.log
@@ -0,0 +1,2 @@
+alloc widgets 0 1
+dealloc widgets 0 2
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1.log
new file mode 100644
index 0000000..605104b
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1.log
@@ -0,0 +1 @@
+begin test1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2.log
new file mode 100644
index 0000000..1ff1b0d
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2.log
@@ -0,0 +1,2 @@
+begin test1
+begin test1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3.log
new file mode 100644
index 0000000..1925e6a
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3.log
@@ -0,0 +1,3 @@
+begin test1
+end test1
+begin test1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4.log
new file mode 100644
index 0000000..3fe7da1
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4.log
@@ -0,0 +1,3 @@
+begin test1
+end test1
+end test1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5.log
new file mode 100644
index 0000000..3a2e7e3
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5.log
@@ -0,0 +1 @@
+end test1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good1.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good1.log
new file mode 100644
index 0000000..2cca0c3
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good1.log
@@ -0,0 +1,14 @@
+begin test1
+alloc widgets 3 4
+alloc widgets 4 1
+alloc transmogrifiers calvin 2
+alloc fluxcapacitors outatime 121
+begin test2
+alloc widgets 3 4
+dealloc widgets 3 4
+dealloc widgets 4 1
+dealloc transmogrifiers calvin 2
+dealloc fluxcapacitors outatime 121
+end test1
+dealloc widgets 3 4
+end test2
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good2.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good2.log
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good2.log
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak.log
new file mode 100644
index 0000000..b900d86
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak.log
@@ -0,0 +1 @@
+alloc widgets 0 1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin.log
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin.log
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend.log
new file mode 100644
index 0000000..605104b
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend.log
@@ -0,0 +1 @@
+begin test1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid.log
new file mode 100644
index 0000000..c718975
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid.log
@@ -0,0 +1,2 @@
+alloc fluxcapacitors train 1
+dealloc fluxcapacitors train 1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nolog-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nolog-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nolog-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores.log
new file mode 100644
index 0000000..a18202b
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores.log
@@ -0,0 +1,2 @@
+alloc gpus 0 1
+dealloc gpus 0 1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough.log b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough.log
new file mode 100644
index 0000000..ac78d5a
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough.log
@@ -0,0 +1,2 @@
+alloc widgets 0 8
+dealloc widgets 0 8
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-noproc-count-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-noproc-count-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-noproc-count-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badcount-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badcount-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badcount-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badres-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badres-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badres-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets1-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets2-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets3-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets4-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets5-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets6-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets6-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets6-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets7-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets7-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets7-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good1-check.cmake b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good1-check.cmake
new file mode 100644
index 0000000..40144c8
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good1-check.cmake
@@ -0,0 +1,20 @@
+ctresalloc_verify_log(
+[[begin test1
+alloc widgets 0 1
+dealloc widgets 0 1
+end test1
+begin ctresalloc-write-proc-good1
+alloc transmogrifiers calvin 1
+alloc widgets 0 2
+alloc widgets 0 1
+alloc widgets 2 2
+alloc widgets 0 1
+alloc widgets 2 2
+dealloc transmogrifiers calvin 1
+dealloc widgets 0 2
+dealloc widgets 0 1
+dealloc widgets 2 2
+dealloc widgets 0 1
+dealloc widgets 2 2
+end ctresalloc-write-proc-good1
+]])
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good2-check.cmake b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good2-check.cmake
new file mode 100644
index 0000000..4545466
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good2-check.cmake
@@ -0,0 +1,6 @@
+ctresalloc_verify_log(
+[[begin ctresalloc-write-proc-good2
+alloc widgets 3 8
+dealloc widgets 3 8
+end ctresalloc-write-proc-good2
+]])
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nocount-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nocount-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nocount-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nores-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nores-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nores-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nowidgets-result.txt b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nowidgets-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nowidgets-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx b/Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx
new file mode 100644
index 0000000..27644af
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx
@@ -0,0 +1,399 @@
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdlib>
+#include <iostream>
+#include <map>
+#include <set>
+#include <string>
+#include <thread>
+#include <utility>
+#include <vector>
+
+#include "cmsys/Encoding.hxx"
+#include "cmsys/FStream.hxx"
+
+#include "cmCTestMultiProcessHandler.h"
+#include "cmCTestResourceAllocator.h"
+#include "cmCTestResourceSpec.h"
+#include "cmCTestTestHandler.h"
+#include "cmFileLock.h"
+#include "cmFileLockResult.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+/*
+ * This helper program is used to verify that the CTest resource allocation
+ * feature is working correctly. It consists of two stages:
+ *
+ * 1) write - This stage receives the RESOURCE_GROUPS property of the test and
+ * compares it with the values passed in the CTEST_RESOURCE_GROUP_*
+ * environment variables. If it received all of the resources it expected,
+ * then it writes this information to a log file, which will be read in
+ * the verify stage.
+ * 2) verify - This stage compares the log file with the resource spec file to
+ * make sure that no resources were over-subscribed, deallocated without
+ * being allocated, or allocated without being deallocated.
+ */
+
+static int usage(const char* argv0)
+{
+ std::cout << "Usage: " << argv0 << " (write|verify) <args...>" << std::endl;
+ return 1;
+}
+
+static int usageWrite(const char* argv0)
+{
+ std::cout << "Usage: " << argv0
+ << " write <log-file> <test-name> <sleep-time-secs>"
+ " [<resource-groups-property>]"
+ << std::endl;
+ return 1;
+}
+
+static int usageVerify(const char* argv0)
+{
+ std::cout << "Usage: " << argv0
+ << " verify <log-file> <resource-spec-file> [<test-names>]"
+ << std::endl;
+ return 1;
+}
+
+static int doWrite(int argc, char const* const* argv)
+{
+ if (argc < 5 || argc > 6) {
+ return usageWrite(argv[0]);
+ }
+ std::string logFile = argv[2];
+ std::string testName = argv[3];
+ unsigned int sleepTime = std::atoi(argv[4]);
+ std::vector<std::map<
+ std::string, std::vector<cmCTestMultiProcessHandler::ResourceAllocation>>>
+ resources;
+ if (argc == 6) {
+ // Parse RESOURCE_GROUPS property
+ std::string resourceGroupsProperty = argv[5];
+ std::vector<
+ std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>
+ resourceGroups;
+ bool result = cmCTestTestHandler::ParseResourceGroupsProperty(
+ resourceGroupsProperty, resourceGroups);
+ (void)result;
+ assert(result);
+
+ // Verify group count
+ const char* resourceGroupCountEnv =
+ cmSystemTools::GetEnv("CTEST_RESOURCE_GROUP_COUNT");
+ if (!resourceGroupCountEnv) {
+ std::cout << "CTEST_RESOURCE_GROUP_COUNT should be defined" << std::endl;
+ return 1;
+ }
+ int resourceGroupCount = std::atoi(resourceGroupCountEnv);
+ if (resourceGroups.size() != std::size_t(resourceGroupCount)) {
+ std::cout
+ << "CTEST_RESOURCE_GROUP_COUNT does not match expected resource groups"
+ << std::endl
+ << "Expected: " << resourceGroups.size() << std::endl
+ << "Actual: " << resourceGroupCount << std::endl;
+ return 1;
+ }
+
+ if (!cmSystemTools::Touch(logFile + ".lock", true)) {
+ std::cout << "Could not create lock file" << std::endl;
+ return 1;
+ }
+ cmFileLock lock;
+ auto lockResult =
+ lock.Lock(logFile + ".lock", static_cast<unsigned long>(-1));
+ if (!lockResult.IsOk()) {
+ std::cout << "Could not lock file" << std::endl;
+ return 1;
+ }
+ std::size_t i = 0;
+ cmsys::ofstream fout(logFile.c_str(), std::ios::app);
+ fout << "begin " << testName << std::endl;
+ for (auto& resourceGroup : resourceGroups) {
+ try {
+ // Build and verify set of expected resources
+ std::set<std::string> expectedResources;
+ for (auto const& it : resourceGroup) {
+ expectedResources.insert(it.ResourceType);
+ }
+
+ std::string prefix = "CTEST_RESOURCE_GROUP_";
+ prefix += std::to_string(i);
+ const char* actualResourcesCStr = cmSystemTools::GetEnv(prefix);
+ if (!actualResourcesCStr) {
+ std::cout << prefix << " should be defined" << std::endl;
+ return 1;
+ }
+
+ auto actualResourcesVec =
+ cmSystemTools::SplitString(actualResourcesCStr, ',');
+ std::set<std::string> actualResources;
+ for (auto const& r : actualResourcesVec) {
+ if (!r.empty()) {
+ actualResources.insert(r);
+ }
+ }
+
+ if (actualResources != expectedResources) {
+ std::cout << prefix << " did not list expected resources"
+ << std::endl;
+ return 1;
+ }
+
+ // Verify that we got what we asked for and write it to the log
+ prefix += '_';
+ std::map<std::string,
+ std::vector<cmCTestMultiProcessHandler::ResourceAllocation>>
+ resEntry;
+ for (auto const& type : actualResources) {
+ auto it = resourceGroup.begin();
+
+ std::string varName = prefix;
+ varName += cmSystemTools::UpperCase(type);
+ const char* varVal = cmSystemTools::GetEnv(varName);
+ if (!varVal) {
+ std::cout << varName << " should be defined" << std::endl;
+ return 1;
+ }
+
+ auto received = cmSystemTools::SplitString(varVal, ';');
+ for (auto const& r : received) {
+ while (it->ResourceType != type || it->UnitsNeeded == 0) {
+ ++it;
+ if (it == resourceGroup.end()) {
+ std::cout << varName << " did not list expected resources"
+ << std::endl;
+ return 1;
+ }
+ }
+ auto split = cmSystemTools::SplitString(r, ',');
+ if (split.size() != 2) {
+ std::cout << varName << " was ill-formed" << std::endl;
+ return 1;
+ }
+ if (!cmHasLiteralPrefix(split[0], "id:")) {
+ std::cout << varName << " was ill-formed" << std::endl;
+ return 1;
+ }
+ auto id = split[0].substr(3);
+ if (!cmHasLiteralPrefix(split[1], "slots:")) {
+ std::cout << varName << " was ill-formed" << std::endl;
+ return 1;
+ }
+ auto slots = split[1].substr(6);
+ unsigned int amount = std::atoi(slots.c_str());
+ if (amount != static_cast<unsigned int>(it->SlotsNeeded)) {
+ std::cout << varName << " did not list expected resources"
+ << std::endl;
+ return 1;
+ }
+ --it->UnitsNeeded;
+
+ fout << "alloc " << type << " " << id << " " << amount
+ << std::endl;
+ resEntry[type].push_back({ id, amount });
+ }
+
+ bool ended = false;
+ while (it->ResourceType != type || it->UnitsNeeded == 0) {
+ ++it;
+ if (it == resourceGroup.end()) {
+ ended = true;
+ break;
+ }
+ }
+
+ if (!ended) {
+ std::cout << varName << " did not list expected resources"
+ << std::endl;
+ return 1;
+ }
+ }
+ resources.push_back(resEntry);
+
+ ++i;
+ } catch (...) {
+ std::cout << "Unknown error while processing resources" << std::endl;
+ return 1;
+ }
+ }
+
+ auto unlockResult = lock.Release();
+ if (!unlockResult.IsOk()) {
+ std::cout << "Could not unlock file" << std::endl;
+ return 1;
+ }
+ } else {
+ if (cmSystemTools::GetEnv("CTEST_RESOURCE_GROUP_COUNT")) {
+ std::cout << "CTEST_RESOURCE_GROUP_COUNT should not be defined"
+ << std::endl;
+ return 1;
+ }
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(sleepTime));
+
+ if (argc == 6) {
+ if (!cmSystemTools::Touch(logFile + ".lock", true)) {
+ std::cout << "Could not create lock file" << std::endl;
+ return 1;
+ }
+ cmFileLock lock;
+ auto lockResult =
+ lock.Lock(logFile + ".lock", static_cast<unsigned long>(-1));
+ if (!lockResult.IsOk()) {
+ std::cout << "Could not lock file" << std::endl;
+ return 1;
+ }
+ cmsys::ofstream fout(logFile.c_str(), std::ios::app);
+ for (auto const& group : resources) {
+ for (auto const& it : group) {
+ for (auto const& it2 : it.second) {
+ fout << "dealloc " << it.first << " " << it2.Id << " " << it2.Slots
+ << std::endl;
+ }
+ }
+ }
+
+ fout << "end " << testName << std::endl;
+
+ auto unlockResult = lock.Release();
+ if (!unlockResult.IsOk()) {
+ std::cout << "Could not unlock file" << std::endl;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int doVerify(int argc, char const* const* argv)
+{
+ if (argc < 4 || argc > 5) {
+ return usageVerify(argv[0]);
+ }
+ std::string logFile = argv[2];
+ std::string resFile = argv[3];
+ std::string testNames;
+ if (argc == 5) {
+ testNames = argv[4];
+ }
+ auto testNameList = cmExpandedList(testNames, false);
+ std::set<std::string> testNameSet(testNameList.begin(), testNameList.end());
+
+ cmCTestResourceSpec spec;
+ if (!spec.ReadFromJSONFile(resFile)) {
+ std::cout << "Could not read resource spec " << resFile << std::endl;
+ return 1;
+ }
+
+ cmCTestResourceAllocator allocator;
+ allocator.InitializeFromResourceSpec(spec);
+
+ cmsys::ifstream fin(logFile.c_str(), std::ios::in);
+ if (!fin) {
+ std::cout << "Could not open log file " << logFile << std::endl;
+ return 1;
+ }
+
+ std::string command;
+ std::string resourceName;
+ std::string resourceId;
+ std::string testName;
+ unsigned int amount;
+ std::set<std::string> inProgressTests;
+ std::set<std::string> completedTests;
+ try {
+ while (fin >> command) {
+ if (command == "begin") {
+ if (!(fin >> testName)) {
+ std::cout << "Could not read begin line" << std::endl;
+ return 1;
+ }
+ if (!testNameSet.count(testName) || inProgressTests.count(testName) ||
+ completedTests.count(testName)) {
+ std::cout << "Could not begin test" << std::endl;
+ return 1;
+ }
+ inProgressTests.insert(testName);
+ } else if (command == "alloc") {
+ if (!(fin >> resourceName) || !(fin >> resourceId) ||
+ !(fin >> amount)) {
+ std::cout << "Could not read alloc line" << std::endl;
+ return 1;
+ }
+ if (!allocator.AllocateResource(resourceName, resourceId, amount)) {
+ std::cout << "Could not allocate resources" << std::endl;
+ return 1;
+ }
+ } else if (command == "dealloc") {
+ if (!(fin >> resourceName) || !(fin >> resourceId) ||
+ !(fin >> amount)) {
+ std::cout << "Could not read dealloc line" << std::endl;
+ return 1;
+ }
+ if (!allocator.DeallocateResource(resourceName, resourceId, amount)) {
+ std::cout << "Could not deallocate resources" << std::endl;
+ return 1;
+ }
+ } else if (command == "end") {
+ if (!(fin >> testName)) {
+ std::cout << "Could not read end line" << std::endl;
+ return 1;
+ }
+ if (!inProgressTests.erase(testName)) {
+ std::cout << "Could not end test" << std::endl;
+ return 1;
+ }
+ if (!completedTests.insert(testName).second) {
+ std::cout << "Could not end test" << std::endl;
+ return 1;
+ }
+ }
+ }
+ } catch (...) {
+ std::cout << "Unknown error while reading log file" << std::endl;
+ return 1;
+ }
+
+ auto const& avail = allocator.GetResources();
+ for (auto const& it : avail) {
+ for (auto const& it2 : it.second) {
+ if (it2.second.Locked != 0) {
+ std::cout << "Resource was not unlocked" << std::endl;
+ return 1;
+ }
+ }
+ }
+
+ if (completedTests != testNameSet) {
+ std::cout << "Tests were not ended" << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char const* const* argv)
+{
+ cmsys::Encoding::CommandLineArguments args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = args.argc();
+ argv = args.argv();
+
+ if (argc < 2) {
+ return usage(argv[0]);
+ }
+
+ std::string argv1 = argv[1];
+ if (argv1 == "write") {
+ return doWrite(argc, argv);
+ }
+ if (argv1 == "verify") {
+ return doVerify(argc, argv);
+ }
+ return usage(argv[0]);
+}
diff --git a/Tests/RunCMake/CTestResourceAllocation/ensure_parallel-ctest-s-res-check.cmake b/Tests/RunCMake/CTestResourceAllocation/ensure_parallel-ctest-s-res-check.cmake
new file mode 100644
index 0000000..d842a76
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ensure_parallel-ctest-s-res-check.cmake
@@ -0,0 +1,16 @@
+verify_ctest_resources()
+
+set(expected_contents [[
+begin Test1
+alloc transmogrifiers calvin 2
+begin Test2
+alloc transmogrifiers hobbes 2
+dealloc transmogrifiers calvin 2
+end Test1
+dealloc transmogrifiers hobbes 2
+end Test2
+]])
+file(READ "${RunCMake_TEST_BINARY_DIR}/ctresalloc.log" actual_contents)
+if(NOT actual_contents STREQUAL expected_contents)
+ string(APPEND RunCMake_TEST_FAILED "ctresalloc.log contents did not match expected\n")
+endif()
diff --git a/Tests/RunCMake/CTestResourceAllocation/ensure_parallel.cmake b/Tests/RunCMake/CTestResourceAllocation/ensure_parallel.cmake
new file mode 100644
index 0000000..562d05a
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/ensure_parallel.cmake
@@ -0,0 +1,11 @@
+setup_resource_tests()
+
+add_resource_test(Test1 4 "transmogrifiers:2")
+
+# Mitigate possible race conditions to ensure that the events are logged in the
+# exact order we want
+add_test(NAME Test2Sleep COMMAND "${CMAKE_COMMAND}" -E sleep 2)
+add_resource_test(Test2 4 "transmogrifiers:2")
+set_property(TEST Test2 APPEND PROPERTY DEPENDS Test2Sleep)
+
+cleanup_resource_tests()
diff --git a/Tests/RunCMake/CTestResourceAllocation/lotsoftests-ctest-s-res-check.cmake b/Tests/RunCMake/CTestResourceAllocation/lotsoftests-ctest-s-res-check.cmake
new file mode 100644
index 0000000..ceda72e
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/lotsoftests-ctest-s-res-check.cmake
@@ -0,0 +1 @@
+verify_ctest_resources()
diff --git a/Tests/RunCMake/CTestResourceAllocation/lotsoftests.cmake b/Tests/RunCMake/CTestResourceAllocation/lotsoftests.cmake
new file mode 100644
index 0000000..4c0a7a5
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/lotsoftests.cmake
@@ -0,0 +1,16 @@
+setup_resource_tests()
+
+add_resource_test(Test1 2 "widgets:8;2,widgets:2")
+add_resource_test(Test2 5 "fluxcapacitors:40")
+add_resource_test(Test3 1 "10,widgets:1,fluxcapacitors:2")
+add_resource_test(Test4 4 "fluxcapacitors:121")
+
+foreach(i RANGE 5 50)
+ add_resource_test(Test${i} 1 "2,widgets:1")
+endforeach()
+
+foreach(i RANGE 51 100)
+ add_resource_test(Test${i} 1 "2,transmogrifiers:2")
+endforeach()
+
+cleanup_resource_tests()
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-check.cmake b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-check.cmake
new file mode 100644
index 0000000..321e9a2
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS "${RunCMake_TEST_BINARY_DIR}/ctresalloc.log")
+ set(RunCMake_TEST_FAILED "ctresalloc.log should not exist")
+endif()
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-result.txt b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt
new file mode 100644
index 0000000..41df5af
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt
@@ -0,0 +1,4 @@
+^Insufficient resources
+CMake Error at [^
+]*/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res/test\.cmake:[0-9]+ \(message\):
+ Tests did not pass$
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough1.cmake b/Tests/RunCMake/CTestResourceAllocation/notenough1.cmake
new file mode 100644
index 0000000..2908812
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough1.cmake
@@ -0,0 +1,5 @@
+setup_resource_tests()
+
+add_resource_test(Test1 1 "fluxcapacitors:200")
+
+cleanup_resource_tests()
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-check.cmake b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-check.cmake
new file mode 100644
index 0000000..321e9a2
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS "${RunCMake_TEST_BINARY_DIR}/ctresalloc.log")
+ set(RunCMake_TEST_FAILED "ctresalloc.log should not exist")
+endif()
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-result.txt b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt
new file mode 100644
index 0000000..6c2f554
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt
@@ -0,0 +1,4 @@
+^Insufficient resources
+CMake Error at [^
+]*/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res/test\.cmake:[0-9]+ \(message\):
+ Tests did not pass$
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough2.cmake b/Tests/RunCMake/CTestResourceAllocation/notenough2.cmake
new file mode 100644
index 0000000..d7600c8
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough2.cmake
@@ -0,0 +1,5 @@
+setup_resource_tests()
+
+add_resource_test(Test1 1 "terminators:2")
+
+cleanup_resource_tests()
diff --git a/Tests/RunCMake/CTestResourceAllocation/process_count-ctest-s-res-check.cmake b/Tests/RunCMake/CTestResourceAllocation/process_count-ctest-s-res-check.cmake
new file mode 100644
index 0000000..ceda72e
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/process_count-ctest-s-res-check.cmake
@@ -0,0 +1 @@
+verify_ctest_resources()
diff --git a/Tests/RunCMake/CTestResourceAllocation/process_count.cmake b/Tests/RunCMake/CTestResourceAllocation/process_count.cmake
new file mode 100644
index 0000000..1457f89
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/process_count.cmake
@@ -0,0 +1,5 @@
+setup_resource_tests()
+
+add_resource_test(Test1 1 "widgets:1")
+
+cleanup_resource_tests()
diff --git a/Tests/RunCMake/CTestResourceAllocation/resspec.json b/Tests/RunCMake/CTestResourceAllocation/resspec.json
new file mode 100644
index 0000000..c67fcca
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/resspec.json
@@ -0,0 +1,55 @@
+{
+ "local": [
+ {
+ "widgets": [
+ {
+ "id": "0",
+ "slots": 4
+ },
+ {
+ "id": "1",
+ "slots": 2
+ },
+ {
+ "id": "2",
+ "slots": 4
+ },
+ {
+ "id": "3",
+ "slots": 8
+ },
+ {
+ "id": "4",
+ "slots": 1
+ },
+ {
+ "id": "5",
+ "slots": 1
+ },
+ {
+ "id": "6",
+ "slots": 1
+ },
+ {
+ "id": "7"
+ }
+ ],
+ "transmogrifiers": [
+ {
+ "id": "calvin",
+ "slots": 2
+ },
+ {
+ "id": "hobbes",
+ "slots": 2
+ }
+ ],
+ "fluxcapacitors": [
+ {
+ "id": "outatime",
+ "slots": 121
+ }
+ ]
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CTestResourceAllocation/test.cmake.in b/Tests/RunCMake/CTestResourceAllocation/test.cmake.in
new file mode 100644
index 0000000..4b426f1
--- /dev/null
+++ b/Tests/RunCMake/CTestResourceAllocation/test.cmake.in
@@ -0,0 +1,23 @@
+set(CTEST_SITE "test-site")
+set(CTEST_BUILD_NAME "test-build-name")
+set(CTEST_SOURCE_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@")
+set(CTEST_BINARY_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@-build")
+set(CTEST_CMAKE_GENERATOR "@RunCMake_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@RunCMake_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@RunCMake_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
+
+ctest_start(Experimental QUIET)
+ctest_configure(OPTIONS
+ "-DCTEST_RESOURCE_ALLOC_ENABLED=${CTEST_RESOURCE_ALLOC_ENABLED};-DCTRESALLOC_COMMAND=${CTRESALLOC_COMMAND}"
+ )
+ctest_build()
+
+if(CTEST_RESOURCE_ALLOC_ENABLED)
+ set(resspec RESOURCE_SPEC_FILE "@RunCMake_SOURCE_DIR@/resspec.json")
+endif()
+ctest_test(${resspec} RETURN_VALUE retval PARALLEL_LEVEL ${CTEST_PARALLEL} SCHEDULE_RANDOM ${CTEST_RANDOM})
+if(retval)
+ message(FATAL_ERROR "Tests did not pass")
+endif()