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,560 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
import testit_api_client
|
|
6
|
+
from testit_api_client import ApiClient, Configuration
|
|
7
|
+
from testit_api_client.apis import (
|
|
8
|
+
AttachmentsApi,
|
|
9
|
+
AutoTestsApi,
|
|
10
|
+
TestRunsApi,
|
|
11
|
+
TestResultsApi,
|
|
12
|
+
WorkItemsApi,
|
|
13
|
+
ProjectsApi,
|
|
14
|
+
WorkflowsApi,
|
|
15
|
+
)
|
|
16
|
+
from testit_api_client.models import (
|
|
17
|
+
ApiV2TestResultsSearchPostRequest,
|
|
18
|
+
AutoTestApiResult,
|
|
19
|
+
AutoTestCreateApiModel,
|
|
20
|
+
AutoTestUpdateApiModel,
|
|
21
|
+
AttachmentPutModel,
|
|
22
|
+
TestResultResponse,
|
|
23
|
+
TestResultShortResponse,
|
|
24
|
+
TestRunV2ApiResult,
|
|
25
|
+
LinkAutoTestToWorkItemRequest,
|
|
26
|
+
AutoTestWorkItemIdentifierApiResult,
|
|
27
|
+
WorkflowApiResult,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from testit_python_commons.client.client_configuration import ClientConfiguration
|
|
31
|
+
from testit_python_commons.client.converter import Converter
|
|
32
|
+
from testit_python_commons.client.helpers.bulk_autotest_helper import BulkAutotestHelper
|
|
33
|
+
from testit_python_commons.models.test_result import TestResult
|
|
34
|
+
from testit_python_commons.services.logger import adapter_logger
|
|
35
|
+
from testit_python_commons.services.retry import (
|
|
36
|
+
is_non_retriable_api_exception,
|
|
37
|
+
is_retriable_connection_error,
|
|
38
|
+
retry,
|
|
39
|
+
retry_on_connection_error,
|
|
40
|
+
)
|
|
41
|
+
from typing import List
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ApiClientWorker:
|
|
45
|
+
__tests_limit = 100
|
|
46
|
+
|
|
47
|
+
def __init__(self, config: ClientConfiguration):
|
|
48
|
+
api_client_config = self.__get_api_client_configuration(
|
|
49
|
+
url=config.get_url(),
|
|
50
|
+
verify_ssl=config.get_cert_validation(),
|
|
51
|
+
proxy=config.get_proxy())
|
|
52
|
+
api_client = self.__get_api_client(api_client_config, config.get_private_token())
|
|
53
|
+
|
|
54
|
+
self.__test_run_api = TestRunsApi(api_client=api_client)
|
|
55
|
+
self.__autotest_api = AutoTestsApi(api_client=api_client)
|
|
56
|
+
self.__attachments_api = AttachmentsApi(api_client=api_client)
|
|
57
|
+
self.__test_results_api = TestResultsApi(api_client=api_client)
|
|
58
|
+
self.__work_items_api = WorkItemsApi(api_client=api_client)
|
|
59
|
+
self.__projects_api = ProjectsApi(api_client=api_client)
|
|
60
|
+
self.__workflows_api = WorkflowsApi(api_client=api_client)
|
|
61
|
+
self.__config = config
|
|
62
|
+
self.__status_codes = self.__get_status_codes()
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
@adapter_logger
|
|
66
|
+
def __get_api_client_configuration(url: str, verify_ssl: bool = True, proxy: str = None) -> Configuration:
|
|
67
|
+
api_client_configuration = Configuration(host=url)
|
|
68
|
+
api_client_configuration.verify_ssl = verify_ssl
|
|
69
|
+
api_client_configuration.proxy = proxy
|
|
70
|
+
|
|
71
|
+
return api_client_configuration
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
@adapter_logger
|
|
75
|
+
def __get_api_client(api_client_config: Configuration, token: str) -> ApiClient:
|
|
76
|
+
return ApiClient(
|
|
77
|
+
configuration=api_client_config,
|
|
78
|
+
header_name='Authorization',
|
|
79
|
+
header_value='PrivateToken ' + token)
|
|
80
|
+
|
|
81
|
+
@adapter_logger
|
|
82
|
+
@retry
|
|
83
|
+
def create_test_run(self, test_run_name: str = None) -> str:
|
|
84
|
+
test_run_name = f'TestRun_{datetime.today().strftime("%Y-%m-%dT%H:%M:%S")}' if \
|
|
85
|
+
not test_run_name else test_run_name
|
|
86
|
+
model = Converter.test_run_to_test_run_short_model(
|
|
87
|
+
self.__config.get_project_id(),
|
|
88
|
+
test_run_name
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
response = self.__test_run_api.create_empty(create_empty_request=model)
|
|
92
|
+
|
|
93
|
+
return Converter.get_id_from_create_test_run_response(response)
|
|
94
|
+
|
|
95
|
+
@retry
|
|
96
|
+
def get_test_run(self, test_run_id: str) -> TestRunV2ApiResult:
|
|
97
|
+
"""Function gets test run and returns test run."""
|
|
98
|
+
logging.debug(f"Getting test run by id {test_run_id}")
|
|
99
|
+
|
|
100
|
+
test_run = self.__test_run_api.get_test_run_by_id(test_run_id)
|
|
101
|
+
if test_run is not None:
|
|
102
|
+
logging.debug(f"Got testrun: {test_run}")
|
|
103
|
+
return test_run
|
|
104
|
+
|
|
105
|
+
logging.error(f"Test run by id {test_run_id} not found!")
|
|
106
|
+
raise Exception(f"Test run by id {test_run_id} not found!")
|
|
107
|
+
|
|
108
|
+
@retry
|
|
109
|
+
def update_test_run(self, test_run: TestRunV2ApiResult) -> None:
|
|
110
|
+
"""Function updates test run."""
|
|
111
|
+
model = Converter.build_update_empty_request(test_run)
|
|
112
|
+
logging.debug(f"Updating test run with model: {model}")
|
|
113
|
+
|
|
114
|
+
self.__test_run_api.update_empty(update_empty_request=model)
|
|
115
|
+
|
|
116
|
+
logging.debug(f'Updated testrun (ID: {test_run.id})')
|
|
117
|
+
|
|
118
|
+
@adapter_logger
|
|
119
|
+
def set_test_run_id(self, test_run_id: str) -> None:
|
|
120
|
+
self.__config.set_test_run_id(test_run_id)
|
|
121
|
+
|
|
122
|
+
@adapter_logger
|
|
123
|
+
def get_external_ids_for_test_run_id(self) -> List[str]:
|
|
124
|
+
test_results: List[TestResultShortResponse] = self.__get_test_results()
|
|
125
|
+
external_ids: List[str] = Converter.get_external_ids_from_autotest_response_list(
|
|
126
|
+
test_results,
|
|
127
|
+
self.__config.get_configuration_id())
|
|
128
|
+
|
|
129
|
+
if len(external_ids) > 0:
|
|
130
|
+
return external_ids
|
|
131
|
+
|
|
132
|
+
raise Exception('The autotests with the status "InProgress" ' +
|
|
133
|
+
f'and the configuration id "{self.__config.get_configuration_id()}" were not found!')
|
|
134
|
+
|
|
135
|
+
@retry
|
|
136
|
+
def __get_test_results(self) -> List[TestResultShortResponse]:
|
|
137
|
+
all_test_results = []
|
|
138
|
+
skip = 0
|
|
139
|
+
model: ApiV2TestResultsSearchPostRequest = (
|
|
140
|
+
Converter.build_test_results_search_post_request_with_in_progress_outcome(
|
|
141
|
+
self.__config.get_test_run_id(),
|
|
142
|
+
self.__config.get_configuration_id()))
|
|
143
|
+
|
|
144
|
+
while skip >= 0:
|
|
145
|
+
logging.debug(f"Getting test results with limit {self.__tests_limit}: {model}")
|
|
146
|
+
|
|
147
|
+
test_results: List[TestResultShortResponse] = self.__test_results_api.api_v2_test_results_search_post(
|
|
148
|
+
skip=skip,
|
|
149
|
+
take=self.__tests_limit,
|
|
150
|
+
api_v2_test_results_search_post_request=model)
|
|
151
|
+
|
|
152
|
+
logging.debug(f"Got {len(test_results)} test results: {test_results}")
|
|
153
|
+
|
|
154
|
+
all_test_results.extend(test_results)
|
|
155
|
+
skip += self.__tests_limit
|
|
156
|
+
|
|
157
|
+
if len(test_results) == 0:
|
|
158
|
+
skip = -1
|
|
159
|
+
|
|
160
|
+
return all_test_results
|
|
161
|
+
|
|
162
|
+
@adapter_logger
|
|
163
|
+
@retry
|
|
164
|
+
def __get_autotests_by_external_id(self, external_id: str) -> List[AutoTestApiResult]:
|
|
165
|
+
model = Converter.project_id_and_external_id_to_auto_tests_search_post_request(
|
|
166
|
+
self.__config.get_project_id(),
|
|
167
|
+
external_id)
|
|
168
|
+
|
|
169
|
+
return self.__autotest_api.api_v2_auto_tests_search_post(api_v2_auto_tests_search_post_request=model)
|
|
170
|
+
|
|
171
|
+
@adapter_logger
|
|
172
|
+
@retry
|
|
173
|
+
def write_test(self, test_result: TestResult) -> str:
|
|
174
|
+
model = Converter.project_id_and_external_id_to_auto_tests_search_post_request(
|
|
175
|
+
self.__config.get_project_id(),
|
|
176
|
+
test_result.get_external_id())
|
|
177
|
+
|
|
178
|
+
autotests = self.__autotest_api.api_v2_auto_tests_search_post(api_v2_auto_tests_search_post_request=model)
|
|
179
|
+
should_create_work_item = test_result.get_automatic_creation_test_cases()
|
|
180
|
+
|
|
181
|
+
if autotests:
|
|
182
|
+
logging.info(
|
|
183
|
+
'Autotest "%s" already exists (external_id="%s"), using update path. '
|
|
184
|
+
"automaticCreationTestCases=%s applies only on create path.",
|
|
185
|
+
test_result.get_autotest_name(),
|
|
186
|
+
test_result.get_external_id(),
|
|
187
|
+
should_create_work_item,
|
|
188
|
+
)
|
|
189
|
+
self.__update_auto_test(test_result, autotests[0])
|
|
190
|
+
|
|
191
|
+
autotest_id = autotests[0].id
|
|
192
|
+
|
|
193
|
+
self.__update_autotest_link_from_work_items(autotest_id, test_result.get_work_item_ids())
|
|
194
|
+
else:
|
|
195
|
+
logging.info(
|
|
196
|
+
'Autotest "%s" not found (external_id="%s"), using create path with '
|
|
197
|
+
"automaticCreationTestCases=%s.",
|
|
198
|
+
test_result.get_autotest_name(),
|
|
199
|
+
test_result.get_external_id(),
|
|
200
|
+
should_create_work_item,
|
|
201
|
+
)
|
|
202
|
+
self.__create_auto_test(test_result)
|
|
203
|
+
|
|
204
|
+
return self.__load_test_result(test_result)
|
|
205
|
+
|
|
206
|
+
@adapter_logger
|
|
207
|
+
@retry
|
|
208
|
+
def write_tests(self, test_results: List[TestResult], fixture_containers: dict) -> None:
|
|
209
|
+
logging.debug("call __write_tests")
|
|
210
|
+
bulk_autotest_helper = BulkAutotestHelper(self.__autotest_api, self.__test_run_api, self.__config)
|
|
211
|
+
create_count = 0
|
|
212
|
+
update_count = 0
|
|
213
|
+
|
|
214
|
+
for test_result in test_results:
|
|
215
|
+
test_result = self.__add_fixtures_to_test_result(test_result, fixture_containers)
|
|
216
|
+
should_create_work_item = test_result.get_automatic_creation_test_cases()
|
|
217
|
+
|
|
218
|
+
test_result_model = Converter.test_result_to_testrun_result_post_model(
|
|
219
|
+
test_result,
|
|
220
|
+
self.__config.get_configuration_id(),
|
|
221
|
+
self.__status_codes)
|
|
222
|
+
|
|
223
|
+
work_item_ids_for_link_with_auto_test = self.__get_work_item_uuids_for_link_with_auto_test(
|
|
224
|
+
test_result.get_work_item_ids())
|
|
225
|
+
|
|
226
|
+
autotests = self.__get_autotests_by_external_id(test_result.get_external_id())
|
|
227
|
+
|
|
228
|
+
if autotests:
|
|
229
|
+
update_count += 1
|
|
230
|
+
logging.debug(
|
|
231
|
+
'Bulk update path for external_id="%s", automaticCreationTestCases=%s '
|
|
232
|
+
"(manual work item auto-creation is create-path behavior).",
|
|
233
|
+
test_result.get_external_id(),
|
|
234
|
+
should_create_work_item,
|
|
235
|
+
)
|
|
236
|
+
autotest_links_to_wi_for_update = {}
|
|
237
|
+
autotest_for_update = Converter.prepare_to_mass_update_autotest(
|
|
238
|
+
test_result,
|
|
239
|
+
autotests[0],
|
|
240
|
+
self.__config.get_project_id())
|
|
241
|
+
|
|
242
|
+
autotest_id = autotests[0].id
|
|
243
|
+
autotest_links_to_wi_for_update[autotest_id] = test_result.get_work_item_ids()
|
|
244
|
+
|
|
245
|
+
bulk_autotest_helper.add_for_update(
|
|
246
|
+
autotest_for_update,
|
|
247
|
+
test_result_model,
|
|
248
|
+
autotest_links_to_wi_for_update)
|
|
249
|
+
else:
|
|
250
|
+
create_count += 1
|
|
251
|
+
logging.debug(
|
|
252
|
+
'Bulk create path for external_id="%s", automaticCreationTestCases=%s.',
|
|
253
|
+
test_result.get_external_id(),
|
|
254
|
+
should_create_work_item,
|
|
255
|
+
)
|
|
256
|
+
autotest_for_create = Converter.prepare_to_mass_create_autotest(
|
|
257
|
+
test_result,
|
|
258
|
+
self.__config.get_project_id(),
|
|
259
|
+
work_item_ids_for_link_with_auto_test)
|
|
260
|
+
|
|
261
|
+
bulk_autotest_helper.add_for_create(autotest_for_create, test_result_model)
|
|
262
|
+
|
|
263
|
+
logging.info(
|
|
264
|
+
"Bulk write summary: create=%d, update=%d, total=%d",
|
|
265
|
+
create_count,
|
|
266
|
+
update_count,
|
|
267
|
+
len(test_results),
|
|
268
|
+
)
|
|
269
|
+
bulk_autotest_helper.teardown()
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
@adapter_logger
|
|
273
|
+
def __add_fixtures_to_test_result(
|
|
274
|
+
test_result: TestResult,
|
|
275
|
+
fixtures_containers: dict) -> TestResult:
|
|
276
|
+
setup_results = []
|
|
277
|
+
teardown_results = []
|
|
278
|
+
|
|
279
|
+
for uuid, fixtures_container in fixtures_containers.items():
|
|
280
|
+
if test_result.get_external_id() in fixtures_container.external_ids:
|
|
281
|
+
if fixtures_container.befores:
|
|
282
|
+
setup_results += fixtures_container.befores[0].steps
|
|
283
|
+
|
|
284
|
+
if fixtures_container.afters:
|
|
285
|
+
teardown_results = fixtures_container.afters[0].steps + teardown_results
|
|
286
|
+
|
|
287
|
+
test_result.set_setup_results(setup_results)
|
|
288
|
+
test_result.set_teardown_results(teardown_results)
|
|
289
|
+
|
|
290
|
+
return test_result
|
|
291
|
+
|
|
292
|
+
@adapter_logger
|
|
293
|
+
def __get_work_item_uuids_for_link_with_auto_test(
|
|
294
|
+
self,
|
|
295
|
+
work_item_ids: List[str],
|
|
296
|
+
autotest_global_id: str = None) -> List[str]:
|
|
297
|
+
linked_work_items = []
|
|
298
|
+
logging.debug("call __get_work_item_uuids_for_link_with_auto_test")
|
|
299
|
+
|
|
300
|
+
if autotest_global_id:
|
|
301
|
+
linked_work_items = self.__get_work_items_linked_to_autotest(autotest_global_id)
|
|
302
|
+
|
|
303
|
+
work_item_uuids = self.__prepare_list_of_work_item_uuids(linked_work_items, work_item_ids)
|
|
304
|
+
|
|
305
|
+
return work_item_uuids
|
|
306
|
+
|
|
307
|
+
@adapter_logger
|
|
308
|
+
def __prepare_list_of_work_item_uuids(
|
|
309
|
+
self,
|
|
310
|
+
linked_work_items: List[AutoTestWorkItemIdentifierApiResult],
|
|
311
|
+
work_item_ids: List[str]) -> List[str]:
|
|
312
|
+
work_item_uuids = []
|
|
313
|
+
|
|
314
|
+
for linked_work_item in linked_work_items:
|
|
315
|
+
linked_work_item_id = str(linked_work_item.global_id)
|
|
316
|
+
linked_work_item_uuid = linked_work_item.id
|
|
317
|
+
|
|
318
|
+
if linked_work_item_id in work_item_ids:
|
|
319
|
+
work_item_ids.remove(linked_work_item_id)
|
|
320
|
+
work_item_uuids.append(linked_work_item_uuid)
|
|
321
|
+
|
|
322
|
+
continue
|
|
323
|
+
|
|
324
|
+
if not self.__config.get_automatic_updation_links_to_test_cases():
|
|
325
|
+
work_item_uuids.append(linked_work_item_uuid)
|
|
326
|
+
|
|
327
|
+
for work_item_id in work_item_ids:
|
|
328
|
+
work_item_uuid = self.__get_work_item_uuid_by_work_item_id(work_item_id)
|
|
329
|
+
|
|
330
|
+
if work_item_uuid:
|
|
331
|
+
work_item_uuids.append(work_item_uuid)
|
|
332
|
+
|
|
333
|
+
return work_item_uuids
|
|
334
|
+
|
|
335
|
+
@adapter_logger
|
|
336
|
+
def __get_work_item_uuid_by_work_item_id(self, work_item_id: str) -> str or None:
|
|
337
|
+
logging.debug('Getting workitem by id ' + work_item_id)
|
|
338
|
+
|
|
339
|
+
try:
|
|
340
|
+
work_item = self.__work_items_api.get_work_item_by_id(id=work_item_id)
|
|
341
|
+
|
|
342
|
+
# logging.debug(f'Got workitem {work_item}')
|
|
343
|
+
|
|
344
|
+
return work_item.id
|
|
345
|
+
except testit_api_client.exceptions.ApiException as exc:
|
|
346
|
+
if is_retriable_connection_error(exc):
|
|
347
|
+
raise
|
|
348
|
+
if is_non_retriable_api_exception(exc):
|
|
349
|
+
logging.warning(f'Getting workitem by id {work_item_id} status: {exc}')
|
|
350
|
+
return
|
|
351
|
+
raise
|
|
352
|
+
except Exception as exc:
|
|
353
|
+
if is_retriable_connection_error(exc):
|
|
354
|
+
raise
|
|
355
|
+
logging.error(f'Getting workitem by id {work_item_id} status: {exc}')
|
|
356
|
+
|
|
357
|
+
@adapter_logger
|
|
358
|
+
@retry_on_connection_error
|
|
359
|
+
def __get_work_items_linked_to_autotest(self, autotest_global_id: str) -> List[AutoTestWorkItemIdentifierApiResult]:
|
|
360
|
+
return self.__autotest_api.get_work_items_linked_to_auto_test(id=autotest_global_id)
|
|
361
|
+
|
|
362
|
+
@adapter_logger
|
|
363
|
+
def __update_autotest_link_from_work_items(self, autotest_global_id: str, work_item_ids: list):
|
|
364
|
+
linked_work_items = self.__get_work_items_linked_to_autotest(autotest_global_id)
|
|
365
|
+
|
|
366
|
+
for linked_work_item in linked_work_items:
|
|
367
|
+
linked_work_item_id = str(linked_work_item.global_id)
|
|
368
|
+
|
|
369
|
+
if linked_work_item_id in work_item_ids:
|
|
370
|
+
work_item_ids.remove(linked_work_item_id)
|
|
371
|
+
|
|
372
|
+
continue
|
|
373
|
+
|
|
374
|
+
if self.__config.get_automatic_updation_links_to_test_cases():
|
|
375
|
+
self.__unlink_test_to_work_item(autotest_global_id, linked_work_item_id)
|
|
376
|
+
|
|
377
|
+
for work_item_id in work_item_ids:
|
|
378
|
+
self.__link_test_to_work_item(autotest_global_id, work_item_id)
|
|
379
|
+
|
|
380
|
+
@adapter_logger
|
|
381
|
+
@retry
|
|
382
|
+
def __create_auto_test(self, test_result: TestResult) -> str:
|
|
383
|
+
logging.debug(f'Autotest "{test_result.get_autotest_name()}" was not found')
|
|
384
|
+
|
|
385
|
+
logging.debug("call __create_auto_test")
|
|
386
|
+
work_item_ids_for_link_with_auto_test = self.__get_work_item_uuids_for_link_with_auto_test(
|
|
387
|
+
test_result.get_work_item_ids())
|
|
388
|
+
|
|
389
|
+
model = Converter.prepare_to_create_autotest(
|
|
390
|
+
test_result,
|
|
391
|
+
self.__config.get_project_id(),
|
|
392
|
+
work_item_ids_for_link_with_auto_test)
|
|
393
|
+
|
|
394
|
+
autotest_response = self.__autotest_api.create_auto_test(create_auto_test_request=model)
|
|
395
|
+
|
|
396
|
+
logging.debug(f'Autotest "{test_result.get_autotest_name()}" was created')
|
|
397
|
+
|
|
398
|
+
return autotest_response.id
|
|
399
|
+
|
|
400
|
+
@adapter_logger
|
|
401
|
+
@retry
|
|
402
|
+
def __create_tests(self, autotests_for_create: List[AutoTestCreateApiModel]) -> None:
|
|
403
|
+
logging.debug(f'Creating autotests: "{autotests_for_create}')
|
|
404
|
+
|
|
405
|
+
self.__autotest_api.create_multiple(auto_test_create_api_model=autotests_for_create)
|
|
406
|
+
|
|
407
|
+
logging.debug(f'Autotests were created')
|
|
408
|
+
|
|
409
|
+
@adapter_logger
|
|
410
|
+
@retry
|
|
411
|
+
def __update_auto_test(self, test_result: TestResult, autotest: AutoTestApiResult) -> None:
|
|
412
|
+
logging.debug(f'Autotest "{test_result.get_autotest_name()}" was found')
|
|
413
|
+
|
|
414
|
+
model = Converter.prepare_to_update_autotest(test_result, autotest, self.__config.get_project_id())
|
|
415
|
+
|
|
416
|
+
try:
|
|
417
|
+
self.__autotest_api.update_auto_test(update_auto_test_request=model)
|
|
418
|
+
except Exception as exc:
|
|
419
|
+
if is_retriable_connection_error(exc):
|
|
420
|
+
raise
|
|
421
|
+
logging.error(f'Cannot update autotest "{test_result.get_autotest_name()}" status: {exc}')
|
|
422
|
+
|
|
423
|
+
logging.debug(f'Autotest "{test_result.get_autotest_name()}" was updated')
|
|
424
|
+
|
|
425
|
+
@adapter_logger
|
|
426
|
+
@retry
|
|
427
|
+
def __update_tests(self, autotests_for_update: List[AutoTestUpdateApiModel]) -> None:
|
|
428
|
+
# logging.debug(f'Updating autotests: {autotests_for_update}')
|
|
429
|
+
|
|
430
|
+
self.__autotest_api.update_multiple(auto_test_update_api_model=autotests_for_update)
|
|
431
|
+
|
|
432
|
+
logging.debug(f'Autotests were updated')
|
|
433
|
+
|
|
434
|
+
@adapter_logger
|
|
435
|
+
@retry
|
|
436
|
+
def __unlink_test_to_work_item(self, autotest_global_id: str, work_item_id: str) -> None:
|
|
437
|
+
try:
|
|
438
|
+
self.__autotest_api.delete_auto_test_link_from_work_item(
|
|
439
|
+
id=autotest_global_id,
|
|
440
|
+
work_item_id=work_item_id)
|
|
441
|
+
except testit_api_client.exceptions.ApiException as exc:
|
|
442
|
+
if is_non_retriable_api_exception(exc):
|
|
443
|
+
logging.warning(
|
|
444
|
+
'Cannot unlink autotest %s from work item %s: %s',
|
|
445
|
+
autotest_global_id,
|
|
446
|
+
work_item_id,
|
|
447
|
+
exc,
|
|
448
|
+
)
|
|
449
|
+
return
|
|
450
|
+
raise
|
|
451
|
+
|
|
452
|
+
logging.debug(f'Autotest was unlinked with workItem "{work_item_id}" by global id "{autotest_global_id}')
|
|
453
|
+
|
|
454
|
+
@adapter_logger
|
|
455
|
+
@retry
|
|
456
|
+
def __link_test_to_work_item(self, autotest_global_id: str, work_item_id: str) -> None:
|
|
457
|
+
try:
|
|
458
|
+
self.__autotest_api.link_auto_test_to_work_item(
|
|
459
|
+
autotest_global_id,
|
|
460
|
+
link_auto_test_to_work_item_request=LinkAutoTestToWorkItemRequest(id=work_item_id))
|
|
461
|
+
except testit_api_client.exceptions.ApiException as exc:
|
|
462
|
+
if is_non_retriable_api_exception(exc):
|
|
463
|
+
logging.warning(
|
|
464
|
+
'Cannot link autotest %s to work item %s: %s',
|
|
465
|
+
autotest_global_id,
|
|
466
|
+
work_item_id,
|
|
467
|
+
exc,
|
|
468
|
+
)
|
|
469
|
+
return
|
|
470
|
+
raise
|
|
471
|
+
|
|
472
|
+
logging.debug(f'Autotest was linked with workItem "{work_item_id}" by global id "{autotest_global_id}')
|
|
473
|
+
|
|
474
|
+
@adapter_logger
|
|
475
|
+
@retry
|
|
476
|
+
def __load_test_result(self, test_result: TestResult) -> str:
|
|
477
|
+
model = Converter.test_result_to_testrun_result_post_model(
|
|
478
|
+
test_result,
|
|
479
|
+
self.__config.get_configuration_id(),
|
|
480
|
+
self.__status_codes)
|
|
481
|
+
|
|
482
|
+
response = self.__test_run_api.set_auto_test_results_for_test_run(
|
|
483
|
+
id=self.__config.get_test_run_id(),
|
|
484
|
+
auto_test_results_for_test_run_model=[model])
|
|
485
|
+
|
|
486
|
+
logging.debug(f'Result of the autotest "{test_result.get_autotest_name()}" was set '
|
|
487
|
+
f'in the test run "{self.__config.get_test_run_id()}"')
|
|
488
|
+
|
|
489
|
+
return Converter.get_test_result_id_from_testrun_result_post_response(response)
|
|
490
|
+
|
|
491
|
+
@adapter_logger
|
|
492
|
+
@retry
|
|
493
|
+
def get_test_result_by_id(self, test_result_id: str) -> TestResultResponse:
|
|
494
|
+
return self.__test_results_api.api_v2_test_results_id_get(id=test_result_id)
|
|
495
|
+
|
|
496
|
+
@adapter_logger
|
|
497
|
+
def update_test_results(self, fixtures_containers: dict, test_result_ids: dict) -> None:
|
|
498
|
+
test_results = Converter.fixtures_containers_to_test_results_with_all_fixture_step_results(
|
|
499
|
+
fixtures_containers, test_result_ids)
|
|
500
|
+
|
|
501
|
+
if not test_results:
|
|
502
|
+
return
|
|
503
|
+
|
|
504
|
+
for test_result in test_results:
|
|
505
|
+
model = Converter.convert_test_result_with_all_setup_and_teardown_steps_to_test_results_id_put_request(
|
|
506
|
+
test_result)
|
|
507
|
+
|
|
508
|
+
try:
|
|
509
|
+
self.__test_results_api.api_v2_test_results_id_put(
|
|
510
|
+
id=test_result.get_test_result_id(),
|
|
511
|
+
api_v2_test_results_id_put_request=model)
|
|
512
|
+
except Exception as exc:
|
|
513
|
+
if is_retriable_connection_error(exc):
|
|
514
|
+
raise
|
|
515
|
+
logging.error(
|
|
516
|
+
f'Cannot update test result with id "{test_result.get_test_result_id()}" status: {exc}')
|
|
517
|
+
|
|
518
|
+
@adapter_logger
|
|
519
|
+
@retry
|
|
520
|
+
def __upload_attachment(self, path: str) -> AttachmentPutModel:
|
|
521
|
+
with open(path, "rb") as file:
|
|
522
|
+
attachment_response = self.__attachments_api.api_v2_attachments_post(file=file)
|
|
523
|
+
return AttachmentPutModel(attachment_response['id'])
|
|
524
|
+
|
|
525
|
+
@adapter_logger
|
|
526
|
+
def load_attachments(self, attach_paths: list or tuple) -> List[AttachmentPutModel]:
|
|
527
|
+
attachments = []
|
|
528
|
+
|
|
529
|
+
for path in attach_paths:
|
|
530
|
+
if os.path.isfile(path):
|
|
531
|
+
try:
|
|
532
|
+
attachments.append(self.__upload_attachment(path))
|
|
533
|
+
logging.debug(f'Attachment "{path}" was uploaded')
|
|
534
|
+
except Exception as exc:
|
|
535
|
+
if is_retriable_connection_error(exc):
|
|
536
|
+
raise
|
|
537
|
+
logging.error(f'Upload attachment "{path}" status: {exc}')
|
|
538
|
+
else:
|
|
539
|
+
logging.error(f'File "{path}" was not found!')
|
|
540
|
+
return attachments
|
|
541
|
+
|
|
542
|
+
def get_configuration_id(self):
|
|
543
|
+
return self.__config.get_configuration_id()
|
|
544
|
+
|
|
545
|
+
@adapter_logger
|
|
546
|
+
@retry
|
|
547
|
+
def __get_project(self):
|
|
548
|
+
return self.__projects_api.get_project_by_id(id=self.__config.get_project_id())
|
|
549
|
+
|
|
550
|
+
@adapter_logger
|
|
551
|
+
@retry
|
|
552
|
+
def __get_workflow_by_id(self, workflow_id: str) -> WorkflowApiResult:
|
|
553
|
+
return self.__workflows_api.api_v2_workflows_id_get(id=workflow_id)
|
|
554
|
+
|
|
555
|
+
@adapter_logger
|
|
556
|
+
def __get_status_codes(self) -> List[str]:
|
|
557
|
+
project = self.__get_project()
|
|
558
|
+
workflow = self.__get_workflow_by_id(project.workflow_id)
|
|
559
|
+
|
|
560
|
+
return [status.code for status in workflow.statuses]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from testit_python_commons.services.logger import adapter_logger
|
|
2
|
+
from testit_python_commons.services.utils import Utils
|
|
3
|
+
from testit_python_commons.configurations.properties_names import PropertiesNames
|
|
4
|
+
|
|
5
|
+
class ClientConfiguration:
|
|
6
|
+
__project_id = None
|
|
7
|
+
__test_run_id = None
|
|
8
|
+
|
|
9
|
+
def __init__(self, app_properties: dict):
|
|
10
|
+
if app_properties.get(PropertiesNames.PROJECT_ID):
|
|
11
|
+
self.__project_id = Utils.uuid_check(app_properties.get(PropertiesNames.PROJECT_ID))
|
|
12
|
+
|
|
13
|
+
if app_properties.get(PropertiesNames.TEST_RUN_ID):
|
|
14
|
+
self.__test_run_id = Utils.uuid_check(app_properties.get(PropertiesNames.TEST_RUN_ID))
|
|
15
|
+
|
|
16
|
+
self.__url = Utils.url_check(app_properties.get(PropertiesNames.URL))
|
|
17
|
+
self.__private_token = app_properties.get(PropertiesNames.PRIVATE_TOKEN)
|
|
18
|
+
self.__configuration_id = Utils.uuid_check(app_properties.get(PropertiesNames.CONFIGURATION_ID))
|
|
19
|
+
self.__tms_proxy = app_properties.get(PropertiesNames.TMS_PROXY)
|
|
20
|
+
self.__adapter_mode = app_properties.get(PropertiesNames.ADAPTER_MODE)
|
|
21
|
+
self.__cert_validation = Utils.convert_value_str_to_bool(app_properties.get(PropertiesNames.CERT_VALIDATION).lower())
|
|
22
|
+
self.__automatic_updation_links_to_test_cases = Utils.convert_value_str_to_bool(
|
|
23
|
+
app_properties.get(PropertiesNames.AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES).lower())
|
|
24
|
+
self.__sync_storage_port = app_properties.get(PropertiesNames.SYNC_STORAGE_PORT)
|
|
25
|
+
self.__legacy_workflow = Utils.convert_value_str_to_bool(
|
|
26
|
+
app_properties.get(PropertiesNames.LEGACY_WORKFLOW).lower())
|
|
27
|
+
|
|
28
|
+
@adapter_logger
|
|
29
|
+
def get_url(self):
|
|
30
|
+
return self.__url
|
|
31
|
+
|
|
32
|
+
@adapter_logger
|
|
33
|
+
def get_private_token(self):
|
|
34
|
+
return self.__private_token
|
|
35
|
+
|
|
36
|
+
@adapter_logger
|
|
37
|
+
def get_project_id(self):
|
|
38
|
+
return self.__project_id
|
|
39
|
+
|
|
40
|
+
@adapter_logger
|
|
41
|
+
def set_project_id(self, project_id: str):
|
|
42
|
+
self.__project_id = project_id
|
|
43
|
+
|
|
44
|
+
@adapter_logger
|
|
45
|
+
def get_configuration_id(self):
|
|
46
|
+
return self.__configuration_id
|
|
47
|
+
|
|
48
|
+
@adapter_logger
|
|
49
|
+
def get_test_run_id(self):
|
|
50
|
+
return self.__test_run_id
|
|
51
|
+
|
|
52
|
+
@adapter_logger
|
|
53
|
+
def set_test_run_id(self, test_run_id: str):
|
|
54
|
+
self.__test_run_id = test_run_id
|
|
55
|
+
|
|
56
|
+
@adapter_logger
|
|
57
|
+
def get_proxy(self):
|
|
58
|
+
return self.__tms_proxy
|
|
59
|
+
|
|
60
|
+
@adapter_logger
|
|
61
|
+
def get_mode(self):
|
|
62
|
+
return self.__adapter_mode
|
|
63
|
+
|
|
64
|
+
def get_cert_validation(self) -> bool:
|
|
65
|
+
return self.__cert_validation
|
|
66
|
+
|
|
67
|
+
def get_automatic_updation_links_to_test_cases(self) -> bool:
|
|
68
|
+
return self.__automatic_updation_links_to_test_cases
|
|
69
|
+
|
|
70
|
+
def get_sync_storage_port(self) -> str:
|
|
71
|
+
return self.__sync_storage_port
|
|
72
|
+
|
|
73
|
+
def is_legacy_workflow(self) -> bool:
|
|
74
|
+
return self.__legacy_workflow
|