qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

check (7428B)


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