testit-cli 2.8.4__tar.gz → 2.9.0__tar.gz

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 (40) hide show
  1. {testit_cli-2.8.4 → testit_cli-2.9.0}/PKG-INFO +2 -2
  2. {testit_cli-2.8.4 → testit_cli-2.9.0}/setup.py +2 -2
  3. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/apiclient.py +102 -12
  4. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/click_commands.py +144 -8
  5. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/converter.py +11 -5
  6. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/importer.py +5 -2
  7. testit_cli-2.9.0/src/testit_cli/models/config.py +35 -0
  8. testit_cli-2.9.0/src/testit_cli/models/status_type.py +9 -0
  9. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/models/testcase.py +14 -8
  10. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/parser.py +5 -3
  11. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/service.py +26 -0
  12. testit_cli-2.9.0/src/testit_cli/validation.py +29 -0
  13. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli.egg-info/PKG-INFO +2 -2
  14. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli.egg-info/SOURCES.txt +1 -1
  15. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli.egg-info/requires.txt +1 -1
  16. testit_cli-2.9.0/tests/test_click.py +59 -0
  17. testit_cli-2.9.0/tests/test_service.py +105 -0
  18. testit_cli-2.8.4/src/testit_cli/models/config.py +0 -22
  19. testit_cli-2.8.4/src/testit_cli/models/status.py +0 -7
  20. testit_cli-2.8.4/src/testit_cli/validation.py +0 -20
  21. testit_cli-2.8.4/tests/test_click.py +0 -136
  22. testit_cli-2.8.4/tests/test_service.py +0 -79
  23. {testit_cli-2.8.4 → testit_cli-2.9.0}/LICENSE +0 -0
  24. {testit_cli-2.8.4 → testit_cli-2.9.0}/README.md +0 -0
  25. {testit_cli-2.8.4 → testit_cli-2.9.0}/setup.cfg +0 -0
  26. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/__init__.py +0 -0
  27. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/__main__.py +0 -0
  28. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/autotests_filter.py +0 -0
  29. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/dir_worker.py +0 -0
  30. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/file_worker.py +0 -0
  31. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/filter_factory.py +0 -0
  32. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/html_escape_utils.py +0 -0
  33. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/logger.py +0 -0
  34. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/models/__init__.py +0 -0
  35. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/models/mode.py +0 -0
  36. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/models/testrun.py +0 -0
  37. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli/service_factory.py +0 -0
  38. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli.egg-info/dependency_links.txt +0 -0
  39. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli.egg-info/entry_points.txt +0 -0
  40. {testit_cli-2.8.4 → testit_cli-2.9.0}/src/testit_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testit-cli
3
- Version: 2.8.4
3
+ Version: 2.9.0
4
4
  Summary: This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT
5
5
  Home-page: https://pypi.org/project/testit-cli/
6
6
  Author: Integration team
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: testit-api-client==7.5.3
19
+ Requires-Dist: testit-api-client==7.5.5
20
20
  Requires-Dist: validators
21
21
  Requires-Dist: tqdm
22
22
  Requires-Dist: click~=8.0.4
@@ -1,6 +1,6 @@
1
1
  from setuptools import find_packages, setup
2
2
 
3
- VERSION = "2.8.4"
3
+ VERSION = "2.9.0"
4
4
 
