qase-python-commons 3.0.2b2__tar.gz → 3.0.2b3__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.
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/PKG-INFO +2 -1
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/pyproject.toml +2 -1
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/client/api_v1_client.py +1 -1
- qase_python_commons-3.0.2b3/src/qase/commons/client/api_v2_client.py +148 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/client/base_api_client.py +3 -3
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/config.py +3 -1
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/testops.py +3 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase_python_commons.egg-info/PKG-INFO +2 -1
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase_python_commons.egg-info/SOURCES.txt +1 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase_python_commons.egg-info/requires.txt +1 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/README.md +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/setup.cfg +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/__init__.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/exceptions/reporter.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/loader.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/logger.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/__init__.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/attachment.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/basemodel.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/relation.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/result.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/run.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/runtime.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/step.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/suite.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/__init__.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/db.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/network.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/sleep.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/__init__.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/core.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/report.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/utils.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/validators/base.py +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase_python_commons.egg-info/dependency_links.txt +0 -0
- {qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase_python_commons.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qase-python-commons
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.2b3
|
|
4
4
|
Summary: A library for Qase TestOps and Qase Report
|
|
5
5
|
Author-email: Qase Team <support@qase.io>
|
|
6
6
|
Project-URL: Homepage, https://github.com/qase-tms/qase-python/tree/master/qase-python-commons
|
|
@@ -23,6 +23,7 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
Requires-Dist: certifi>=2024.2.2
|
|
24
24
|
Requires-Dist: attrs>=23.2.0
|
|
25
25
|
Requires-Dist: qase-api-client~=1.0.0b2
|
|
26
|
+
Requires-Dist: qase-api-v2-client~=1.0.0b2
|
|
26
27
|
Requires-Dist: more_itertools
|
|
27
28
|
Provides-Extra: testing
|
|
28
29
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "qase-python-commons"
|
|
7
|
-
version = "3.0.
|
|
7
|
+
version = "3.0.2b3"
|
|
8
8
|
description = "A library for Qase TestOps and Qase Report"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{name = "Qase Team", email = "support@qase.io"}]
|
|
@@ -31,6 +31,7 @@ dependencies = [
|
|
|
31
31
|
"certifi>=2024.2.2",
|
|
32
32
|
"attrs>=23.2.0",
|
|
33
33
|
"qase-api-client~=1.0.0b2",
|
|
34
|
+
"qase-api-v2-client~=1.0.0b2",
|
|
34
35
|
"more_itertools"
|
|
35
36
|
]
|
|
36
37
|
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/client/api_v1_client.py
RENAMED
|
@@ -120,7 +120,7 @@ class ApiV1Client(BaseApiClient):
|
|
|
120
120
|
return True
|
|
121
121
|
return False
|
|
122
122
|
|
|
123
|
-
def send_results(self, project_code: str, run_id:
|
|
123
|
+
def send_results(self, project_code: str, run_id: str, results: []) -> None:
|
|
124
124
|
api_results = ResultsApi(self.client)
|
|
125
125
|
results_to_send = [self._prepare_result(project_code, result) for result in results]
|
|
126
126
|
self.logger.log_debug(f"Sending results for run {run_id}: {results_to_send}")
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from typing import Dict
|
|
2
|
+
|
|
3
|
+
import certifi
|
|
4
|
+
from qase.api_client_v2 import ResultsApi
|
|
5
|
+
from qase.api_client_v2.api_client import ApiClient
|
|
6
|
+
from qase.api_client_v2.configuration import Configuration
|
|
7
|
+
from qase.api_client_v2.models.create_results_request_v2 import CreateResultsRequestV2
|
|
8
|
+
from qase.api_client_v2.models.relation_suite import RelationSuite
|
|
9
|
+
from qase.api_client_v2.models.relation_suite_item import RelationSuiteItem
|
|
10
|
+
from qase.api_client_v2.models.result_create import ResultCreate
|
|
11
|
+
from qase.api_client_v2.models.result_execution import ResultExecution
|
|
12
|
+
from qase.api_client_v2.models.result_relations import ResultRelations
|
|
13
|
+
from qase.api_client_v2.models.result_step_status import ResultStepStatus
|
|
14
|
+
from qase.api_client_v2.models.result_steps_type import ResultStepsType
|
|
15
|
+
|
|
16
|
+
from .api_v1_client import ApiV1Client
|
|
17
|
+
from .. import ConfigManager, Logger
|
|
18
|
+
from ..exceptions.reporter import ReporterException
|
|
19
|
+
from ..models import Attachment, Result
|
|
20
|
+
from ..models.step import StepType, Step
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ApiV2Client(ApiV1Client):
|
|
24
|
+
def __init__(self, config: ConfigManager, logger: Logger):
|
|
25
|
+
ApiV1Client.__init__(self, config, logger)
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
self.logger.log_debug("Preparing API V2 client")
|
|
29
|
+
configuration = Configuration()
|
|
30
|
+
configuration.api_key['TokenAuth'] = self.config.get('testops.api.token')
|
|
31
|
+
configuration.ssl_ca_cert = certifi.where()
|
|
32
|
+
host = self.config.get('testops.api.host', 'qase.io')
|
|
33
|
+
if self.config.get('testops.api.enterprise', False, bool):
|
|
34
|
+
configuration.host = f'https://api-{host}/v2'
|
|
35
|
+
else:
|
|
36
|
+
configuration.host = f'https://api.{host}/v2'
|
|
37
|
+
|
|
38
|
+
self.client_v2 = ApiClient(configuration)
|
|
39
|
+
self.logger.log_debug("API V2 client prepared")
|
|
40
|
+
except Exception as e:
|
|
41
|
+
self.logger.log(f"Error at preparing API V2 client: {e}", "error")
|
|
42
|
+
raise ReporterException(e)
|
|
43
|
+
|
|
44
|
+
def send_results(self, project_code: str, run_id: str, results: []) -> None:
|
|
45
|
+
api_results = ResultsApi(self.client_v2)
|
|
46
|
+
results_to_send = [self._prepare_result(project_code, result) for result in results]
|
|
47
|
+
self.logger.log_debug(f"Sending results for run {run_id}: {results_to_send}")
|
|
48
|
+
api_results.create_results_v2(project_code, run_id,
|
|
49
|
+
create_results_request_v2=CreateResultsRequestV2(results=results_to_send))
|
|
50
|
+
self.logger.log_debug(f"Results for run {run_id} sent successfully")
|
|
51
|
+
|
|
52
|
+
def _prepare_result(self, project_code: str, result: Result) -> ResultCreate:
|
|
53
|
+
attached = []
|
|
54
|
+
if result.attachments:
|
|
55
|
+
for attachment in result.attachments:
|
|
56
|
+
attached.extend(self._upload_attachment(project_code, attachment))
|
|
57
|
+
|
|
58
|
+
steps = []
|
|
59
|
+
for step in result.steps:
|
|
60
|
+
prepared = self._prepare_step(project_code, step)
|
|
61
|
+
steps.append(prepared)
|
|
62
|
+
|
|
63
|
+
for key, param in result.params.items():
|
|
64
|
+
# Hack to match old TestOps API
|
|
65
|
+
if param == "":
|
|
66
|
+
result.params[key] = "empty"
|
|
67
|
+
|
|
68
|
+
result_model_v2 = ResultCreate(
|
|
69
|
+
title=result.get_title(),
|
|
70
|
+
signature=result.signature,
|
|
71
|
+
testops_id=result.get_testops_id(),
|
|
72
|
+
execution=ResultExecution(start_time=result.execution.start_time, end_time=result.execution.end_time,
|
|
73
|
+
status=result.execution.status, duration=result.execution.duration,
|
|
74
|
+
stacktrace=result.execution.stacktrace, thread=result.execution.thread),
|
|
75
|
+
fields=result.fields,
|
|
76
|
+
attachments=[attach.hash for attach in attached],
|
|
77
|
+
steps=steps,
|
|
78
|
+
step_type=ResultStepsType.CLASSIC,
|
|
79
|
+
params=result.params,
|
|
80
|
+
muted=False,
|
|
81
|
+
message=result.message,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if result.get_suite_title():
|
|
85
|
+
data = []
|
|
86
|
+
|
|
87
|
+
for suite in result.get_suite_title().split("."):
|
|
88
|
+
data.append(RelationSuiteItem(title=suite))
|
|
89
|
+
|
|
90
|
+
result_model_v2.relations = ResultRelations(suite=RelationSuite(data=data))
|
|
91
|
+
|
|
92
|
+
self.logger.log_debug(f"Prepared result: {result_model_v2.to_json()}")
|
|
93
|
+
|
|
94
|
+
return result_model_v2
|
|
95
|
+
|
|
96
|
+
def _prepare_step(self, project_code: str, step: Step) -> Dict:
|
|
97
|
+
prepared_children = []
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
prepared_step = {'execution': {}, 'data': {}, 'steps': []}
|
|
101
|
+
prepared_step['execution']['status'] = ResultStepStatus(step.execution.status)
|
|
102
|
+
prepared_step['execution']['duration'] = step.execution.duration
|
|
103
|
+
|
|
104
|
+
if step.step_type == StepType.TEXT:
|
|
105
|
+
prepared_step['data']['action'] = step.data.action
|
|
106
|
+
if step.data.expected_result:
|
|
107
|
+
prepared_step['data']['expected_result'] = step.data.expected_result
|
|
108
|
+
|
|
109
|
+
if step.step_type == StepType.REQUEST:
|
|
110
|
+
prepared_step['data']['action'] = step.data.request_method + " " + step.data.request_url
|
|
111
|
+
|
|
112
|
+
if step.data.request_body:
|
|
113
|
+
step.attachments.append(
|
|
114
|
+
Attachment(file_name='request_body.txt', content=step.data.request_body, mime_type='text/plain',
|
|
115
|
+
temporary=True))
|
|
116
|
+
if step.data.request_headers:
|
|
117
|
+
step.attachments.append(
|
|
118
|
+
Attachment(file_name='request_headers.txt', content=step.data.request_headers,
|
|
119
|
+
mime_type='text/plain', temporary=True))
|
|
120
|
+
if step.data.response_body:
|
|
121
|
+
step.attachments.append(Attachment(file_name='response_body.txt', content=step.data.response_body,
|
|
122
|
+
mime_type='text/plain', temporary=True))
|
|
123
|
+
if step.data.response_headers:
|
|
124
|
+
step.attachments.append(
|
|
125
|
+
Attachment(file_name='response_headers.txt', content=step.data.response_headers,
|
|
126
|
+
mime_type='text/plain', temporary=True))
|
|
127
|
+
|
|
128
|
+
if step.step_type == StepType.GHERKIN:
|
|
129
|
+
prepared_step['data']['action'] = step.data.keyword
|
|
130
|
+
|
|
131
|
+
if step.step_type == StepType.SLEEP:
|
|
132
|
+
prepared_step['data']['action'] = f"Sleep for {step.data.duration} seconds"
|
|
133
|
+
|
|
134
|
+
if step.attachments:
|
|
135
|
+
uploaded_attachments = []
|
|
136
|
+
for file in step.attachments:
|
|
137
|
+
uploaded_attachments.extend(self._upload_attachment(project_code, file))
|
|
138
|
+
|
|
139
|
+
prepared_step['execution']['attachments'] = [attach.hash for attach in uploaded_attachments]
|
|
140
|
+
|
|
141
|
+
if step.steps:
|
|
142
|
+
for substep in step.steps:
|
|
143
|
+
prepared_children.append(self._prepare_step(project_code, substep))
|
|
144
|
+
prepared_step['steps'] = prepared_children
|
|
145
|
+
return prepared_step
|
|
146
|
+
except Exception as e:
|
|
147
|
+
self.logger.log(f"Error at preparing step: {e}", "error")
|
|
148
|
+
raise ReporterException(e)
|
|
@@ -53,7 +53,7 @@ class BaseApiClient(abc.ABC):
|
|
|
53
53
|
|
|
54
54
|
@abc.abstractmethod
|
|
55
55
|
def create_test_run(self, project_code: str, title: str, description: str, plan_id=None,
|
|
56
|
-
environment_id=None) ->
|
|
56
|
+
environment_id=None) -> str:
|
|
57
57
|
"""
|
|
58
58
|
Create a test run in Qase TestOps
|
|
59
59
|
|
|
@@ -67,7 +67,7 @@ class BaseApiClient(abc.ABC):
|
|
|
67
67
|
pass
|
|
68
68
|
|
|
69
69
|
@abc.abstractmethod
|
|
70
|
-
def check_test_run(self, project_code: str, run_id:
|
|
70
|
+
def check_test_run(self, project_code: str, run_id: str) -> bool:
|
|
71
71
|
"""
|
|
72
72
|
Check if test run exists in Qase TestOps
|
|
73
73
|
:param project_code: project code
|
|
@@ -77,7 +77,7 @@ class BaseApiClient(abc.ABC):
|
|
|
77
77
|
pass
|
|
78
78
|
|
|
79
79
|
@abc.abstractmethod
|
|
80
|
-
def send_results(self, project_code: str, run_id:
|
|
80
|
+
def send_results(self, project_code: str, run_id: str, results: []) -> None:
|
|
81
81
|
"""
|
|
82
82
|
Send test results to Qase TestOps
|
|
83
83
|
:param project_code: project code
|
|
@@ -13,7 +13,9 @@ class ConfigManager:
|
|
|
13
13
|
try:
|
|
14
14
|
if os.path.exists(config_file):
|
|
15
15
|
with open(config_file, "r") as file:
|
|
16
|
-
|
|
16
|
+
def transform_keys(obj):
|
|
17
|
+
return {k.lower(): v for k, v in obj.items()}
|
|
18
|
+
self.config = json.load(file, object_hook=transform_keys)
|
|
17
19
|
except Exception as e:
|
|
18
20
|
self.logger.log("Failed to load config from file", "error")
|
|
19
21
|
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/testops.py
RENAMED
|
@@ -65,6 +65,9 @@ class QaseTestOps:
|
|
|
65
65
|
self.client.get_project(self.project_code)
|
|
66
66
|
|
|
67
67
|
def _prepare_client(self) -> BaseApiClient:
|
|
68
|
+
if self.config.get('testops.usev2', False, bool):
|
|
69
|
+
from ..client.api_v2_client import ApiV2Client
|
|
70
|
+
return ApiV2Client(self.config, self.logger)
|
|
68
71
|
return ApiV1Client(self.config, self.logger)
|
|
69
72
|
|
|
70
73
|
def _send_results_threaded(self, results):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qase-python-commons
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.2b3
|
|
4
4
|
Summary: A library for Qase TestOps and Qase Report
|
|
5
5
|
Author-email: Qase Team <support@qase.io>
|
|
6
6
|
Project-URL: Homepage, https://github.com/qase-tms/qase-python/tree/master/qase-python-commons
|
|
@@ -23,6 +23,7 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
Requires-Dist: certifi>=2024.2.2
|
|
24
24
|
Requires-Dist: attrs>=23.2.0
|
|
25
25
|
Requires-Dist: qase-api-client~=1.0.0b2
|
|
26
|
+
Requires-Dist: qase-api-v2-client~=1.0.0b2
|
|
26
27
|
Requires-Dist: more_itertools
|
|
27
28
|
Provides-Extra: testing
|
|
28
29
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -6,6 +6,7 @@ src/qase/commons/loader.py
|
|
|
6
6
|
src/qase/commons/logger.py
|
|
7
7
|
src/qase/commons/utils.py
|
|
8
8
|
src/qase/commons/client/api_v1_client.py
|
|
9
|
+
src/qase/commons/client/api_v2_client.py
|
|
9
10
|
src/qase/commons/client/base_api_client.py
|
|
10
11
|
src/qase/commons/exceptions/reporter.py
|
|
11
12
|
src/qase/commons/models/__init__.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/exceptions/reporter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/__init__.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/attachment.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/basemodel.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/relation.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/result.py
RENAMED
|
File without changes
|
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/runtime.py
RENAMED
|
File without changes
|
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/models/suite.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/__init__.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/db.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/network.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/profilers/sleep.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/__init__.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/core.py
RENAMED
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/reporters/report.py
RENAMED
|
File without changes
|
|
File without changes
|
{qase_python_commons-3.0.2b2 → qase_python_commons-3.0.2b3}/src/qase/commons/validators/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|