Author: philip
Date: Mon Mar 20 01:22:52 2023
New Revision: 1908546
URL: http://svn.apache.org/viewvc?rev=1908546&view=rev
Log:
Add suport for running valgrind during 'make check'.
* Makefile.in (check): Add options.
* build/run_tests.py
(_init_c_tests, _init_py_tests): Add options.
(_maybe_prepend_valgrind): New.
(_run_c_test): Prepend valgrind.
(create_parser): Add options.
* subversion/tests/cmdline/svntest/main.py
(libtool_script): New variable.
(open_pipe): Prepend valgrind.
(TestSpawningThread): Add options.
(_create_parser): Add options.
* subversion/tests/README: Describe valgrind testing..
Modified:
subversion/trunk/Makefile.in
subversion/trunk/build/run_tests.py
subversion/trunk/subversion/tests/README
subversion/trunk/subversion/tests/cmdline/svntest/main.py
Modified: subversion/trunk/Makefile.in
URL:
http://svn.apache.org/viewvc/subversion/trunk/Makefile.in?rev=1908546&r1=1908545&r2=1908546&view=diff
==============================================================================
--- subversion/trunk/Makefile.in (original)
+++ subversion/trunk/Makefile.in Mon Mar 20 01:22:52 2023
@@ -632,6 +632,12 @@ check: bin @TRANSFORM_LIBTOOL_SCRIPTS@ $
if test "$(STORE_PRISTINE)" != ""; then \
flags="--store-pristine $(STORE_PRISTINE) $$flags"; \
fi; \
+ if test "$(VALGRIND)" != ""; then \
+ flags="--valgrind $(VALGRIND) $$flags"; \
+ fi; \
+ if test "$(VALGRIND_OPTS)" != ""; then \
+ flags="--valgrind-opts $(VALGRIND_OPTS) $$flags"; \
+ fi; \
LD_LIBRARY_PATH='$(auth_plugin_dirs):$(LD_LIBRARY_PATH)' \
$(PYTHON) $(top_srcdir)/build/run_tests.py \
--config-file $(top_srcdir)/subversion/tests/tests.conf \
Modified: subversion/trunk/build/run_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/build/run_tests.py?rev=1908546&r1=1908545&r2=1908546&view=diff
==============================================================================
--- subversion/trunk/build/run_tests.py (original)
+++ subversion/trunk/build/run_tests.py Mon Mar 20 01:22:52 2023
@@ -266,6 +266,10 @@ class TestHarness:
cmdline.append('--parallel')
if self.opts.store_pristine is not None:
cmdline.append('--store-pristine=%s' % self.opts.store_pristine)
+ if self.opts.valgrind is not None:
+ cmdline.append('--valgrind=%s' % self.opts.valgrind)
+ if self.opts.valgrind_opts is not None:
+ cmdline.append('--valgrind-opts=%s' % self.opts.valgrind_opts)
self.c_test_cmdline = cmdline
@@ -335,6 +339,10 @@ class TestHarness:
cmdline.append('--allow-remote-http-connection')
if self.opts.store_pristine is not None:
cmdline.append('--store-pristine=%s' % self.opts.store_pristine)
+ if self.opts.valgrind is not None:
+ cmdline.append('--valgrind=%s' % self.opts.valgrind)
+ if self.opts.valgrind_opts is not None:
+ cmdline.append('--valgrind-opts=%s' % self.opts.valgrind_opts)
self.py_test_cmdline = cmdline
@@ -814,6 +822,17 @@ class TestHarness:
log.write('FAIL: %s: Unknown test failure (%s).\n'
% (progbase, test_failed))
+ def _maybe_prepend_valgrind(self, cmdline, progbase):
+ if self.opts.valgrind:
+ if (progbase in self.opts.valgrind.split(',')
+ or 'C' in self.opts.valgrind.split(',')):
+ valgrind = [os.path.join(self.builddir, 'libtool'), '--mode=execute',
+ 'valgrind', '--quiet', '--error-exitcode=1']
+ if self.opts.valgrind_opts:
+ valgrind += self.opts.valgrind_opts.split(' ')
+ cmdline = valgrind + cmdline
+ return cmdline
+
def _run_c_test(self, progabs, progdir, progbase, test_nums, dot_count):
'Run a c test, escaping parameters as required.'
if self.opts.list_tests and self.opts.milestone_filter:
@@ -849,6 +868,7 @@ class TestHarness:
self.dots_written = dots
tests_completed = 0
+ cmdline = self._maybe_prepend_valgrind(cmdline, progbase)
with Popen(cmdline, stdout=subprocess.PIPE, stderr=self.log) as prog:
line = prog.stdout.readline()
while line:
@@ -1095,6 +1115,10 @@ def create_parser():
help='Run tests that connect to remote HTTP(S) servers')
parser.add_option('--store-pristine', action='store', type='str',
help='Set the WC pristine mode')
+ parser.add_option('--valgrind', action='store',
+ help='programs to run under valgrind')
+ parser.add_option('--valgrind-opts', action='store',
+ help='options to pass valgrind')
parser.set_defaults(set_log_level=None)
return parser
Modified: subversion/trunk/subversion/tests/README
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/README?rev=1908546&r1=1908545&r2=1908546&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/README (original)
+++ subversion/trunk/subversion/tests/README Mon Mar 20 01:22:52 2023
@@ -261,6 +261,72 @@ Testing Over DAV
Please see subversion/tests/cmdline/README for how to run the
command-line client test suite against a remote repository.
+
+Testing with valgrind
+---------------------
+
+The test suite has support for valgrind. For this to be useful
+Subversion must be compiled with pool debugging enabled by
+adding -DAPR_POOL_DEBUG to CFLAGS. It is sufficient to compile
+just Subversion with pool debugging but compiling apr, apr-util
+and serf will cause more of the code to be checked.
+
+Valgrind can be used on the C test programs, and/or on svn,
+svnlook, svnadmin, etc. invoked during the python tests. To test
+the C programs use:
+
+ make check VALGRIND=C
+
+To test svn during the python tests use:
+
+ make check SKIP_C_TESTS=1 VALGRIND=svn
+
+To test svnlook during the python tests use:
+
+ make check VALGRIND=svnlook TESTS=subversion/tests/cmdline/svnlook_tests.py
+
+The VALGRIND settings can be combined:
+
+ make check PARALLEL=1 VALGRIND=C,svn,svnlook
+
+Any valgrind error causes diagnostic output on stderr but the program
+will continue to run. For the C tests valgrind is invoked with the
+option --error-exitcode=1 so that the although the individual
+tests within each C test program may PASS the test as a whole will
+FAIL. For the python tests the test harness parses stderr and detects
+the valgrind diagnostic, so individual tests will FAIL. In both cases
+the stderr diagnostic output from valgrind is available in tests.log.
+
+If valgind is producing unwanted diagnostics in some of the system
+libraries then create a suppression file and pass it as:
+
+ make check VALGRIND=svn VALGRIND_OPTS=--suppressions=$PWD/vg.supp
+
+Running valgrind in the testsuite will only check the client-side code.
+To check the server-side code invoke the server using valgrind and
+arrange for it to remain in the foreground so valgrind output will
+appear on stderr in the terminal. For svnserve something like:
+
+ ./libtool --mode=execute valgrind \
+ subversion/svnserve/svnserve -Tdr subversion/tests/cmdline --foreground
+ make check BASE_URL=svn://localhost # in another terminal
+
+For apache use a threaded MPM and then something like:
+
+ valgrind httpd -X -f /path/to/cfg
+ make check BASE_URL=http://localhost:8888 # in another terminal
+
+Note that using valgrind will make the testsuite much slower; expect more
+than an order of magnitude slowdown if using valgrind on svn during the
+python tests. Using the ASAN/MSAN/LSAN sanitizers in gcc/clang is an
+alternative; they will catch similar types of bugs and are much faster.
+The sanitizers also benefit from pool debugging.
+
+Debian's 1:3.19.0-1 version of valgrind seems to have a problem with
+the Dwarf 5 debugging info produced by Debian's compilers, so compile
+with -gdwarf-4 if using -g.
+
+
Conclusion
----------
Modified: subversion/trunk/subversion/tests/cmdline/svntest/main.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/main.py?rev=1908546&r1=1908545&r2=1908546&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/main.py Mon Mar 20
01:22:52 2023
@@ -211,6 +211,9 @@ svnauthz_validate_binary = os.path.abspa
)
svnmover_binary = os.path.abspath('../../../tools/dev/svnmover/svnmover' +
_exe)
+# Where to find the libtool script created during build
+libtool_script = os.path.abspath('../../../libtool')
+
# Location to the pristine repository, will be calculated from test_area_url
# when we know what the user specified for --url.
pristine_greek_repos_url = None
@@ -508,6 +511,13 @@ def open_pipe(command, bufsize=-1, stdin
if command[0].endswith('.py'):
command.insert(0, sys.executable)
+ if options.valgrind:
+ if os.path.basename(command[0]) in options.valgrind.split(','):
+ valgrind = [libtool_script, '--mode=execute', 'valgrind', '--quiet']
+ if options.valgrind_opts is not None:
+ valgrind += options.valgrind_opts.split(' ')
+ command = valgrind + command
+
command_string = command[0] + ' ' + ' '.join(map(_quote_arg, command[1:]))
if not stdin:
@@ -1856,6 +1866,10 @@ class TestSpawningThread(threading.Threa
args.append('--bin=' + options.svn_bin)
if options.store_pristine:
args.append('--store-pristine=' + options.store_pristine)
+ if options.valgrind:
+ args.append('--valgrind=' + options.valgrind)
+ if options.valgrind_opts:
+ args.append('--valgrind-opts=' + options.valgrind_opts)
result, stdout_lines, stderr_lines = spawn_process(command, 0, False, None,
*args)
@@ -2297,6 +2311,10 @@ def _create_parser(usage=None):
help='Run tests that connect to remote HTTP(S) servers')
parser.add_option('--store-pristine', action='store', type='str',
help='Set the WC pristine mode')
+ parser.add_option('--valgrind', action='store',
+ help='programs to run under valgrind')
+ parser.add_option('--valgrind-opts', action='store',
+ help='options to pass to valgrind')
# most of the defaults are None, but some are other values, set them here
parser.set_defaults(