summaryrefslogtreecommitdiff
path: root/tests/qemu-iotests/iotests.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/qemu-iotests/iotests.py')
-rw-r--r--tests/qemu-iotests/iotests.py75
1 files changed, 61 insertions, 14 deletions
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 89663dac06..11276f380a 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -74,6 +74,13 @@ if os.environ.get('QEMU_NBD_OPTIONS'):
qemu_prog = os.environ.get('QEMU_PROG', 'qemu')
qemu_opts = os.environ.get('QEMU_OPTIONS', '').strip().split(' ')
+gdb_qemu_env = os.environ.get('GDB_OPTIONS')
+qemu_gdb = []
+if gdb_qemu_env:
+ qemu_gdb = ['gdbserver'] + gdb_qemu_env.strip().split(' ')
+
+qemu_print = os.environ.get('PRINT_QEMU', False)
+
imgfmt = os.environ.get('IMGFMT', 'raw')
imgproto = os.environ.get('IMGPROTO', 'file')
output_dir = os.environ.get('OUTPUT_DIR', '.')
@@ -91,6 +98,17 @@ except KeyError:
sys.stderr.write('Please run this test via the "check" script\n')
sys.exit(os.EX_USAGE)
+qemu_valgrind = []
+if os.environ.get('VALGRIND_QEMU') == "y" and \
+ os.environ.get('NO_VALGRIND') != "y":
+ valgrind_logfile = "--log-file=" + test_dir
+ # %p allows to put the valgrind process PID, since
+ # we don't know it a priori (subprocess.Popen is
+ # not yet invoked)
+ valgrind_logfile += "/%p.valgrind"
+
+ qemu_valgrind = ['valgrind', valgrind_logfile, '--error-exitcode=99']
+
socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper')
luks_default_secret_object = 'secret,id=keysec0,data=' + \
@@ -219,18 +237,18 @@ def qemu_io_silent(*args):
default_args = qemu_io_args
args = default_args + list(args)
- exitcode = subprocess.call(args, stdout=open('/dev/null', 'w'))
- if exitcode < 0:
+ result = subprocess.run(args, stdout=subprocess.DEVNULL, check=False)
+ if result.returncode < 0:
sys.stderr.write('qemu-io received signal %i: %s\n' %
- (-exitcode, ' '.join(args)))
- return exitcode
+ (-result.returncode, ' '.join(args)))
+ return result.returncode
def qemu_io_silent_check(*args):
'''Run qemu-io and return the true if subprocess returned 0'''
args = qemu_io_args + list(args)
- exitcode = subprocess.call(args, stdout=open('/dev/null', 'w'),
- stderr=subprocess.STDOUT)
- return exitcode == 0
+ result = subprocess.run(args, stdout=subprocess.DEVNULL,
+ stderr=subprocess.STDOUT, check=False)
+ return result.returncode == 0
class QemuIoInteractive:
def __init__(self, *args):
@@ -472,10 +490,14 @@ class Timeout:
self.seconds = seconds
self.errmsg = errmsg
def __enter__(self):
+ if qemu_gdb or qemu_valgrind:
+ return self
signal.signal(signal.SIGALRM, self.timeout)
signal.setitimer(signal.ITIMER_REAL, self.seconds)
return self
def __exit__(self, exc_type, value, traceback):
+ if qemu_gdb or qemu_valgrind:
+ return False
signal.setitimer(signal.ITIMER_REAL, 0)
return False
def timeout(self, signum, frame):
@@ -570,12 +592,35 @@ class VM(qtest.QEMUQtestMachine):
def __init__(self, path_suffix=''):
name = "qemu%s-%d" % (path_suffix, os.getpid())
- super().__init__(qemu_prog, qemu_opts, name=name,
+ timer = 15.0 if not (qemu_gdb or qemu_valgrind) else None
+ if qemu_gdb and qemu_valgrind:
+ sys.stderr.write('gdb and valgrind are mutually exclusive\n')
+ sys.exit(1)
+ wrapper = qemu_gdb if qemu_gdb else qemu_valgrind
+ super().__init__(qemu_prog, qemu_opts, wrapper=wrapper,
+ name=name,
base_temp_dir=test_dir,
socket_scm_helper=socket_scm_helper,
- sock_dir=sock_dir)
+ sock_dir=sock_dir, qmp_timer=timer)
self._num_drives = 0
+ def _post_shutdown(self) -> None:
+ super()._post_shutdown()
+ if not qemu_valgrind or not self._popen:
+ return
+ valgrind_filename = f"{test_dir}/{self._popen.pid}.valgrind"
+ if self.exitcode() == 99:
+ with open(valgrind_filename) as f:
+ print(f.read())
+ else:
+ os.remove(valgrind_filename)
+
+ def _pre_launch(self) -> None:
+ super()._pre_launch()
+ if qemu_print:
+ # set QEMU binary output to stdout
+ self._close_qemu_log_file()
+
def add_object(self, opts):
self._args.append('-object')
self._args.append(opts)
@@ -651,9 +696,10 @@ class VM(qtest.QEMUQtestMachine):
self.hmp(f'qemu-io {drive} "remove_break bp_{drive}"')
def hmp_qemu_io(self, drive: str, cmd: str,
- use_log: bool = False) -> QMPMessage:
+ use_log: bool = False, qdev: bool = False) -> QMPMessage:
"""Write to a given drive using an HMP command"""
- return self.hmp(f'qemu-io {drive} "{cmd}"', use_log=use_log)
+ d = '-d ' if qdev else ''
+ return self.hmp(f'qemu-io {d}{drive} "{cmd}"', use_log=use_log)
def flatten_qmp_object(self, obj, output=None, basestr=''):
if output is None:
@@ -1075,7 +1121,8 @@ def notrun(reason):
# Each test in qemu-iotests has a number ("seq")
seq = os.path.basename(sys.argv[0])
- open('%s/%s.notrun' % (output_dir, seq), 'w').write(reason + '\n')
+ with open('%s/%s.notrun' % (output_dir, seq), 'w') as outfile:
+ outfile.write(reason + '\n')
logger.warning("%s not run: %s", seq, reason)
sys.exit(0)
@@ -1088,8 +1135,8 @@ def case_notrun(reason):
# Each test in qemu-iotests has a number ("seq")
seq = os.path.basename(sys.argv[0])
- open('%s/%s.casenotrun' % (output_dir, seq), 'a').write(
- ' [case not run] ' + reason + '\n')
+ with open('%s/%s.casenotrun' % (output_dir, seq), 'a') as outfile:
+ outfile.write(' [case not run] ' + reason + '\n')
def _verify_image_format(supported_fmts: Sequence[str] = (),
unsupported_fmts: Sequence[str] = ()) -> None: