-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathrun_dpdk_test_suite.py
More file actions
executable file
·215 lines (177 loc) · 6.81 KB
/
run_dpdk_test_suite.py
File metadata and controls
executable file
·215 lines (177 loc) · 6.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!/usr/bin/env python3
"""Script to execute DPDK Tests Suites on remote DTS controller.
Copyright 2025 Canonical Ltd.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3,
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import logging
import os
import json
import argparse
import shutil
import subprocess
from typing import Optional, Dict, Any
from pathlib import Path
DPDK_SNAP_BIN = "/snap/bin/dpdk-dts"
DPDK_DTS_SNAP_COMMON = Path("/var/snap/dpdk-dts/common")
DPDK_CONFIG_SNAP_PATH = DPDK_DTS_SNAP_COMMON / "dts_config.yaml"
DEFAULT_OUTPUT_DIR = DPDK_DTS_SNAP_COMMON / "dpdk_test_results"
DEFAULT_TIMEOUT = 600
class DTSRunner:
"""Class to execute snap-based DPDK Test Suite (DTS)"""
def __init__(self, test_suite: str, config_file: Path):
"""Initialize class attributes."""
self.test_suite = test_suite
self.config_file = config_file
def run_test_suite(
self,
verbose: bool,
) -> None:
"""Run specified test suite in DTS controller
:param verbose: verbosity level on test suite execution
"""
output_dir = DEFAULT_OUTPUT_DIR / self.test_suite
if output_dir.exists():
shutil.rmtree(output_dir)
output_dir.mkdir(parents=True)
# Copy config file to SNAP_COMMON so the strict snap can access it
shutil.copy(self.config_file, DPDK_CONFIG_SNAP_PATH)
dts_command = [
DPDK_SNAP_BIN,
"--test-suite",
self.test_suite,
"--config-file",
str(DPDK_CONFIG_SNAP_PATH),
"--output-dir",
str(output_dir),
]
if verbose:
dts_command.append("--verbose")
logging.info(
"Starting execution of %s",
self.test_suite,
)
try:
subprocess.run(
dts_command,
check=True,
timeout=DEFAULT_TIMEOUT,
)
except subprocess.CalledProcessError as exc:
logging.error("DPDK Test Suite execution failed: %s", exc)
raise
except subprocess.TimeoutExpired as exc:
logging.error("DPDK Test Suite execution timed out: %s", exc)
raise
logging.info("DTS Test Suite Run completed")
def get_results(self) -> Optional[Dict[str, Any]]:
"""Get the results from test suite execution.
:return: Results in json format if any returned during test execution
"""
logging.info("Getting test suite results")
results_path = DEFAULT_OUTPUT_DIR / self.test_suite / "results.json"
if not results_path.is_file():
logging.warning("No results file found at %s", results_path)
return None
with results_path.open("r") as f:
results = f.read()
if results:
try:
return json.loads(results)
except ValueError:
logging.error("Unable to parse results file as JSON")
return None
def print_results(self) -> bool:
"""Print tests results from execution.
:return: True if results were printed, False otherwise
"""
test_results = self.get_results()
if not test_results:
return False
# Print Test Suite Results and Summary
print("\nDPDK Test Results")
print("-" * 50)
try:
for test_run in test_results["test_runs"]:
for test_suite in test_run["test_suites"]:
suite_name = test_suite["test_suite_name"]
print("\nTest Suite: {}".format(suite_name))
print("{:<30} {}".format("Test Case", "Result"))
print("-" * 40)
# Print test case details
for test_case in test_suite["test_cases"]:
print(
"{:<30} {}".format(
test_case["test_case_name"],
test_case["result"],
)
)
# Print summary
print("\nSummary:")
print("-" * 40)
for status, count in test_suite["summary"].items():
print("{}: {}".format(status, count))
except KeyError:
# If unable to pretty print, dump the test results
print(json.dumps(test_results, indent=2))
return True
def cleanup(self) -> None:
"""Remove config file copied to SNAP_COMMON after test execution."""
if DPDK_CONFIG_SNAP_PATH.is_file():
try:
DPDK_CONFIG_SNAP_PATH.unlink()
except OSError as exc:
logging.warning(
"Failed to remove config file %s: %s",
DPDK_CONFIG_SNAP_PATH,
exc,
)
def parse_args():
"""Parses command-line arguments."""
parser = argparse.ArgumentParser(description="DPDK Test Suite Execution")
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Increase logging level in test suite execution",
)
parser.add_argument(
"-T", "--test-suite", required=True, help="Specified Test Suite to run"
)
args = parser.parse_args()
return args
def main():
"""Main entrypoint to the program."""
args = parse_args()
logging.basicConfig(level=logging.INFO)
dts_config = os.getenv("DTS_CONFIG_FILE")
# Print environment variables used for test suite run
logging.info("DTS_CONFIG_FILE: %s", dts_config)
# Validate configuration before test suite execution
if not dts_config or not Path(dts_config).is_file():
raise SystemExit("Unable to locate config file for test execution.")
# Run snap-based DPDK Test Suite
dts_runner = DTSRunner(
test_suite=args.test_suite,
config_file=Path(dts_config),
)
try:
dts_runner.run_test_suite(args.verbose)
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
# Attempt to print test results before exit
dts_runner.print_results()
raise SystemExit("Test Suite execution failed")
finally:
dts_runner.cleanup()
# Print test suite execution results
if not dts_runner.print_results():
raise SystemExit("No test results found")
if __name__ == "__main__":
main()