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 == "":
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 == "":
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"
206 "--force-foreground",
208 help="force running in foreground - don't fork",
214 type=positive_int_or_auto,
216 help="maximum concurrent test jobs",
220 "--venv-dir", action="store", type=directory, help="path to virtual environment"
223 default_rnd_seed = time.time()
227 default=default_rnd_seed,
228 type=positive_float_or_default(default_rnd_seed),
229 help="random generator seed (default: current time)",
233 "--vpp-worker-count",
237 help="number of vpp workers",
241 "--gcov", action="store_true", default=False, help="running gcov tests"
245 "--cache-vpp-output",
248 help="cache VPP stdout/stderr and log as one block after test finishes",
256 help="vpp workspace directory",
265 help="vpp tag (e.g. vpp, vpp_debug, vpp_gcov)",
271 help="path to vpp binary (default: derive from VPP_WS_DIR and VPP_TAG)",
278 help="path to vpp install directory"
279 "(default: derive from VPP_WS_DIR and VPP_TAG)",
286 help="vpp build directory (default: derive from VPP_WS_DIR and VPP_TAG)",
293 help="directory containing vpp plugins"
294 "(default: derive from VPP_WS_DIR and VPP_TAG)",
298 "--vpp-test-plugin-dir",
301 help="directory containing vpp api test plugins"
302 "(default: derive from VPP_WS_DIR and VPP_TAG)",
306 "--extern-plugin-dir",
310 help="directory containing external plugins",
318 help="directory to look for API JSON files",
325 help="specify vpp coredump size",
333 help="max cpus used by vpp",
336 variant_help_string = """\
337 specify which march node variant to unit test
338 e.g. --variant=skx - test the skx march variants
339 e.g. --variant=icl - test the icl march variants
342 parser.add_argument("--variant", action="store", help=variant_help_string)
345 "--api-fuzz", action="store", default=None, help="specify api fuzzing parameters"
352 help="remove test tmp directory before running test",
359 type=directory_verify_or_create,
360 help="directory where to store test temporary directories",
366 type=directory_verify_or_create,
367 help="directory where to store directories "
368 "containing log files (default: --tmp-dir)",
371 default_keep_pcaps = False
375 default=default_keep_pcaps,
376 help=f"if set, keep all pcap files from a test run (default: {default_keep_pcaps})",
386 help="Runs tests against a running VPP.",
396 help="Relative or absolute path to running VPP's socket directory.\n"
397 "The directory must contain VPP's socket files:api.sock & stats.sock.\n"
398 "Default: /var/run/vpp if VPP is started as the root user, else "
399 "/var/run/user/${uid}/vpp.",
402 config = parser.parse_args()
404 ws = config.vpp_ws_dir
405 br = f"{ws}/build-root"
408 if config.vpp_install_dir is None:
409 config.vpp_install_dir = f"{br}/install-{tag}-native"
411 if config.vpp is None:
412 config.vpp = f"{config.vpp_install_dir}/vpp/bin/vpp"
414 if config.vpp_build_dir is None:
415 config.vpp_build_dir = f"{br}/build-{tag}-native"
417 libs = ["lib", "lib64"]
419 if config.vpp_plugin_dir is None:
420 config.vpp_plugin_dir = [
421 f"{config.vpp_install_dir}/vpp/{lib}/vpp_plugins" for lib in libs
424 if config.vpp_test_plugin_dir is None:
425 config.vpp_test_plugin_dir = [
426 f"{config.vpp_install_dir}/vpp/{lib}/vpp_api_test_plugins" for lib in libs
429 test_dirs = [f"{ws}/test"]
431 if config.test_src_dir is not None:
432 test_dirs.extend(config.test_src_dir)
434 config.test_src_dir = test_dirs
437 if config.venv_dir is None:
438 config.venv_dir = f"{ws}/build-root/test/venv"
440 if config.failed_dir is None:
441 config.failed_dir = f"{config.tmp_dir}"
443 available_cpus = psutil.Process().cpu_affinity()
444 num_cpus = len(available_cpus)
446 if config.max_vpp_cpus == "auto":
447 max_vpp_cpus = num_cpus
448 elif config.max_vpp_cpus > 0:
449 max_vpp_cpus = min(config.max_vpp_cpus, num_cpus)
451 max_vpp_cpus = num_cpus
453 if not config.skip_netns_tests:
454 if not can_create_namespaces():
455 config.skip_netns_tests = True
457 if __name__ == "__main__":
458 print("Provided arguments:")
459 for i in config.__dict__:
460 print(f" {i} is {config.__dict__[i]}")