5
5
  setup(
6
6
  name='testit-cli',
@@ -26,7 +26,7 @@ setup(
26
26
  py_modules=['testit_cli'],
27
27
  packages=find_packages(where='src'),
28
28
  package_dir={'': 'src'},
29
- install_requires=['testit-api-client==7.5.3', 'validators', 'tqdm', 'click~=8.0.4'],
29
+ install_requires=['testit-api-client==7.5.5', 'validators', 'tqdm', 'click~=8.0.4'],
30
30
  entry_points={
31
31
  'console_scripts': [
32
32
  'testit = testit_cli.__main__:console_main'
@@ -5,18 +5,29 @@ import typing
5
5
 
6
6
  from testit_api_client import ApiClient as TmsClient
7
7
  from testit_api_client import Configuration
8
- from testit_api_client.apis import AttachmentsApi, AutoTestsApi, TestRunsApi, TestResultsApi
9
- from testit_api_client.model.api_v2_auto_tests_search_post_request import ApiV2AutoTestsSearchPostRequest
10
- from testit_api_client.model.api_v2_test_results_search_post_request import ApiV2TestResultsSearchPostRequest
11
- from testit_api_client.model.attachment_model import AttachmentModel
12
- from testit_api_client.model.attachment_put_model import AttachmentPutModel
13
- from testit_api_client.model.auto_test_model import AutoTestModel
14
- from testit_api_client.model.auto_test_results_for_test_run_model import AutoTestResultsForTestRunModel
15
- from testit_api_client.model.create_auto_test_request import CreateAutoTestRequest
16
- from testit_api_client.model.test_run_v2_api_result import TestRunV2ApiResult
17
- from testit_api_client.model.update_auto_test_request import UpdateAutoTestRequest
18
- from testit_api_client.model.update_empty_request import UpdateEmptyRequest
19
- from testit_api_client.models import TestResultShortResponse, CreateEmptyRequest, AutoTestApiResult
8
+ from testit_api_client.apis import AttachmentsApi, AutoTestsApi, TestRunsApi, TestResultsApi, ProjectsApi, WorkflowsApi
9
+ from testit_api_client.models import (
10
+ ApiV2AutoTestsSearchPostRequest,
11
+ ApiV2TestResultsSearchPostRequest,
12
+ ApiV2TestRunsIdRerunsPostRequest,
13
+ AttachmentModel,
14
+ AttachmentPutModel,
15
+ AutoTestModel,
16
+ AutoTestResultsForTestRunModel,
17
+ CreateAutoTestRequest,
18
+ ManualRerunApiResult,
19
+ ManualRerunSelectTestResultsApiModelExtractionModel,
20
+ ManualRerunSelectTestResultsApiModelFilter,
21
+ TestRunV2ApiResult,
22
+ UpdateAutoTestRequest,
23
+ UpdateEmptyRequest,
24
+ TestResultShortResponse,
25
+ CreateEmptyRequest,
26
+ AutoTestApiResult,
27
+ ProjectModel,
28
+ WorkflowApiResult,
29
+ CreateProjectRequest,
30
+ )
20
31
 
21
32
  from .converter import Converter
22
33
  from .models.testrun import TestRun
@@ -40,6 +51,8 @@ class ApiClient:
40
51
  self.__autotest_api = AutoTestsApi(api_client=client)
41
52
  self.__attachments_api = AttachmentsApi(api_client=client)
42
53
  self.__test_results_api = TestResultsApi(api_client=client)
54
+ self.__projects_api = ProjectsApi(api_client=client)
55
+ self.__workflows_api = WorkflowsApi(api_client=client)
43
56
 
44
57
  def create_test_run(self, project_id: str, name: str) -> TestRun:
45
58
  """Function creates test run and returns test run id."""
@@ -54,6 +67,55 @@ class ApiClient:
54
67
 
55
68
  return Converter.test_run_v2_get_model_to_test_run(test_run)
56
69
 
70
+ def rerun_test_run(self, test_run_id: str,
71
+ configuration_ids: list[str] = None,
72
+ status_codes: list[str] = None,
73
+ failure_categories: list[str] = None,
74
+ namespace: str = None,
75
+ class_name: str = None,
76
+ auto_test_global_ids: list[int] = None,
77
+ auto_test_tags: list[str] = None,
78
+ exclude_auto_test_tags: list[str] = None,
79
+ auto_test_name: str = None,
80
+ test_result_ids: list[str] = None,
81
+ webhook_ids: list[str] = None) -> None:
82
+ """Function reruns test run and returns manual rerun result."""
83
+ filter_model = ManualRerunSelectTestResultsApiModelFilter(
84
+ configuration_ids=configuration_ids,
85
+ status_codes=status_codes,
86
+ failure_categories=failure_categories,
87
+ namespace=namespace,
88
+ class_name=class_name,
89
+ auto_test_global_ids=auto_test_global_ids,
90
+ auto_test_tags=auto_test_tags,
91
+ exclude_auto_test_tags=exclude_auto_test_tags,
92
+ name=auto_test_name
93
+ ) if any(param is not None for param in [
94
+ configuration_ids, status_codes, failure_categories,
95
+ namespace, class_name, auto_test_global_ids, auto_test_tags,
96
+ exclude_auto_test_tags, auto_test_name
97
+ ]) else None
98
+
99
+ extraction_model = ManualRerunSelectTestResultsApiModelExtractionModel(
100
+ test_result_ids=test_result_ids
101
+ ) if test_result_ids is not None else None
102
+
103
+ model = ApiV2TestRunsIdRerunsPostRequest(
104
+ filter=filter_model,
105
+ extraction_model=extraction_model,
106
+ webhook_ids=webhook_ids
107
+ )
108
+
109
+ logging.debug(f"Rerunning test run {test_run_id} with model: {model}")
110
+
111
+ result: ManualRerunApiResult = self.__test_run_api.api_v2_test_runs_id_reruns_post(
112
+ id=test_run_id,
113
+ api_v2_test_runs_id_reruns_post_request=model
114
+ )
115
+
116
+ logging.info(f'Reran testrun (ID: {test_run_id})\nTest results count: {result.test_results_count}')
117
+ logging.debug(f"Test run rerun result: {result}")
118
+
57
119
  def update_test_run(self, test_run: TestRun) -> None:
58
120
  """Function updates test run."""
59
121
  model: UpdateEmptyRequest = Converter.test_run_to_update_empty_request(test_run)
@@ -178,3 +240,31 @@ class ApiClient:
178
240
  logging.debug(f"Got test results: {test_results}")
179
241
 
180
242
  return test_results
243
+
244
+ def __get_project(self, project_id: str) -> ProjectModel:
245
+ """Function returns ProjectModel."""
246
+ return self.__projects_api.get_project_by_id(id=project_id)
247
+
248
+ def __get_workflow_by_id(self, workflow_id: str) -> WorkflowApiResult:
249
+ """Function returns WorkflowApiResult."""
250
+ return self.__workflows_api.api_v2_workflows_id_get(id=workflow_id)
251
+
252
+ def get_status_codes(self, project_id: str) -> typing.List[str]:
253
+ """Function returns list of statuses from project."""
254
+ project: ProjectModel = self.__get_project(project_id)
255
+ workflow: WorkflowApiResult = self.__get_workflow_by_id(project.workflow_id)
256
+
257
+ return [status.code for status in workflow.statuses]
258
+
259
+ def create_project(self, name: str, description: str = None, is_favorite: bool = None, workflow_id: str = None) -> str:
260
+ """Function creates project and returns project id."""
261
+ model = CreateProjectRequest(name=name, description=description, is_favorite=is_favorite, workflow_id=workflow_id)
262
+ model = HtmlEscapeUtils.escape_html_in_object(model)
263
+ logging.debug(f"Creating project with model: {model}")
264
+
265
+ project = self.__projects_api.create_project(create_project_request=model)
266
+
267
+ logging.info(f'Created new project (ID: {project.id})')
268
+ logging.debug(f"Project created: {project}")
269
+
270
+ return str(project.id)
@@ -76,7 +76,20 @@ class ExtraArgsForOption(click.Option):
76
76
  @click.option("-iff", "--ignore-flaky-failure", is_flag=True, help="Ignore status flakyFailure in results")
77
77
  def upload_results(url, token, configuration_id, testrun_id, separator, namespace, classname, results, debug, attachments, disable_cert_validation, ignore_flaky_failure):
78
78
  """Uploading results from different streams"""
79
- config = Config(url, token, "", configuration_id, testrun_id, "", separator, namespace, classname, list(chain.from_iterable(results)), debug, "", list(chain.from_iterable(attachments)), disable_cert_validation, "", ignore_flaky_failure)
79
+ config = Config(
80
+ url=url,
81
+ token=token,
82
+ configuration_id=configuration_id,
83
+ testrun_id=testrun_id,
84
+ separator=separator,
85
+ namespace=namespace,
86
+ classname=classname,
87
+ results=list(chain.from_iterable(results)),
88
+ is_debug=debug,
89
+ paths_to_attachments=list(chain.from_iterable(attachments)),
90
+ disable_cert_validation=disable_cert_validation,
91
+ ignore_flaky_failure=ignore_flaky_failure,
92
+ )
80
93
  service = ServiceFactory().get(config)
81
94
 
82
95
  service.upload_results()
@@ -103,9 +116,22 @@ def import_results(url, token, project_id, configuration_id, testrun_id, testrun
103
116
  if testrun_id is not None and testrun_name is not None:
104
117
  click.echo("Illegal usage: `{}` are mutually exclusive arguments.".format(', '.join(["--testrun-id", "--testrun-name"])), err=True)
105
118
 
106
- config = Config(url, token, project_id, configuration_id, testrun_id, testrun_name,
107
- separator, namespace, classname, list(chain.from_iterable(results)), debug, "", list(chain.from_iterable(attachments)),
108
- disable_cert_validation, "", ignore_flaky_failure)
119
+ config = Config(
120
+ url=url,
121
+ token=token,
122
+ project_id=project_id,
123
+ configuration_id=configuration_id,
124
+ testrun_id=testrun_id,
125
+ testrun_name=testrun_name,
126
+ separator=separator,
127
+ namespace=namespace,
128
+ classname=classname,
129
+ results=list(chain.from_iterable(results)),
130
+ is_debug=debug,
131
+ paths_to_attachments=list(chain.from_iterable(attachments)),
132
+ disable_cert_validation=disable_cert_validation,
133
+ ignore_flaky_failure=ignore_flaky_failure,
134
+ )
109
135
  service = ServiceFactory().get(config)
110
136
 
111
137
  service.import_results()
@@ -128,7 +154,16 @@ def testrun():
128
154
  @click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
129
155
  def create_test_run(url, token, project_id, testrun_name, output, debug, attachments, disable_cert_validation):
130
156
  """Creating a new test run"""
131
- config = Config(url, token, project_id, "", "", testrun_name, "", "", "", [], debug, output, list(chain.from_iterable(attachments)), disable_cert_validation, "", False)
157
+ config = Config(
158
+ url=url,
159
+ token=token,
160
+ project_id=project_id,
161
+ testrun_name=testrun_name,
162
+ is_debug=debug,
163
+ output=output,
164
+ paths_to_attachments=list(chain.from_iterable(attachments)),
165
+ disable_cert_validation=disable_cert_validation,
166
+ )
132
167
  service = ServiceFactory().get(config)
133
168
 
134
169
  service.create_test_run()
@@ -143,7 +178,14 @@ def create_test_run(url, token, project_id, testrun_name, output, debug, attachm
143
178
  @click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
144
179
  def complete_test_run(url, token, testrun_id, debug, attachments, disable_cert_validation):
145
180
  """Completing the test run"""
146
- config = Config(url, token, "", "", testrun_id, "", "", "", "", [], debug, "", list(chain.from_iterable(attachments)), disable_cert_validation, "", False)
181
+ config = Config(
182
+ url=url,
183
+ token=token,
184
+ testrun_id=testrun_id,
185
+ is_debug=debug,
186
+ paths_to_attachments=list(chain.from_iterable(attachments)),
187
+ disable_cert_validation=disable_cert_validation,
188
+ )
147
189
  service = ServiceFactory().get(config)
148
190
 
149
191
  service.finished_test_run()
@@ -158,12 +200,63 @@ def complete_test_run(url, token, testrun_id, debug, attachments, disable_cert_v
158
200
  @click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
159
201
  def upload_attachments_for_test_run(url, token, testrun_id, debug, attachments, disable_cert_validation):
160
202
  """Uploading attachments for the test run"""
161
- config = Config(url, token, "", "", testrun_id, "", "", "", "", [], debug, "", list(chain.from_iterable(attachments)), disable_cert_validation, "", False)
203
+ config = Config(
204
+ url=url,
205
+ token=token,
206
+ testrun_id=testrun_id,
207
+ is_debug=debug,
208
+ paths_to_attachments=list(chain.from_iterable(attachments)),
209
+ disable_cert_validation=disable_cert_validation,
210
+ )
162
211
  service = ServiceFactory().get(config)
163
212
 
164
213
  service.upload_attachments_for_test_run()
165
214
 
166
215
 
216
+ @testrun.command("rerun")
217
+ @click.option("-u", "--url", type=str, envvar='TMS_URL', required=True, help="Set url address of the Test IT instance (https://demo.testit.software)", callback=validate_url)
218
+ @click.option("-t", "--token", type=str, envvar='TMS_TOKEN', required=True, help="Set API token (T2lKd2pLZGI4WHRhaVZUejNl)")
219
+ @click.option("-ti", "--testrun-id", type=str, envvar='TMS_TEST_RUN_ID', required=True, help="Set test run id (3802f329-190c-4617-8bb0-2c3696abeb8f)", callback=validate_uuid)
220
+ @click.option("-ci", "--configuration-id", type=str, envvar='TMS_CONFIGURATION_ID', multiple=True, help="Set configuration id (15dbb164-c1aa-4cbf-830c-8c01ae14f4fb)", callback=validate_uuid)
221
+ @click.option("-sc", "--status-code", type=str, multiple=True, help="Set status code for filtering test results")
222
+ @click.option("-fc", "--failure-category", type=str, multiple=True, help="Set failure category for filtering test results")
223
+ @click.option("-ns", "--namespace", type=str, help="Set namespace for filtering test results")
224
+ @click.option("-cn", "--classname", type=str, help="Set class name for filtering test results")
225
+ @click.option("-atgi", "--autotest-global-id", type=int, multiple=True, help="Set autotest global ID for filtering test results")
226
+ @click.option("-att", "--autotest-tag", type=str, multiple=True, help="Set autotest tag for filtering test results")
227
+ @click.option("-eatt", "--exclude-autotest-tag", type=str, multiple=True, help="Set autotest tag to exclude from filtering test results")
228
+ @click.option("-atn", "--autotest-name", type=str, help="Set autotest name for filtering test results")
229
+ @click.option("-tri", "--test-result-id", type=str, multiple=True, help="Set test result ID for extraction (UUID)", callback=validate_uuid)
230
+ @click.option("-wi", "--webhook-id", type=str, multiple=True, help="Set webhook ID for rerunning (UUID)", callback=validate_uuid)
231
+ @click.option("-d", "--debug", is_flag=True, help="Set debug logs")
232
+ @click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
233
+ def rerun_test_run(url, token, testrun_id, configuration_id, status_code, failure_category,
234
+ namespace, classname, autotest_global_id, autotest_tag, exclude_autotest_tag,
235
+ autotest_name, test_result_id, webhook_id, debug, disable_cert_validation):
236
+ """Rerunning the test run"""
237
+ config = Config(
238
+ url=url,
239
+ token=token,
240
+ testrun_id=testrun_id,
241
+ is_debug=debug,
242
+ disable_cert_validation=disable_cert_validation,
243
+ configuration_ids=list(configuration_id) if configuration_id else None,
244
+ status_codes=list(status_code) if status_code else None,
245
+ failure_categories=list(failure_category) if failure_category else None,
246
+ namespace=namespace,
247
+ classname=classname,
248
+ auto_test_global_ids=list(autotest_global_id) if autotest_global_id else None,
249
+ auto_test_tags=list(autotest_tag) if autotest_tag else None,
250
+ exclude_auto_test_tags=list(exclude_autotest_tag) if exclude_autotest_tag else None,
251
+ auto_test_name=autotest_name,
252
+ test_result_ids=list(test_result_id) if test_result_id else None,
253
+ webhook_ids=list(webhook_id) if webhook_id else None,
254
+ )
255
+ service = ServiceFactory().get(config)
256
+
257
+ service.rerun_test_run()
258
+
259
+
167
260
  PYTHON_FRAMEWORKS = ['pytest', 'robotframework', 'behave', 'nose']
168
261
  JAVA_FRAMEWORKS = ['gradle-testng', 'gradle-junit5', 'gradle-junit4', 'gradle-cucumber', 'maven-testng', 'maven-junit5', 'maven-junit4', 'maven-cucumber']
169
262
  KOTLIN_FRAMEWORKS = ['kotest']
@@ -184,7 +277,50 @@ SWIFT_FRAMEWORKS = ['xctest']
184
277
  @click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
185
278
  def create_filter_for_framework(url, token, configuration_id, testrun_id, framework, debug, output, disable_cert_validation):
186
279
  """Creating filter by autotests for test frameworks"""
187
- config = Config(url, token, "", configuration_id, testrun_id, "", "", "", "", [], debug, output, [], disable_cert_validation, framework, False)
280
+ config = Config(
281
+ url=url,
282
+ token=token,
283
+ configuration_id=configuration_id,
284
+ testrun_id=testrun_id,
285
+ is_debug=debug,
286
+ output=output,
287
+ disable_cert_validation=disable_cert_validation,
288
+ framework=framework,
289
+ )
188
290
  service = ServiceFactory().get(config)
189
291
 
190
292
  service.create_filter_for_test_framework()
293
+
294
+
295
+ @execute.group()
296
+ def project():
297
+ """Working with projects"""
298
+ pass
299
+
300
+
301
+ @project.command("create")
302
+ @click.option("-u", "--url", type=str, envvar='TMS_URL', required=True, help="Set url address of the Test IT instance (https://demo.testit.software)", callback=validate_url)
303
+ @click.option("-t", "--token", type=str, envvar='TMS_TOKEN', required=True, help="Set API token (T2lKd2pLZGI4WHRhaVZUejNl)")
304
+ @click.option("-n", "--name", type=str, envvar='TMS_PROJECT_NAME', required=True, help="Set project name (Project01)")
305
+ @click.option("-d", "--description", type=str, help="Set project description (Description of the project)", default=None)
306
+ @click.option("-f", "--favorite", is_flag=True, help="Mark project as favorite")
307
+ @click.option("-wf", "--workflow-id", type=str, help="Set workflow id for the project", default=None)
308
+ @click.option("-o", "--output", type=str, required=True, help="Set file path for output (FILE)")
309
+ @click.option("-d", "--debug", is_flag=True, help="Set debug logs")
310
+ @click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
311
+ def create_project(url, token, name, description, favorite, workflow_id, output, debug, disable_cert_validation):
312
+ """Creating a new project"""
313
+ config = Config(
314
+ url=url,
315
+ token=token,
316
+ project_name=name,
317
+ project_description=description,
318
+ project_is_favorite=favorite,
319
+ project_workflow_id=workflow_id,
320
+ is_debug=debug,
321
+ output=output,
322
+ disable_cert_validation=disable_cert_validation,
323
+ )
324
+ service = ServiceFactory().get(config)
325
+
326
+ service.create_project()
@@ -15,7 +15,8 @@ from testit_api_client.models import (
15
15
  AutoTestResultsForTestRunModel,
16
16
  AttachmentPutModel,
17
17
  LinkPutModel,
18
- TestResultOutcome,
18
+ TestStatusType,
19
+ TestStatusApiType,
19
20
  TestResultShortResponse,
20
21
  )
21
22
  from testit_api_client.model.assign_attachment_api_model import AssignAttachmentApiModel
@@ -58,7 +59,7 @@ class Converter:
58
59
  return ApiV2TestResultsSearchPostRequest(
59
60
  test_run_ids=[testrun_id],
60
61
  configuration_ids=[configuration_id],
61
- outcomes=[TestResultOutcome("InProgress")])
62
+ status_types=[TestStatusApiType("InProgress")])
62
63
 
63
64
  @staticmethod
64
65
  def test_result_short_get_models_to_autotest_ids(
@@ -110,17 +111,22 @@ class Converter:
110
111
 
111
112
  @staticmethod
112
113
  def test_result_to_testrun_result_post_model(
113
- result: TestCase, external_id: str, configuration_id: str
114
+ result: TestCase, external_id: str, configuration_id: str, status_codes: typing.List[str]
114
115
  ) -> AutoTestResultsForTestRunModel:
115
- return AutoTestResultsForTestRunModel(
116
+ model = AutoTestResultsForTestRunModel(
116
117
  configuration_id=configuration_id,
117
118
  auto_test_external_id=external_id,
118
- outcome=result.get_status(),
119
+ status_type=TestStatusType(result.get_status_type()),
119
120
  traces=result.get_trace(),
120
121
  duration=round(result.get_duration()),
121
122
  message=result.get_message(),
122
123
  )
123
124
 
125
+ if result.get_status().upper() in status_codes:
126
+ model.status_code = result.get_status()
127
+
128
+ return model
129
+
124
130
  @classmethod
125
131
  def test_run_v2_get_model_to_test_run(cls, test_run_model: TestRunV2ApiResult) -> TestRun:
126
132
  return TestRun(
@@ -1,4 +1,5 @@
1
1
  import hashlib
2
+ import typing
2
3
 
3
4
  from testit_api_client.model.api_v2_auto_tests_search_post_request import ApiV2AutoTestsSearchPostRequest
4
5
  from testit_api_client.model.auto_test_api_result import AutoTestApiResult
@@ -15,7 +16,9 @@ class Importer:
15
16
  self.__api_client = api_client
16
17
  self.__config = config
17
18
 
18
- def send_results(self, results: list[TestCase]) -> None:
19
+ def send_results(self, results: typing.List[TestCase]) -> None:
20
+ status_codes = self.__api_client.get_status_codes(self.__config.project_id)
21
+
19
22
  for result in tqdm(results, desc="Uploading"):
20
23
  external_id = self.__get_external_id(
21
24
  result.get_name_space()
@@ -46,7 +49,7 @@ class Importer:
46
49
  self.__api_client.send_test_result(
47
50
  self.__config.testrun_id,
48
51
  Converter.test_result_to_testrun_result_post_model(
49
- result, external_id, self.__config.configuration_id
52
+ result, external_id, self.__config.configuration_id, status_codes
50
53
  ),
51
54
  )
52
55
 
@@ -0,0 +1,35 @@
1
+ from dataclasses import dataclass, field
2
+ import typing
3
+
4
+
5
+ @dataclass
6
+ class Config:
7
+ url: str
8
+ token: str
9
+ project_id: str = ""
10
+ project_name: str = ""
11
+ project_description: typing.Optional[str] = None
12
+ project_is_favorite: bool = False
13
+ project_workflow_id: typing.Optional[str] = None
14
+ configuration_id: str = ""
15
+ configuration_ids: typing.Optional[list[str]] = None
16
+ testrun_id: typing.Optional[str] = None
17
+ testrun_name: typing.Optional[str] = None
18
+ separator: typing.Optional[str] = None
19
+ namespace: typing.Optional[str] = None
20
+ classname: typing.Optional[str] = None
21
+ status_codes: typing.Optional[list[str]] = None
22
+ failure_categories: typing.Optional[list[str]] = None
23
+ auto_test_global_ids: typing.Optional[list[int]] = None
24
+ auto_test_tags: typing.Optional[list[str]] = None
25
+ exclude_auto_test_tags: typing.Optional[list[str]] = None
26
+ auto_test_name: typing.Optional[str] = None
27
+ test_result_ids: typing.Optional[list[str]] = None
28
+ webhook_ids: typing.Optional[list[str]] = None
29
+ results: list[typing.Any] = field(default_factory=list)
30
+ is_debug: bool = False
31
+ output: str = ""
32
+ paths_to_attachments: list[typing.Any] = field(default_factory=list)
33
+ disable_cert_validation: bool = False
34
+ framework: str = ""
35
+ ignore_flaky_failure: bool = False
@@ -0,0 +1,9 @@
1
+ from enum import Enum
2
+
3
+
4
+ class StatusType(Enum):
5
+ SUCCEEDED = 'Succeeded'
6
+ FAILED = 'Failed'
7
+ INCOMPLETE = 'Incomplete'
8
+ INPROGRESS = 'InProgress'
9
+ PENDING = 'Pending'
@@ -1,9 +1,7 @@
1
1
  from datetime import timedelta
2
2
  from typing import Optional
3
3
 
4
- from testit_api_client.models import AvailableTestResultOutcome
5
-
6
- from .status import Status
4
+ from .status_type import StatusType
7
5
 
8
6
 
9
7
  class TestCase:
@@ -11,7 +9,8 @@ class TestCase:
11
9
  __name_space: Optional[str] = None
12
10
  __class_name: Optional[str] = None
13
11
  __duration: Optional[timedelta] = None
14
- __status: Optional[Status] = None
12
+ __status: Optional[str] = None
13
+ __status_type: Optional[StatusType] = None
15
14
  __message: Optional[str] = None
16
15
  __trace: Optional[str] = None
17
16
  __is_flaky: Optional[bool] = None
@@ -21,7 +20,8 @@ class TestCase:
21
20
  self.__name_space = name_space
22
21
  self.__class_name = class_name
23
22
  self.__duration = timedelta(seconds=float(duration))
24
- self.__status = Status.PASSED
23
+ self.__status = "passed"
24
+ self.__status_type = StatusType.SUCCEEDED
25
25
  self.__trace = ""
26
26
 
27
27
  def get_name(self) -> Optional[str]:
@@ -48,12 +48,18 @@ class TestCase:
48
48
  def set_trace(self, value: str) -> None:
49
49
  self.__trace = value
50
50
 
51
- def get_status(self) -> AvailableTestResultOutcome:
52
- return AvailableTestResultOutcome(self.__status.value)
51
+ def get_status(self) -> str:
52
+ return self.__status
53
53
 
54
- def set_status(self, value: Status) -> None:
54
+ def set_status(self, value: str) -> None:
55
55
  self.__status = value
56
56
 
57
+ def get_status_type(self) -> StatusType:
58
+ return self.__status_type
59
+
60
+ def set_status_type(self, value: StatusType) -> None:
61
+ self.__status_type = value
62
+
57
63
  def get_is_flaky(self) -> Optional[bool]:
58
64
  return self.__is_flaky
59
65
 
@@ -3,7 +3,7 @@ import typing
3
3
  from xml.dom import minidom
4
4
 
5
5
  from .models.config import Config
6
- from .models.status import Status
6
+ from .models.status_type import StatusType
7
7
  from .models.testcase import TestCase
8
8
  from .file_worker import FileWorker
9
9
 
@@ -64,11 +64,13 @@ class Parser:
64
64
 
65
65
  if elem.childNodes is not None:
66
66
  for child in elem.childNodes:
67
+ testcase.set_status(child.nodeName)
68
+
67
69
  if child.attributes and self.__MESSAGE_ATTRIBUTE_NAME in child.attributes:
68
70
  testcase.set_message(child.attributes[self.__MESSAGE_ATTRIBUTE_NAME].value)
69
71
 
70
72
  if child.nodeName == "skipped":
71
- testcase.set_status(Status.SKIPPED)
73
+ testcase.set_status_type(StatusType.INCOMPLETE)
72
74
  continue
73
75
 
74
76
  # if in failure node names and not flaky
@@ -79,7 +81,7 @@ class Parser:
79
81
  if len(child.childNodes) == 0 and len(child.attributes) == 0:
80
82
  continue
81
83
 
82
- testcase.set_status(Status.FAILED)
84
+ testcase.set_status_type(StatusType.FAILED)
83
85
 
84
86
  testcase.set_trace(
85
87
  testcase.get_trace() + self.__form_trace(child.childNodes))
@@ -43,6 +43,22 @@ class Service:
43
43
 
44
44
  self.__write_to_output(test_run.id)
45
45
 
46
+ def rerun_test_run(self) -> None:
47
+ self.__api_client.rerun_test_run(
48
+ self.__config.testrun_id,
49
+ configuration_ids=self.__config.configuration_ids,
50
+ status_codes=self.__config.status_codes,
51
+ failure_categories=self.__config.failure_categories,
52
+ namespace=self.__config.namespace,
53
+ class_name=self.__config.classname,
54
+ auto_test_global_ids=self.__config.auto_test_global_ids,
55
+ auto_test_tags=self.__config.auto_test_tags,
56
+ exclude_auto_test_tags=self.__config.exclude_auto_test_tags,
57
+ auto_test_name=self.__config.auto_test_name,
58
+ test_result_ids=self.__config.test_result_ids,
59
+ webhook_ids=self.__config.webhook_ids
60
+ )
61
+
46
62
  def finished_test_run(self):
47
63
  test_run = self.__api_client.get_test_run(self.__config.testrun_id)
48
64
  self.__update_test_run_with_attachments(test_run)
@@ -103,3 +119,13 @@ class Service:
103
119
  autotests_filter = self.__autotests_filter.create_filter()
104
120
 
105
121
  self.__write_to_output(autotests_filter)
122
+
123
+ def create_project(self):
124
+ project_id = self.__api_client.create_project(
125
+ self.__config.project_name,
126
+ self.__config.project_description,
127
+ self.__config.project_is_favorite,
128
+ self.__config.project_workflow_id
129
+ )
130
+
131
+ self.__write_to_output(project_id)
@@ -0,0 +1,29 @@
1
+ import click
2
+ import validators
3
+
4
+
5
+ def validate_uuid(ctx, param, value):
6
+ if value is None:
7
+ return value
8
+ if isinstance(value, (tuple, list)):
9
+ if len(value) == 0:
10
+ return value
11
+ for item in value:
12
+ if item is not None and not validators.uuid(item):
13
+ raise click.BadParameter(
14
+ f'"{item}" uuid of {param.name} (3802f329-190c-4617-8bb0-2c3696abeb8f)'
15
+ )
16
+ return value
17
+ if not validators.uuid(value):
18
+ raise click.BadParameter(f'"{value}" uuid of {param.name} (3802f329-190c-4617-8bb0-2c3696abeb8f)')
19
+ return value
20
+
21
+
22
+ def validate_url(ctx, param, value):
23
+ if not validators.url(value):
24
+ raise click.BadParameter(f'"{value}" url address of the Test IT instance (https://demo.testit.software)')
25
+
26
+ if value.endswith("/"):
27
+ return value[:-1]
28
+
29
+ return value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testit-cli
3
- Version: 2.8.4
3
+ Version: 2.9.0
4
4
  Summary: This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT
5
5
  Home-page: https://pypi.org/project/testit-cli/
6
6
  Author: Integration team
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: testit-api-client==7.5.3
19
+ Requires-Dist: testit-api-client==7.5.5
20
20
  Requires-Dist: validators
21
21
  Requires-Dist: tqdm
22
22
  Requires-Dist: click~=8.0.4
@@ -26,7 +26,7 @@ src/testit_cli.egg-info/top_level.txt
26
26
  src/testit_cli/models/__init__.py
27
27
  src/testit_cli/models/config.py
28
28
  src/testit_cli/models/mode.py
29
- src/testit_cli/models/status.py
29
+ src/testit_cli/models/status_type.py
30
30
  src/testit_cli/models/testcase.py
31
31
  src/testit_cli/models/testrun.py
32
32
  tests/test_click.py
@@ -1,4 +1,4 @@
1
- testit-api-client==7.5.3
1
+ testit-api-client==7.5.5
2
2
  validators
3
3
  tqdm
4
4
  click~=8.0.4
@@ -0,0 +1,59 @@
1
+ import pytest
2
+
3
+ from tests.cli_support import (
4
+ assert_exit_code,
5
+ assert_help_ok,
6
+ assert_invalid_parameter_value,
7
+ assert_missing_required_option,
8
+ invoke,
9
+ )
10
+ from tests.helper import Helper
11
+
12
+
13
+ @pytest.fixture()
14
+ def runner():
15
+ from click.testing import CliRunner
16
+
17
+ return CliRunner()
18
+
19
+
20
+ def test_root_help_lists_known_commands(runner):
21
+ result = invoke(runner, [])
22
+ assert_help_ok(result, "Commands:")
23
+ for line in Helper.root_help_command_lines():
24
+ assert line in result.output
25
+
26
+
27
+ @pytest.mark.parametrize("argv, unknown_token", Helper.unknown_subcommand_cases())
28
+ def test_unknown_command_reports_error(runner, argv, unknown_token):
29
+ result = invoke(runner, argv)
30
+ assert_exit_code(result, 2)
31
+ assert f"No such command '{unknown_token}'" in result.output
32
+
33
+
34
+ @pytest.mark.parametrize("argv, command_lines", Helper.subgroup_help_cases())
35
+ def test_subgroup_help_lists_nested_commands(runner, argv, command_lines):
36
+ result = invoke(runner, argv)
37
+ assert_help_ok(result, "Commands:")
38
+ for fragment in command_lines:
39
+ assert fragment in result.output
40
+
41
+
42
+ @pytest.mark.parametrize("argv, missing_long_option", Helper.missing_required_option_cases())
43
+ def test_missing_required_option(runner, argv, missing_long_option):
44
+ assert_missing_required_option(invoke(runner, argv), missing_long_option)
45
+
46
+
47
+ @pytest.mark.parametrize("argv", Helper.invalid_option_cases())
48
+ def test_unrecognized_option_exits_with_usage_error(runner, argv):
49
+ assert_exit_code(invoke(runner, argv), 2)
50
+
51
+
52
+ @pytest.mark.parametrize("argv, doc_fragment", Helper.command_help_doc_cases())
53
+ def test_command_help_includes_description(runner, argv, doc_fragment):
54
+ assert_help_ok(invoke(runner, argv), doc_fragment)
55
+
56
+
57
+ @pytest.mark.parametrize("argv, option_hint", Helper.invalid_rerun_uuid_multi_option_cases())
58
+ def test_rerun_rejects_invalid_uuid_for_optional_multi_options(runner, argv, option_hint):
59
+ assert_invalid_parameter_value(invoke(runner, argv), option_hint)
@@ -0,0 +1,105 @@
1
+ import os
2
+ import tempfile
3
+
4
+ import pytest
5
+ from unittest.mock import Mock
6
+
7
+ from src.testit_cli.service import Service
8
+ from src.testit_cli.models.config import Config
9
+
10
+
11
+ @pytest.fixture
12
+ def mock_config():
13
+ return Mock(spec=Config)
14
+
15
+
16
+ @pytest.fixture
17
+ def api_client():
18
+ return Mock()
19
+
20
+
21
+ @pytest.fixture
22
+ def service(mock_config, api_client):
23
+ return Service(
24
+ config=mock_config,
25
+ api_client=api_client,
26
+ parser=Mock(),
27
+ importer=Mock(),
28
+ autotests_filter=Mock(),
29
+ )
30
+
31
+
32
+ def _assert_utf8_file_equals(path: str, expected: str) -> None:
33
+ with open(path, "r", encoding="utf-8") as f:
34
+ assert f.read() == expected
35
+ with open(path, "rb") as f:
36
+ assert f.read().decode("utf-8") == expected
37
+
38
+
39
+ def test_write_to_output_uses_utf8_encoding(service, mock_config):
40
+ # Deliberate non-ASCII payload to assert UTF-8 read/write round-trip.
41
+ content = "Тестовый контент с кириллицей: АБВГД абвгд"
42
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, encoding="utf-8") as tmp:
43
+ path = tmp.name
44
+ mock_config.output = path
45
+ try:
46
+ service._Service__write_to_output(content)
47
+ _assert_utf8_file_equals(path, content)
48
+ finally:
49
+ if os.path.exists(path):
50
+ os.unlink(path)
51
+
52
+
53
+ def test_write_to_output_creates_parent_directory(service, mock_config):
54
+ with tempfile.TemporaryDirectory() as tmp_dir:
55
+ path = os.path.join(tmp_dir, "nested", "out.txt")
56
+ mock_config.output = path
57
+ service._Service__write_to_output("test content")
58
+ assert os.path.isfile(path)
59
+ _assert_utf8_file_equals(path, "test content")
60
+
61
+
62
+ def test_rerun_test_run_forwards_config_to_api_client(service, mock_config, api_client):
63
+ mock_config.testrun_id = "3802f329-190c-4617-8bb0-2c3696abeb8f"
64
+ mock_config.configuration_ids = [
65
+ "15dbb164-c1aa-4cbf-830c-8c01ae14f4fb",
66
+ "5236eb3f-7c05-46f9-a609-dc0278896464",
67
+ ]
68
+ mock_config.status_codes = ["Failed"]
69
+ mock_config.failure_categories = ["cat-1"]
70
+ mock_config.namespace = "ns"
71
+ mock_config.classname = "MyClass"
72
+ mock_config.auto_test_global_ids = [10, 20]
73
+ mock_config.auto_test_tags = ["smoke"]
74
+ mock_config.exclude_auto_test_tags = ["slow"]
75
+ mock_config.auto_test_name = "test-name"
76
+ mock_config.test_result_ids = [
77
+ "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
78
+ "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
79
+ ]
80
+ mock_config.webhook_ids = [
81
+ "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
82
+ ]
83
+
84
+ service.rerun_test_run()
85
+
86
+ api_client.rerun_test_run.assert_called_once_with(
87
+ "3802f329-190c-4617-8bb0-2c3696abeb8f",
88
+ configuration_ids=[
89
+ "15dbb164-c1aa-4cbf-830c-8c01ae14f4fb",
90
+ "5236eb3f-7c05-46f9-a609-dc0278896464",
91
+ ],
92
+ status_codes=["Failed"],
93
+ failure_categories=["cat-1"],
94
+ namespace="ns",
95
+ class_name="MyClass",
96
+ auto_test_global_ids=[10, 20],
97
+ auto_test_tags=["smoke"],
98
+ exclude_auto_test_tags=["slow"],
99
+ auto_test_name="test-name",
100
+ test_result_ids=[
101
+ "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
102
+ "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
103
+ ],
104
+ webhook_ids=["cccccccc-cccc-4ccc-8ccc-cccccccccccc"],
105
+ )
@@ -1,22 +0,0 @@
1
- from dataclasses import dataclass
2
- import typing
3
-
4
-
5
- @dataclass
6
- class Config:
7
- url: str
8
- token: str
9
- project_id: str
10
- configuration_id: str
11
- testrun_id: str
12
- testrun_name: str
13
- separator: str
14
- namespace: str
15
- classname: str
16
- results: list[typing.Any]
17
- is_debug: bool
18
- output: str
19
- paths_to_attachments: list[typing.Any]
20
- disable_cert_validation: bool
21
- framework: str
22
- ignore_flaky_failure: bool
@@ -1,7 +0,0 @@
1
- from enum import Enum
2
-
3
-
4
- class Status(Enum):
5
- PASSED = "Passed"
6
- FAILED = "Failed"
7
- SKIPPED = "Skipped"
@@ -1,20 +0,0 @@
1
- import click
2
- import validators
3
-
4
-
5
- def validate_uuid(ctx, param, value):
6
- if value is not None:
7
- if not validators.uuid(value):
8
- raise click.BadParameter(f'"{value}" uuid of {param.name} (3802f329-190c-4617-8bb0-2c3696abeb8f)')
9
-
10
- return value
11
-
12
-
13
- def validate_url(ctx, param, value):
14
- if not validators.url(value):
15
- raise click.BadParameter(f'"{value}" url address of the Test IT instance (https://demo.testit.software)')
16
-
17
- if value.endswith("/"):
18
- return value[:-1]
19
-
20
- return value
@@ -1,136 +0,0 @@
1
- from click.testing import CliRunner
2
- import pytest
3
-
4
- from src.testit_cli.click_commands import execute
5
- from tests.helper import Helper
6
-
7
-
8
- @pytest.fixture()
9
- def runner():
10
- return CliRunner()
11
-
12
-
13
- def test_run_without_command(runner):
14
- message = ("Options:\n --help Show this message and exit.\n\nCommands:\n autotests_filter "
15
- "Creating filter by autotests for test frameworks\n results "
16
- "Uploading the test results\n testrun Working with the test run\n")
17
- result = runner.invoke(execute, [])
18
-
19
- assert message in result.output
20
- assert result.exit_code == 0
21
-
22
-
23
- def test_run_with_another_command(runner):
24
- another_command = "run"
25
- message = f"Error: No such command '{another_command}'"
26
- result = runner.invoke(execute, [another_command])
27
-
28
- assert message in result.output
29
- assert result.exit_code == 2
30
-
31
-
32
- @pytest.mark.parametrize("command, message", [
33
- ("results", "Options:\n --help Show this message and exit.\n\nCommands:\n import Uploading the first test results\n upload Uploading results from different streams\n"),
34
- ("testrun", "Options:\n --help Show this message and exit.\n\nCommands:\n complete Completing the test run\n create Creating a new test run\n upload_attachments Uploading attachments for the test run\n")])
35
- def test_run_with_command(runner, command, message):
36
- result = runner.invoke(execute, [command])
37
-
38
- assert message in result.output
39
- assert result.exit_code == 0
40
-
41
-
42
- def test_run_results_with_another_command(runner):
43
- another_command = "run"
44
- message = f"Error: No such command '{another_command}'"
45
- result = runner.invoke(execute, ["results", another_command])
46
-
47
- assert message in result.output
48
- assert result.exit_code == 2
49
-
50
-
51
- @pytest.mark.parametrize("commands, output", [
52
- (Helper.get_command_results_import_with_long_arguments_without_url_argument(), Helper.get_output_for_results_import_without_url_argument()),
53
- (Helper.get_command_results_import_with_short_arguments_without_url_argument(), Helper.get_output_for_results_import_without_url_argument()),
54
- (Helper.get_command_results_import_with_long_arguments_without_token_argument(), Helper.get_output_for_results_import_without_token_argument()),
55
- (Helper.get_command_results_import_with_short_arguments_without_token_argument(), Helper.get_output_for_results_import_without_token_argument()),
56
- (Helper.get_command_results_import_with_long_arguments_without_project_id_argument(), Helper.get_output_for_results_import_without_project_id_argument()),
57
- (Helper.get_command_results_import_with_short_arguments_without_project_id_argument(), Helper.get_output_for_results_import_without_project_id_argument()),
58
- (Helper.get_command_results_import_with_long_arguments_without_configuration_id_argument(), Helper.get_output_for_results_import_without_configuration_id_argument()),
59
- (Helper.get_command_results_import_with_short_arguments_without_configuration_id_argument(), Helper.get_output_for_results_import_without_configuration_id_argument()),
60
- (Helper.get_command_results_import_with_long_arguments_without_results_argument(), Helper.get_output_for_results_import_without_results_argument()),
61
- (Helper.get_command_results_import_with_short_arguments_without_results_argument(), Helper.get_output_for_results_import_without_results_argument()),
62
- (Helper.get_command_results_upload_with_long_arguments_without_url_argument(), Helper.get_output_for_results_upload_without_url_argument()),
63
- (Helper.get_command_results_upload_with_short_arguments_without_url_argument(), Helper.get_output_for_results_upload_without_url_argument()),
64
- (Helper.get_command_results_upload_with_long_arguments_without_token_argument(), Helper.get_output_for_results_upload_without_token_argument()),
65
- (Helper.get_command_results_upload_with_short_arguments_without_token_argument(), Helper.get_output_for_results_upload_without_token_argument()),
66
- (Helper.get_command_results_upload_with_long_arguments_without_testrun_id_argument(), Helper.get_output_for_results_upload_without_testrun_id_argument()),
67
- (Helper.get_command_results_upload_with_short_arguments_without_testrun_id_argument(), Helper.get_output_for_results_upload_without_testrun_id_argument()),
68
- (Helper.get_command_results_upload_with_long_arguments_without_configuration_id_argument(), Helper.get_output_for_results_upload_without_configuration_id_argument()),
69
- (Helper.get_command_results_upload_with_short_arguments_without_configuration_id_argument(), Helper.get_output_for_results_upload_without_configuration_id_argument()),
70
- (Helper.get_command_results_upload_with_long_arguments_without_results_argument(), Helper.get_output_for_results_upload_without_results_argument()),
71
- (Helper.get_command_results_upload_with_short_arguments_without_results_argument(), Helper.get_output_for_results_upload_without_results_argument()),
72
- (Helper.get_command_testrun_create_with_long_arguments_without_url_argument(), Helper.get_output_for_testrun_create_without_url_argument()),
73
- (Helper.get_command_testrun_create_with_short_arguments_without_url_argument(), Helper.get_output_for_testrun_create_without_url_argument()),
74
- (Helper.get_command_testrun_create_with_long_arguments_without_token_argument(), Helper.get_output_for_testrun_create_without_token_argument()),
75
- (Helper.get_command_testrun_create_with_short_arguments_without_token_argument(), Helper.get_output_for_testrun_create_without_token_argument()),
76
- (Helper.get_command_testrun_create_with_long_arguments_without_project_id_argument(), Helper.get_output_for_testrun_create_without_project_id_argument()),
77
- (Helper.get_command_testrun_create_with_short_arguments_without_project_id_argument(), Helper.get_output_for_testrun_create_without_project_id_argument()),
78
- (Helper.get_command_testrun_create_with_long_arguments_without_output_argument(), Helper.get_output_for_testrun_create_without_output_argument()),
79
- (Helper.get_command_testrun_create_with_short_arguments_without_output_argument(), Helper.get_output_for_testrun_create_without_output_argument()),
80
- (Helper.get_command_testrun_complete_with_long_arguments_without_url_argument(), Helper.get_output_for_testrun_complete_without_url_argument()),
81
- (Helper.get_command_testrun_complete_with_short_arguments_without_url_argument(), Helper.get_output_for_testrun_complete_without_url_argument()),
82
- (Helper.get_command_testrun_complete_with_long_arguments_without_token_argument(), Helper.get_output_for_testrun_complete_without_token_argument()),
83
- (Helper.get_command_testrun_complete_with_short_arguments_without_token_argument(), Helper.get_output_for_testrun_complete_without_token_argument()),
84
- (Helper.get_command_testrun_complete_with_long_arguments_without_testrun_id_argument(), Helper.get_output_for_testrun_complete_without_testrun_id_argument()),
85
- (Helper.get_command_testrun_complete_with_short_arguments_without_testrun_id_argument(), Helper.get_output_for_testrun_complete_without_testrun_id_argument()),
86
- (Helper.get_command_testrun_upload_attachments_with_long_arguments_without_url_argument(), Helper.get_output_for_testrun_upload_attachments_without_url_argument()),
87
- (Helper.get_command_testrun_upload_attachments_with_short_arguments_without_url_argument(), Helper.get_output_for_testrun_upload_attachments_without_url_argument()),
88
- (Helper.get_command_testrun_upload_attachments_with_long_arguments_without_token_argument(), Helper.get_output_for_testrun_upload_attachments_without_token_argument()),
89
- (Helper.get_command_testrun_upload_attachments_with_short_arguments_without_token_argument(), Helper.get_output_for_testrun_upload_attachments_without_token_argument()),
90
- (Helper.get_command_testrun_upload_attachments_with_long_arguments_without_testrun_id_argument(), Helper.get_output_for_testrun_upload_attachments_without_testrun_id_argument()),
91
- (Helper.get_command_testrun_upload_attachments_with_short_arguments_without_testrun_id_argument(), Helper.get_output_for_testrun_upload_attachments_without_testrun_id_argument())])
92
- def test_run_results_with_command_without_arguments(runner, commands, output):
93
- result = runner.invoke(execute, commands)
94
-
95
- assert output in result.output
96
- assert result.exit_code == 2
97
-
98
- # TODO: inifinite loading, fix
99
-
100
- # @pytest.mark.parametrize("commands_with_args", [
101
- # Helper.get_command_results_import_with_long_arguments(),
102
- # Helper.get_command_results_upload_with_long_arguments(),
103
- # Helper.get_command_results_import_with_short_arguments(),
104
- # Helper.get_command_results_upload_with_short_arguments(),
105
- # Helper.get_command_results_import_with_all_long_arguments(),
106
- # Helper.get_command_results_upload_with_all_long_arguments(),
107
- # Helper.get_command_results_import_with_all_short_arguments(),
108
- # Helper.get_command_results_upload_with_all_short_arguments(),
109
- # Helper.get_command_testrun_complete_with_long_arguments(),
110
- # Helper.get_command_testrun_create_with_long_arguments(),
111
- # Helper.get_command_testrun_upload_attachments_with_long_arguments(),
112
- # Helper.get_command_testrun_complete_with_short_arguments(),
113
- # Helper.get_command_testrun_create_with_short_arguments(),
114
- # Helper.get_command_testrun_upload_attachments_with_short_arguments(),
115
- # Helper.get_command_testrun_complete_with_all_long_arguments(),
116
- # Helper.get_command_testrun_create_with_all_long_arguments(),
117
- # Helper.get_command_testrun_upload_attachments_with_all_long_arguments(),
118
- # Helper.get_command_testrun_complete_with_all_short_arguments(),
119
- # Helper.get_command_testrun_create_with_all_short_arguments(),
120
- # Helper.get_command_testrun_upload_attachments_with_all_short_arguments()])
121
- # def test_run_with_commands_and_arguments(runner, commands_with_args):
122
- # result = runner.invoke(execute, commands_with_args)
123
-
124
- # assert result.exit_code == 1
125
-
126
-
127
- @pytest.mark.parametrize("commands_with_another_arg", [
128
- Helper.get_command_results_upload_with_another_argument(),
129
- Helper.get_command_results_import_with_another_argument(),
130
- Helper.get_command_testrun_complete_with_another_argument(),
131
- Helper.get_command_testrun_create_with_another_argument(),
132
- Helper.get_command_testrun_upload_attachments_with_another_argument()])
133
- def test_run_with_command_and_another_argument(runner, commands_with_another_arg):
134
- result = runner.invoke(execute, commands_with_another_arg)
135
-
136
- assert result.exit_code == 2
@@ -1,79 +0,0 @@
1
- import os
2
- import tempfile
3
- import pytest
4
- from unittest.mock import Mock
5
-
6
- from src.testit_cli.service import Service
7
- from src.testit_cli.models.config import Config
8
-
9
-
10
- @pytest.fixture
11
- def mock_config():
12
- """Fixture for creating mock config object"""
13
- config = Mock(spec=Config)
14
- return config
15
-
16
-
17
- @pytest.fixture
18
- def service(mock_config):
19
- """Fixture for creating Service instance with mock dependencies"""
20
- api_client = Mock()
21
- parser = Mock()
22
- importer = Mock()
23
- autotests_filter = Mock()
24
-
25
- return Service(
26
- config=mock_config,
27
- api_client=api_client,
28
- parser=parser,
29
- importer=importer,
30
- autotests_filter=autotests_filter
31
- )
32
-
33
-
34
- def test_write_to_output_uses_utf8_encoding(service, mock_config):
35
- """Test verifies that file is written using UTF-8 encoding"""
36
- # Arrange
37
- cyrillic_content = "Тестовый контент с кириллицей: АБВГД абвгд"
38
-
39
- with tempfile.NamedTemporaryFile(mode='w', delete=False, encoding='utf-8') as temp_file:
40
- temp_output_path = temp_file.name
41
-
42
- mock_config.output = temp_output_path
43
-
44
- try:
45
- # Act - call private method using name mangling
46
- service._Service__write_to_output(cyrillic_content)
47
-
48
- # Assert - verify file is written in UTF-8
49
- with open(temp_output_path, 'r', encoding='utf-8') as file:
50
- written_content = file.read()
51
- assert written_content == cyrillic_content
52
-
53
- # Additional check - read as bytes and verify UTF-8 BOM is absent
54
- with open(temp_output_path, 'rb') as file:
55
- raw_content = file.read()
56
- # Verify content can be decoded as UTF-8
57
- decoded_content = raw_content.decode('utf-8')
58
- assert decoded_content == cyrillic_content
59
-
60
- finally:
61
- # Cleanup
62
- if os.path.exists(temp_output_path):
63
- os.unlink(temp_output_path)
64
-
65
-
66
- def test_write_to_output_creates_directory(service, mock_config):
67
- """Test verifies that directory is created if it doesn't exist"""
68
- # Arrange
69
- with tempfile.TemporaryDirectory() as temp_dir:
70
- output_path = os.path.join(temp_dir, "subdir", "output.txt")
71
- mock_config.output = output_path
72
-
73
- # Act
74
- service._Service__write_to_output("test content")
75
-
76
- # Assert
77
- assert os.path.exists(output_path)
78
- with open(output_path, 'r', encoding='utf-8') as file:
79
- assert file.read() == "test content"
File without changes
File without changes
File without changes