1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright(c) 2010-2014 Intel Corporation 3# Copyright(c) 2022-2023 PANTHEON.tech s.r.o. 4# Copyright(c) 2022-2023 University of New Hampshire 5 6""" 7User-defined exceptions used across the framework. 8""" 9 10from enum import IntEnum, unique 11from typing import ClassVar 12 13 14@unique 15class ErrorSeverity(IntEnum): 16 """ 17 The severity of errors that occur during DTS execution. 18 All exceptions are caught and the most severe error is used as return code. 19 """ 20 21 NO_ERR = 0 22 GENERIC_ERR = 1 23 CONFIG_ERR = 2 24 REMOTE_CMD_EXEC_ERR = 3 25 SSH_ERR = 4 26 DPDK_BUILD_ERR = 10 27 TESTCASE_VERIFY_ERR = 20 28 BLOCKING_TESTSUITE_ERR = 25 29 30 31class DTSError(Exception): 32 """ 33 The base exception from which all DTS exceptions are derived. 34 Stores error severity. 35 """ 36 37 severity: ClassVar[ErrorSeverity] = ErrorSeverity.GENERIC_ERR 38 39 40class SSHTimeoutError(DTSError): 41 """ 42 Command execution timeout. 43 """ 44 45 command: str 46 output: str 47 severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR 48 49 def __init__(self, command: str, output: str): 50 self.command = command 51 self.output = output 52 53 def __str__(self) -> str: 54 return f"TIMEOUT on {self.command}" 55 56 def get_output(self) -> str: 57 return self.output 58 59 60class SSHConnectionError(DTSError): 61 """ 62 SSH connection error. 63 """ 64 65 host: str 66 errors: list[str] 67 severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR 68 69 def __init__(self, host: str, errors: list[str] | None = None): 70 self.host = host 71 self.errors = [] if errors is None else errors 72 73 def __str__(self) -> str: 74 message = f"Error trying to connect with {self.host}." 75 if self.errors: 76 message += f" Errors encountered while retrying: {', '.join(self.errors)}" 77 78 return message 79 80 81class SSHSessionDeadError(DTSError): 82 """ 83 SSH session is not alive. 84 It can no longer be used. 85 """ 86 87 host: str 88 severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR 89 90 def __init__(self, host: str): 91 self.host = host 92 93 def __str__(self) -> str: 94 return f"SSH session with {self.host} has died" 95 96 97class ConfigurationError(DTSError): 98 """ 99 Raised when an invalid configuration is encountered. 100 """ 101 102 severity: ClassVar[ErrorSeverity] = ErrorSeverity.CONFIG_ERR 103 104 105class RemoteCommandExecutionError(DTSError): 106 """ 107 Raised when a command executed on a Node returns a non-zero exit status. 108 """ 109 110 command: str 111 command_return_code: int 112 severity: ClassVar[ErrorSeverity] = ErrorSeverity.REMOTE_CMD_EXEC_ERR 113 114 def __init__(self, command: str, command_return_code: int): 115 self.command = command 116 self.command_return_code = command_return_code 117 118 def __str__(self) -> str: 119 return f"Command {self.command} returned a non-zero exit code: {self.command_return_code}" 120 121 122class RemoteDirectoryExistsError(DTSError): 123 """ 124 Raised when a remote directory to be created already exists. 125 """ 126 127 severity: ClassVar[ErrorSeverity] = ErrorSeverity.REMOTE_CMD_EXEC_ERR 128 129 130class DPDKBuildError(DTSError): 131 """ 132 Raised when DPDK build fails for any reason. 133 """ 134 135 severity: ClassVar[ErrorSeverity] = ErrorSeverity.DPDK_BUILD_ERR 136 137 138class TestCaseVerifyError(DTSError): 139 """ 140 Used in test cases to verify the expected behavior. 141 """ 142 143 value: str 144 severity: ClassVar[ErrorSeverity] = ErrorSeverity.TESTCASE_VERIFY_ERR 145 146 def __init__(self, value: str): 147 self.value = value 148 149 def __str__(self) -> str: 150 return repr(self.value) 151 152 153class BlockingTestSuiteError(DTSError): 154 suite_name: str 155 severity: ClassVar[ErrorSeverity] = ErrorSeverity.BLOCKING_TESTSUITE_ERR 156 157 def __init__(self, suite_name: str) -> None: 158 self.suite_name = suite_name 159 160 def __str__(self) -> str: 161 return f"Blocking suite {self.suite_name} failed." 162