orionis 0.282.0__py3-none-any.whl → 0.283.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orionis/application.py +2 -7
- orionis/metadata/framework.py +1 -1
- orionis/services/environment/dot_env.py +37 -7
- orionis/services/environment/env.py +4 -4
- orionis/test/logs/contracts/__init__.py +0 -0
- orionis/test/logs/contracts/history.py +81 -0
- orionis/test/logs/history.py +251 -0
- orionis/test/suites/test_suite.py +15 -4
- orionis/test/suites/test_unit.py +2 -2
- orionis/unittesting.py +5 -1
- {orionis-0.282.0.dist-info → orionis-0.283.0.dist-info}/METADATA +1 -1
- {orionis-0.282.0.dist-info → orionis-0.283.0.dist-info}/RECORD +17 -15
- tests/services/environment/test_env.py +3 -3
- orionis/test/logs/log_test.py +0 -211
- {orionis-0.282.0.dist-info → orionis-0.283.0.dist-info}/WHEEL +0 -0
- {orionis-0.282.0.dist-info → orionis-0.283.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.282.0.dist-info → orionis-0.283.0.dist-info}/top_level.txt +0 -0
- {orionis-0.282.0.dist-info → orionis-0.283.0.dist-info}/zip-safe +0 -0
orionis/application.py
CHANGED
@@ -1,15 +1,10 @@
|
|
1
1
|
from orionis.foundation.config.startup import Configuration
|
2
|
+
from orionis.patterns.singleton.meta_class import Singleton
|
2
3
|
|
3
|
-
class Orionis:
|
4
|
+
class Orionis(metaclass=Singleton):
|
4
5
|
|
5
6
|
def __init__(
|
6
7
|
self,
|
7
8
|
config: Configuration = None
|
8
9
|
):
|
9
|
-
"""
|
10
|
-
Initializes the Orionis instance with optional configuration objects.
|
11
|
-
|
12
|
-
Args:
|
13
|
-
config (Configuration, optional): Custom application configuration.
|
14
|
-
"""
|
15
10
|
self.__config = config or Configuration()
|
orionis/metadata/framework.py
CHANGED
@@ -39,7 +39,7 @@ class DotEnv(metaclass=Singleton):
|
|
39
39
|
|
40
40
|
load_dotenv(self._resolved_path)
|
41
41
|
|
42
|
-
def get(self, key: str, default: Optional[Any] = None) -> Any:
|
42
|
+
def get(self, key: str, default: Optional[Any] = None, is_path:bool=False) -> Any:
|
43
43
|
"""
|
44
44
|
Retrieve the value of an environment variable by key.
|
45
45
|
|
@@ -54,6 +54,8 @@ class DotEnv(metaclass=Singleton):
|
|
54
54
|
key (str): The name of the environment variable to retrieve.
|
55
55
|
default (Optional[Any], optional): The value to return if the key is not found.
|
56
56
|
Defaults to None.
|
57
|
+
is_path (bool, optional): If True, the value is treated as a file path and backslashes are replaced with forward slashes.
|
58
|
+
This is useful for Windows paths. Defaults to False.
|
57
59
|
|
58
60
|
Returns:
|
59
61
|
Any: The parsed value of the environment variable, or the default if not found.
|
@@ -62,9 +64,9 @@ class DotEnv(metaclass=Singleton):
|
|
62
64
|
value = dotenv_values(self._resolved_path).get(key)
|
63
65
|
if value is None:
|
64
66
|
value = os.getenv(key)
|
65
|
-
return self.__parseValue(value) if value is not None else default
|
67
|
+
return self.__parseValue(value, is_path) if value is not None else default
|
66
68
|
|
67
|
-
def set(self, key: str, value: Union[str, int, float, bool, list, dict]) -> bool:
|
69
|
+
def set(self, key: str, value: Union[str, int, float, bool, list, dict], is_path:bool=False) -> bool:
|
68
70
|
"""
|
69
71
|
Sets an environment variable with the specified key and value.
|
70
72
|
|
@@ -73,13 +75,16 @@ class DotEnv(metaclass=Singleton):
|
|
73
75
|
Args:
|
74
76
|
key (str): The name of the environment variable to set.
|
75
77
|
value (Union[str, int, float, bool, list, dict]): The value to assign to the environment variable. Supported types include string, integer, float, boolean, list, and dictionary.
|
78
|
+
is_path (bool, optional): If True, the value is treated as a file path and backslashes are replaced with forward slashes.
|
79
|
+
This is useful for Windows paths. Defaults to False.
|
76
80
|
|
77
81
|
Returns:
|
78
82
|
bool: True if the environment variable was successfully set.
|
79
83
|
"""
|
84
|
+
|
80
85
|
with self._lock:
|
81
|
-
serialized_value = self.__serializeValue(value)
|
82
|
-
set_key(str(self._resolved_path), key,
|
86
|
+
serialized_value = self.__serializeValue(value, is_path)
|
87
|
+
set_key(str(self._resolved_path), key, serialized_value)
|
83
88
|
os.environ[key] = str(value)
|
84
89
|
return True
|
85
90
|
|
@@ -133,7 +138,7 @@ class DotEnv(metaclass=Singleton):
|
|
133
138
|
with self._lock:
|
134
139
|
return base64.b64encode(json.dumps(self.all()).encode()).decode()
|
135
140
|
|
136
|
-
def __parseValue(self, value: Any) -> Any:
|
141
|
+
def __parseValue(self, value: Any, is_path:bool=False) -> Any:
|
137
142
|
"""
|
138
143
|
Parses and converts the input value to an appropriate Python data type.
|
139
144
|
|
@@ -151,38 +156,51 @@ class DotEnv(metaclass=Singleton):
|
|
151
156
|
"""
|
152
157
|
if value is None:
|
153
158
|
return None
|
159
|
+
|
154
160
|
if isinstance(value, (bool, int, float)):
|
155
161
|
return value
|
162
|
+
|
156
163
|
value_str = str(value).strip()
|
157
164
|
if not value_str or value_str.lower() in {'none', 'null', 'nan'}:
|
158
165
|
return None
|
166
|
+
|
159
167
|
if value_str.lower() == 'true':
|
160
168
|
return True
|
169
|
+
|
161
170
|
if value_str.lower() == 'false':
|
162
171
|
return False
|
172
|
+
|
173
|
+
if is_path:
|
174
|
+
return value_str.replace("\\", "/")
|
175
|
+
|
163
176
|
try:
|
164
177
|
if value_str.isdigit() or (value_str.startswith('-') and value_str[1:].isdigit()):
|
165
178
|
return int(value_str)
|
166
179
|
except Exception:
|
167
180
|
pass
|
181
|
+
|
168
182
|
try:
|
169
183
|
float_val = float(value_str)
|
170
184
|
if '.' in value_str or 'e' in value_str.lower():
|
171
185
|
return float_val
|
172
186
|
except Exception:
|
173
187
|
pass
|
188
|
+
|
174
189
|
try:
|
175
190
|
return ast.literal_eval(value_str)
|
176
191
|
except Exception:
|
177
192
|
pass
|
193
|
+
|
178
194
|
return value_str
|
179
195
|
|
180
|
-
def __serializeValue(self, value: Any) -> str:
|
196
|
+
def __serializeValue(self, value: Any, is_path:bool=False) -> str:
|
181
197
|
"""
|
182
198
|
Serializes a given value to a string suitable for storage in a .env file.
|
183
199
|
|
184
200
|
Parameters:
|
185
201
|
value (Any): The value to serialize. Supported types are None, str, bool, int, float, list, and dict.
|
202
|
+
is_path (bool): If True, the value is treated as a file path and backslashes are replaced with forward slashes.
|
203
|
+
This is useful for Windows paths.
|
186
204
|
|
187
205
|
Returns:
|
188
206
|
str: The serialized string representation of the value.
|
@@ -191,27 +209,39 @@ class DotEnv(metaclass=Singleton):
|
|
191
209
|
ValueError: If a float value is in scientific notation.
|
192
210
|
TypeError: If the value's type is not serializable for .env files.
|
193
211
|
"""
|
212
|
+
if is_path:
|
213
|
+
return str(value).replace("\\", "/")
|
214
|
+
|
194
215
|
if value is None:
|
195
216
|
return "None"
|
217
|
+
|
196
218
|
if isinstance(value, str):
|
197
219
|
return value
|
220
|
+
|
198
221
|
if isinstance(value, bool):
|
199
222
|
return str(value).lower()
|
223
|
+
|
200
224
|
if isinstance(value, int):
|
201
225
|
return str(value)
|
226
|
+
|
202
227
|
if isinstance(value, float):
|
203
228
|
value = str(value)
|
204
229
|
if 'e' in value or 'E' in value:
|
205
230
|
raise ValueError('scientific notation is not supported, use a string instead')
|
206
231
|
return value
|
232
|
+
|
207
233
|
if isinstance(value, (list, dict)):
|
208
234
|
return repr(value)
|
235
|
+
|
209
236
|
if hasattr(value, '__dict__'):
|
210
237
|
raise TypeError(f"Type {type(value).__name__} is not serializable for .env")
|
238
|
+
|
211
239
|
if not isinstance(value, (list, dict, bool, int, float, str)):
|
212
240
|
raise TypeError(f"Type {type(value).__name__} is not serializable for .env")
|
241
|
+
|
213
242
|
if isinstance(value, (list, dict, bool, int, float, str)):
|
214
243
|
if type(value).__module__ != "builtins" and not isinstance(value, str):
|
215
244
|
raise TypeError(f"Type {type(value).__name__} is not serializable for .env")
|
216
245
|
return repr(value) if not isinstance(value, str) else value
|
246
|
+
|
217
247
|
raise TypeError(f"Type {type(value).__name__} is not serializable for .env")
|
@@ -24,18 +24,18 @@ class Env(IEnv):
|
|
24
24
|
return cls._dotenv_instance
|
25
25
|
|
26
26
|
@staticmethod
|
27
|
-
def get(key: str, default: Any = None) -> Any:
|
27
|
+
def get(key: str, default: Any = None, is_path: bool = False) -> Any:
|
28
28
|
"""
|
29
29
|
Retrieve the value of an environment variable by key.
|
30
30
|
"""
|
31
|
-
return Env._dotenv().get(key, default)
|
31
|
+
return Env._dotenv().get(key, default, is_path)
|
32
32
|
|
33
33
|
@staticmethod
|
34
|
-
def set(key: str, value: str) -> bool:
|
34
|
+
def set(key: str, value: str, is_path: bool = False) -> bool:
|
35
35
|
"""
|
36
36
|
Sets the value of an environment variable.
|
37
37
|
"""
|
38
|
-
return Env._dotenv().set(key, value)
|
38
|
+
return Env._dotenv().set(key, value, is_path)
|
39
39
|
|
40
40
|
@staticmethod
|
41
41
|
def unset(key: str) -> bool:
|
File without changes
|
@@ -0,0 +1,81 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
from typing import Dict, List, Tuple
|
3
|
+
|
4
|
+
class ITestHistory(ABC):
|
5
|
+
|
6
|
+
@abstractmethod
|
7
|
+
def createTableIfNotExists(self) -> None:
|
8
|
+
"""
|
9
|
+
Create the 'reportes' table if it does not already exist.
|
10
|
+
|
11
|
+
The table includes fields for the full JSON report and individual
|
12
|
+
statistics for querying and filtering.
|
13
|
+
|
14
|
+
Raises
|
15
|
+
------
|
16
|
+
RuntimeError
|
17
|
+
If table creation fails due to a database error.
|
18
|
+
"""
|
19
|
+
pass
|
20
|
+
|
21
|
+
@abstractmethod
|
22
|
+
def insertReport(self, report: Dict) -> None:
|
23
|
+
"""
|
24
|
+
Insert a test report into the database.
|
25
|
+
|
26
|
+
Parameters
|
27
|
+
----------
|
28
|
+
report : dict
|
29
|
+
Dictionary containing test statistics and metadata.
|
30
|
+
|
31
|
+
Required keys:
|
32
|
+
- total_tests : int
|
33
|
+
- passed : int
|
34
|
+
- failed : int
|
35
|
+
- errors : int
|
36
|
+
- skipped : int
|
37
|
+
- total_time : float
|
38
|
+
- success_rate : float
|
39
|
+
- timestamp : str (ISO format)
|
40
|
+
|
41
|
+
Raises
|
42
|
+
------
|
43
|
+
ValueError
|
44
|
+
If required keys are missing from the report.
|
45
|
+
RuntimeError
|
46
|
+
If insertion into the database fails.
|
47
|
+
"""
|
48
|
+
pass
|
49
|
+
|
50
|
+
def getReports(self) -> List[Tuple]:
|
51
|
+
"""
|
52
|
+
Retrieve all test reports from the database.
|
53
|
+
|
54
|
+
Returns
|
55
|
+
-------
|
56
|
+
List[Tuple]
|
57
|
+
A list of tuples representing each row in the `reportes` table.
|
58
|
+
|
59
|
+
Raises
|
60
|
+
------
|
61
|
+
RuntimeError
|
62
|
+
If retrieval fails due to a database error.
|
63
|
+
"""
|
64
|
+
pass
|
65
|
+
|
66
|
+
def resetDatabase(self) -> None:
|
67
|
+
"""
|
68
|
+
Drop the `reportes` table, effectively clearing the report history.
|
69
|
+
|
70
|
+
Raises
|
71
|
+
------
|
72
|
+
RuntimeError
|
73
|
+
If table deletion fails.
|
74
|
+
"""
|
75
|
+
pass
|
76
|
+
|
77
|
+
def close(self) -> None:
|
78
|
+
"""
|
79
|
+
Close the SQLite database connection gracefully.
|
80
|
+
"""
|
81
|
+
pass
|
@@ -0,0 +1,251 @@
|
|
1
|
+
import json
|
2
|
+
import sqlite3
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Dict, List, Tuple, Optional
|
5
|
+
from contextlib import closing
|
6
|
+
from orionis.services.environment.env import Env
|
7
|
+
from orionis.test.logs.contracts.history import ITestHistory
|
8
|
+
|
9
|
+
class TestHistory(ITestHistory):
|
10
|
+
"""
|
11
|
+
A utility class for managing test execution reports using a local SQLite database.
|
12
|
+
|
13
|
+
Attributes
|
14
|
+
----------
|
15
|
+
TABLE_NAME : str
|
16
|
+
The name of the database table where reports are stored.
|
17
|
+
DB_NAME : str
|
18
|
+
The filename of the SQLite database.
|
19
|
+
FIELDS : List[str]
|
20
|
+
List of expected keys in the report dictionary.
|
21
|
+
_conn : sqlite3.Connection or None
|
22
|
+
SQLite database connection instance.
|
23
|
+
"""
|
24
|
+
|
25
|
+
TABLE_NAME = "reportes"
|
26
|
+
DB_NAME = "tests.sqlite"
|
27
|
+
FIELDS = [
|
28
|
+
"json", "total_tests", "passed", "failed", "errors",
|
29
|
+
"skipped", "total_time", "success_rate", "timestamp"
|
30
|
+
]
|
31
|
+
|
32
|
+
def __init__(self, test_db_path: Optional[str] = None) -> None:
|
33
|
+
"""
|
34
|
+
Initializes the class instance, setting up the path to the test database.
|
35
|
+
Parameters:
|
36
|
+
test_db_path (Optional[str]): Optional path to the test database file or directory. If a directory is provided, the database file name is appended. If not provided, the method checks the 'TEST_DB_PATH' environment variable, or defaults to a database file in the current file's directory.
|
37
|
+
Behavior:
|
38
|
+
- Resolves the database path to an absolute path.
|
39
|
+
- Ensures the parent directory for the database exists.
|
40
|
+
- Stores the resolved database path in the 'TEST_DB_PATH' environment variable.
|
41
|
+
- Prepares the instance for database connection initialization.
|
42
|
+
"""
|
43
|
+
|
44
|
+
if test_db_path:
|
45
|
+
|
46
|
+
# Resolve the provided test_db_path to an absolute path
|
47
|
+
db_path = Path(test_db_path).resolve()
|
48
|
+
|
49
|
+
# If the provided path is a directory, append the database name
|
50
|
+
if db_path.is_dir():
|
51
|
+
db_path = db_path / self.DB_NAME
|
52
|
+
|
53
|
+
else:
|
54
|
+
|
55
|
+
# Check if the TEST_DB_PATH environment variable is set
|
56
|
+
env_path = Env.get(
|
57
|
+
key="TEST_DB_PATH",
|
58
|
+
default=None,
|
59
|
+
is_path=True
|
60
|
+
)
|
61
|
+
|
62
|
+
# If the environment variable is set, resolve it to an absolute path
|
63
|
+
if env_path:
|
64
|
+
db_path = Path(env_path).resolve()
|
65
|
+
if db_path.is_dir():
|
66
|
+
db_path = db_path / self.DB_NAME
|
67
|
+
else:
|
68
|
+
db_path = Path(__file__).parent / self.DB_NAME
|
69
|
+
|
70
|
+
# Ensure directory exists
|
71
|
+
db_path.parent.mkdir(parents=True, exist_ok=True)
|
72
|
+
|
73
|
+
# Store the absolute string path in the environment
|
74
|
+
Env.set(
|
75
|
+
key="TEST_DB_PATH",
|
76
|
+
value=str(db_path),
|
77
|
+
is_path=True
|
78
|
+
)
|
79
|
+
|
80
|
+
# Initialize the database connection.
|
81
|
+
self._conn: Optional[sqlite3.Connection] = None
|
82
|
+
|
83
|
+
def __connect(self) -> None:
|
84
|
+
"""
|
85
|
+
Establishes a connection to the SQLite database using the path specified in the
|
86
|
+
'TEST_DB_PATH' environment variable. If the environment variable is not set,
|
87
|
+
raises a ConnectionError. If a connection error occurs during the attempt to
|
88
|
+
connect, raises a ConnectionError with the error details.
|
89
|
+
Raises:
|
90
|
+
ConnectionError: If the database path is not set or if a connection error occurs.
|
91
|
+
"""
|
92
|
+
|
93
|
+
if self._conn is None:
|
94
|
+
|
95
|
+
# Check if the TEST_DB_PATH environment variable is set
|
96
|
+
db_path = Env.get(
|
97
|
+
key="TEST_DB_PATH",
|
98
|
+
default=None,
|
99
|
+
is_path=True
|
100
|
+
)
|
101
|
+
|
102
|
+
# If not set, raise an error
|
103
|
+
if not db_path:
|
104
|
+
raise ConnectionError("Database path is not set in environment variables.")
|
105
|
+
|
106
|
+
# Try to connect to the SQLite database
|
107
|
+
try:
|
108
|
+
self._conn = sqlite3.connect(db_path)
|
109
|
+
except sqlite3.Error as e:
|
110
|
+
raise ConnectionError(f"Database connection error: {e}")
|
111
|
+
|
112
|
+
def createTableIfNotExists(self) -> None:
|
113
|
+
"""
|
114
|
+
Creates the history table in the database if it does not already exist.
|
115
|
+
This method establishes a connection to the database and attempts to create a table
|
116
|
+
with the schema defined by `self.TABLE_NAME`. The table includes columns for test
|
117
|
+
results and metadata such as total tests, passed, failed, errors, skipped, total time,
|
118
|
+
success rate, and timestamp. If the table already exists, no changes are made.
|
119
|
+
Raises a RuntimeError if the table creation fails due to a database error.
|
120
|
+
"""
|
121
|
+
|
122
|
+
self.__connect()
|
123
|
+
try:
|
124
|
+
with closing(self._conn.cursor()) as cursor:
|
125
|
+
cursor.execute(f'''
|
126
|
+
CREATE TABLE IF NOT EXISTS {self.TABLE_NAME} (
|
127
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
128
|
+
json TEXT NOT NULL,
|
129
|
+
total_tests INTEGER,
|
130
|
+
passed INTEGER,
|
131
|
+
failed INTEGER,
|
132
|
+
errors INTEGER,
|
133
|
+
skipped INTEGER,
|
134
|
+
total_time REAL,
|
135
|
+
success_rate REAL,
|
136
|
+
timestamp TEXT
|
137
|
+
)
|
138
|
+
''')
|
139
|
+
self._conn.commit()
|
140
|
+
except sqlite3.Error as e:
|
141
|
+
raise RuntimeError(f"Failed to create table: {e}")
|
142
|
+
|
143
|
+
def insertReport(self, report: Dict) -> None:
|
144
|
+
"""
|
145
|
+
Inserts a test report into the database.
|
146
|
+
Args:
|
147
|
+
report (Dict): A dictionary containing the report data. Must include the following keys:
|
148
|
+
- total_tests
|
149
|
+
- passed
|
150
|
+
- failed
|
151
|
+
- errors
|
152
|
+
- skipped
|
153
|
+
- total_time
|
154
|
+
- success_rate
|
155
|
+
- timestamp
|
156
|
+
Raises:
|
157
|
+
ValueError: If any required report fields are missing.
|
158
|
+
RuntimeError: If there is an error inserting the report into the database.
|
159
|
+
"""
|
160
|
+
|
161
|
+
self.__connect()
|
162
|
+
missing = [key for key in self.FIELDS if key != "json" and key not in report]
|
163
|
+
if missing:
|
164
|
+
raise ValueError(f"Missing report fields: {missing}")
|
165
|
+
|
166
|
+
try:
|
167
|
+
with closing(self._conn.cursor()) as cursor:
|
168
|
+
cursor.execute(f'''
|
169
|
+
INSERT INTO {self.TABLE_NAME} (
|
170
|
+
json, total_tests, passed, failed, errors,
|
171
|
+
skipped, total_time, success_rate, timestamp
|
172
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
173
|
+
''', (
|
174
|
+
json.dumps(report),
|
175
|
+
report["total_tests"],
|
176
|
+
report["passed"],
|
177
|
+
report["failed"],
|
178
|
+
report["errors"],
|
179
|
+
report["skipped"],
|
180
|
+
report["total_time"],
|
181
|
+
report["success_rate"],
|
182
|
+
report["timestamp"]
|
183
|
+
))
|
184
|
+
self._conn.commit()
|
185
|
+
except sqlite3.Error as e:
|
186
|
+
raise RuntimeError(f"Failed to insert report: {e}")
|
187
|
+
|
188
|
+
def getReportsWhere(self, where: Optional[str] = None, params: Optional[Tuple] = None) -> List[Tuple]:
|
189
|
+
"""
|
190
|
+
Retrieves reports from the database table with optional WHERE conditions.
|
191
|
+
Args:
|
192
|
+
where (Optional[str]): SQL WHERE clause (without the 'WHERE' keyword).
|
193
|
+
params (Optional[Tuple]): Parameters to substitute in the WHERE clause.
|
194
|
+
Returns:
|
195
|
+
List[Tuple]: A list of tuples, each representing a row from the reports table.
|
196
|
+
Raises:
|
197
|
+
RuntimeError: If there is an error retrieving the reports from the database.
|
198
|
+
"""
|
199
|
+
self.__connect()
|
200
|
+
try:
|
201
|
+
with closing(self._conn.cursor()) as cursor:
|
202
|
+
query = f'SELECT * FROM {self.TABLE_NAME}'
|
203
|
+
if where:
|
204
|
+
query += f' WHERE {where}'
|
205
|
+
cursor.execute(query, params or ())
|
206
|
+
return cursor.fetchall()
|
207
|
+
except sqlite3.Error as e:
|
208
|
+
raise RuntimeError(f"Failed to retrieve reports: {e}")
|
209
|
+
|
210
|
+
def getReports(self) -> List[Tuple]:
|
211
|
+
"""
|
212
|
+
Retrieves all reports from the database table.
|
213
|
+
Returns:
|
214
|
+
List[Tuple]: A list of tuples, each representing a row from the reports table.
|
215
|
+
Raises:
|
216
|
+
RuntimeError: If there is an error retrieving the reports from the database.
|
217
|
+
"""
|
218
|
+
|
219
|
+
self.__connect()
|
220
|
+
try:
|
221
|
+
with closing(self._conn.cursor()) as cursor:
|
222
|
+
cursor.execute(f'SELECT * FROM {self.TABLE_NAME}')
|
223
|
+
return cursor.fetchall()
|
224
|
+
except sqlite3.Error as e:
|
225
|
+
raise RuntimeError(f"Failed to retrieve reports: {e}")
|
226
|
+
|
227
|
+
def resetDatabase(self) -> None:
|
228
|
+
"""
|
229
|
+
Resets the database by dropping the table specified by TABLE_NAME if it exists.
|
230
|
+
This method establishes a connection to the database, attempts to drop the table,
|
231
|
+
and commits the changes. If an error occurs during the process, a RuntimeError is raised.
|
232
|
+
Raises:
|
233
|
+
RuntimeError: If the database reset operation fails.
|
234
|
+
"""
|
235
|
+
|
236
|
+
self.__connect()
|
237
|
+
try:
|
238
|
+
with closing(self._conn.cursor()) as cursor:
|
239
|
+
cursor.execute(f'DROP TABLE IF EXISTS {self.TABLE_NAME}')
|
240
|
+
self._conn.commit()
|
241
|
+
except sqlite3.Error as e:
|
242
|
+
raise RuntimeError(f"Failed to reset database: {e}")
|
243
|
+
|
244
|
+
def close(self) -> None:
|
245
|
+
"""
|
246
|
+
Closes the current database connection if it exists and sets the connection attribute to None.
|
247
|
+
"""
|
248
|
+
|
249
|
+
if self._conn:
|
250
|
+
self._conn.close()
|
251
|
+
self._conn = None
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import re
|
2
2
|
from os import walk
|
3
3
|
from orionis.foundation.config.testing.entities.testing import Testing as Configuration
|
4
|
+
from orionis.test.exceptions.test_config_exception import OrionisTestConfigException
|
4
5
|
from orionis.test.suites.contracts.test_suite import ITestSuite
|
5
6
|
from orionis.test.suites.test_unit import UnitTest
|
6
|
-
from orionis.test.exceptions.test_config_exception import OrionisTestConfigException
|
7
7
|
|
8
8
|
class TestSuite(ITestSuite):
|
9
9
|
"""
|
@@ -27,7 +27,8 @@ class TestSuite(ITestSuite):
|
|
27
27
|
Attributes:
|
28
28
|
_config (Configuration): The configuration used by the object. If no configuration is provided, a new Configuration instance is created.
|
29
29
|
"""
|
30
|
-
self.
|
30
|
+
self.__config = config or Configuration()
|
31
|
+
self.__result = None
|
31
32
|
|
32
33
|
def run(self) -> UnitTest:
|
33
34
|
"""
|
@@ -42,7 +43,7 @@ class TestSuite(ITestSuite):
|
|
42
43
|
"""
|
43
44
|
|
44
45
|
# Check if the config is provided
|
45
|
-
config = self.
|
46
|
+
config = self.__config
|
46
47
|
|
47
48
|
# Check if the config is an instance of Configuration
|
48
49
|
if not isinstance(config, Configuration):
|
@@ -99,4 +100,14 @@ class TestSuite(ITestSuite):
|
|
99
100
|
)
|
100
101
|
|
101
102
|
# Return the initialized test suite
|
102
|
-
|
103
|
+
self.__result = tests.run()
|
104
|
+
return self.__result
|
105
|
+
|
106
|
+
def getResult(self) -> UnitTest:
|
107
|
+
"""
|
108
|
+
Returns the results of the executed test suite.
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
UnitTest: The result of the executed test suite.
|
112
|
+
"""
|
113
|
+
return self.__result
|
orionis/test/suites/test_unit.py
CHANGED
@@ -14,7 +14,7 @@ from rich.panel import Panel
|
|
14
14
|
from rich.syntax import Syntax
|
15
15
|
from rich.table import Table
|
16
16
|
from orionis.console.output.console import Console
|
17
|
-
from orionis.test.logs.
|
17
|
+
from orionis.test.logs.history import TestHistory
|
18
18
|
from orionis.test.suites.contracts.test_unit import IUnitTest
|
19
19
|
from orionis.test.entities.test_result import TestResult
|
20
20
|
from orionis.test.enums.test_mode import ExecutionMode
|
@@ -612,7 +612,7 @@ class UnitTest(IUnitTest):
|
|
612
612
|
None
|
613
613
|
"""
|
614
614
|
full_path = os.path.abspath(os.path.join(os.getcwd(), self.base_path))
|
615
|
-
log =
|
615
|
+
log = TestHistory(full_path)
|
616
616
|
try:
|
617
617
|
log.createTableIfNotExists()
|
618
618
|
log.insertReport(summary)
|
orionis/unittesting.py
CHANGED
@@ -3,6 +3,9 @@ from orionis.test.cases.test_case import TestCase
|
|
3
3
|
from orionis.test.cases.test_sync import SyncTestCase
|
4
4
|
from orionis.test.cases.test_async import AsyncTestCase
|
5
5
|
|
6
|
+
# Import the custom TestHistory class for logging test results
|
7
|
+
from orionis.test.logs.history import TestHistory
|
8
|
+
|
6
9
|
# Import the custom TestResult entity
|
7
10
|
from orionis.test.entities.test_result import TestResult
|
8
11
|
|
@@ -48,5 +51,6 @@ __all__ = [
|
|
48
51
|
"UnittestTestResult",
|
49
52
|
"UnittestMock",
|
50
53
|
"UnittestMagicMock",
|
54
|
+
"TestHistory",
|
51
55
|
"unittest_mock_patch",
|
52
|
-
]
|
56
|
+
]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
orionis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
orionis/_application.py,sha256=dMjJ0nFcIIOBGb5zr-tHNzcgTOZ1vJ7iMdFAlqSQph0,9405
|
3
|
-
orionis/application.py,sha256=
|
4
|
-
orionis/unittesting.py,sha256=
|
3
|
+
orionis/application.py,sha256=Off5uOUj-IYvvR8DcqLUoBW_98opWa7MQrtqTr0SZGc,292
|
4
|
+
orionis/unittesting.py,sha256=am9rM3IcnG5NP_jA1Bj-VxjBGRTb0tGcehfkt9OoKGU,1761
|
5
5
|
orionis/_container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
orionis/_container/container.py,sha256=0AOqTNwpN_OtWbq9mBI99qfJ7LMkN71y0lP0JWKzut0,18289
|
7
7
|
orionis/_container/container_integrity.py,sha256=vrqZrkJaP6ghbiAzr-nEul9f_lEWVa2nMUSugQXDfWk,10095
|
@@ -226,7 +226,7 @@ orionis/foundation/config/testing/entities/testing.py,sha256=pIMb2DCwvu8K37ryiMX
|
|
226
226
|
orionis/foundation/config/testing/enums/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
227
227
|
orionis/foundation/config/testing/enums/test_mode.py,sha256=IbFpauu7J-iSAfmC8jDbmTEYl8eZr-AexL-lyOh8_74,337
|
228
228
|
orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
229
|
-
orionis/metadata/framework.py,sha256=
|
229
|
+
orionis/metadata/framework.py,sha256=coJ-vdD_2l2ZfOFX6TgRpUlhDKlYAg8GimtIagyREhs,4960
|
230
230
|
orionis/metadata/package.py,sha256=5p4fxjPpaktsreJ458pAl-Oi1363MWACPQvqXi_N6oA,6704
|
231
231
|
orionis/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
232
232
|
orionis/patterns/singleton/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -235,8 +235,8 @@ orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
235
235
|
orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
236
236
|
orionis/services/asynchrony/async_io.py,sha256=22rHi-sIHL3ESHpxKFps8O-9O_5Uoq-BbtZpMmgFTrA,1023
|
237
237
|
orionis/services/environment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
238
|
-
orionis/services/environment/dot_env.py,sha256=
|
239
|
-
orionis/services/environment/env.py,sha256=
|
238
|
+
orionis/services/environment/dot_env.py,sha256=PXU62gbOtzj-cZ4pt4dqYy17ywVVmomiSqUgXgcZm3M,9898
|
239
|
+
orionis/services/environment/env.py,sha256=SQo6PRGlsYHcXzm8WU5ownoS4F9JzPs-nNT0b7_w_Mo,2099
|
240
240
|
orionis/services/environment/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
241
241
|
orionis/services/environment/contracts/env.py,sha256=5g7jppzR5_ln8HlxJu2r0sSxLOkvBfSk3t4x_BKkYYk,1811
|
242
242
|
orionis/services/introspection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -313,20 +313,22 @@ orionis/test/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
313
313
|
orionis/test/exceptions/test_config_exception.py,sha256=yJv0JUTkZcF0Z4J8UHtffUipNgwNgmLhaqlOnnXFLyQ,995
|
314
314
|
orionis/test/exceptions/test_failure_exception.py,sha256=pcMhzF1Z5kkJm4yM7gZiQI0SvGjKFixJkRd6VBE03AY,2199
|
315
315
|
orionis/test/logs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
316
|
-
orionis/test/logs/
|
316
|
+
orionis/test/logs/history.py,sha256=8AqkCsGhd8S0PCBah2xFA0LN1YUnCmnwQvNmBmGmM2w,10097
|
317
|
+
orionis/test/logs/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
318
|
+
orionis/test/logs/contracts/history.py,sha256=6L-ELdCcn1kdTKD9XRGuqeP1TuLQiLrOSanOnoaLrKg,2088
|
317
319
|
orionis/test/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
318
320
|
orionis/test/output/dumper.py,sha256=pHD_HeokfWUydvaxxSvdJHdm2-VsrgL0PBr9ZSaavd8,3749
|
319
321
|
orionis/test/output/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
320
322
|
orionis/test/output/contracts/dumper.py,sha256=ZpzlSJixGNbjFUVl53mCg_5djC-xwiit4ozQlzUps4g,1161
|
321
323
|
orionis/test/suites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
322
|
-
orionis/test/suites/test_suite.py,sha256=
|
323
|
-
orionis/test/suites/test_unit.py,sha256=
|
324
|
+
orionis/test/suites/test_suite.py,sha256=e8n9rDmym6Uj5D8E93ZUu_pQawKI-Gx5Fc1gaDlfN0o,5177
|
325
|
+
orionis/test/suites/test_unit.py,sha256=hWtGRubx0iV0dOZrirrvjfTTZQQ1FYwoyxEicweuHmg,44585
|
324
326
|
orionis/test/suites/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
325
327
|
orionis/test/suites/contracts/test_suite.py,sha256=arJSxWGjOHTVGiJrmqdqDrb9Ymt3SitDPZKVMBsWCf8,888
|
326
328
|
orionis/test/suites/contracts/test_unit.py,sha256=5gaGXqCx07aDlAQJi8J-GF83kVj3uIx_fdPF1HYMKcg,5596
|
327
329
|
orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
328
330
|
orionis/test/view/index.html,sha256=U4XYO4hA-mAJCK1gcVRgIysmISK3g3Vgi2ntLofFAhE,6592
|
329
|
-
orionis-0.
|
331
|
+
orionis-0.283.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
|
330
332
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
331
333
|
tests/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
332
334
|
tests/example/test_example.py,sha256=DUZU6lWVFsyHtBEXx0cBxMrSCpOtAOL3PUoi9-tXAas,583
|
@@ -390,7 +392,7 @@ tests/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
390
392
|
tests/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
391
393
|
tests/services/asynchrony/test_async_io.py,sha256=oS_PRgAluASK-7MEwEktRoPG6lSubWBPrtLMyhGOum4,1526
|
392
394
|
tests/services/environment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
393
|
-
tests/services/environment/test_env.py,sha256=
|
395
|
+
tests/services/environment/test_env.py,sha256=Fg4NejwmTdTTj4FezrWkJc639CzodGEgmdFa4EPlmqk,7084
|
394
396
|
tests/services/inspection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
395
397
|
tests/services/inspection/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
396
398
|
tests/services/inspection/dependencies/test_reflect_dependencies.py,sha256=z0C9KkhV27Y7jKpLSCN9XCmHbjJDCPbBb7NkRFs3oMI,5803
|
@@ -424,8 +426,8 @@ tests/support/inspection/fakes/fake_reflection_instance_with_abstract.py,sha256=
|
|
424
426
|
tests/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
425
427
|
tests/testing/test_testing_result.py,sha256=54QDn6_v9feIcDcA6LPXcvYhlt_X8JqLGTYWS9XjKXM,3029
|
426
428
|
tests/testing/test_testing_unit.py,sha256=MeVL4gc4cGRPXdVOOKJx6JPKducrZ8cN7F52Iiciixg,5443
|
427
|
-
orionis-0.
|
428
|
-
orionis-0.
|
429
|
-
orionis-0.
|
430
|
-
orionis-0.
|
431
|
-
orionis-0.
|
429
|
+
orionis-0.283.0.dist-info/METADATA,sha256=7vHRB13iBUP3YekJnOOmvDd4coBejC3q-AHrsQzWr14,4772
|
430
|
+
orionis-0.283.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
431
|
+
orionis-0.283.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
|
432
|
+
orionis-0.283.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
433
|
+
orionis-0.283.0.dist-info/RECORD,,
|
@@ -14,7 +14,7 @@ class TestEnv(TestCase):
|
|
14
14
|
"""
|
15
15
|
with unittest_mock_patch.object(DotEnv, 'get', return_value='test_value') as mock_get:
|
16
16
|
result = Env.get('TEST_KEY')
|
17
|
-
mock_get.assert_called_once_with('TEST_KEY', None)
|
17
|
+
mock_get.assert_called_once_with('TEST_KEY', None, False)
|
18
18
|
self.assertEqual(result, 'test_value')
|
19
19
|
|
20
20
|
async def testGetMethodWithDefault(self):
|
@@ -24,7 +24,7 @@ class TestEnv(TestCase):
|
|
24
24
|
"""
|
25
25
|
with unittest_mock_patch.object(DotEnv, 'get', return_value='default_value') as mock_get:
|
26
26
|
result = Env.get('NON_EXISTENT_KEY', 'default_value')
|
27
|
-
mock_get.assert_called_once_with('NON_EXISTENT_KEY', 'default_value')
|
27
|
+
mock_get.assert_called_once_with('NON_EXISTENT_KEY', 'default_value', False)
|
28
28
|
self.assertEqual(result, 'default_value')
|
29
29
|
|
30
30
|
async def testSetMethod(self):
|
@@ -34,7 +34,7 @@ class TestEnv(TestCase):
|
|
34
34
|
"""
|
35
35
|
with unittest_mock_patch.object(DotEnv, 'set', return_value=True) as mock_set:
|
36
36
|
result = Env.set('TEST_KEY', 'test_value')
|
37
|
-
mock_set.assert_called_once_with('TEST_KEY', 'test_value')
|
37
|
+
mock_set.assert_called_once_with('TEST_KEY', 'test_value', False)
|
38
38
|
self.assertTrue(result)
|
39
39
|
|
40
40
|
async def testUnsetMethod(self):
|
orionis/test/logs/log_test.py
DELETED
@@ -1,211 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
import sqlite3
|
3
|
-
from pathlib import Path
|
4
|
-
from typing import Dict, List, Tuple, Optional
|
5
|
-
from contextlib import closing
|
6
|
-
from orionis.services.environment.env import Env
|
7
|
-
|
8
|
-
class LogTest:
|
9
|
-
"""
|
10
|
-
A utility class for managing test execution reports using a local SQLite database.
|
11
|
-
|
12
|
-
This class provides methods to create a report table, insert new test reports,
|
13
|
-
retrieve stored reports, reset the database, and close the connection.
|
14
|
-
|
15
|
-
Each test report is stored as a JSON string along with individual statistical fields
|
16
|
-
for easier filtering and analysis.
|
17
|
-
|
18
|
-
Attributes
|
19
|
-
----------
|
20
|
-
TABLE_NAME : str
|
21
|
-
The name of the database table where reports are stored.
|
22
|
-
DB_NAME : str
|
23
|
-
The filename of the SQLite database.
|
24
|
-
FIELDS : List[str]
|
25
|
-
List of expected keys in the report dictionary.
|
26
|
-
_conn : sqlite3.Connection or None
|
27
|
-
SQLite database connection instance.
|
28
|
-
"""
|
29
|
-
|
30
|
-
TABLE_NAME = "reportes"
|
31
|
-
DB_NAME = "tests.sqlite"
|
32
|
-
FIELDS = [
|
33
|
-
"json", "total_tests", "passed", "failed", "errors",
|
34
|
-
"skipped", "total_time", "success_rate", "timestamp"
|
35
|
-
]
|
36
|
-
|
37
|
-
def __init__(self, test_path_root: Optional[str] = None) -> None:
|
38
|
-
"""
|
39
|
-
Initialize the LogTest instance and configure the database path.
|
40
|
-
|
41
|
-
Parameters
|
42
|
-
----------
|
43
|
-
test_path_root : str, optional
|
44
|
-
Absolute or relative path to the directory where the SQLite file will be stored.
|
45
|
-
If None, the path is derived from the current file location.
|
46
|
-
|
47
|
-
Raises
|
48
|
-
------
|
49
|
-
ValueError
|
50
|
-
If the path cannot be resolved correctly.
|
51
|
-
"""
|
52
|
-
if test_path_root:
|
53
|
-
db_dir = Path(test_path_root).resolve()
|
54
|
-
else:
|
55
|
-
env_path = Env.get("TEST_PATH_ROOT")
|
56
|
-
if env_path:
|
57
|
-
db_dir = Path(env_path).resolve()
|
58
|
-
else:
|
59
|
-
db_dir = Path(__file__).resolve().parent
|
60
|
-
|
61
|
-
dbPath = db_dir.joinpath(self.DB_NAME)
|
62
|
-
Env.set("TEST_PATH_ROOT", str(dbPath).replace("\\", "\\\\"))
|
63
|
-
self._conn: Optional[sqlite3.Connection] = None
|
64
|
-
|
65
|
-
def __connect(self) -> None:
|
66
|
-
"""
|
67
|
-
Establish a connection to the SQLite database.
|
68
|
-
|
69
|
-
Raises
|
70
|
-
------
|
71
|
-
ConnectionError
|
72
|
-
If the connection to the database cannot be established.
|
73
|
-
"""
|
74
|
-
if self._conn is None:
|
75
|
-
try:
|
76
|
-
self._conn = sqlite3.connect(Env.get("TEST_PATH_ROOT"))
|
77
|
-
except sqlite3.Error as e:
|
78
|
-
raise ConnectionError(f"Database connection error: {e}")
|
79
|
-
|
80
|
-
def createTableIfNotExists(self) -> None:
|
81
|
-
"""
|
82
|
-
Create the 'reportes' table if it does not already exist.
|
83
|
-
|
84
|
-
The table includes fields for the full JSON report and individual
|
85
|
-
statistics for querying and filtering.
|
86
|
-
|
87
|
-
Raises
|
88
|
-
------
|
89
|
-
RuntimeError
|
90
|
-
If table creation fails due to a database error.
|
91
|
-
"""
|
92
|
-
self.__connect()
|
93
|
-
try:
|
94
|
-
with closing(self._conn.cursor()) as cursor:
|
95
|
-
cursor.execute(f'''
|
96
|
-
CREATE TABLE IF NOT EXISTS {self.TABLE_NAME} (
|
97
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
98
|
-
json TEXT NOT NULL,
|
99
|
-
total_tests INTEGER,
|
100
|
-
passed INTEGER,
|
101
|
-
failed INTEGER,
|
102
|
-
errors INTEGER,
|
103
|
-
skipped INTEGER,
|
104
|
-
total_time REAL,
|
105
|
-
success_rate REAL,
|
106
|
-
timestamp TEXT
|
107
|
-
)
|
108
|
-
''')
|
109
|
-
self._conn.commit()
|
110
|
-
except sqlite3.Error as e:
|
111
|
-
raise RuntimeError(f"Failed to create table: {e}")
|
112
|
-
|
113
|
-
def insertReport(self, report: Dict) -> None:
|
114
|
-
"""
|
115
|
-
Insert a test report into the database.
|
116
|
-
|
117
|
-
Parameters
|
118
|
-
----------
|
119
|
-
report : dict
|
120
|
-
Dictionary containing test statistics and metadata.
|
121
|
-
|
122
|
-
Required keys:
|
123
|
-
- total_tests : int
|
124
|
-
- passed : int
|
125
|
-
- failed : int
|
126
|
-
- errors : int
|
127
|
-
- skipped : int
|
128
|
-
- total_time : float
|
129
|
-
- success_rate : float
|
130
|
-
- timestamp : str (ISO format)
|
131
|
-
|
132
|
-
Raises
|
133
|
-
------
|
134
|
-
ValueError
|
135
|
-
If required keys are missing from the report.
|
136
|
-
RuntimeError
|
137
|
-
If insertion into the database fails.
|
138
|
-
"""
|
139
|
-
self.__connect()
|
140
|
-
missing = [key for key in self.FIELDS if key != "json" and key not in report]
|
141
|
-
if missing:
|
142
|
-
raise ValueError(f"Missing report fields: {missing}")
|
143
|
-
|
144
|
-
try:
|
145
|
-
with closing(self._conn.cursor()) as cursor:
|
146
|
-
cursor.execute(f'''
|
147
|
-
INSERT INTO {self.TABLE_NAME} (
|
148
|
-
json, total_tests, passed, failed, errors,
|
149
|
-
skipped, total_time, success_rate, timestamp
|
150
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
151
|
-
''', (
|
152
|
-
json.dumps(report),
|
153
|
-
report["total_tests"],
|
154
|
-
report["passed"],
|
155
|
-
report["failed"],
|
156
|
-
report["errors"],
|
157
|
-
report["skipped"],
|
158
|
-
report["total_time"],
|
159
|
-
report["success_rate"],
|
160
|
-
report["timestamp"]
|
161
|
-
))
|
162
|
-
self._conn.commit()
|
163
|
-
except sqlite3.Error as e:
|
164
|
-
raise RuntimeError(f"Failed to insert report: {e}")
|
165
|
-
|
166
|
-
def getReports(self) -> List[Tuple]:
|
167
|
-
"""
|
168
|
-
Retrieve all test reports from the database.
|
169
|
-
|
170
|
-
Returns
|
171
|
-
-------
|
172
|
-
List[Tuple]
|
173
|
-
A list of tuples representing each row in the `reportes` table.
|
174
|
-
|
175
|
-
Raises
|
176
|
-
------
|
177
|
-
RuntimeError
|
178
|
-
If retrieval fails due to a database error.
|
179
|
-
"""
|
180
|
-
self.__connect()
|
181
|
-
try:
|
182
|
-
with closing(self._conn.cursor()) as cursor:
|
183
|
-
cursor.execute(f'SELECT * FROM {self.TABLE_NAME}')
|
184
|
-
return cursor.fetchall()
|
185
|
-
except sqlite3.Error as e:
|
186
|
-
raise RuntimeError(f"Failed to retrieve reports: {e}")
|
187
|
-
|
188
|
-
def resetDatabase(self) -> None:
|
189
|
-
"""
|
190
|
-
Drop the `reportes` table, effectively clearing the report history.
|
191
|
-
|
192
|
-
Raises
|
193
|
-
------
|
194
|
-
RuntimeError
|
195
|
-
If table deletion fails.
|
196
|
-
"""
|
197
|
-
self.__connect()
|
198
|
-
try:
|
199
|
-
with closing(self._conn.cursor()) as cursor:
|
200
|
-
cursor.execute(f'DROP TABLE IF EXISTS {self.TABLE_NAME}')
|
201
|
-
self._conn.commit()
|
202
|
-
except sqlite3.Error as e:
|
203
|
-
raise RuntimeError(f"Failed to reset database: {e}")
|
204
|
-
|
205
|
-
def close(self) -> None:
|
206
|
-
"""
|
207
|
-
Close the SQLite database connection gracefully.
|
208
|
-
"""
|
209
|
-
if self._conn:
|
210
|
-
self._conn.close()
|
211
|
-
self._conn = None
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|