Coverage for src/pytest_xray/plugin.py: 96.0%
75 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 14:00 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 14:00 +0000
1# Modified in the parameter-details prototype; see NOTICE.
2import os
3from pathlib import Path
4from typing import Union
6import pytest
7from requests.auth import AuthBase
9from pytest_xray import hooks
10from pytest_xray.case_report import CaseReportPlugin
11from pytest_xray.comment_limits import DEFAULT_COMMENT_LIMIT
12from pytest_xray.constant import (
13 JIRA_API_KEY,
14 JIRA_CLIENT_SECRET_AUTH,
15 JIRA_CLOUD,
16 JIRA_XRAY_FLAG,
17 TEST_EXECUTION_ENDPOINT,
18 TEST_EXECUTION_ENDPOINT_CLOUD,
19 XRAY_ADD_CAPTURES,
20 XRAY_ALLOW_DUPLICATE_IDS,
21 XRAY_EXECUTION_ID,
22 XRAY_PLUGIN,
23 XRAY_TEST_PLAN_ID,
24 XRAYPATH,
25)
26from pytest_xray.file_publisher import FilePublisher
27from pytest_xray.helper import get_api_key_auth, get_basic_auth, get_bearer_auth
28from pytest_xray.xray_plugin import Publisher, XrayPlugin
29from pytest_xray.xray_publisher import ApiKeyAuth, ClientSecretAuth, XrayPublisher
32def pytest_addoption(parser: pytest.Parser) -> None:
33 xray = parser.getgroup('Jira Xray report')
34 xray.addoption(
35 '--xray-comment-limit',
36 type=int,
37 default=DEFAULT_COMMENT_LIMIT,
38 help='Maximum UTF-8 bytes per exported comment (default: 32000; minimum: 256)',
39 )
40 xray.addoption(
41 '--xray-full-report',
42 metavar='path',
43 default=None,
44 help='Retain complete legacy Xray JSON locally before bounding comments',
45 )
46 xray.addoption(
47 '--xray-case-report',
48 metavar='path',
49 default=None,
50 help='Write a transport-independent offline JSON case report',
51 )
52 xray.addoption(
53 '--xray-case-values',
54 action='store_true',
55 default=False,
56 help='Opt in to potentially sensitive scalar values in the offline case report',
57 )
58 xray.addoption(
59 '--xray-case-redact-identities',
60 action='store_true',
61 default=False,
62 help='Replace offline node and parameter IDs with per-run opaque aliases',
63 )
64 xray.addoption(
65 '--xray-parameter-details',
66 action='store_true',
67 default=False,
68 help='Include parameter case identity, values and phase outcomes in test run comments',
69 )
70 xray.addoption(JIRA_XRAY_FLAG, action='store_true', default=False, help='Upload test results to JIRA XRAY')
71 xray.addoption(JIRA_CLOUD, action='store_true', default=False, help='Use with JIRA XRAY cloud server')
72 xray.addoption(
73 JIRA_API_KEY,
74 action='store_true',
75 default=False,
76 help='Use Jira API Key authentication',
77 )
78 xray.addoption(
79 JIRA_CLIENT_SECRET_AUTH,
80 action='store_true',
81 default=False,
82 help='Use client secret authentication',
83 )
84 xray.addoption(
85 XRAY_EXECUTION_ID, action='store', metavar='ExecutionId', default=None, help='XRAY Test Execution ID'
86 )
87 xray.addoption(XRAY_TEST_PLAN_ID, action='store', metavar='TestplanId', default=None, help='XRAY Test Plan ID')
88 xray.addoption(
89 XRAYPATH,
90 action='store',
91 metavar='path',
92 default=None,
93 help='Do not upload to a server but create JSON report file at given path',
94 )
95 xray.addoption(
96 XRAY_ALLOW_DUPLICATE_IDS,
97 action='store_true',
98 default=False,
99 help='Allow test ids to be present on multiple pytest tests',
100 )
101 xray.addoption(
102 XRAY_ADD_CAPTURES,
103 action='store_true',
104 default=False,
105 help='Add captures from log, stdout or/and stderr, to the report comment field',
106 )
109def pytest_addhooks(pluginmanager):
110 pluginmanager.add_hookspecs(hooks)
113def pytest_configure(config: pytest.Config) -> None:
114 config.addinivalue_line('markers', 'xray(JIRA_ID): mark test with JIRA XRAY test case ID')
115 if config.option.collectonly:
116 return
118 full_path = config.getoption('--xray-full-report')
119 if config.getoption('--xray-comment-limit') < 256:
120 raise pytest.UsageError('--xray-comment-limit must be at least 256 bytes')
121 if full_path and not config.getoption(JIRA_XRAY_FLAG):
122 raise pytest.UsageError('--xray-full-report requires --jira-xray')
123 paths = [(config.getoption('--xray-case-report'), False), (config.getoption(XRAYPATH), True), (full_path, True)]
124 normalized = [Path(os.path.expandvars(p) if expand else p).expanduser().resolve() for p, expand in paths if p]
125 if len(set(normalized)) != len(normalized):
126 raise pytest.UsageError('Report paths must be different: --xray-case-report, --xraypath, --xray-full-report')
127 case_path = config.getoption('--xray-case-report')
128 redact_ids = config.getoption('--xray-case-redact-identities')
129 if redact_ids and not case_path: 129 ↛ 130line 129 didn't jump to line 130 because the condition on line 129 was never true
130 raise pytest.UsageError('--xray-case-redact-identities requires --xray-case-report')
131 if redact_ids and config.getoption('--xray-case-values'):
132 raise pytest.UsageError('--xray-case-redact-identities cannot be combined with --xray-case-values')
133 if config.getoption('--xray-case-values') and not case_path:
134 raise pytest.UsageError('--xray-case-values requires --xray-case-report')
135 if case_path:
136 xray_path = config.getoption(XRAYPATH)
137 if ( 137 ↛ 141line 137 didn't jump to line 141 because the condition on line 137 was never true
138 xray_path
139 and Path(case_path).expanduser().resolve() == Path(os.path.expandvars(xray_path)).expanduser().resolve()
140 ):
141 raise pytest.UsageError('--xray-case-report and --xraypath must use different files')
142 config.pluginmanager.register(
143 CaseReportPlugin(config, case_path, config.getoption('--xray-case-values'), redact_ids),
144 name='xray-offline-cases',
145 )
147 if not config.getoption(JIRA_XRAY_FLAG):
148 return
150 xray_path = config.getoption(XRAYPATH)
152 if xray_path:
153 publisher: Publisher = FilePublisher(xray_path)
154 else:
155 endpoint = TEST_EXECUTION_ENDPOINT_CLOUD if config.getoption(JIRA_CLOUD) else TEST_EXECUTION_ENDPOINT
157 if config.getoption(JIRA_CLIENT_SECRET_AUTH):
158 options = get_bearer_auth()
159 auth: Union[AuthBase, tuple[str, str]] = ClientSecretAuth(
160 options['BASE_URL'], options['CLIENT_ID'], options['CLIENT_SECRET'], options['VERIFY']
161 )
162 elif config.getoption(JIRA_API_KEY):
163 options = get_api_key_auth()
164 auth = ApiKeyAuth(options['API_KEY'])
165 else:
166 options = get_basic_auth()
167 auth = (options['USER'], options['PASSWORD'])
169 publisher = XrayPublisher(base_url=options['BASE_URL'], endpoint=endpoint, auth=auth, verify=options['VERIFY'])
171 plugin = XrayPlugin(config, publisher)
172 config.pluginmanager.register(plugin=plugin, name=XRAY_PLUGIN)