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.
Files changed (71) hide show
  1. api_client_syncstorage/__init__.py +27 -0
  2. api_client_syncstorage/api/__init__.py +3 -0
  3. api_client_syncstorage/api/completion_api.py +302 -0
  4. api_client_syncstorage/api/health_api.py +158 -0
  5. api_client_syncstorage/api/system_api.py +158 -0
  6. api_client_syncstorage/api/test_results_api.py +182 -0
  7. api_client_syncstorage/api/workers_api.py +308 -0
  8. api_client_syncstorage/api_client.py +898 -0
  9. api_client_syncstorage/apis/__init__.py +21 -0
  10. api_client_syncstorage/configuration.py +450 -0
  11. api_client_syncstorage/exceptions.py +158 -0
  12. api_client_syncstorage/model/__init__.py +5 -0
  13. api_client_syncstorage/model/completion_response.py +267 -0
  14. api_client_syncstorage/model/health_status_response.py +267 -0
  15. api_client_syncstorage/model/register_request.py +275 -0
  16. api_client_syncstorage/model/register_response.py +279 -0
  17. api_client_syncstorage/model/set_worker_status_request.py +271 -0
  18. api_client_syncstorage/model/set_worker_status_response.py +267 -0
  19. api_client_syncstorage/model/shutdown_response.py +267 -0
  20. api_client_syncstorage/model/test_result_cut_api_model.py +279 -0
  21. api_client_syncstorage/model/test_result_save_response.py +267 -0
  22. api_client_syncstorage/model_utils.py +2058 -0
  23. api_client_syncstorage/models/__init__.py +20 -0
  24. api_client_syncstorage/rest.py +356 -0
  25. testit.py +69 -0
  26. testit_python_commons/__init__.py +0 -0
  27. testit_python_commons/app_properties.py +257 -0
  28. testit_python_commons/client/__init__.py +9 -0
  29. testit_python_commons/client/api_client.py +560 -0
  30. testit_python_commons/client/client_configuration.py +74 -0
  31. testit_python_commons/client/converter.py +618 -0
  32. testit_python_commons/client/helpers/__init__.py +0 -0
  33. testit_python_commons/client/helpers/bulk_autotest_helper.py +246 -0
  34. testit_python_commons/client/helpers/threads_manager.py +86 -0
  35. testit_python_commons/client/models/__init__.py +8 -0
  36. testit_python_commons/client/models/threads_for_create_and_result.py +35 -0
  37. testit_python_commons/client/models/threads_for_update_and_result.py +45 -0
  38. testit_python_commons/configurations/__init__.py +0 -0
  39. testit_python_commons/configurations/properties_names.py +51 -0
  40. testit_python_commons/decorators.py +221 -0
  41. testit_python_commons/dynamic_methods.py +237 -0
  42. testit_python_commons/models/__init__.py +5 -0
  43. testit_python_commons/models/adapter_mode.py +4 -0
  44. testit_python_commons/models/fixture.py +24 -0
  45. testit_python_commons/models/link.py +53 -0
  46. testit_python_commons/models/link_type.py +10 -0
  47. testit_python_commons/models/outcome_type.py +5 -0
  48. testit_python_commons/models/status_type.py +6 -0
  49. testit_python_commons/models/step_result.py +90 -0
  50. testit_python_commons/models/test_result.py +297 -0
  51. testit_python_commons/models/test_result_with_all_fixture_step_results_model.py +28 -0
  52. testit_python_commons/services/__init__.py +41 -0
  53. testit_python_commons/services/adapter_manager.py +318 -0
  54. testit_python_commons/services/adapter_manager_configuration.py +42 -0
  55. testit_python_commons/services/fixture_manager.py +60 -0
  56. testit_python_commons/services/fixture_storage.py +40 -0
  57. testit_python_commons/services/logger.py +32 -0
  58. testit_python_commons/services/plugin_manager.py +101 -0
  59. testit_python_commons/services/retry.py +92 -0
  60. testit_python_commons/services/step_manager.py +36 -0
  61. testit_python_commons/services/step_result_storage.py +26 -0
  62. testit_python_commons/services/sync_storage/__init__.py +9 -0
  63. testit_python_commons/services/sync_storage/sync_storage_runner.py +589 -0
  64. testit_python_commons/services/utils.py +132 -0
  65. testit_python_commons/step.py +101 -0
  66. testit_python_commons/utils/__init__.py +3 -0
  67. testit_python_commons/utils/html_escape_utils.py +219 -0
  68. testit_python_commons-4.2.8.dist-info/METADATA +52 -0
  69. testit_python_commons-4.2.8.dist-info/RECORD +71 -0
  70. testit_python_commons-4.2.8.dist-info/WHEEL +5 -0
  71. testit_python_commons-4.2.8.dist-info/top_level.txt +3 -0
