Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Christoph Hellwig | 6bf19c9 | 2009-06-22 18:29:05 +0200 | [diff] [blame] | 2 | # |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 3 | # Configure environment and run group of tests in it. |
| 4 | # |
| 5 | # Copyright (c) 2020-2021 Virtuozzo International GmbH |
Christoph Hellwig | 6bf19c9 | 2009-06-22 18:29:05 +0200 | [diff] [blame] | 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 |
Christoph Hellwig | e8c212d | 2009-07-16 19:26:54 +0200 | [diff] [blame] | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
Christoph Hellwig | 6bf19c9 | 2009-06-22 18:29:05 +0200 | [diff] [blame] | 18 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 19 | import os |
| 20 | import sys |
| 21 | import argparse |
Paolo Bonzini | 480b75e | 2021-05-03 13:01:09 +0200 | [diff] [blame] | 22 | import shutil |
| 23 | from pathlib import Path |
| 24 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 25 | from findtests import TestFinder |
| 26 | from testenv import TestEnv |
| 27 | from testrunner import TestRunner |
Christoph Hellwig | 6bf19c9 | 2009-06-22 18:29:05 +0200 | [diff] [blame] | 28 | |
Daniel P. Berrangé | 0c8076b | 2023-03-15 17:43:17 +0000 | [diff] [blame] | 29 | def get_default_path(follow_link=False): |
| 30 | """ |
| 31 | Try to automagically figure out the path we are running from. |
| 32 | """ |
| 33 | # called from the build tree? |
| 34 | if os.path.islink(sys.argv[0]): |
| 35 | if follow_link: |
| 36 | return os.path.dirname(os.readlink(sys.argv[0])) |
| 37 | else: |
| 38 | return os.path.dirname(os.path.abspath(sys.argv[0])) |
| 39 | else: # or source tree? |
| 40 | return os.getcwd() |
Max Reitz | e8f8624 | 2014-05-24 23:24:55 +0200 | [diff] [blame] | 41 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 42 | def make_argparser() -> argparse.ArgumentParser: |
Daniel P. Berrangé | 0c8076b | 2023-03-15 17:43:17 +0000 | [diff] [blame] | 43 | p = argparse.ArgumentParser( |
| 44 | description="Test run options", |
| 45 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
Max Reitz | e8f8624 | 2014-05-24 23:24:55 +0200 | [diff] [blame] | 46 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 47 | p.add_argument('-n', '--dry-run', action='store_true', |
| 48 | help='show me, do not run tests') |
Vladimir Sementsov-Ogievskiy | 722f87d | 2021-12-03 13:22:23 +0100 | [diff] [blame] | 49 | p.add_argument('-j', dest='jobs', type=int, default=1, |
| 50 | help='run tests in multiple parallel jobs') |
Max Reitz | e8f8624 | 2014-05-24 23:24:55 +0200 | [diff] [blame] | 51 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 52 | p.add_argument('-d', dest='debug', action='store_true', help='debug') |
Emanuele Giuseppe Esposito | eb7a91d | 2021-08-09 11:01:13 +0200 | [diff] [blame] | 53 | p.add_argument('-p', dest='print', action='store_true', |
Emanuele Giuseppe Esposito | 87e4d4a | 2021-10-08 02:28:20 -0400 | [diff] [blame] | 54 | help='redirects qemu\'s stdout and stderr to ' |
| 55 | 'the test output') |
Emanuele Giuseppe Esposito | cfb9b0b | 2021-08-09 11:01:03 +0200 | [diff] [blame] | 56 | p.add_argument('-gdb', action='store_true', |
Emanuele Giuseppe Esposito | 87e4d4a | 2021-10-08 02:28:20 -0400 | [diff] [blame] | 57 | help="start gdbserver with $GDB_OPTIONS options " |
| 58 | "('localhost:12345' if $GDB_OPTIONS is empty)") |
Emanuele Giuseppe Esposito | a9b4c6b | 2021-08-09 11:01:08 +0200 | [diff] [blame] | 59 | p.add_argument('-valgrind', action='store_true', |
Emanuele Giuseppe Esposito | 87e4d4a | 2021-10-08 02:28:20 -0400 | [diff] [blame] | 60 | help='use valgrind, sets VALGRIND_QEMU environment ' |
| 61 | 'variable') |
Emanuele Giuseppe Esposito | a9b4c6b | 2021-08-09 11:01:08 +0200 | [diff] [blame] | 62 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 63 | p.add_argument('-misalign', action='store_true', |
| 64 | help='misalign memory allocations') |
| 65 | p.add_argument('--color', choices=['on', 'off', 'auto'], |
| 66 | default='auto', help="use terminal colors. The default " |
| 67 | "'auto' value means use colors if terminal stdout detected") |
Paolo Bonzini | d316859 | 2022-01-07 13:18:11 +0100 | [diff] [blame] | 68 | p.add_argument('-tap', action='store_true', |
| 69 | help='produce TAP output') |
Max Reitz | 7fed1a4 | 2014-05-24 23:24:57 +0200 | [diff] [blame] | 70 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 71 | g_env = p.add_argument_group('test environment options') |
| 72 | mg = g_env.add_mutually_exclusive_group() |
| 73 | # We don't set default for cachemode, as we need to distinguish default |
| 74 | # from user input later. |
| 75 | mg.add_argument('-nocache', dest='cachemode', action='store_const', |
| 76 | const='none', help='set cache mode "none" (O_DIRECT), ' |
| 77 | 'sets CACHEMODE environment variable') |
| 78 | mg.add_argument('-c', dest='cachemode', |
| 79 | help='sets CACHEMODE environment variable') |
Christoph Hellwig | 6bf19c9 | 2009-06-22 18:29:05 +0200 | [diff] [blame] | 80 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 81 | g_env.add_argument('-i', dest='aiomode', default='threads', |
| 82 | help='sets AIOMODE environment variable') |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 83 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 84 | p.set_defaults(imgfmt='raw', imgproto='file') |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 85 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 86 | format_list = ['raw', 'bochs', 'cloop', 'parallels', 'qcow', 'qcow2', |
| 87 | 'qed', 'vdi', 'vpc', 'vhdx', 'vmdk', 'luks', 'dmg'] |
| 88 | g_fmt = p.add_argument_group( |
| 89 | ' image format options', |
| 90 | 'The following options set the IMGFMT environment variable. ' |
| 91 | 'At most one choice is allowed, default is "raw"') |
| 92 | mg = g_fmt.add_mutually_exclusive_group() |
| 93 | for fmt in format_list: |
| 94 | mg.add_argument('-' + fmt, dest='imgfmt', action='store_const', |
| 95 | const=fmt, help=f'test {fmt}') |
Alex Bennée | 70ff5b0 | 2019-05-03 15:39:04 +0100 | [diff] [blame] | 96 | |
Markus Armbruster | 09ec851 | 2021-05-01 09:57:47 +0200 | [diff] [blame] | 97 | protocol_list = ['file', 'rbd', 'nbd', 'ssh', 'nfs', 'fuse'] |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 98 | g_prt = p.add_argument_group( |
| 99 | ' image protocol options', |
| 100 | 'The following options set the IMGPROTO environment variable. ' |
| 101 | 'At most one choice is allowed, default is "file"') |
| 102 | mg = g_prt.add_mutually_exclusive_group() |
| 103 | for prt in protocol_list: |
| 104 | mg.add_argument('-' + prt, dest='imgproto', action='store_const', |
| 105 | const=prt, help=f'test {prt}') |
Alex Bennée | 70ff5b0 | 2019-05-03 15:39:04 +0100 | [diff] [blame] | 106 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 107 | g_bash = p.add_argument_group('bash tests options', |
| 108 | 'The following options are ignored by ' |
| 109 | 'python tests.') |
| 110 | # TODO: make support for the following options in iotests.py |
| 111 | g_bash.add_argument('-o', dest='imgopts', |
| 112 | help='options to pass to qemu-img create/convert, ' |
| 113 | 'sets IMGOPTS environment variable') |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 114 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 115 | g_sel = p.add_argument_group('test selecting options', |
| 116 | 'The following options specify test set ' |
| 117 | 'to run.') |
| 118 | g_sel.add_argument('-g', '--groups', metavar='group1,...', |
| 119 | help='include tests from these groups') |
| 120 | g_sel.add_argument('-x', '--exclude-groups', metavar='group1,...', |
| 121 | help='exclude tests from these groups') |
| 122 | g_sel.add_argument('--start-from', metavar='TEST', |
| 123 | help='Start from specified test: make sorted sequence ' |
| 124 | 'of tests as usual and then drop tests from the first ' |
| 125 | 'one to TEST (not inclusive). This may be used to ' |
| 126 | 'rerun failed ./check command, starting from the ' |
| 127 | 'middle of the process.') |
| 128 | g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*', |
Paolo Bonzini | 480b75e | 2021-05-03 13:01:09 +0200 | [diff] [blame] | 129 | help='tests to run, or "--" followed by a command') |
Daniel P. Berrangé | 0c8076b | 2023-03-15 17:43:17 +0000 | [diff] [blame] | 130 | g_sel.add_argument('--build-dir', default=get_default_path(), |
| 131 | help='Path to iotests build directory') |
| 132 | g_sel.add_argument('--source-dir', |
| 133 | default=get_default_path(follow_link=True), |
| 134 | help='Path to iotests build directory') |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 135 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 136 | return p |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 137 | |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 138 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 139 | if __name__ == '__main__': |
| 140 | args = make_argparser().parse_args() |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 141 | |
Daniel P. Berrangé | 0c8076b | 2023-03-15 17:43:17 +0000 | [diff] [blame] | 142 | env = TestEnv(source_dir=args.source_dir, |
| 143 | build_dir=args.build_dir, |
| 144 | imgfmt=args.imgfmt, imgproto=args.imgproto, |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 145 | aiomode=args.aiomode, cachemode=args.cachemode, |
| 146 | imgopts=args.imgopts, misalign=args.misalign, |
Emanuele Giuseppe Esposito | cfb9b0b | 2021-08-09 11:01:03 +0200 | [diff] [blame] | 147 | debug=args.debug, valgrind=args.valgrind, |
Daniel P. Berrangé | a9e2178 | 2023-03-15 17:43:18 +0000 | [diff] [blame] | 148 | gdb=args.gdb, qprint=args.print, |
| 149 | dry_run=args.dry_run) |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 150 | |
Paolo Bonzini | 480b75e | 2021-05-03 13:01:09 +0200 | [diff] [blame] | 151 | if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--': |
| 152 | if not args.tests: |
| 153 | sys.exit("missing command after '--'") |
| 154 | cmd = args.tests |
| 155 | env.print_env() |
| 156 | exec_pathstr = shutil.which(cmd[0]) |
| 157 | if exec_pathstr is None: |
| 158 | sys.exit('command not found: ' + cmd[0]) |
| 159 | exec_path = Path(exec_pathstr).resolve() |
| 160 | cmd[0] = str(exec_path) |
| 161 | full_env = env.prepare_subprocess(cmd) |
| 162 | os.chdir(exec_path.parent) |
| 163 | os.execve(cmd[0], cmd, full_env) |
| 164 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 165 | testfinder = TestFinder(test_dir=env.source_iotests) |
Eric Blake | 8803714 | 2017-10-05 14:02:45 -0500 | [diff] [blame] | 166 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 167 | groups = args.groups.split(',') if args.groups else None |
| 168 | x_groups = args.exclude_groups.split(',') if args.exclude_groups else None |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 169 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 170 | group_local = os.path.join(env.source_iotests, 'group.local') |
| 171 | if os.path.isfile(group_local): |
| 172 | try: |
| 173 | testfinder.add_group_file(group_local) |
| 174 | except ValueError as e: |
| 175 | sys.exit(f"Failed to parse group file '{group_local}': {e}") |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 176 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 177 | try: |
| 178 | tests = testfinder.find_tests(groups=groups, exclude_groups=x_groups, |
| 179 | tests=args.tests, |
| 180 | start_from=args.start_from) |
| 181 | if not tests: |
| 182 | raise ValueError('No tests selected') |
| 183 | except ValueError as e: |
John Snow | 5bcf18b | 2022-12-02 19:52:33 -0500 | [diff] [blame] | 184 | sys.exit(str(e)) |
Paolo Bonzini | 09d653e | 2017-09-12 16:44:59 +0200 | [diff] [blame] | 185 | |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 186 | if args.dry_run: |
Daniel P. Berrangé | c645bac | 2024-02-05 15:40:19 +0000 | [diff] [blame] | 187 | with env: |
| 188 | print('\n'.join([os.path.basename(t) for t in tests])) |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 189 | else: |
Paolo Bonzini | d316859 | 2022-01-07 13:18:11 +0100 | [diff] [blame] | 190 | with TestRunner(env, tap=args.tap, |
Vladimir Sementsov-Ogievskiy | f203080 | 2021-01-25 21:50:55 +0300 | [diff] [blame] | 191 | color=args.color) as tr: |
Vladimir Sementsov-Ogievskiy | 3ae5094 | 2021-02-01 11:50:41 +0300 | [diff] [blame] | 192 | paths = [os.path.join(env.source_iotests, t) for t in tests] |
Vladimir Sementsov-Ogievskiy | 722f87d | 2021-12-03 13:22:23 +0100 | [diff] [blame] | 193 | ok = tr.run_tests(paths, args.jobs) |
Vladimir Sementsov-Ogievskiy | 3ae5094 | 2021-02-01 11:50:41 +0300 | [diff] [blame] | 194 | if not ok: |
| 195 | sys.exit(1) |