blob: b91973f7f956450e59b4cd42fd464d21c0bff145 [file] [log] [blame]
Klement Sekerab23ffd72021-05-31 16:08:53 +02001import argparse
2import os
3import psutil
4import textwrap
5import time
6
7
8def positive_int_or_default(default):
9 def positive_integer(v):
10 if v is None or v == "":
11 return default
12 return int(v)
13 return positive_integer
14
15
16def positive_int_or_auto(v):
17 if v is None or v in ("", "auto"):
18 return "auto"
19 if int(v) <= 0:
20 raise ValueError("value must be positive or auto")
21 return int(v)
22
23
24def int_or_auto(v):
25 if v is None or v in ("", "auto"):
26 return "auto"
27 if int(v) < 0:
28 raise ValueError("value must be positive or auto")
29 return int(v)
30
31
32def int_choice_or_default(options, default):
33 assert default in options
34
35 def choice(v):
36 if v is None or v == "":
37 return default
38 if int(v) in options:
39 return int(v)
40 raise ValueError("invalid choice")
41 return choice
42
43
44def worker_config(v):
45 if v is None or v == "":
46 return 0
47 if v.startswith("workers "):
48 return(int(v.split(" ")[1]))
49 return int(v)
50
51
52def directory(v):
53 if not os.path.isdir(v):
54 raise ValueError(f"provided path '{v}' doesn't exist "
55 "or is not a directory")
56 return v
57
58
59def directory_verify_or_create(v):
60 if not os.path.isdir(v):
61 os.mkdir(v)
62 return v
63
64
65parser = argparse.ArgumentParser(description="VPP unit tests",
66 formatter_class=argparse.RawTextHelpFormatter)
67
68parser.add_argument("--failfast", action="store_true",
69 help="stop running tests on first failure")
70
71parser.add_argument("--test-src-dir", action="append", type=directory,
72 help="directory containing test files "
73 "(may be specified multiple times) "
74 "(VPP_WS_DIR/test is added automatically to the set)")
75
76default_verbose = 0
77
78parser.add_argument("--verbose", action="store", default=default_verbose,
79 type=int_choice_or_default((0, 1, 2), default_verbose),
80 help="verbosity setting - 0 - least verbose, "
81 "2 - most verbose (default: 0)")
82
83default_test_run_timeout = 600
84
85parser.add_argument("--timeout", action="store",
86 type=positive_int_or_default(default_test_run_timeout),
87 default=default_test_run_timeout,
88 metavar="TEST_RUN_TIMEOUT",
89 help="test run timeout in seconds - per test "
90 f"(default: {default_test_run_timeout})")
91
92parser.add_argument("--failed-dir", action="store", type=directory,
93 help="directory containing failed tests")
94
95filter_help_string = """\
96expression consists of 3 string selectors separated by '.' separators:
97
98 <file>.<class>.<function>
99
100- selectors restrict which files/classes/functions are run
101- selector can be replaced with '*' or omitted entirely if not needed
102- <file> selector is automatically prepended with 'test_' if required
103- '.' separators are required only if selector(s) follow(s)
104
105examples:
106
1071. all of the following expressions are equivalent and will select
108 all test classes and functions from test_bfd.py:
109 'test_bfd' 'bfd' 'test_bfd..' 'bfd.' 'bfd.*.*' 'test_bfd.*.*'
1102. 'bfd.BFDAPITestCase' selects all tests from test_bfd.py,
111 which are part of BFDAPITestCase class
1123. 'bfd.BFDAPITestCase.test_add_bfd' selects a single test named
113 test_add_bfd from test_bfd.py/BFDAPITestCase
1144. '.*.test_add_bfd' selects all test functions named test_add_bfd
115 from all files/classes
116"""
117parser.add_argument("--filter", action="store",
118 metavar="FILTER_EXPRESSION", help=filter_help_string)
119
120default_retries = 0
121
122parser.add_argument("--retries", action="store", default=default_retries,
123 type=positive_int_or_default(default_retries),
124 help="retry failed tests RETRIES times")
125
126parser.add_argument("--step", action="store_true", default=False,
127 help="enable stepping through tests")
128
129debug_help_string = """\
130attach - attach to already running vpp
131core - detect coredump and load core in gdb on crash
132gdb - print VPP PID and pause allowing attaching gdb
133gdbserver - same as above, but run gdb in gdbserver
134"""
135
136parser.add_argument("--debug", action="store",
137 choices=["attach", "core", "gdb", "gdbserver"],
138 help=debug_help_string)
139
140parser.add_argument("--debug-framework", action="store_true",
141 help="enable internal test framework debugging")
142
143parser.add_argument("--compress-core", action="store_true",
144 help="compress core files if not debugging them")
145
146parser.add_argument("--extended", action="store_true",
147 help="run extended tests")
148
149parser.add_argument("--sanity", action="store_true",
150 help="perform sanity vpp run before running tests")
151
152parser.add_argument("--force-foreground", action="store_true",
153 help="force running in foreground - don't fork")
154
155parser.add_argument("--jobs", action="store", type=positive_int_or_auto,
156 default="auto", help="maximum concurrent test jobs")
157
158parser.add_argument("--venv-dir", action="store",
159 type=directory, help="path to virtual environment")
160
161default_rnd_seed = time.time()
162parser.add_argument("--rnd-seed", action="store", default=default_rnd_seed,
163 type=positive_int_or_default(default_rnd_seed),
164 help="random generator seed (default: current time)")
165
166parser.add_argument("--vpp-worker-count", action="store", type=worker_config,
167 default=0, help="number of vpp workers")
168
169parser.add_argument("--gcov", action="store_true",
170 default=False, help="running gcov tests")
171
172parser.add_argument("--cache-vpp-output", action="store_true", default=False,
173 help="cache VPP stdout/stderr and log as one block "
174 "after test finishes")
175
176parser.add_argument("--vpp-ws-dir", action="store", required=True,
177 type=directory, help="vpp workspace directory")
178
179parser.add_argument("--vpp-tag", action="store", default="vpp_debug",
180 metavar="VPP_TAG", required=True,
181 help="vpp tag (e.g. vpp, vpp_debug, vpp_gcov)")
182
183parser.add_argument("--vpp", action="store", help="path to vpp binary "
184 "(default: derive from VPP_WS_DIR and VPP_TAG)")
185
186parser.add_argument("--vpp-install-dir", type=directory,
187 action="store", help="path to vpp install directory"
188 "(default: derive from VPP_WS_DIR and VPP_TAG)")
189
190parser.add_argument("--vpp-build-dir", action="store", type=directory,
191 help="vpp build directory"
192 "(default: derive from VPP_WS_DIR and VPP_TAG)")
193
194parser.add_argument("--vpp-plugin-dir", action="append", type=directory,
195 help="directory containing vpp plugins"
196 "(default: derive from VPP_WS_DIR and VPP_TAG)")
197
198parser.add_argument("--vpp-test-plugin-dir", action="append", type=directory,
199 help="directory containing vpp api test plugins"
200 "(default: derive from VPP_WS_DIR and VPP_TAG)")
201
202parser.add_argument("--extern-plugin-dir", action="append", type=directory,
203 default=[], help="directory containing external plugins")
204
205parser.add_argument("--coredump-size", action="store", default="unlimited",
206 help="specify vpp coredump size")
207
208parser.add_argument("--max-vpp-cpus", action="store", type=int_or_auto,
209 default=0, help="max cpus used by vpp")
210
211variant_help_string = """\
212specify which march node variant to unit test
213 e.g. --variant=skx - test the skx march variants
214 e.g. --variant=icl - test the icl march variants
215"""
216
217parser.add_argument("--variant", action="store", help=variant_help_string)
218
219parser.add_argument("--api-fuzz", action="store", default=None,
220 help="specify api fuzzing parameters")
221
222parser.add_argument("--wipe-tmp-dir", action="store_true", default=True,
223 help="remove test tmp directory before running test")
224
225parser.add_argument("--tmp-dir", action="store", default="/tmp",
226 type=directory_verify_or_create,
227 help="directory where to store test temporary directories")
228
229parser.add_argument("--log-dir", action="store",
230 type=directory_verify_or_create,
231 help="directory where to store directories "
232 "containing log files (default: --tmp-dir)")
233
234default_keep_pcaps = False
235parser.add_argument("--keep-pcaps", action="store_true",
236 default=default_keep_pcaps,
237 help="if set, keep all pcap files from a test run"
238 f" (default: {default_keep_pcaps})")
239
240config = parser.parse_args()
241
242ws = config.vpp_ws_dir
243br = f"{ws}/build-root"
244tag = config.vpp_tag
245
246if config.vpp_install_dir is None:
247 config.vpp_install_dir = f"{br}/install-{tag}-native"
248
249if config.vpp is None:
250 config.vpp = f"{config.vpp_install_dir}/vpp/bin/vpp"
251
252if config.vpp_build_dir is None:
253 config.vpp_build_dir = f"{br}/build-{tag}-native"
254
255libs = ["lib", "lib64"]
256
257if config.vpp_plugin_dir is None:
258 config.vpp_plugin_dir = [
259 f"{config.vpp_install_dir}/vpp/{lib}/vpp_plugins" for lib in libs]
260
261if config.vpp_test_plugin_dir is None:
262 config.vpp_test_plugin_dir = [
263 f"{config.vpp_install_dir}/vpp/{lib}/vpp_api_test_plugins"
264 for lib in libs]
265
266test_dirs = [f"{ws}/test"]
267
268if config.test_src_dir is not None:
269 test_dirs.extend(config.test_src_dir)
270
271config.test_src_dir = test_dirs
272
273
274if config.venv_dir is None:
275 config.venv_dir = f"{ws}/test/venv"
276
277available_cpus = psutil.Process().cpu_affinity()
278num_cpus = len(available_cpus)
279
280if config.max_vpp_cpus == 'auto':
281 max_vpp_cpus = num_cpus
282elif config.max_vpp_cpus > 0:
283 max_vpp_cpus = min(config.max_vpp_cpus, num_cpus)
284else:
285 max_vpp_cpus = num_cpus
286
287if __name__ == "__main__":
288 print("Provided arguments:")
289 for i in config.__dict__:
290 print(f" {i} is {config.__dict__[i]}")