1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
#!/usr/bin/env python3
#
# Configure environment and run group of tests in it.
#
# Copyright (c) 2020-2021 Virtuozzo International GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import argparse
import shutil
from pathlib import Path
from findtests import TestFinder
from testenv import TestEnv
from testrunner import TestRunner
def make_argparser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(description="Test run options")
p.add_argument('-n', '--dry-run', action='store_true',
help='show me, do not run tests')
p.add_argument('-j', dest='jobs', type=int, default=1,
help='run tests in multiple parallel jobs')
p.add_argument('-d', dest='debug', action='store_true', help='debug')
p.add_argument('-p', dest='print', action='store_true',
help='redirects qemu\'s stdout and stderr to '
'the test output')
p.add_argument('-gdb', action='store_true',
help="start gdbserver with $GDB_OPTIONS options "
"('localhost:12345' if $GDB_OPTIONS is empty)")
p.add_argument('-valgrind', action='store_true',
help='use valgrind, sets VALGRIND_QEMU environment '
'variable')
p.add_argument('-misalign', action='store_true',
help='misalign memory allocations')
p.add_argument('--color', choices=['on', 'off', 'auto'],
default='auto', help="use terminal colors. The default "
"'auto' value means use colors if terminal stdout detected")
p.add_argument('-tap', action='store_true',
help='produce TAP output')
g_env = p.add_argument_group('test environment options')
mg = g_env.add_mutually_exclusive_group()
# We don't set default for cachemode, as we need to distinguish default
# from user input later.
mg.add_argument('-nocache', dest='cachemode', action='store_const',
const='none', help='set cache mode "none" (O_DIRECT), '
'sets CACHEMODE environment variable')
mg.add_argument('-c', dest='cachemode',
help='sets CACHEMODE environment variable')
g_env.add_argument('-i', dest='aiomode', default='threads',
help='sets AIOMODE environment variable')
p.set_defaults(imgfmt='raw', imgproto='file')
format_list = ['raw', 'bochs', 'cloop', 'parallels', 'qcow', 'qcow2',
'qed', 'vdi', 'vpc', 'vhdx', 'vmdk', 'luks', 'dmg', 'vvfat']
g_fmt = p.add_argument_group(
' image format options',
'The following options set the IMGFMT environment variable. '
'At most one choice is allowed, default is "raw"')
mg = g_fmt.add_mutually_exclusive_group()
for fmt in format_list:
mg.add_argument('-' + fmt, dest='imgfmt', action='store_const',
const=fmt, help=f'test {fmt}')
protocol_list = ['file', 'rbd', 'nbd', 'ssh', 'nfs', 'fuse']
g_prt = p.add_argument_group(
' image protocol options',
'The following options set the IMGPROTO environment variable. '
'At most one choice is allowed, default is "file"')
mg = g_prt.add_mutually_exclusive_group()
for prt in protocol_list:
mg.add_argument('-' + prt, dest='imgproto', action='store_const',
const=prt, help=f'test {prt}')
g_bash = p.add_argument_group('bash tests options',
'The following options are ignored by '
'python tests.')
# TODO: make support for the following options in iotests.py
g_bash.add_argument('-o', dest='imgopts',
help='options to pass to qemu-img create/convert, '
'sets IMGOPTS environment variable')
g_sel = p.add_argument_group('test selecting options',
'The following options specify test set '
'to run.')
g_sel.add_argument('-g', '--groups', metavar='group1,...',
help='include tests from these groups')
g_sel.add_argument('-x', '--exclude-groups', metavar='group1,...',
help='exclude tests from these groups')
g_sel.add_argument('--start-from', metavar='TEST',
help='Start from specified test: make sorted sequence '
'of tests as usual and then drop tests from the first '
'one to TEST (not inclusive). This may be used to '
'rerun failed ./check command, starting from the '
'middle of the process.')
g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*',
help='tests to run, or "--" followed by a command')
return p
if __name__ == '__main__':
args = make_argparser().parse_args()
env = TestEnv(imgfmt=args.imgfmt, imgproto=args.imgproto,
aiomode=args.aiomode, cachemode=args.cachemode,
imgopts=args.imgopts, misalign=args.misalign,
debug=args.debug, valgrind=args.valgrind,
gdb=args.gdb, qprint=args.print)
if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--':
if not args.tests:
sys.exit("missing command after '--'")
cmd = args.tests
env.print_env()
exec_pathstr = shutil.which(cmd[0])
if exec_pathstr is None:
sys.exit('command not found: ' + cmd[0])
exec_path = Path(exec_pathstr).resolve()
cmd[0] = str(exec_path)
full_env = env.prepare_subprocess(cmd)
os.chdir(exec_path.parent)
os.execve(cmd[0], cmd, full_env)
testfinder = TestFinder(test_dir=env.source_iotests)
groups = args.groups.split(',') if args.groups else None
x_groups = args.exclude_groups.split(',') if args.exclude_groups else None
group_local = os.path.join(env.source_iotests, 'group.local')
if os.path.isfile(group_local):
try:
testfinder.add_group_file(group_local)
except ValueError as e:
sys.exit(f"Failed to parse group file '{group_local}': {e}")
try:
tests = testfinder.find_tests(groups=groups, exclude_groups=x_groups,
tests=args.tests,
start_from=args.start_from)
if not tests:
raise ValueError('No tests selected')
except ValueError as e:
sys.exit(e)
if args.dry_run:
print('\n'.join(tests))
else:
with TestRunner(env, tap=args.tap,
color=args.color) as tr:
paths = [os.path.join(env.source_iotests, t) for t in tests]
ok = tr.run_tests(paths, args.jobs)
if not ok:
sys.exit(1)
|