Skip to content

Commit debd6b5

Browse files
committed
CMake: Speed up test discovery when expanded by using a Python script that
lists all the tests in a single invocation. This optimizes the amount of executables we run, because now we need to once run the script instead of doing this for each test script. Now we can discover all the tests instantly, without any additional time needed for this. * build/list_tests.py: New script for listing all the tests in many scripts at the same time. * CMakeLists.txt (tests): Use the new script to list the tests if expand is enables, otherwise just enumerate the files and add them without any manipulations as it was before. git-svn-id: https://svn.apache.org/repos/asf/subversion/trunk@1923451 13f79535-47bb-0310-9956-ffa450edef68
1 parent 2d87233 commit debd6b5

File tree

2 files changed

+127
-27
lines changed

2 files changed

+127
-27
lines changed

CMakeLists.txt

+37-27
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ include("build/cmake/targets.cmake")
771771
if(SVN_ENABLE_TESTS)
772772
find_package(Python3 COMPONENTS Interpreter REQUIRED)
773773
set(run_tests_script "${CMAKE_CURRENT_SOURCE_DIR}/build/run_tests.py")
774+
set(list_tests_script "${CMAKE_CURRENT_SOURCE_DIR}/build/list_tests.py")
774775

775776
function(add_py_test name prog)
776777
if(SVN_TEST_CONFIGURE_FOR_PARALLEL)
@@ -803,41 +804,50 @@ if(SVN_ENABLE_TESTS)
803804
"subversion/tests/cmdline/*_tests.py"
804805
)
805806

806-
foreach(py_test_abspath ${PYTHON_TESTS})
807-
# Keep `.py'.
808-
get_filename_component(py_test_name ${py_test_abspath} NAME_WLE)
809-
file(RELATIVE_PATH py_test_relpath ${CMAKE_CURRENT_SOURCE_DIR} ${py_test_abspath})
810-
set(binary_dir $<TARGET_FILE_DIR:svn>)
811-
812-
if(SVN_TEST_EXPAND)
813-
message("Listing tests in ${py_test_name}")
814-
execute_process(
815-
COMMAND
816-
"${Python3_EXECUTABLE}" "${run_tests_script}"
817-
--log-to-stdout
818-
--list
819-
${CMAKE_CURRENT_SOURCE_DIR}
820-
${binary_dir}
821-
${py_test_abspath}
822-
OUTPUT_VARIABLE tests_list_output
823-
)
824-
string(REGEX MATCHALL "\n *([0-9]+)" tests_list ${tests_list_output})
807+
set(binary_dir $<TARGET_FILE_DIR:svn>)
825808

826-
foreach(test_num ${tests_list})
827-
string(REGEX MATCH "([0-9]+)" test_num ${test_num})
809+
if(SVN_TEST_EXPAND)
810+
execute_process(
811+
COMMAND
812+
"${Python3_EXECUTABLE}" "${list_tests_script}"
813+
${PYTHON_TESTS}
814+
OUTPUT_VARIABLE tests_list_output
815+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
816+
RESULT_VARIABLE command_result
817+
)
818+
819+
if (command_result)
820+
message(FATAL_ERROR "list_tests.py failed.")
821+
endif()
822+
823+
string(REGEX MATCHALL "[^\n\r]+" tests_list "${tests_list_output}")
824+
825+
foreach(test_case ${tests_list})
826+
if(test_case MATCHES "(.+)#(.+)")
827+
set(py_test_abspath "${CMAKE_MATCH_1}")
828+
set(py_test_num "${CMAKE_MATCH_2}")
829+
830+
get_filename_component(py_test_name ${py_test_abspath} NAME_WLE)
831+
file(RELATIVE_PATH py_test_relpath ${CMAKE_CURRENT_SOURCE_DIR} ${py_test_abspath})
828832

829833
add_py_test(
830-
"cmdline.${py_test_name}.${test_num}"
831-
"${py_test_relpath}#${test_num}"
834+
"cmdline.${py_test_name}.${py_test_num}"
835+
"${py_test_relpath}#${py_test_num}"
832836
)
833-
endforeach()
834-
else()
837+
endif()
838+
endforeach()
839+
else()
840+
foreach(py_test_abspath ${PYTHON_TESTS})
841+
# Keep `.py'.
842+
get_filename_component(py_test_name ${py_test_abspath} NAME_WLE)
843+
file(RELATIVE_PATH py_test_relpath ${CMAKE_CURRENT_SOURCE_DIR} ${py_test_abspath})
844+
835845
add_py_test(
836846
"cmdline.${py_test_name}"
837847
"${py_test_relpath}"
838848
)
839-
endif()
840-
endforeach()
849+
endforeach()
850+
endif()
841851
endif()
842852

843853
if (SVN_ENABLE_SVNXX)

build/list_tests.py

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python
2+
#
3+
# Licensed to the Apache Software Foundation (ASF) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The ASF licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
#
20+
# list_tests.py - lists all the tests in a Python test script
21+
#
22+
23+
'''usage: python list_tests.py <prog ...>
24+
25+
This script will print out all the tests in the `TESTPATH#TESTNUM`
26+
format for each of these tests.
27+
'''
28+
29+
import os, sys
30+
import traceback
31+
32+
if sys.version_info < (3, 5):
33+
import imp
34+
else:
35+
# The imp module is deprecated since Python 3.4; the replacement we use,
36+
# module_from_spec(), is available since Python 3.5.
37+
import importlib.util
38+
39+
# Placeholder for the svntest module
40+
svntest = None
41+
42+
tests = sys.argv[1:]
43+
44+
def _load_py_test_module(progabs, modname):
45+
'Run a python test, passing parameters as needed.'
46+
try:
47+
if sys.version_info < (3, 0):
48+
prog_mod = imp.load_module(modname, open(progabs, 'r'), progabs,
49+
('.py', 'U', imp.PY_SOURCE))
50+
elif sys.version_info < (3, 5):
51+
prog_mod = imp.load_module(modname,
52+
open(progabs, 'r', encoding="utf-8"),
53+
progabs, ('.py', 'U', imp.PY_SOURCE))
54+
else:
55+
spec = importlib.util.spec_from_file_location(modname, progabs)
56+
prog_mod = importlib.util.module_from_spec(spec)
57+
sys.modules[modname] = prog_mod
58+
spec.loader.exec_module(prog_mod)
59+
except:
60+
print("\nError loading test (details in following traceback): " + modname)
61+
traceback.print_exc()
62+
sys.exit(1)
63+
64+
return prog_mod
65+
66+
basedir = os.path.join("subversion/tests/cmdline")
67+
68+
# The svntest module is very pedantic about the current working directory
69+
old_cwd = os.getcwd()
70+
try:
71+
sys.path.insert(0, os.path.abspath(basedir))
72+
73+
os.chdir(basedir)
74+
75+
__import__('svntest')
76+
__import__('svntest.main')
77+
__import__('svntest.testcase')
78+
svntest = sys.modules['svntest']
79+
svntest.main = sys.modules['svntest.main']
80+
svntest.testcase = sys.modules['svntest.testcase']
81+
82+
finally:
83+
os.chdir(old_cwd)
84+
85+
for progabs in tests:
86+
modname = os.path.basename(progabs)[:-3]
87+
88+
testlist = _load_py_test_module(progabs, modname).test_list
89+
for testnum in range(1, len(testlist)):
90+
print(progabs + "#" + str(testnum))

0 commit comments

Comments
 (0)