1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright(c) 2010-2021 Intel Corporation 3# Copyright(c) 2022-2023 PANTHEON.tech s.r.o. 4# Copyright(c) 2022 University of New Hampshire 5 6import argparse 7import os 8from collections.abc import Callable, Iterable, Sequence 9from dataclasses import dataclass 10from pathlib import Path 11from typing import Any, TypeVar 12 13from .utils import DPDKGitTarball 14 15_T = TypeVar("_T") 16 17 18def _env_arg(env_var: str) -> Any: 19 class _EnvironmentArgument(argparse.Action): 20 def __init__( 21 self, 22 option_strings: Sequence[str], 23 dest: str, 24 nargs: str | int | None = None, 25 const: str | None = None, 26 default: str = None, 27 type: Callable[[str], _T | argparse.FileType | None] = None, 28 choices: Iterable[_T] | None = None, 29 required: bool = False, 30 help: str | None = None, 31 metavar: str | tuple[str, ...] | None = None, 32 ) -> None: 33 env_var_value = os.environ.get(env_var) 34 default = env_var_value or default 35 super(_EnvironmentArgument, self).__init__( 36 option_strings, 37 dest, 38 nargs=nargs, 39 const=const, 40 default=default, 41 type=type, 42 choices=choices, 43 required=required, 44 help=help, 45 metavar=metavar, 46 ) 47 48 def __call__( 49 self, 50 parser: argparse.ArgumentParser, 51 namespace: argparse.Namespace, 52 values: Any, 53 option_string: str = None, 54 ) -> None: 55 setattr(namespace, self.dest, values) 56 57 return _EnvironmentArgument 58 59 60@dataclass(slots=True, frozen=True) 61class _Settings: 62 config_file_path: str 63 output_dir: str 64 timeout: float 65 verbose: bool 66 skip_setup: bool 67 dpdk_tarball_path: Path 68 compile_timeout: float 69 test_cases: list 70 re_run: int 71 72 73def _get_parser() -> argparse.ArgumentParser: 74 parser = argparse.ArgumentParser( 75 description="Run DPDK test suites. All options may be specified with " 76 "the environment variables provided in brackets. " 77 "Command line arguments have higher priority.", 78 formatter_class=argparse.ArgumentDefaultsHelpFormatter, 79 ) 80 81 parser.add_argument( 82 "--config-file", 83 action=_env_arg("DTS_CFG_FILE"), 84 default="conf.yaml", 85 help="[DTS_CFG_FILE] configuration file that describes the test cases, SUTs " 86 "and targets.", 87 ) 88 89 parser.add_argument( 90 "--output-dir", 91 "--output", 92 action=_env_arg("DTS_OUTPUT_DIR"), 93 default="output", 94 help="[DTS_OUTPUT_DIR] Output directory where dts logs and results are saved.", 95 ) 96 97 parser.add_argument( 98 "-t", 99 "--timeout", 100 action=_env_arg("DTS_TIMEOUT"), 101 default=15, 102 type=float, 103 help="[DTS_TIMEOUT] The default timeout for all DTS operations except for " 104 "compiling DPDK.", 105 ) 106 107 parser.add_argument( 108 "-v", 109 "--verbose", 110 action=_env_arg("DTS_VERBOSE"), 111 default="N", 112 help="[DTS_VERBOSE] Set to 'Y' to enable verbose output, logging all messages " 113 "to the console.", 114 ) 115 116 parser.add_argument( 117 "-s", 118 "--skip-setup", 119 action=_env_arg("DTS_SKIP_SETUP"), 120 default="N", 121 help="[DTS_SKIP_SETUP] Set to 'Y' to skip all setup steps on SUT and TG nodes.", 122 ) 123 124 parser.add_argument( 125 "--tarball", 126 "--snapshot", 127 "--git-ref", 128 action=_env_arg("DTS_DPDK_TARBALL"), 129 default="dpdk.tar.xz", 130 type=Path, 131 help="[DTS_DPDK_TARBALL] Path to DPDK source code tarball or a git commit ID, " 132 "tag ID or tree ID to test. To test local changes, first commit them, " 133 "then use the commit ID with this option.", 134 ) 135 136 parser.add_argument( 137 "--compile-timeout", 138 action=_env_arg("DTS_COMPILE_TIMEOUT"), 139 default=1200, 140 type=float, 141 help="[DTS_COMPILE_TIMEOUT] The timeout for compiling DPDK.", 142 ) 143 144 parser.add_argument( 145 "--test-cases", 146 action=_env_arg("DTS_TESTCASES"), 147 default="", 148 help="[DTS_TESTCASES] Comma-separated list of test cases to execute. " 149 "Unknown test cases will be silently ignored.", 150 ) 151 152 parser.add_argument( 153 "--re-run", 154 "--re_run", 155 action=_env_arg("DTS_RERUN"), 156 default=0, 157 type=int, 158 help="[DTS_RERUN] Re-run each test case the specified amount of times " 159 "if a test failure occurs", 160 ) 161 162 return parser 163 164 165def _get_settings() -> _Settings: 166 parsed_args = _get_parser().parse_args() 167 return _Settings( 168 config_file_path=parsed_args.config_file, 169 output_dir=parsed_args.output_dir, 170 timeout=parsed_args.timeout, 171 verbose=(parsed_args.verbose == "Y"), 172 skip_setup=(parsed_args.skip_setup == "Y"), 173 dpdk_tarball_path=Path( 174 DPDKGitTarball(parsed_args.tarball, parsed_args.output_dir) 175 ) 176 if not os.path.exists(parsed_args.tarball) 177 else Path(parsed_args.tarball), 178 compile_timeout=parsed_args.compile_timeout, 179 test_cases=parsed_args.test_cases.split(",") if parsed_args.test_cases else [], 180 re_run=parsed_args.re_run, 181 ) 182 183 184SETTINGS: _Settings = _get_settings() 185