testit-python-commons 4.2.8__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.
- api_client_syncstorage/__init__.py +27 -0
- api_client_syncstorage/api/__init__.py +3 -0
- api_client_syncstorage/api/completion_api.py +302 -0
- api_client_syncstorage/api/health_api.py +158 -0
- api_client_syncstorage/api/system_api.py +158 -0
- api_client_syncstorage/api/test_results_api.py +182 -0
- api_client_syncstorage/api/workers_api.py +308 -0
- api_client_syncstorage/api_client.py +898 -0
- api_client_syncstorage/apis/__init__.py +21 -0
- api_client_syncstorage/configuration.py +450 -0
- api_client_syncstorage/exceptions.py +158 -0
- api_client_syncstorage/model/__init__.py +5 -0
- api_client_syncstorage/model/completion_response.py +267 -0
- api_client_syncstorage/model/health_status_response.py +267 -0
- api_client_syncstorage/model/register_request.py +275 -0
- api_client_syncstorage/model/register_response.py +279 -0
- api_client_syncstorage/model/set_worker_status_request.py +271 -0
- api_client_syncstorage/model/set_worker_status_response.py +267 -0
- api_client_syncstorage/model/shutdown_response.py +267 -0
- api_client_syncstorage/model/test_result_cut_api_model.py +279 -0
- api_client_syncstorage/model/test_result_save_response.py +267 -0
- api_client_syncstorage/model_utils.py +2058 -0
- api_client_syncstorage/models/__init__.py +20 -0
- api_client_syncstorage/rest.py +356 -0
- testit.py +69 -0
- testit_python_commons/__init__.py +0 -0
- testit_python_commons/app_properties.py +257 -0
- testit_python_commons/client/__init__.py +9 -0
- testit_python_commons/client/api_client.py +560 -0
- testit_python_commons/client/client_configuration.py +74 -0
- testit_python_commons/client/converter.py +618 -0
- testit_python_commons/client/helpers/__init__.py +0 -0
- testit_python_commons/client/helpers/bulk_autotest_helper.py +246 -0
- testit_python_commons/client/helpers/threads_manager.py +86 -0
- testit_python_commons/client/models/__init__.py +8 -0
- testit_python_commons/client/models/threads_for_create_and_result.py +35 -0
- testit_python_commons/client/models/threads_for_update_and_result.py +45 -0
- testit_python_commons/configurations/__init__.py +0 -0
- testit_python_commons/configurations/properties_names.py +51 -0
- testit_python_commons/decorators.py +221 -0
- testit_python_commons/dynamic_methods.py +237 -0
- testit_python_commons/models/__init__.py +5 -0
- testit_python_commons/models/adapter_mode.py +4 -0
- testit_python_commons/models/fixture.py +24 -0
- testit_python_commons/models/link.py +53 -0
- testit_python_commons/models/link_type.py +10 -0
- testit_python_commons/models/outcome_type.py +5 -0
- testit_python_commons/models/status_type.py +6 -0
- testit_python_commons/models/step_result.py +90 -0
- testit_python_commons/models/test_result.py +297 -0
- testit_python_commons/models/test_result_with_all_fixture_step_results_model.py +28 -0
- testit_python_commons/services/__init__.py +41 -0
- testit_python_commons/services/adapter_manager.py +318 -0
- testit_python_commons/services/adapter_manager_configuration.py +42 -0
- testit_python_commons/services/fixture_manager.py +60 -0
- testit_python_commons/services/fixture_storage.py +40 -0
- testit_python_commons/services/logger.py +32 -0
- testit_python_commons/services/plugin_manager.py +101 -0
- testit_python_commons/services/retry.py +92 -0
- testit_python_commons/services/step_manager.py +36 -0
- testit_python_commons/services/step_result_storage.py +26 -0
- testit_python_commons/services/sync_storage/__init__.py +9 -0
- testit_python_commons/services/sync_storage/sync_storage_runner.py +589 -0
- testit_python_commons/services/utils.py +132 -0
- testit_python_commons/step.py +101 -0
- testit_python_commons/utils/__init__.py +3 -0
- testit_python_commons/utils/html_escape_utils.py +219 -0
- testit_python_commons-4.2.8.dist-info/METADATA +52 -0
- testit_python_commons-4.2.8.dist-info/RECORD +71 -0
- testit_python_commons-4.2.8.dist-info/WHEEL +5 -0
- testit_python_commons-4.2.8.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import configparser
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import warnings
|
|
5
|
+
import uuid
|
|
6
|
+
import re
|
|
7
|
+
from urllib.parse import urlparse
|
|
8
|
+
import tomli
|
|
9
|
+
|
|
10
|
+
from testit_python_commons.models.adapter_mode import AdapterMode
|
|
11
|
+
from testit_python_commons.configurations.properties_names import PropertiesNames, ENV_TO_PROPERTY, OPTION_TO_PROPERTY
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AppProperties:
|
|
15
|
+
__toml_extension = '.toml'
|
|
16
|
+
__ini_extension = '.ini'
|
|
17
|
+
__project_metadata_file = 'pyproject' + __toml_extension
|
|
18
|
+
__tms_config_file = 'connection_config' + __ini_extension
|
|
19
|
+
__properties_file = __tms_config_file
|
|
20
|
+
__available_extensions = [__toml_extension, __ini_extension]
|
|
21
|
+
|
|
22
|
+
ENV_CONFIG_FILE = 'TMS_CONFIG_FILE'
|
|
23
|
+
__config_section_name = 'testit'
|
|
24
|
+
__debug_section_name = 'debug'
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def load_properties(option=None):
|
|
28
|
+
properties = AppProperties.load_file_properties(
|
|
29
|
+
option.set_config_file if hasattr(option, 'set_config_file') else None)
|
|
30
|
+
|
|
31
|
+
AppProperties.__check_token_property(properties)
|
|
32
|
+
|
|
33
|
+
properties.update(AppProperties.load_env_properties())
|
|
34
|
+
|
|
35
|
+
if option:
|
|
36
|
+
properties.update(AppProperties.load_cli_properties(option))
|
|
37
|
+
|
|
38
|
+
AppProperties.__check_properties(properties)
|
|
39
|
+
|
|
40
|
+
return properties
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def load_file_properties(cls, cli_file_path: str = None):
|
|
44
|
+
if os.path.isfile(cls.__project_metadata_file):
|
|
45
|
+
# https://peps.python.org/pep-0621/
|
|
46
|
+
cls.__properties_file = cls.__project_metadata_file
|
|
47
|
+
|
|
48
|
+
path = os.path.abspath('')
|
|
49
|
+
root = path[:path.index(os.sep)]
|
|
50
|
+
|
|
51
|
+
while not os.path.isfile(
|
|
52
|
+
path + os.sep + cls.__tms_config_file) and path != root:
|
|
53
|
+
path = path[:path.rindex(os.sep)]
|
|
54
|
+
|
|
55
|
+
path = path + os.sep + cls.__tms_config_file
|
|
56
|
+
|
|
57
|
+
if os.path.isfile(path):
|
|
58
|
+
cls.__properties_file = cls.__tms_config_file
|
|
59
|
+
|
|
60
|
+
if os.environ.get(cls.ENV_CONFIG_FILE):
|
|
61
|
+
cls.__properties_file = cls.__tms_config_file
|
|
62
|
+
path = os.environ.get(cls.ENV_CONFIG_FILE)
|
|
63
|
+
|
|
64
|
+
if cli_file_path:
|
|
65
|
+
cls.__properties_file = cls.__tms_config_file
|
|
66
|
+
path = cli_file_path
|
|
67
|
+
|
|
68
|
+
_, extension = os.path.splitext(cls.__properties_file)
|
|
69
|
+
if extension not in cls.__available_extensions:
|
|
70
|
+
raise FileNotFoundError(
|
|
71
|
+
f'{cls.__properties_file} is not a valid file ({_, extension}). Available extensions: {cls.__available_extensions}'
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if extension == cls.__toml_extension:
|
|
75
|
+
toml_properties = cls.__load_file_properties_from_toml()
|
|
76
|
+
if toml_properties is not None:
|
|
77
|
+
return toml_properties
|
|
78
|
+
|
|
79
|
+
return cls.__load_file_properties_from_ini(path)
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def load_cli_properties(cls, option):
|
|
83
|
+
# Формируем словарь `cli_properties` с помощью генератора
|
|
84
|
+
return {
|
|
85
|
+
prop: getattr(option, option_attr)
|
|
86
|
+
for option_attr, prop in OPTION_TO_PROPERTY.items()
|
|
87
|
+
if hasattr(option, option_attr) and cls.__check_property_value(getattr(option, option_attr))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def map_env_to_properties(cls) -> dict:
|
|
92
|
+
env_properties = {}
|
|
93
|
+
for env_key, property_name in ENV_TO_PROPERTY.items():
|
|
94
|
+
if env_key in os.environ and cls.__check_property_value(os.environ.get(env_key)):
|
|
95
|
+
env_properties[property_name] = os.environ.get(env_key)
|
|
96
|
+
return env_properties
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def load_env_properties(cls):
|
|
100
|
+
env_properties = cls.map_env_to_properties()
|
|
101
|
+
return env_properties
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def __check_properties(cls, properties: dict):
|
|
105
|
+
adapter_mode = properties.get(PropertiesNames.ADAPTER_MODE)
|
|
106
|
+
|
|
107
|
+
if adapter_mode == AdapterMode.NEW_TEST_RUN:
|
|
108
|
+
try:
|
|
109
|
+
uuid.UUID(str(properties.get(PropertiesNames.TEST_RUN_ID)))
|
|
110
|
+
logging.warning('Adapter mode "2" is enabled. Config should not contains test run id!')
|
|
111
|
+
properties[PropertiesNames.TEST_RUN_ID] = None
|
|
112
|
+
except ValueError:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
elif adapter_mode in (
|
|
116
|
+
AdapterMode.RUN_ALL_TESTS,
|
|
117
|
+
AdapterMode.USE_FILTER,
|
|
118
|
+
None):
|
|
119
|
+
try:
|
|
120
|
+
uuid.UUID(str(properties.get(PropertiesNames.TEST_RUN_ID)))
|
|
121
|
+
except ValueError:
|
|
122
|
+
logging.error(f'Adapter mode "{adapter_mode if adapter_mode else "0"}" is enabled. '
|
|
123
|
+
f'The test run ID is needed, but it was not found!')
|
|
124
|
+
raise SystemExit
|
|
125
|
+
else:
|
|
126
|
+
logging.error(f'Unknown adapter mode "{adapter_mode}"!')
|
|
127
|
+
raise SystemExit
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
uuid.UUID(str(properties.get(PropertiesNames.PROJECT_ID)))
|
|
131
|
+
except ValueError:
|
|
132
|
+
logging.error('Project ID was not found!')
|
|
133
|
+
raise SystemExit
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
url = urlparse(properties.get(PropertiesNames.URL))
|
|
137
|
+
if not all([url.scheme, url.netloc]):
|
|
138
|
+
raise AttributeError
|
|
139
|
+
except AttributeError:
|
|
140
|
+
logging.error('URL is invalid!')
|
|
141
|
+
raise SystemExit
|
|
142
|
+
|
|
143
|
+
if not cls.__check_property_value(properties.get(PropertiesNames.PRIVATE_TOKEN)):
|
|
144
|
+
logging.error('Private token was not found!')
|
|
145
|
+
raise SystemExit
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
uuid.UUID(str(properties.get(PropertiesNames.CONFIGURATION_ID)))
|
|
149
|
+
except ValueError:
|
|
150
|
+
logging.error('Configuration ID was not found!')
|
|
151
|
+
raise SystemExit
|
|
152
|
+
|
|
153
|
+
if not cls.__check_property_value(properties.get(PropertiesNames.CERT_VALIDATION)):
|
|
154
|
+
properties[PropertiesNames.CERT_VALIDATION] = 'true'
|
|
155
|
+
|
|
156
|
+
if not cls.__check_property_value(properties.get(PropertiesNames.AUTOMATIC_CREATION_TEST_CASES)):
|
|
157
|
+
properties[PropertiesNames.AUTOMATIC_CREATION_TEST_CASES] = 'false'
|
|
158
|
+
|
|
159
|
+
if not cls.__check_property_value(properties.get(PropertiesNames.AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES)):
|
|
160
|
+
properties[PropertiesNames.AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES] = 'false'
|
|
161
|
+
|
|
162
|
+
if not cls.__check_property_value(properties.get(PropertiesNames.IMPORT_REALTIME)):
|
|
163
|
+
# import realtime false by default
|
|
164
|
+
properties[PropertiesNames.IMPORT_REALTIME] = 'false'
|
|
165
|
+
|
|
166
|
+
if not cls.__check_property_value(properties.get(PropertiesNames.SYNC_STORAGE_PORT)):
|
|
167
|
+
# import realtime false by default
|
|
168
|
+
properties[PropertiesNames.SYNC_STORAGE_PORT] = '49152'
|
|
169
|
+
|
|
170
|
+
if not cls.__check_property_value(properties.get(PropertiesNames.LEGACY_WORKFLOW)):
|
|
171
|
+
properties[PropertiesNames.LEGACY_WORKFLOW] = 'false'
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def __load_file_properties_from_toml(cls):
|
|
175
|
+
properties = {}
|
|
176
|
+
|
|
177
|
+
with open(cls.__project_metadata_file, "rb+") as file:
|
|
178
|
+
toml_dict = tomli.load(file)
|
|
179
|
+
|
|
180
|
+
if not cls.__check_toml_section(toml_dict, cls.__config_section_name):
|
|
181
|
+
logging.warning(
|
|
182
|
+
f'Config section "[{cls.__config_section_name}]" in "{cls.__properties_file}" was not found. '
|
|
183
|
+
f'Skipping "{cls.__properties_file}" and continuing with other sources (ini/env/cli).'
|
|
184
|
+
)
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
config_section = toml_dict.get(cls.__config_section_name)
|
|
188
|
+
|
|
189
|
+
for key, value in config_section.items():
|
|
190
|
+
properties[key.lower()] = cls.__search_in_environ(str(value))
|
|
191
|
+
|
|
192
|
+
if cls.__check_toml_section(toml_dict, cls.__debug_section_name):
|
|
193
|
+
debug_section = toml_dict.get(cls.__debug_section_name)
|
|
194
|
+
|
|
195
|
+
for key, value in debug_section.items():
|
|
196
|
+
if key == PropertiesNames.TMS_PROXY:
|
|
197
|
+
properties[PropertiesNames.TMS_PROXY] = cls.__search_in_environ(str(value))
|
|
198
|
+
|
|
199
|
+
if key == '__dev':
|
|
200
|
+
properties['logs'] = cls.__search_in_environ(str(value)).lower()
|
|
201
|
+
|
|
202
|
+
return properties
|
|
203
|
+
|
|
204
|
+
@classmethod
|
|
205
|
+
def __load_file_properties_from_ini(cls, path: str) -> dict:
|
|
206
|
+
properties = {}
|
|
207
|
+
parser = configparser.RawConfigParser()
|
|
208
|
+
|
|
209
|
+
parser.read(path, encoding="utf-8")
|
|
210
|
+
|
|
211
|
+
if parser.has_section(cls.__config_section_name):
|
|
212
|
+
for key, value in parser.items(cls.__config_section_name):
|
|
213
|
+
properties[key] = cls.__search_in_environ(value)
|
|
214
|
+
|
|
215
|
+
if parser.has_section('debug'):
|
|
216
|
+
if parser.has_option('debug', PropertiesNames.TMS_PROXY):
|
|
217
|
+
properties[PropertiesNames.TMS_PROXY] = cls.__search_in_environ(
|
|
218
|
+
parser.get('debug', PropertiesNames.TMS_PROXY))
|
|
219
|
+
|
|
220
|
+
if parser.has_option('debug', '__dev'):
|
|
221
|
+
properties['logs'] = cls.__search_in_environ(
|
|
222
|
+
parser.get('debug', '__dev')).lower()
|
|
223
|
+
|
|
224
|
+
return properties
|
|
225
|
+
|
|
226
|
+
@staticmethod
|
|
227
|
+
def __search_in_environ(var_name: str):
|
|
228
|
+
if re.fullmatch(r'{[a-zA-Z_]\w*}', var_name) and var_name[1:-1] in os.environ:
|
|
229
|
+
return os.environ[var_name[1:-1]]
|
|
230
|
+
|
|
231
|
+
return var_name
|
|
232
|
+
|
|
233
|
+
@staticmethod
|
|
234
|
+
def __check_property_value(value: str):
|
|
235
|
+
if value is not None and value != "":
|
|
236
|
+
return True
|
|
237
|
+
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
def __check_toml_section(toml_dict: dict, section_name: str) -> bool:
|
|
242
|
+
if section_name not in toml_dict.keys():
|
|
243
|
+
return False
|
|
244
|
+
if not type(toml_dict.get(section_name)) is dict:
|
|
245
|
+
return False
|
|
246
|
+
|
|
247
|
+
return True
|
|
248
|
+
|
|
249
|
+
@staticmethod
|
|
250
|
+
def __check_token_property(properties: dict):
|
|
251
|
+
if PropertiesNames.PRIVATE_TOKEN in properties:
|
|
252
|
+
warnings.warn(
|
|
253
|
+
'The configuration file specifies a private token. It is not safe.'
|
|
254
|
+
' Use TMS_PRIVATE_TOKEN environment variable',
|
|
255
|
+
category=Warning,
|
|
256
|
+
stacklevel=2)
|
|
257
|
+
warnings.simplefilter('default', Warning)
|