testhide-pytest-plugin 0.2.0__tar.gz → 0.2.2__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.
- {testhide_pytest_plugin-0.2.0/src/testhide_pytest_plugin.egg-info → testhide_pytest_plugin-0.2.2}/PKG-INFO +23 -2
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/README.md +22 -1
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/pyproject.toml +1 -1
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_plugin/plugin.py +61 -27
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2/src/testhide_pytest_plugin.egg-info}/PKG-INFO +23 -2
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/LICENSE +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/setup.cfg +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_plugin/__init__.py +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_plugin/hookspecs.py +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_pytest_plugin.egg-info/SOURCES.txt +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_pytest_plugin.egg-info/dependency_links.txt +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_pytest_plugin.egg-info/entry_points.txt +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_pytest_plugin.egg-info/requires.txt +0 -0
- {testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_pytest_plugin.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testhide-pytest-plugin
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A pytest plugin for creating incremental XML test reports for Testhide system.
|
|
5
5
|
Author-email: Mykola Kovhanko <thuesdays@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -76,7 +76,10 @@ pytest --reruns 5 --report-xml=junittests.xml
|
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
## JIRA Integration
|
|
79
|
-
|
|
79
|
+
The plugin can automatically enrich failure reports with information from JIRA, linking test failures to known bugs and their statuses. There are two ways to configure this integration.
|
|
80
|
+
|
|
81
|
+
### Method 1: Command-Line Arguments
|
|
82
|
+
You can enable JIRA integration by providing the connection details as command-line options. The integration is activated automatically when all three parameters are present.
|
|
80
83
|
|
|
81
84
|
* **--jira-url**: The URL of your JIRA instance.
|
|
82
85
|
* **--jira-username**: The username for the connection.
|
|
@@ -88,6 +91,24 @@ pytest --report-xml=junittests.xml \
|
|
|
88
91
|
--jira-password="your-api-token"
|
|
89
92
|
```
|
|
90
93
|
|
|
94
|
+
### Method 2: Programmatic Configuration (for Frameworks)
|
|
95
|
+
If you are developing a test framework plugin and manage credentials in a central configuration object (e.g., a YAML file), you can programmatically set the JIRA options. This avoids exposing credentials in CI scripts.
|
|
96
|
+
Use the `pytest_cmdline_main` hook in your own plugin to set the configuration options before the `testhide-plugin` is configured.
|
|
97
|
+
```python
|
|
98
|
+
import pytest
|
|
99
|
+
|
|
100
|
+
class MyFrameworkPlugin:
|
|
101
|
+
@pytest.hookimpl(tryfirst=True)
|
|
102
|
+
def pytest_cmdline_main(self, config):
|
|
103
|
+
# Assuming ConfigApp loads your central configuration
|
|
104
|
+
# from a file or environment variables.
|
|
105
|
+
from my_framework.config import ConfigApp
|
|
106
|
+
|
|
107
|
+
config.option.jira_url = ConfigApp.jira.url
|
|
108
|
+
config.option.jira_username = ConfigApp.jira.username
|
|
109
|
+
config.option.jira_password = ConfigApp.jira.password
|
|
110
|
+
```
|
|
111
|
+
|
|
91
112
|
## Extending the Plugin (For Framework Developers)
|
|
92
113
|
`testhide-pytest-plugin` provides custom hooks for integration with your own plugins, allowing you to inject project-specific metadata into the report.
|
|
93
114
|
|
|
@@ -37,7 +37,10 @@ pytest --reruns 5 --report-xml=junittests.xml
|
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## JIRA Integration
|
|
40
|
-
|
|
40
|
+
The plugin can automatically enrich failure reports with information from JIRA, linking test failures to known bugs and their statuses. There are two ways to configure this integration.
|
|
41
|
+
|
|
42
|
+
### Method 1: Command-Line Arguments
|
|
43
|
+
You can enable JIRA integration by providing the connection details as command-line options. The integration is activated automatically when all three parameters are present.
|
|
41
44
|
|
|
42
45
|
* **--jira-url**: The URL of your JIRA instance.
|
|
43
46
|
* **--jira-username**: The username for the connection.
|
|
@@ -49,6 +52,24 @@ pytest --report-xml=junittests.xml \
|
|
|
49
52
|
--jira-password="your-api-token"
|
|
50
53
|
```
|
|
51
54
|
|
|
55
|
+
### Method 2: Programmatic Configuration (for Frameworks)
|
|
56
|
+
If you are developing a test framework plugin and manage credentials in a central configuration object (e.g., a YAML file), you can programmatically set the JIRA options. This avoids exposing credentials in CI scripts.
|
|
57
|
+
Use the `pytest_cmdline_main` hook in your own plugin to set the configuration options before the `testhide-plugin` is configured.
|
|
58
|
+
```python
|
|
59
|
+
import pytest
|
|
60
|
+
|
|
61
|
+
class MyFrameworkPlugin:
|
|
62
|
+
@pytest.hookimpl(tryfirst=True)
|
|
63
|
+
def pytest_cmdline_main(self, config):
|
|
64
|
+
# Assuming ConfigApp loads your central configuration
|
|
65
|
+
# from a file or environment variables.
|
|
66
|
+
from my_framework.config import ConfigApp
|
|
67
|
+
|
|
68
|
+
config.option.jira_url = ConfigApp.jira.url
|
|
69
|
+
config.option.jira_username = ConfigApp.jira.username
|
|
70
|
+
config.option.jira_password = ConfigApp.jira.password
|
|
71
|
+
```
|
|
72
|
+
|
|
52
73
|
## Extending the Plugin (For Framework Developers)
|
|
53
74
|
`testhide-pytest-plugin` provides custom hooks for integration with your own plugins, allowing you to inject project-specific metadata into the report.
|
|
54
75
|
|
|
@@ -67,7 +67,7 @@ class TesthidePlugin:
|
|
|
67
67
|
self.report_xml_path = config.option.report_xml
|
|
68
68
|
self.temp_dir = os.path.join(str(config.rootdir), f".{os.path.basename(self.report_xml_path)}_temp")
|
|
69
69
|
self.is_xdist_master = not hasattr(config, "workerinput")
|
|
70
|
-
self.is_xdist_run = config.option
|
|
70
|
+
self.is_xdist_run = getattr(config.option, 'dist', 'no') != 'no'
|
|
71
71
|
self.rerun_counters = {}
|
|
72
72
|
self.test_reports = {}
|
|
73
73
|
|
|
@@ -152,7 +152,7 @@ class TesthidePlugin:
|
|
|
152
152
|
if summary not in "".join(final_trace_lines):
|
|
153
153
|
final_trace_lines.append(summary)
|
|
154
154
|
|
|
155
|
-
return "
|
|
155
|
+
return "".join(final_trace_lines)
|
|
156
156
|
else:
|
|
157
157
|
return summary
|
|
158
158
|
|
|
@@ -167,6 +167,21 @@ class TesthidePlugin:
|
|
|
167
167
|
|
|
168
168
|
if report.when in ('setup', 'call') and getattr(report, 'outcome', '') != 'rerun':
|
|
169
169
|
item._final_report = report
|
|
170
|
+
|
|
171
|
+
if call.when == 'call' and call.excinfo:
|
|
172
|
+
fail_message = str(call.excinfo.value)
|
|
173
|
+
try:
|
|
174
|
+
fail_id = '%s.%s.%s.%s' % \
|
|
175
|
+
(item.module.__name__,
|
|
176
|
+
item.cls.__name__ if item.cls
|
|
177
|
+
else item.module.__name__,
|
|
178
|
+
re.sub(r'\[.+\]$', '', item.name),
|
|
179
|
+
'%s(%s)' % (call.excinfo.typename, fail_message))
|
|
180
|
+
except AttributeError:
|
|
181
|
+
return
|
|
182
|
+
fail_id = fail_id.encode('utf-8')
|
|
183
|
+
fail_id = md5(fail_id).hexdigest()
|
|
184
|
+
item.fail_id = fail_id
|
|
170
185
|
|
|
171
186
|
@pytest.hookimpl(trylast=True)
|
|
172
187
|
def pytest_runtest_teardown(self, item):
|
|
@@ -178,19 +193,17 @@ class TesthidePlugin:
|
|
|
178
193
|
if not report:
|
|
179
194
|
return
|
|
180
195
|
|
|
181
|
-
filepath, line,
|
|
196
|
+
filepath, line, _ = report.location
|
|
197
|
+
name = item.originalname if hasattr(item, 'originalname') else item.name
|
|
198
|
+
name = name.split('[')[0]
|
|
182
199
|
classname_path = report.nodeid.split('::')
|
|
183
200
|
if len(classname_path) > 2:
|
|
184
201
|
classname = ".".join(classname_path[:-1]).replace('/', '.')
|
|
185
202
|
else:
|
|
186
203
|
classname = os.path.splitext(os.path.basename(filepath))[0]
|
|
187
204
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
'line': str(line), 'time': f"{report.duration:.3f}"
|
|
191
|
-
}
|
|
192
|
-
testcase = ET.Element('testcase', **testcase_attrs)
|
|
193
|
-
|
|
205
|
+
fail_id = getattr(item, 'fail_id', None)
|
|
206
|
+
test_resolution = 'Product Defect'
|
|
194
207
|
if report.failed:
|
|
195
208
|
tag = 'error' if report.when == 'setup' else 'failure'
|
|
196
209
|
failure_message = str(report.longrepr.reprcrash.message) if hasattr(report.longrepr, 'reprcrash') else str(
|
|
@@ -198,34 +211,55 @@ class TesthidePlugin:
|
|
|
198
211
|
|
|
199
212
|
if self.jira_enabled:
|
|
200
213
|
try:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
214
|
+
if fail_id:
|
|
215
|
+
issue = self._get_issue_by_test_id(fail_id)
|
|
216
|
+
if issue:
|
|
217
|
+
issue_text = issue.fields.summary
|
|
218
|
+
issue_type = issue.fields.issuetype.name
|
|
219
|
+
issue_id = issue.permalink()
|
|
220
|
+
status_name = issue.fields.status.name
|
|
221
|
+
if status_name in ('Verified', 'Closed'):
|
|
222
|
+
if hasattr(issue.fields, 'customfield_10020') and issue.fields.customfield_10020:
|
|
223
|
+
status = issue.fields.customfield_10020.value
|
|
224
|
+
if status_name == 'Verified' and status == 'Verified at Branch':
|
|
225
|
+
test_resolution = 'Verified at Branch'
|
|
226
|
+
else:
|
|
227
|
+
test_resolution = 'Need to reopen'
|
|
228
|
+
else:
|
|
229
|
+
test_resolution = 'Need to reopen'
|
|
230
|
+
elif status_name in ['Resolved', 'In Testing']:
|
|
231
|
+
test_resolution = 'Resolved in branch'
|
|
232
|
+
else:
|
|
233
|
+
test_resolution = 'Known issue'
|
|
234
|
+
failure_message = f'{test_resolution} {issue_id} {issue_type} [{issue_text}]'
|
|
219
235
|
except Exception as e:
|
|
220
236
|
self.config.warn('JIRA_MARKER_ERROR', f"JIRA marker failed: {e}")
|
|
221
237
|
|
|
238
|
+
testcase_attrs = {
|
|
239
|
+
'classname': classname, 'name': name, 'file': str(filepath),
|
|
240
|
+
'line': str(line), 'time': f"{report.duration:.3f}", "fail_id": fail_id, "test_resolution": test_resolution,
|
|
241
|
+
}
|
|
242
|
+
testcase = ET.Element('testcase', **testcase_attrs)
|
|
222
243
|
failure_element = ET.SubElement(testcase, tag, message=failure_message)
|
|
223
244
|
failure_element.text = self._get_cleaned_traceback(report)
|
|
224
245
|
|
|
225
246
|
elif report.skipped:
|
|
247
|
+
testcase_attrs = {
|
|
248
|
+
'classname': classname, 'name': name, 'file': str(filepath),
|
|
249
|
+
'line': str(line), 'time': f"{report.duration:.3f}", "fail_id": '',
|
|
250
|
+
"test_resolution": "Skipped",
|
|
251
|
+
}
|
|
252
|
+
testcase = ET.Element('testcase', **testcase_attrs)
|
|
226
253
|
skipped_attrs = {'type': 'pytest.skip', 'message': report.longrepr[2]}
|
|
227
254
|
ET.SubElement(testcase, 'skipped',
|
|
228
255
|
**skipped_attrs).text = f"{report.longrepr[0]}:{report.longrepr[1]}: {report.longrepr[2]}"
|
|
256
|
+
else:
|
|
257
|
+
testcase_attrs = {
|
|
258
|
+
'classname': classname, 'name': name, 'file': str(filepath),
|
|
259
|
+
'line': str(line), 'time': f"{report.duration:.3f}", "fail_id": '',
|
|
260
|
+
"test_resolution": "Passed",
|
|
261
|
+
}
|
|
262
|
+
testcase = ET.Element('testcase', **testcase_attrs)
|
|
229
263
|
|
|
230
264
|
all_properties = self.config.hook.pytest_testhide_get_test_case_properties(item=item, report=report)
|
|
231
265
|
flat_properties = [prop for sublist in all_properties for prop in sublist]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testhide-pytest-plugin
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A pytest plugin for creating incremental XML test reports for Testhide system.
|
|
5
5
|
Author-email: Mykola Kovhanko <thuesdays@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -76,7 +76,10 @@ pytest --reruns 5 --report-xml=junittests.xml
|
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
## JIRA Integration
|
|
79
|
-
|
|
79
|
+
The plugin can automatically enrich failure reports with information from JIRA, linking test failures to known bugs and their statuses. There are two ways to configure this integration.
|
|
80
|
+
|
|
81
|
+
### Method 1: Command-Line Arguments
|
|
82
|
+
You can enable JIRA integration by providing the connection details as command-line options. The integration is activated automatically when all three parameters are present.
|
|
80
83
|
|
|
81
84
|
* **--jira-url**: The URL of your JIRA instance.
|
|
82
85
|
* **--jira-username**: The username for the connection.
|
|
@@ -88,6 +91,24 @@ pytest --report-xml=junittests.xml \
|
|
|
88
91
|
--jira-password="your-api-token"
|
|
89
92
|
```
|
|
90
93
|
|
|
94
|
+
### Method 2: Programmatic Configuration (for Frameworks)
|
|
95
|
+
If you are developing a test framework plugin and manage credentials in a central configuration object (e.g., a YAML file), you can programmatically set the JIRA options. This avoids exposing credentials in CI scripts.
|
|
96
|
+
Use the `pytest_cmdline_main` hook in your own plugin to set the configuration options before the `testhide-plugin` is configured.
|
|
97
|
+
```python
|
|
98
|
+
import pytest
|
|
99
|
+
|
|
100
|
+
class MyFrameworkPlugin:
|
|
101
|
+
@pytest.hookimpl(tryfirst=True)
|
|
102
|
+
def pytest_cmdline_main(self, config):
|
|
103
|
+
# Assuming ConfigApp loads your central configuration
|
|
104
|
+
# from a file or environment variables.
|
|
105
|
+
from my_framework.config import ConfigApp
|
|
106
|
+
|
|
107
|
+
config.option.jira_url = ConfigApp.jira.url
|
|
108
|
+
config.option.jira_username = ConfigApp.jira.username
|
|
109
|
+
config.option.jira_password = ConfigApp.jira.password
|
|
110
|
+
```
|
|
111
|
+
|
|
91
112
|
## Extending the Plugin (For Framework Developers)
|
|
92
113
|
`testhide-pytest-plugin` provides custom hooks for integration with your own plugins, allowing you to inject project-specific metadata into the report.
|
|
93
114
|
|
|
File without changes
|
|
File without changes
|
{testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_plugin/__init__.py
RENAMED
|
File without changes
|
{testhide_pytest_plugin-0.2.0 → testhide_pytest_plugin-0.2.2}/src/testhide_plugin/hookspecs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|