xref: /dpdk/dts/framework/exception.py (revision f995766758403e13a7b97e6e3e863ac900716844)
1812c4071SJuraj Linkeš# SPDX-License-Identifier: BSD-3-Clause
2812c4071SJuraj Linkeš# Copyright(c) 2010-2014 Intel Corporation
378534506SJuraj Linkeš# Copyright(c) 2022-2023 PANTHEON.tech s.r.o.
478534506SJuraj Linkeš# Copyright(c) 2022-2023 University of New Hampshire
53b8dd3b9SLuca Vizzarro# Copyright(c) 2024 Arm Limited
6812c4071SJuraj Linkeš
76ef07151SJuraj Linkeš"""DTS exceptions.
86ef07151SJuraj Linkeš
96ef07151SJuraj LinkešThe exceptions all have different severities expressed as an integer.
106ef07151SJuraj LinkešThe highest severity of all raised exceptions is used as the exit code of DTS.
11812c4071SJuraj Linkeš"""
12812c4071SJuraj Linkeš
1378534506SJuraj Linkešfrom enum import IntEnum, unique
1478534506SJuraj Linkešfrom typing import ClassVar
15812c4071SJuraj Linkeš
1678534506SJuraj Linkeš
1778534506SJuraj Linkeš@unique
1878534506SJuraj Linkešclass ErrorSeverity(IntEnum):
196ef07151SJuraj Linkeš    """The severity of errors that occur during DTS execution.
206ef07151SJuraj Linkeš
2178534506SJuraj Linkeš    All exceptions are caught and the most severe error is used as return code.
2278534506SJuraj Linkeš    """
2378534506SJuraj Linkeš
246ef07151SJuraj Linkeš    #:
2578534506SJuraj Linkeš    NO_ERR = 0
266ef07151SJuraj Linkeš    #:
2778534506SJuraj Linkeš    GENERIC_ERR = 1
286ef07151SJuraj Linkeš    #:
2978534506SJuraj Linkeš    CONFIG_ERR = 2
306ef07151SJuraj Linkeš    #:
31ad80f550SJuraj Linkeš    REMOTE_CMD_EXEC_ERR = 3
326ef07151SJuraj Linkeš    #:
33ad80f550SJuraj Linkeš    SSH_ERR = 4
346ef07151SJuraj Linkeš    #:
35818fe14eSLuca Vizzarro    INTERNAL_ERR = 5
36818fe14eSLuca Vizzarro    #:
37680d8a24SJuraj Linkeš    DPDK_BUILD_ERR = 10
386ef07151SJuraj Linkeš    #:
396fc05ca7SJuraj Linkeš    TESTCASE_VERIFY_ERR = 20
406ef07151SJuraj Linkeš    #:
4188489c05SJeremy Spewock    BLOCKING_TESTSUITE_ERR = 25
4278534506SJuraj Linkeš
4378534506SJuraj Linkeš
4478534506SJuraj Linkešclass DTSError(Exception):
456ef07151SJuraj Linkeš    """The base exception from which all DTS exceptions are subclassed.
466ef07151SJuraj Linkeš
476ef07151SJuraj Linkeš    Do not use this exception, only use subclassed exceptions.
4878534506SJuraj Linkeš    """
4978534506SJuraj Linkeš
506ef07151SJuraj Linkeš    #:
5178534506SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.GENERIC_ERR
5278534506SJuraj Linkeš
5378534506SJuraj Linkeš
5478534506SJuraj Linkešclass SSHConnectionError(DTSError):
556ef07151SJuraj Linkeš    """An unsuccessful SSH connection."""
56812c4071SJuraj Linkeš
576ef07151SJuraj Linkeš    #:
5878534506SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR
59840b1e01SJuraj Linkeš    _host: str
60840b1e01SJuraj Linkeš    _errors: list[str]
61812c4071SJuraj Linkeš
62b8bdc4c5SJuraj Linkeš    def __init__(self, host: str, errors: list[str] | None = None):
636ef07151SJuraj Linkeš        """Define the meaning of the first two arguments.
646ef07151SJuraj Linkeš
656ef07151SJuraj Linkeš        Args:
666ef07151SJuraj Linkeš            host: The hostname to which we're trying to connect.
676ef07151SJuraj Linkeš            errors: Any errors that occurred during the connection attempt.
686ef07151SJuraj Linkeš        """
69840b1e01SJuraj Linkeš        self._host = host
70840b1e01SJuraj Linkeš        self._errors = [] if errors is None else errors
71812c4071SJuraj Linkeš
72812c4071SJuraj Linkeš    def __str__(self) -> str:
736ef07151SJuraj Linkeš        """Include the errors in the string representation."""
74840b1e01SJuraj Linkeš        message = f"Error trying to connect with {self._host}."
75840b1e01SJuraj Linkeš        if self._errors:
76840b1e01SJuraj Linkeš            message += f" Errors encountered while retrying: {', '.join(self._errors)}"
77b8bdc4c5SJuraj Linkeš
78b8bdc4c5SJuraj Linkeš        return message
79812c4071SJuraj Linkeš
80812c4071SJuraj Linkeš
816713e286SJeremy Spewockclass _SSHTimeoutError(DTSError):
826713e286SJeremy Spewock    """The execution of a command via SSH timed out.
836713e286SJeremy Spewock
846713e286SJeremy Spewock    This class is private and meant to be raised as its interactive and non-interactive variants.
856713e286SJeremy Spewock    """
866713e286SJeremy Spewock
876713e286SJeremy Spewock    #:
886713e286SJeremy Spewock    severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR
896713e286SJeremy Spewock    _command: str
906713e286SJeremy Spewock
916713e286SJeremy Spewock    def __init__(self, command: str):
926713e286SJeremy Spewock        """Define the meaning of the first argument.
936713e286SJeremy Spewock
946713e286SJeremy Spewock        Args:
956713e286SJeremy Spewock            command: The executed command.
966713e286SJeremy Spewock        """
976713e286SJeremy Spewock        self._command = command
986713e286SJeremy Spewock
996713e286SJeremy Spewock    def __str__(self) -> str:
1006713e286SJeremy Spewock        """Add some context to the string representation."""
1016713e286SJeremy Spewock        return f"{self._command} execution timed out."
1026713e286SJeremy Spewock
1036713e286SJeremy Spewock
1046713e286SJeremy Spewockclass SSHTimeoutError(_SSHTimeoutError):
1056713e286SJeremy Spewock    """The execution of a command on a non-interactive SSH session timed out."""
1066713e286SJeremy Spewock
1076713e286SJeremy Spewock
1086713e286SJeremy Spewockclass InteractiveSSHTimeoutError(_SSHTimeoutError):
1096713e286SJeremy Spewock    """The execution of a command on an interactive SSH session timed out."""
1106713e286SJeremy Spewock
1116713e286SJeremy Spewock
1126713e286SJeremy Spewockclass _SSHSessionDeadError(DTSError):
1136713e286SJeremy Spewock    """The SSH session is no longer alive.
1146713e286SJeremy Spewock
1156713e286SJeremy Spewock    This class is private and meant to be raised as its interactive and non-interactive variants.
1166713e286SJeremy Spewock    """
117812c4071SJuraj Linkeš
1186ef07151SJuraj Linkeš    #:
11978534506SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR
120840b1e01SJuraj Linkeš    _host: str
121812c4071SJuraj Linkeš
122812c4071SJuraj Linkeš    def __init__(self, host: str):
1236ef07151SJuraj Linkeš        """Define the meaning of the first argument.
1246ef07151SJuraj Linkeš
1256ef07151SJuraj Linkeš        Args:
1266ef07151SJuraj Linkeš            host: The hostname of the disconnected node.
1276ef07151SJuraj Linkeš        """
128840b1e01SJuraj Linkeš        self._host = host
129812c4071SJuraj Linkeš
130812c4071SJuraj Linkeš    def __str__(self) -> str:
1316ef07151SJuraj Linkeš        """Add some context to the string representation."""
1326ef07151SJuraj Linkeš        return f"SSH session with {self._host} has died."
13378534506SJuraj Linkeš
13478534506SJuraj Linkeš
1356713e286SJeremy Spewockclass SSHSessionDeadError(_SSHSessionDeadError):
1366713e286SJeremy Spewock    """Non-interactive SSH session has died."""
1376713e286SJeremy Spewock
1386713e286SJeremy Spewock
1396713e286SJeremy Spewockclass InteractiveSSHSessionDeadError(_SSHSessionDeadError):
1406713e286SJeremy Spewock    """Interactive SSH session as died."""
1416713e286SJeremy Spewock
1426713e286SJeremy Spewock
14378534506SJuraj Linkešclass ConfigurationError(DTSError):
1446ef07151SJuraj Linkeš    """An invalid configuration."""
14578534506SJuraj Linkeš
1466ef07151SJuraj Linkeš    #:
14778534506SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.CONFIG_ERR
148ad80f550SJuraj Linkeš
149ad80f550SJuraj Linkeš
150ad80f550SJuraj Linkešclass RemoteCommandExecutionError(DTSError):
1516ef07151SJuraj Linkeš    """An unsuccessful execution of a remote command."""
152ad80f550SJuraj Linkeš
1536ef07151SJuraj Linkeš    #:
154ad80f550SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.REMOTE_CMD_EXEC_ERR
1556ef07151SJuraj Linkeš    #: The executed command.
156840b1e01SJuraj Linkeš    command: str
1573b8dd3b9SLuca Vizzarro    _command_stderr: str
158840b1e01SJuraj Linkeš    _command_return_code: int
159ad80f550SJuraj Linkeš
1603b8dd3b9SLuca Vizzarro    def __init__(self, command: str, command_stderr: str, command_return_code: int):
1616ef07151SJuraj Linkeš        """Define the meaning of the first two arguments.
1626ef07151SJuraj Linkeš
1636ef07151SJuraj Linkeš        Args:
1646ef07151SJuraj Linkeš            command: The executed command.
1653b8dd3b9SLuca Vizzarro            command_stderr: The stderr of the executed command.
1666ef07151SJuraj Linkeš            command_return_code: The return code of the executed command.
1676ef07151SJuraj Linkeš        """
168ad80f550SJuraj Linkeš        self.command = command
1693b8dd3b9SLuca Vizzarro        self._command_stderr = command_stderr
170840b1e01SJuraj Linkeš        self._command_return_code = command_return_code
171ad80f550SJuraj Linkeš
172ad80f550SJuraj Linkeš    def __str__(self) -> str:
1733b8dd3b9SLuca Vizzarro        """Include the command, its return code and stderr in the string representation."""
1743b8dd3b9SLuca Vizzarro        return (
1753b8dd3b9SLuca Vizzarro            f"Command '{self.command}' returned a non-zero exit code: "
1763b8dd3b9SLuca Vizzarro            f"{self._command_return_code}\nStderr: {self._command_stderr}"
1773b8dd3b9SLuca Vizzarro        )
178680d8a24SJuraj Linkeš
179680d8a24SJuraj Linkeš
180369d34b8SJeremy Spewockclass InteractiveCommandExecutionError(DTSError):
181369d34b8SJeremy Spewock    """An unsuccessful execution of a remote command in an interactive environment."""
182369d34b8SJeremy Spewock
183369d34b8SJeremy Spewock    #:
184369d34b8SJeremy Spewock    severity: ClassVar[ErrorSeverity] = ErrorSeverity.REMOTE_CMD_EXEC_ERR
185369d34b8SJeremy Spewock
186369d34b8SJeremy Spewock
187*f9957667STomáš Ďurovecclass RemoteFileNotFoundError(DTSError):
188*f9957667STomáš Ďurovec    """A remote file or directory is requested but doesn’t exist."""
189680d8a24SJuraj Linkeš
1906ef07151SJuraj Linkeš    #:
191680d8a24SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.REMOTE_CMD_EXEC_ERR
192680d8a24SJuraj Linkeš
193680d8a24SJuraj Linkeš
194680d8a24SJuraj Linkešclass DPDKBuildError(DTSError):
1956ef07151SJuraj Linkeš    """A DPDK build failure."""
196680d8a24SJuraj Linkeš
1976ef07151SJuraj Linkeš    #:
198680d8a24SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.DPDK_BUILD_ERR
1996fc05ca7SJuraj Linkeš
2006fc05ca7SJuraj Linkeš
2016fc05ca7SJuraj Linkešclass TestCaseVerifyError(DTSError):
2026ef07151SJuraj Linkeš    """A test case failure."""
2036fc05ca7SJuraj Linkeš
2046ef07151SJuraj Linkeš    #:
2056fc05ca7SJuraj Linkeš    severity: ClassVar[ErrorSeverity] = ErrorSeverity.TESTCASE_VERIFY_ERR
2066fc05ca7SJuraj Linkeš
20788489c05SJeremy Spewock
20888489c05SJeremy Spewockclass BlockingTestSuiteError(DTSError):
2096ef07151SJuraj Linkeš    """A failure in a blocking test suite."""
2106ef07151SJuraj Linkeš
2116ef07151SJuraj Linkeš    #:
21288489c05SJeremy Spewock    severity: ClassVar[ErrorSeverity] = ErrorSeverity.BLOCKING_TESTSUITE_ERR
213840b1e01SJuraj Linkeš    _suite_name: str
21488489c05SJeremy Spewock
21588489c05SJeremy Spewock    def __init__(self, suite_name: str) -> None:
2166ef07151SJuraj Linkeš        """Define the meaning of the first argument.
2176ef07151SJuraj Linkeš
2186ef07151SJuraj Linkeš        Args:
2196ef07151SJuraj Linkeš            suite_name: The blocking test suite.
2206ef07151SJuraj Linkeš        """
221840b1e01SJuraj Linkeš        self._suite_name = suite_name
22288489c05SJeremy Spewock
22388489c05SJeremy Spewock    def __str__(self) -> str:
2246ef07151SJuraj Linkeš        """Add some context to the string representation."""
225840b1e01SJuraj Linkeš        return f"Blocking suite {self._suite_name} failed."
226818fe14eSLuca Vizzarro
227818fe14eSLuca Vizzarro
228818fe14eSLuca Vizzarroclass InternalError(DTSError):
229818fe14eSLuca Vizzarro    """An internal error or bug has occurred in DTS."""
230818fe14eSLuca Vizzarro
231818fe14eSLuca Vizzarro    #:
232818fe14eSLuca Vizzarro    severity: ClassVar[ErrorSeverity] = ErrorSeverity.INTERNAL_ERR
233