Files
scylladb/test/scylla_gdb/run
Andrei Chekun e55c8a9936 test.py: modify run to use different junit output filenames
Currently, run will execute twice pytest without modifying the path of the
JUnit XML report. This leads that the second execution of the pytest
will override the report. This PR fixing this issue so both reports will
be stored.

Closes scylladb/scylladb#25726
2025-09-01 08:56:48 +03:00

120 lines
4.4 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
import os
import subprocess
from pathlib import Path
# Use the run.py library from ../cqlpy:
sys.path.insert(1, sys.path[0] + '/../cqlpy')
import run
print('Scylla is: ' + run.find_scylla() + '.')
# Gdb will only work if the executable was built with debug symbols
# (e.g., Scylla's release or debug build modes mode, but not dev mode).
# Check this quickly up-front, instead of waiting for gdb to fail in a
# mysterious way when it can't look up types.
if not '.debug_info' in subprocess.run(['objdump', '-h', run.scylla],
capture_output=True, text=True).stdout:
print(f'Scylla executable was compiled without debugging information (-g)')
print(f'so cannot be used to test gdb. Please set SCYLLA environment variable.')
exit(1)
# Run Scylla, waiting until it can respond to CQL
pid = run.run_with_temporary_dir(run.run_scylla_cmd)
ip = run.pid_to_ip(pid)
run.wait_for_services(pid, [lambda: run.check_cql(ip)])
# We do something strange here: We start pytest *inside* gdb's Python
# interpreter. This will allow us to test various gdb commands added
# by scylla-gdb.py inside gdb using the pytest framework.
# TODO: consider a more straightforward implementation, where we don't
# run pytest inside gdb - and instead run gdb as a separate process and
# pytest just sends commands to it.
# TODO: think if we can avoid code duplication with run.run_ptest().
def run_pytest_in_gdb(pytest_dir, executable, additional_parameters):
sys.stdout.flush()
sys.stderr.flush()
pid = os.fork()
if pid == 0:
# child:
run.run_with_temporary_dir_pids = set() # no children to clean up on child
run.run_pytest_pids = set()
os.chdir(pytest_dir)
pytest_args = ['-o', 'junit_family=xunit2'] + additional_parameters
pytest_cmd = f'print("Starting pytest {" ".join(pytest_args)}"); import pytest; sys.argv[0]="pytest"; sys.exit(pytest.main({str(pytest_args)}))'
print(f'Starting gdb {executable}')
sys.stdout.flush()
args = ['gdb',
'-batch', '-n',
'-ex', 'set python print-stack full',
'-ex', 'python ' + pytest_cmd,
]
if executable:
args += ['-se', executable]
os.execvp('gdb', args)
exit(1)
# parent:
run.run_pytest_pids.add(pid)
if os.waitpid(pid, 0)[1]:
return False
else:
return True
def modify_junit_xml_filename(args, filename_modifier):
"""
Modify the filename part of --junit-xml parameter while preserving the path.
Args:
args: List of command line arguments
filename_modifier: suffix to append to the filename part of --junit-xml
Returns:
Modified list of arguments
"""
if filename_modifier is None:
return args
modified_args = []
for arg in args:
if arg.startswith('--junit-xml='):
junit_xml = Path(arg.split('=', 1)[1])
new_junit_xml = junit_xml.with_suffix(f'.{filename_modifier}{junit_xml.suffix}')
modified_args.append(f'--junit-xml={new_junit_xml}')
else:
modified_args.append(arg)
return modified_args
# Interesting note: We must use "--scylla-tmp-dir=DIR" here instead of
# "--scylla-tmp-dir DIR": While the latter does work, pytest has a bug that
# its command-line parser finds the given directory name in the original
# command line, saves it as "initialpaths", and uses it to print what it
# thinks are nice (but are really incorrect) relative paths for "nodes" (test
# source files).
success = True
for with_scylla in [True, False]:
modified_argv = None
if with_scylla:
args = ['--scylla-pid='+str(pid),
'--scylla-tmp-dir='+run.pid_to_dir(pid),
'-m', 'not without_scylla']
executable = run.scylla
modified_argv = modify_junit_xml_filename(sys.argv[1:], 'with_scylla')
else:
args = ['-m', 'without_scylla']
executable = ''
modified_argv = modify_junit_xml_filename(sys.argv[1:], 'without_scylla')
if not run_pytest_in_gdb(sys.path[0], executable, args + modified_argv):
success = False
run.summary = 'Scylla GDB tests pass' if success else 'Scylla GDB tests failure'
exit(0 if success else 1)
# Note that the run.cleanup_all() function runs now, just like on any exit
# for any reason in this script. It will delete the temporary files and
# announce the failure or success of the test (printing run.summary).