@@ -0,0 +1,297 @@
1
+ from typing import List
2
+
3
+ from testit_python_commons.models.link import Link
4
+ from testit_python_commons.models.step_result import StepResult
5
+ from testit_python_commons.services.logger import adapter_logger
6
+ from testit_python_commons.utils import HtmlEscapeUtils
7
+
8
+
9
+ class TestResult:
10
+ __external_id: str = None
11
+ __autotest_name: str = None
12
+ __outcome: str = None
13
+ __status_type: str = None
14
+ __title: str = None
15
+ __description: str = None
16
+ __duration: int = None
17
+ __started_on: str = None
18
+ __completed_on: str = None
19
+ __namespace: str = None
20
+ __classname: str = None
21
+ __message: str = None
22
+ __traces: str = None
23
+ __step_results: List[StepResult] = []
24
+ __setup_results: List[StepResult] = []
25
+ __teardown_results: List[StepResult] = []
26
+ __links: List[Link] = []
27
+ __result_links: List[Link] = []
28
+ __attachments: List[str] = []
29
+ __labels: List[str] = []
30
+ __tags: List[str] = []
31
+ __work_item_ids: List[str] = []
32
+ __parameters: dict = {}
33
+ __properties: dict = {}
34
+ __automatic_creation_test_cases: bool = False
35
+ __external_key: str = None
36
+
37
+ @adapter_logger
38
+ def set_external_id(self, external_id: str):
39
+ # don't use escaping for externalId
40
+ # self.__external_id = HtmlEscapeUtils.escape_html_tags(external_id)
41
+ self.__external_id = external_id
42
+
43
+ return self
44
+
45
+ @adapter_logger
46
+ def get_external_id(self) -> str:
47
+ return self.__external_id
48
+
49
+ @adapter_logger
50
+ def set_autotest_name(self, autotest_name: str):
51
+ self.__autotest_name = HtmlEscapeUtils.escape_html_tags(autotest_name)
52
+
53
+ return self
54
+
55
+ @adapter_logger
56
+ def get_autotest_name(self) -> str:
57
+ return self.__autotest_name
58
+
59
+ @adapter_logger
60
+ def set_outcome(self, outcome: str):
61
+ self.__outcome = HtmlEscapeUtils.escape_html_tags(outcome)
62
+
63
+ return self
64
+
65
+ @adapter_logger
66
+ def get_outcome(self) -> str:
67
+ return self.__outcome
68
+
69
+ @adapter_logger
70
+ def set_status_type(self, status_type: str):
71
+ self.__status_type = HtmlEscapeUtils.escape_html_tags(status_type)
72
+
73
+ return self
74
+
75
+ @adapter_logger
76
+ def get_status_type(self) -> str:
77
+ return self.__status_type
78
+
79
+ @adapter_logger
80
+ def set_title(self, title: str):
81
+ self.__title = HtmlEscapeUtils.escape_html_tags(title)
82
+
83
+ return self
84
+
85
+ @adapter_logger
86
+ def get_title(self) -> str:
87
+ return self.__title
88
+
89
+ @adapter_logger
90
+ def set_description(self, description: str):
91
+ self.__description = HtmlEscapeUtils.escape_html_tags(description)
92
+
93
+ return self
94
+
95
+ @adapter_logger
96
+ def get_description(self) -> str:
97
+ return self.__description
98
+
99
+ @adapter_logger
100
+ def set_duration(self, duration: int):
101
+ self.__duration = duration
102
+
103
+ return self
104
+
105
+ @adapter_logger
106
+ def get_duration(self) -> int:
107
+ return self.__duration
108
+
109
+ @adapter_logger
110
+ def set_started_on(self, started_on: str):
111
+ self.__started_on = started_on
112
+
113
+ return self
114
+
115
+ @adapter_logger
116
+ def get_started_on(self) -> str:
117
+ return self.__started_on
118
+
119
+ @adapter_logger
120
+ def set_completed_on(self, completed_on: str):
121
+ self.__completed_on = completed_on
122
+
123
+ return self
124
+
125
+ @adapter_logger
126
+ def get_completed_on(self) -> str:
127
+ return self.__completed_on
128
+
129
+ @adapter_logger
130
+ def set_namespace(self, namespace: str):
131
+ self.__namespace = HtmlEscapeUtils.escape_html_tags(namespace)
132
+
133
+ return self
134
+
135
+ @adapter_logger
136
+ def get_namespace(self) -> str:
137
+ return self.__namespace
138
+
139
+ @adapter_logger
140
+ def set_classname(self, classname: str):
141
+ self.__classname = HtmlEscapeUtils.escape_html_tags(classname)
142
+
143
+ return self
144
+
145
+ @adapter_logger
146
+ def get_classname(self) -> str:
147
+ return self.__classname
148
+
149
+ @adapter_logger
150
+ def set_message(self, message: str):
151
+ self.__message = HtmlEscapeUtils.escape_html_tags(message)
152
+
153
+ return self
154
+
155
+ @adapter_logger
156
+ def get_message(self) -> str:
157
+ return self.__message
158
+
159
+ @adapter_logger
160
+ def set_traces(self, traces: str):
161
+ self.__traces = HtmlEscapeUtils.escape_html_tags(traces)
162
+
163
+ return self
164
+
165
+ @adapter_logger
166
+ def get_traces(self) -> str:
167
+ return self.__traces
168
+
169
+ @adapter_logger
170
+ def set_step_results(self, step_results: list):
171
+ self.__step_results = step_results
172
+
173
+ return self
174
+
175
+ @adapter_logger
176
+ def get_step_results(self) -> List[StepResult]:
177
+ return self.__step_results
178
+
179
+ @adapter_logger
180
+ def set_setup_results(self, setup_results: list):
181
+ self.__setup_results = setup_results
182
+
183
+ return self
184
+
185
+ @adapter_logger
186
+ def get_setup_results(self) -> List[StepResult]:
187
+ return self.__setup_results
188
+
189
+ @adapter_logger
190
+ def set_teardown_results(self, teardown_results: list):
191
+ self.__teardown_results = teardown_results
192
+
193
+ return self
194
+
195
+ @adapter_logger
196
+ def get_teardown_results(self) -> List[StepResult]:
197
+ return self.__teardown_results
198
+
199
+ @adapter_logger
200
+ def set_links(self, links: list):
201
+ self.__links = links
202
+
203
+ return self
204
+
205
+ @adapter_logger
206
+ def get_links(self) -> list:
207
+ return self.__links
208
+
209
+ @adapter_logger
210
+ def set_result_links(self, result_links: list):
211
+ self.__result_links = result_links
212
+
213
+ return self
214
+
215
+ @adapter_logger
216
+ def get_result_links(self) -> list:
217
+ return self.__result_links
218
+
219
+ @adapter_logger
220
+ def set_attachments(self, attachments: list):
221
+ self.__attachments = attachments
222
+
223
+ return self
224
+
225
+ @adapter_logger
226
+ def get_attachments(self) -> list:
227
+ return self.__attachments
228
+
229
+ @adapter_logger
230
+ def set_labels(self, labels: list):
231
+ self.__labels = HtmlEscapeUtils.escape_html_in_object(labels)
232
+
233
+ return self
234
+
235
+ @adapter_logger
236
+ def get_labels(self) -> list:
237
+ return self.__labels
238
+
239
+ @adapter_logger
240
+ def set_tags(self, tags: list):
241
+ self.__tags = HtmlEscapeUtils.escape_html_in_object(tags)
242
+
243
+ return self
244
+
245
+ @adapter_logger
246
+ def get_tags(self) -> list:
247
+ return self.__tags
248
+
249
+ @adapter_logger
250
+ def set_work_item_ids(self, work_item_ids: list):
251
+ self.__work_item_ids = work_item_ids
252
+
253
+ return self
254
+
255
+ @adapter_logger
256
+ def get_work_item_ids(self) -> list:
257
+ return self.__work_item_ids
258
+
259
+ @adapter_logger
260
+ def set_parameters(self, parameters: dict):
261
+ self.__parameters = HtmlEscapeUtils.escape_html_in_object(parameters)
262
+
263
+ return self
264
+
265
+ @adapter_logger
266
+ def get_parameters(self) -> dict:
267
+ return self.__parameters
268
+
269
+ @adapter_logger
270
+ def set_properties(self, properties: dict):
271
+ self.__properties = HtmlEscapeUtils.escape_html_in_object(properties)
272
+
273
+ return self
274
+
275
+ @adapter_logger
276
+ def get_properties(self) -> dict:
277
+ return self.__properties
278
+
279
+ @adapter_logger
280
+ def set_automatic_creation_test_cases(self, automatic_creation_test_cases: bool):
281
+ self.__automatic_creation_test_cases = automatic_creation_test_cases
282
+
283
+ return self
284
+
285
+ @adapter_logger
286
+ def get_automatic_creation_test_cases(self) -> bool:
287
+ return self.__automatic_creation_test_cases
288
+
289
+ @adapter_logger
290
+ def set_external_key(self, external_key: str):
291
+ self.__external_key = external_key
292
+
293
+ return self
294
+
295
+ @adapter_logger
296
+ def get_external_key(self) -> str:
297
+ return self.__external_key
@@ -0,0 +1,28 @@
1
+ from testit_python_commons.models.step_result import StepResult
2
+ from typing import List
3
+
4
+
5
+ class TestResultWithAllFixtureStepResults:
6
+ def __init__(self, test_result_id: str):
7
+ self.__test_result_id = test_result_id
8
+ self.__setup_results = []
9
+ self.__teardown_results = []
10
+
11
+ def get_test_result_id(self) -> str:
12
+ return self.__test_result_id
13
+
14
+ def set_setup_results(self, setup_results: List[StepResult]):
15
+ self.__setup_results += setup_results
16
+
17
+ return self
18
+
19
+ def get_setup_results(self) -> List[StepResult]:
20
+ return self.__setup_results
21
+
22
+ def set_teardown_results(self, teardown_results: List[StepResult]):
23
+ self.__teardown_results = teardown_results + self.__teardown_results
24
+
25
+ return self
26
+
27
+ def get_teardown_results(self) -> List[StepResult]:
28
+ return self.__teardown_results
@@ -0,0 +1,41 @@
1
+ from pluggy import HookimplMarker
2
+
3
+ __all__ = [
4
+ "AdapterManager",
5
+ "TmsPluginManager",
6
+ "FixtureManager",
7
+ "StepManager",
8
+ "Utils",
9
+ "SyncStorageRunner",
10
+ "hookimpl",
11
+ ]
12
+
13
+ hookimpl = HookimplMarker("testit")
14
+
15
+
16
+ def __getattr__(name):
17
+ if name == "AdapterManager":
18
+ from testit_python_commons.services.adapter_manager import AdapterManager
19
+
20
+ return AdapterManager
21
+ if name == "TmsPluginManager":
22
+ from testit_python_commons.services.plugin_manager import TmsPluginManager
23
+
24
+ return TmsPluginManager
25
+ if name == "FixtureManager":
26
+ from testit_python_commons.services.fixture_manager import FixtureManager
27
+
28
+ return FixtureManager
29
+ if name == "StepManager":
30
+ from testit_python_commons.services.step_manager import StepManager
31
+
32
+ return StepManager
33
+ if name == "Utils":
34
+ from testit_python_commons.services.utils import Utils
35
+
36
+ return Utils
37
+ if name == "SyncStorageRunner":
38
+ from testit_python_commons.services.sync_storage import SyncStorageRunner
39
+
40
+ return SyncStorageRunner
41
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,318 @@
1
+ import logging
2
+ import os
3
+ import uuid
4
+
5
+ from testit_python_commons.client.api_client import ApiClientWorker
6
+ from testit_python_commons.client.client_configuration import ClientConfiguration
7
+ from testit_python_commons.models.adapter_mode import AdapterMode
8
+ from testit_python_commons.models.test_result import TestResult
9
+ from testit_python_commons.services.adapter_manager_configuration import (
10
+ AdapterManagerConfiguration,
11
+ )
12
+ from testit_python_commons.services.fixture_manager import FixtureManager
13
+ from testit_python_commons.services.logger import adapter_logger
14
+ from testit_python_commons.services.utils import Utils
15
+
16
+ from testit_python_commons.services.sync_storage.sync_storage_runner import (
17
+ SyncStorageRunner,
18
+ )
19
+
20
+ SYNC_STORAGE_AVAILABLE = True
21
+ IN_PROGRESS_LITERAL = "InProgress"
22
+
23
+
24
+ class AdapterManager:
25
+ def __init__(
26
+ self,
27
+ adapter_configuration: AdapterManagerConfiguration,
28
+ client_configuration: ClientConfiguration,
29
+ fixture_manager: FixtureManager,
30
+ ):
31
+
32
+ self.__config = adapter_configuration
33
+ self.__client_config = client_configuration
34
+ self.__api_client = ApiClientWorker(client_configuration)
35
+ self.__fixture_manager = fixture_manager
36
+ self.__test_result_map = {}
37
+ self.__test_results = []
38
+
39
+ # Sync Storage integration
40
+ self.__sync_storage_runner = None
41
+ legacy_workflow_enabled = client_configuration.is_legacy_workflow() is True
42
+ # Initialize Sync Storage if available and enabled
43
+ if SYNC_STORAGE_AVAILABLE and not legacy_workflow_enabled:
44
+ self.__sync_storage_runner = self._initialize_sync_storage(
45
+ client_configuration
46
+ )
47
+
48
+
49
+ def _initialize_sync_storage(self, client_configuration: ClientConfiguration):
50
+ """Initialize Sync Storage runner if enabled."""
51
+ if client_configuration.is_legacy_workflow():
52
+ return None
53
+
54
+ test_run_id = self.__config.get_test_run_id()
55
+ if not test_run_id and self.__config.get_mode() == AdapterMode.NEW_TEST_RUN:
56
+ return None
57
+
58
+ if not test_run_id:
59
+ logging.warning('Sync Storage requires test run ID; skipping initialization')
60
+ return None
61
+
62
+ return self._start_sync_storage(test_run_id, client_configuration)
63
+
64
+ def _start_sync_storage(
65
+ self,
66
+ test_run_id: str,
67
+ client_configuration: ClientConfiguration):
68
+ try:
69
+ if not SYNC_STORAGE_AVAILABLE:
70
+ return None
71
+
72
+ sync_storage_runner = SyncStorageRunner(
73
+ test_run_id=test_run_id,
74
+ port=client_configuration.get_sync_storage_port(),
75
+ base_url=client_configuration.get_url(),
76
+ private_token=client_configuration.get_private_token(),
77
+ )
78
+
79
+ if sync_storage_runner.start():
80
+ logging.info("Sync Storage started successfully")
81
+ return sync_storage_runner
82
+
83
+ logging.warning("Failed to start Sync Storage")
84
+ except Exception as e:
85
+ logging.warning(f"Failed to initialize SyncStorage: {e}", exc_info=True)
86
+
87
+ return None
88
+
89
+ @adapter_logger
90
+ def set_test_run_id(self, test_run_id: str) -> None:
91
+
92
+ self.__config.set_test_run_id(test_run_id)
93
+
94
+ self.__api_client.set_test_run_id(test_run_id)
95
+
96
+ if self.__sync_storage_runner:
97
+ self.__sync_storage_runner.test_run_id = test_run_id
98
+ return
99
+
100
+ if SYNC_STORAGE_AVAILABLE and not self.__client_config.is_legacy_workflow():
101
+ self.__sync_storage_runner = self._start_sync_storage(
102
+ test_run_id, self.__client_config)
103
+
104
+ @adapter_logger
105
+ def get_test_run_id(self) -> str:
106
+ if self.__config.get_mode() != AdapterMode.NEW_TEST_RUN:
107
+ test_run_id = self.__config.get_test_run_id()
108
+
109
+ if test_run_id:
110
+ self.__update_test_run_name(test_run_id)
111
+
112
+ return test_run_id or ""
113
+
114
+ result = self.__config.get_test_run_id()
115
+ if result is not None:
116
+ return result
117
+
118
+ # create if not exists
119
+ test_run_name = self.__config.get_test_run_name()
120
+ return self.__api_client.create_test_run(test_run_name if test_run_name else "")
121
+
122
+ @adapter_logger
123
+ def __update_test_run_name(self, test_run_id: str) -> None:
124
+ test_run_name = self.__config.get_test_run_name()
125
+
126
+ if not test_run_name:
127
+ return
128
+
129
+ test_run = self.__api_client.get_test_run(test_run_id)
130
+
131
+ if test_run_name == test_run.name:
132
+ return
133
+
134
+ test_run.name = test_run_name
135
+
136
+ self.__api_client.update_test_run(test_run)
137
+
138
+ @adapter_logger
139
+ def get_autotests_for_launch(self):
140
+ if self.__config.get_mode() == AdapterMode.USE_FILTER:
141
+ return self.__api_client.get_external_ids_for_test_run_id()
142
+
143
+ return
144
+
145
+ @adapter_logger
146
+ def write_test(self, test_result: TestResult) -> None:
147
+ if self.__config.should_import_realtime():
148
+ self.__write_test_realtime(test_result)
149
+ return
150
+
151
+ # for realtime false
152
+ # if
153
+ logging.debug("Is already in progress: " + str(self.__is_already_in_progress()))
154
+ # Handle Sync Storage integration if available
155
+ # Check if current worker is master and no test is in progress
156
+ if self.__is_active_syncstorage_instance() and self.__is_master_and_no_in_progress():
157
+ logging.debug(f"Outcome: {test_result.get_outcome()}")
158
+ is_ok = self.on_master_no_already_in_progress(test_result)
159
+ if is_ok:
160
+ return
161
+ # else continue normal processing
162
+
163
+ self.__test_results.append(test_result)
164
+
165
+
166
+ @adapter_logger
167
+ def on_master_no_already_in_progress(self, test_result: TestResult) -> bool:
168
+ # Convert TestResult to TestResultCutApiModel
169
+
170
+ project_id = self.__client_config.get_project_id()
171
+ tr_cut_api_model = SyncStorageRunner.test_result_to_test_result_cut_api_model(
172
+ test_result, project_id
173
+ )
174
+ logging.debug("Set as in progress status_code, auto_test_external_id: "
175
+ + tr_cut_api_model.status_code + " " + tr_cut_api_model.auto_test_external_id)
176
+ logging.debug("Started_on: " + str(test_result.get_started_on()))
177
+
178
+ # Send test result to Sync Storage
179
+ success = self.__sync_storage_runner.send_in_progress_test_result(
180
+ tr_cut_api_model
181
+ )
182
+
183
+ if not success:
184
+ return False
185
+
186
+ # Set the in-progress flag in the runner
187
+ self.__sync_storage_runner.set_is_already_in_progress(True)
188
+
189
+ try:
190
+ # Write test result normally (mark as IN PROGRESS in Test IT)
191
+ logging.debug("Write internally, change status to in progress")
192
+ test_result.set_outcome(IN_PROGRESS_LITERAL)
193
+ self._write_test_realtime_internal(test_result)
194
+ return True
195
+ except Exception as e:
196
+ logging.warning(
197
+ f"Error in Sync Storage handling, falling back to normal processing: {e}"
198
+ )
199
+ # Reset in-progress flag and continue with normal processing
200
+ self.__sync_storage_runner.set_is_already_in_progress(False)
201
+ return False
202
+
203
+ @adapter_logger
204
+ def __write_test_realtime(self, test_result: TestResult) -> None:
205
+
206
+ logging.debug("Is already in progress: " + str(self.__is_already_in_progress()))
207
+
208
+ # Handle Sync Storage integration if available
209
+ if self.__is_active_syncstorage_instance() and self.__is_master_and_no_in_progress():
210
+ # Check if current worker is master and no test is in progress
211
+ is_ok = self.on_master_no_already_in_progress(test_result)
212
+ if is_ok:
213
+ return
214
+ # else continue normal processing
215
+
216
+ # Normal processing (also fallback for Sync Storage errors)
217
+ self._write_test_realtime_internal(test_result)
218
+
219
+ def _write_test_realtime_internal(self, test_result: TestResult) -> None:
220
+ """Internal method for writing test results to maintain clean separation."""
221
+ test_result.set_automatic_creation_test_cases(
222
+ self.__config.should_automatic_creation_test_cases()
223
+ )
224
+
225
+ ext_id = test_result.get_external_id()
226
+ test_result_id = self.__api_client.write_test(test_result)
227
+ if ext_id is None or test_result_id is None:
228
+ logging.warning("test_result got empty external_id or test_result_id")
229
+ logging.warning(test_result)
230
+ return
231
+
232
+ self.__test_result_map[ext_id] = test_result_id
233
+
234
+ @adapter_logger
235
+ def write_tests(self) -> None:
236
+ if self.__config.should_import_realtime():
237
+ self.__load_setup_and_teardown_step_results()
238
+
239
+ return
240
+
241
+ self.__write_tests_after_all()
242
+
243
+ @adapter_logger
244
+ def __load_setup_and_teardown_step_results(self) -> None:
245
+ fixtures = self.__fixture_manager.get_all_items()
246
+ if not fixtures:
247
+ return
248
+
249
+ self.__api_client.update_test_results(fixtures, self.__test_result_map)
250
+
251
+ @adapter_logger
252
+ def __write_tests_after_all(self) -> None:
253
+
254
+ fixtures = self.__fixture_manager.get_all_items()
255
+
256
+ # Ensure this option is propagated for each buffered test result in bulk mode.
257
+ should_create_work_item = self.__config.should_automatic_creation_test_cases()
258
+ for test_result in self.__test_results:
259
+ test_result.set_automatic_creation_test_cases(should_create_work_item)
260
+
261
+ self.__api_client.write_tests(self.__test_results, fixtures)
262
+
263
+ @adapter_logger
264
+ def load_attachments(self, attach_paths):
265
+ return self.__api_client.load_attachments(attach_paths)
266
+
267
+ @adapter_logger
268
+ def create_attachment(self, body, name: str):
269
+ if name is None:
270
+ name = str(uuid.uuid4()) + "-attachment.txt"
271
+
272
+ path = os.path.join(os.path.abspath(""), name)
273
+
274
+ with open(path, "wb") as attached_file:
275
+ attached_file.write(Utils.convert_body_of_attachment(body))
276
+
277
+ attachment_id = self.__api_client.load_attachments((path,))
278
+
279
+ os.remove(path)
280
+
281
+ return attachment_id
282
+
283
+ @adapter_logger
284
+ def on_block_completed(self):
285
+ self.set_worker_status("completed")
286
+
287
+ @adapter_logger
288
+ def on_running_started(self):
289
+ self.set_worker_status("in_progress")
290
+
291
+ @adapter_logger
292
+ def set_worker_status(self, status: str):
293
+ logging.debug(f"Set worker_status to {status}")
294
+ if not self.__is_active_syncstorage_instance():
295
+ return
296
+
297
+ self.__sync_storage_runner.set_worker_status(status)
298
+
299
+ def is_realtime(self):
300
+ return self.__config.should_import_realtime()
301
+
302
+ def __is_active_syncstorage_instance(self):
303
+ return (self.__sync_storage_runner
304
+ and self.__sync_storage_runner.is_running_status()
305
+ )
306
+
307
+ def __is_master_and_no_in_progress(self) -> bool:
308
+ return (
309
+ self.__sync_storage_runner is not None
310
+ and self.__sync_storage_runner.is_master_worker()
311
+ and not self.__sync_storage_runner.is_already_in_progress_flag()
312
+ )
313
+
314
+ def __is_already_in_progress(self) -> bool:
315
+ return (
316
+ self.__sync_storage_runner is not None
317
+ and self.__sync_storage_runner.is_already_in_progress_flag()
318
+ )