aboutsummaryrefslogtreecommitdiff
path: root/tests/qemu-iotests/iotests.py
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-09-02 13:00:52 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-09-02 13:00:52 +0100
commit9093028dd48c50bc0392791f78aab44afef57ead (patch)
treeac9ab96c78172fff29ac3da160f39e0bc012637e /tests/qemu-iotests/iotests.py
parent59a89510b62ec23dbeab8b02fa4e3526e353d8b6 (diff)
parentebd979c74e2b8a7275090475df36dde4ab858320 (diff)
Merge remote-tracking branch 'remotes/hreitz/tags/pull-block-2021-09-01' into staging
Block patches: - Make the backup-top filter driver available for user-created block nodes (i.e. via blockdev-add) - Allow running iotests with gdb or valgrind being attached to qemu instances - Fix the raw format driver's permissions: There is no metadata, so we only need WRITE or RESIZE when the parent needs it - Basic reopen implementation for win32 files (file-win32.c) so that qemu-img commit can work - uclibc/musl build fix for the FUSE export code - Some iotests delinting - block-hmp-cmds.c refactoring # gpg: Signature made Wed 01 Sep 2021 16:01:54 BST # gpg: using RSA key CB62D7A0EE3829E45F004D34A1FA40D098019CDF # gpg: issuer "hreitz@redhat.com" # gpg: Good signature from "Hanna Reitz <hreitz@redhat.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: CB62 D7A0 EE38 29E4 5F00 4D34 A1FA 40D0 9801 9CDF * remotes/hreitz/tags/pull-block-2021-09-01: (56 commits) block/file-win32: add reopen handlers block/export/fuse.c: fix fuse-lseek on uclibc or musl block/block-copy: block_copy_state_new(): drop extra arguments iotests/image-fleecing: add test-case for copy-before-write filter iotests/image-fleecing: prepare for adding new test-case iotests/image-fleecing: rename tgt_node iotests/image-fleecing: proper source device iotests.py: hmp_qemu_io: support qdev iotests: move 222 to tests/image-fleecing iotests/222: constantly use single quotes for strings iotests/222: fix pylint and mypy complains python:QEMUMachine: template typing for self returning methods python/qemu/machine: QEMUMachine: improve qmp() method python/qemu/machine.py: refactor _qemu_args() qapi: publish copy-before-write filter block/copy-before-write: make public block driver block/block-copy: make setting progress optional block/copy-before-write: initialize block-copy bitmap block/copy-before-write: cbw_init(): use options block/copy-before-write: bdrv_cbw_append(): drop unused compress arg ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
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: