mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-21 09:00:35 +00:00
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
120 lines
4.4 KiB
Python
Executable File
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).
|