5 from vpp_qemu_utils import can_create_namespaces
8 def positive_int_or_default(default):
9 def positive_integer(v):
10 if v is None or v == "" or int(v) == default:
13 raise ValueError("value must be positive")
16 return positive_integer
19 def positive_float_or_default(default):
20 def positive_float(v):
21 if v is None or v == "" or float(v) == default:
24 raise ValueError("value must be positive")
30 def positive_int_or_auto(v):
31 if v is None or v in ("", "auto"):
34 raise ValueError("value must be positive or auto")
39 if v is None or v in ("", "auto"):
42 raise ValueError("value must be positive or auto")
46 def int_choice_or_default(options, default):
47 assert default in options
50 if v is None or v == "":
54 raise ValueError("invalid choice")
60 if v is None or v == "":
62 if v.startswith("workers "):
63 return int(v.split(" ")[1])
68 if not os.path.isdir(v):
69 raise ValueError(f"provided path '{v}' doesn't exist or is not a directory")
73 def directory_verify_or_create(v):
74 if not os.path.isdir(v):
79 parser = argparse.ArgumentParser(
80 description="VPP unit tests", formatter_class=argparse.RawTextHelpFormatter
84 "--failfast", action="store_true", help="stop running tests on first failure"
91 help="directory containing test files "
92 "(may be specified multiple times) "
93 "(VPP_WS_DIR/test is added automatically to the set)",
101 default=default_verbose,
102 type=int_choice_or_default((0, 1, 2), default_verbose),
103 help="verbosity setting - 0 - least verbose, 2 - most verbose (default: 0)",
106 default_test_run_timeout = 600
111 type=positive_int_or_default(default_test_run_timeout),
112 default=default_test_run_timeout,
113 metavar="TEST_RUN_TIMEOUT",
114 help="test run timeout in seconds - per test "
115 f"(default: {default_test_run_timeout})",
122 help="directory containing failed tests (default: --tmp-dir)",
125 filter_help_string = """\
126 expression consists of one or more filters separated by commas (',')
127 filter consists of 3 string selectors separated by dots ('.')
129 <file>.<class>.<function>
131 - selectors restrict which files/classes/functions are run
132 - selector can be replaced with '*' or omitted entirely if not needed
133 - <file> selector is automatically prepended with 'test_' if required
134 - '.' separators are required only if selector(s) follow(s)
138 1. all of the following expressions are equivalent and will select
139 all test classes and functions from test_bfd.py:
140 'test_bfd' 'bfd' 'test_bfd..' 'bfd.' 'bfd.*.*' 'test_bfd.*.*'
141 2. 'bfd.BFDAPITestCase' selects all tests from test_bfd.py,
142 which are part of BFDAPITestCase class
143 3. 'bfd.BFDAPITestCase.test_add_bfd' selects a single test named
144 test_add_bfd from test_bfd.py/BFDAPITestCase
145 4. '.*.test_add_bfd' selects all test functions named test_add_bfd
146 from all files/classes
147 5. 'bfd,ip4,..test_icmp_error' selects all test functions in test_bfd.py,
148 test_ip4.py and all test functions named 'test_icmp_error' in all files
151 "--filter", action="store", metavar="FILTER_EXPRESSION", help=filter_help_string
159 default=default_retries,
160 type=positive_int_or_default(default_retries),
161 help="retry failed tests RETRIES times",
165 "--step", action="store_true", default=False, help="enable stepping through tests"
168 debug_help_string = """\
169 attach - attach to already running vpp
170 core - detect coredump and load core in gdb on crash
171 gdb - print VPP PID and pause allowing attaching gdb
172 gdbserver - same as above, but run gdb in gdbserver
178 choices=["attach", "core", "gdb", "gdbserver"],
179 help=debug_help_string,
185 help="enable internal test framework debugging",
191 help="compress core files if not debugging them",
194 parser.add_argument("--extended", action="store_true", help="run extended tests")
196 "--skip-netns-tests",
198 help="skip tests involving netns operations",
202 "--sanity", action="store_true", help="perform sanity vpp run before running tests"
204 parser.add_argument("--api-preload", action="store_true", help="preload API files")
207 "--force-foreground",
209 help="force running in foreground - don't fork",
215 type=positive_int_or_auto,
217 help="maximum concurrent test jobs",
221 "--venv-dir", action="store", type=directory, help="path to virtual environment"
224 default_rnd_seed = time.time()
228 default=default_rnd_seed,
229 type=positive_float_or_default(default_rnd_seed),
230 help="random generator seed (default: current time)",
234 "--vpp-worker-count",
238 help="number of vpp workers",
242 "--gcov", action="store_true", default=False, help="running gcov tests"
246 "--cache-vpp-output",
249 help="cache VPP stdout/stderr and log as one block after test finishes",
257 help="vpp workspace directory",
266 help="vpp tag (e.g. vpp, vpp_debug, vpp_gcov)",
272 help="path to vpp binary (default: derive from VPP_WS_DIR and VPP_TAG)",
279 help="path to vpp install directory"
280 "(default: derive from VPP_WS_DIR and VPP_TAG)",
287 help="vpp build directory (default: derive from VPP_WS_DIR and VPP_TAG)",
294 help="directory containing vpp plugins"
295 "(default: derive from VPP_WS_DIR and VPP_TAG)",
299 "--vpp-test-plugin-dir",
302 help="directory containing vpp api test plugins"
303 "(default: derive from VPP_WS_DIR and VPP_TAG)",
307 "--extern-plugin-dir",
311 help="directory containing external plugins",
319 help="directory to look for API JSON files",
326 help="specify vpp coredump size",
334 help="max cpus used by vpp",
337 variant_help_string = """\
338 specify which march node variant to unit test
339 e.g. --variant=skx - test the skx march variants
340 e.g. --variant=icl - test the icl march variants
343 parser.add_argument("--variant", action="store", help=variant_help_string)
346 "--api-fuzz", action="store", default=None, help="specify api fuzzing parameters"
353 help="remove test tmp directory before running test",
360 type=directory_verify_or_create,
361 help="directory where to store test temporary directories",
367 type=directory_verify_or_create,
368 help="directory where to store directories "
369 "containing log files (default: --tmp-dir)",
372 default_keep_pcaps = False
376 default=default_keep_pcaps,
377 help=f"if set, keep all pcap files from a test run (default: {default_keep_pcaps})",
387 help="Runs tests against a running VPP.",
392 dest="excluded_plugins",
396 help="Exclude the tests that indicate they require this plugin(s)",
406 help="Relative or absolute path to running VPP's socket directory.\n"
407 "The directory must contain VPP's socket files:api.sock & stats.sock.\n"
408 "Default: /var/run/vpp if VPP is started as the root user, else "
409 "/var/run/user/${uid}/vpp.",
412 default_decode_pcaps = False
416 default=default_decode_pcaps,
417 help=f"if set, decode all pcap files from a test run (default: {default_decode_pcaps})",
420 config = parser.parse_args()
422 ws = config.vpp_ws_dir
423 br = f"{ws}/build-root"
426 if config.vpp_install_dir is None:
427 config.vpp_install_dir = f"{br}/install-{tag}-native"
429 if config.vpp is None:
430 config.vpp = f"{config.vpp_install_dir}/vpp/bin/vpp"
432 if config.vpp_build_dir is None:
433 config.vpp_build_dir = f"{br}/build-{tag}-native"
435 libs = ["lib", "lib64"]
437 if config.vpp_plugin_dir is None:
438 config.vpp_plugin_dir = [
439 f"{config.vpp_install_dir}/vpp/{lib}/vpp_plugins" for lib in libs
442 if config.vpp_test_plugin_dir is None:
443 config.vpp_test_plugin_dir = [
444 f"{config.vpp_install_dir}/vpp/{lib}/vpp_api_test_plugins" for lib in libs
447 test_dirs = [f"{ws}/test"]
449 if config.test_src_dir is not None:
450 test_dirs.extend(config.test_src_dir)
452 config.test_src_dir = test_dirs
455 if config.venv_dir is None:
456 config.venv_dir = f"{ws}/build-root/test/venv"
458 if config.failed_dir is None:
459 config.failed_dir = f"{config.tmp_dir}"
461 available_cpus = psutil.Process().cpu_affinity()
462 num_cpus = len(available_cpus)
464 if config.max_vpp_cpus == "auto":
465 max_vpp_cpus = num_cpus
466 elif config.max_vpp_cpus > 0:
467 max_vpp_cpus = min(config.max_vpp_cpus, num_cpus)
469 max_vpp_cpus = num_cpus
471 if not config.skip_netns_tests:
472 if not can_create_namespaces():
473 config.skip_netns_tests = True
475 if __name__ == "__main__":
476 print("Provided arguments:")
477 for i in config.__dict__:
478 print(f" {i} is {config.__dict__[i]}")