Skip to content

Commit 2a4e78c

Browse files
authored
Merge pull request #380 from reportportal/develop
Release
2 parents 6dfe010 + dcb1782 commit 2a4e78c

File tree

6 files changed

+115
-44
lines changed

6 files changed

+115
-44
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44
### Fixed
5+
- Issue [#379](https://github.com/reportportal/agent-python-pytest/issues/379): Fix TypeError when using pytest.skip() in fixtures, by @HardNorth
6+
7+
## [5.4.4]
8+
### Fixed
59
- Issue [#375](https://github.com/reportportal/agent-python-pytest/issues/375): Fix max Item name length, by @HardNorth
610

711
## [5.4.3]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright 2024 EPAM Systems
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
17+
18+
@pytest.fixture(scope="session")
19+
def base_fixture():
20+
return False
21+
22+
23+
@pytest.fixture()
24+
def skip_fixture(base_fixture):
25+
if not base_fixture:
26+
pytest.skip("Skip if base condition is false")
27+
28+
29+
def test_will_skip(skip_fixture):
30+
pass

pytest_reportportal/plugin.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -295,21 +295,32 @@ def pytest_runtest_makereport(item: Item) -> None:
295295
service.process_results(item, report)
296296

297297

298-
def report_fixture(request, name: str, error_msg: str) -> None:
298+
def report_fixture(request, fixturedef, name: str, error_msg: str) -> None:
299299
"""Report fixture setup and teardown.
300300
301301
:param request: Object of the FixtureRequest class
302+
:param fixturedef: represents definition of the texture class
302303
:param name: Name of the fixture
303304
:param error_msg: Error message
304305
"""
305306
config = request.config
306307
enabled = getattr(config, '_rp_enabled', False)
307-
agent_config = getattr(config, '_reporter_config', None)
308308
service = getattr(config, 'py_test_service', None)
309-
if not enabled or not agent_config.rp_report_fixtures or not service:
309+
agent_config = getattr(config, '_reporter_config', object())
310+
report_fixtures = getattr(agent_config, 'rp_report_fixtures', False)
311+
if not enabled or not service or not report_fixtures:
310312
yield
311313
return
312314

315+
cached_result = getattr(fixturedef, 'cached_result', None)
316+
if cached_result and hasattr(cached_result, '__getitem__'):
317+
result = fixturedef.cached_result[2]
318+
if hasattr(result, '__getitem__'):
319+
result = result[0]
320+
if result and isinstance(result, BaseException):
321+
yield
322+
return
323+
313324
yield from service.report_fixture(name, error_msg)
314325

315326

@@ -322,7 +333,7 @@ def pytest_fixture_setup(fixturedef, request) -> None:
322333
:param request: represents fixture execution metadata
323334
"""
324335
yield from report_fixture(
325-
request, f'{fixturedef.scope} fixture setup: {fixturedef.argname}',
336+
request, fixturedef, f'{fixturedef.scope} fixture setup: {fixturedef.argname}',
326337
f'{fixturedef.scope} fixture setup failed: {fixturedef.argname}')
327338

328339

@@ -334,15 +345,8 @@ def pytest_fixture_post_finalizer(fixturedef, request) -> None:
334345
:param fixturedef: represents definition of the texture class
335346
:param request: represents fixture execution metadata
336347
"""
337-
cached_result = getattr(fixturedef, 'cached_result', None)
338-
if cached_result and cached_result[2]:
339-
exception = fixturedef.cached_result[2][0]
340-
if exception and isinstance(exception, BaseException):
341-
yield
342-
return
343-
344348
yield from report_fixture(
345-
request, f'{fixturedef.scope} fixture teardown: {fixturedef.argname}',
349+
request, fixturedef, f'{fixturedef.scope} fixture teardown: {fixturedef.argname}',
346350
f'{fixturedef.scope} fixture teardown failed: {fixturedef.argname}')
347351

348352

pytest_reportportal/service.py

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
get_package_version
5151
)
5252

53-
log = logging.getLogger(__name__)
53+
LOGGER = logging.getLogger(__name__)
5454

5555
MAX_ITEM_NAME_LENGTH: int = 1024
5656
TRUNCATION_STR: str = '...'
@@ -204,9 +204,9 @@ def start_launch(self) -> Optional[str]:
204204
:return: item ID
205205
"""
206206
sl_pt = self._build_start_launch_rq()
207-
log.debug('ReportPortal - Start launch: request_body=%s', sl_pt)
207+
LOGGER.debug('ReportPortal - Start launch: request_body=%s', sl_pt)
208208
self._launch_id = self.rp.start_launch(**sl_pt)
209-
log.debug('ReportPortal - Launch started: id=%s', self._launch_id)
209+
LOGGER.debug('ReportPortal - Launch started: id=%s', self._launch_id)
210210
return self._launch_id
211211

212212
def _get_item_dirs(self, item: Item) -> List[str]:
@@ -366,7 +366,7 @@ def _get_item_name(self, name: str) -> str:
366366
"""
367367
if len(name) > MAX_ITEM_NAME_LENGTH:
368368
name = name[:MAX_ITEM_NAME_LENGTH - len(TRUNCATION_STR)] + TRUNCATION_STR
369-
log.warning(PytestWarning(
369+
LOGGER.warning(PytestWarning(
370370
f'Test leaf ID was truncated to "{name}" because of name size constrains on Report Portal'))
371371
return name
372372

@@ -411,8 +411,7 @@ def _build_start_suite_rq(self, leaf):
411411
return payload
412412

413413
def _start_suite(self, suite_rq):
414-
log.debug('ReportPortal - Start Suite: request_body=%s',
415-
suite_rq)
414+
LOGGER.debug('ReportPortal - Start Suite: request_body=%s', suite_rq)
416415
return self.rp.start_test_item(**suite_rq)
417416

418417
def _create_suite(self, leaf):
@@ -655,7 +654,7 @@ def _build_start_step_rq(self, leaf):
655654
return payload
656655

657656
def _start_step(self, step_rq):
658-
log.debug('ReportPortal - Start TestItem: request_body=%s', step_rq)
657+
LOGGER.debug('ReportPortal - Start TestItem: request_body=%s', step_rq)
659658
return self.rp.start_test_item(**step_rq)
660659

661660
def __unique_id(self):
@@ -729,11 +728,11 @@ def _build_finish_step_rq(self, leaf):
729728
return payload
730729

731730
def _finish_step(self, finish_rq):
732-
log.debug('ReportPortal - Finish TestItem: request_body=%s', finish_rq)
731+
LOGGER.debug('ReportPortal - Finish TestItem: request_body=%s', finish_rq)
733732
self.rp.finish_test_item(**finish_rq)
734733

735734
def _finish_suite(self, finish_rq):
736-
log.debug('ReportPortal - End TestSuite: request_body=%s', finish_rq)
735+
LOGGER.debug('ReportPortal - End TestSuite: request_body=%s', finish_rq)
737736
self.rp.finish_test_item(**finish_rq)
738737

739738
def _build_finish_suite_rq(self, leaf):
@@ -815,7 +814,7 @@ def _build_finish_launch_rq(self):
815814
return finish_rq
816815

817816
def _finish_launch(self, finish_rq):
818-
log.debug('ReportPortal - Finish launch: request_body=%s', finish_rq)
817+
LOGGER.debug('ReportPortal - Finish launch: request_body=%s', finish_rq)
819818
self.rp.finish_launch(**finish_rq)
820819

821820
@check_rp_enabled
@@ -828,8 +827,19 @@ def finish_launch(self):
828827
# To finish launch session str parameter is needed
829828
self._finish_launch(self._build_finish_launch_rq())
830829

830+
def _build_log(self, item_id: str, message: str, log_level: str, attachment: Optional[Any] = None):
831+
sl_rq = {
832+
'item_id': item_id,
833+
'time': timestamp(),
834+
'message': message,
835+
'level': log_level,
836+
}
837+
if attachment:
838+
sl_rq['attachment'] = attachment
839+
return sl_rq
840+
831841
@check_rp_enabled
832-
def post_log(self, test_item, message, log_level='INFO', attachment=None):
842+
def post_log(self, test_item, message: str, log_level: str = 'INFO', attachment: Optional[Any] = None):
833843
"""
834844
Send a log message to the Report Portal.
835845
@@ -841,16 +851,11 @@ def post_log(self, test_item, message, log_level='INFO', attachment=None):
841851
:return: None
842852
"""
843853
if log_level not in self._log_levels:
844-
log.warning('Incorrect loglevel = %s. Force set to INFO. '
845-
'Available levels: %s.', log_level, self._log_levels)
854+
LOGGER.warning('Incorrect loglevel = %s. Force set to INFO. '
855+
'Available levels: %s.', log_level, self._log_levels)
846856
item_id = self._tree_path[test_item][-1]['item_id']
847-
sl_rq = {
848-
'item_id': item_id,
849-
'time': timestamp(),
850-
'message': message,
851-
'level': log_level,
852-
'attachment': attachment
853-
}
857+
858+
sl_rq = self._build_log(item_id, message, log_level, attachment)
854859
self.rp.log(**sl_rq)
855860

856861
def report_fixture(self, name: str, error_msg: str) -> None:
@@ -864,15 +869,15 @@ def report_fixture(self, name: str, error_msg: str) -> None:
864869

865870
try:
866871
outcome = yield
867-
if outcome.exception:
868-
log.error(error_msg)
869-
log.exception(outcome.exception)
870-
reporter.finish_nested_step(item_id, timestamp(), 'FAILED')
871-
else:
872-
reporter.finish_nested_step(item_id, timestamp(), 'PASSED')
872+
exception = outcome.exception
873+
status = 'PASSED'
874+
if exception:
875+
if type(exception).__name__ != 'Skipped':
876+
status = 'FAILED'
877+
reporter.finish_nested_step(item_id, timestamp(), status)
873878
except Exception as e:
874-
log.error('Failed to report fixture: %s', name)
875-
log.exception(e)
879+
LOGGER.error('Failed to report fixture: %s', name)
880+
LOGGER.exception(e)
876881
reporter.finish_nested_step(item_id, timestamp(), 'FAILED')
877882

878883
def start(self) -> None:
@@ -883,9 +888,9 @@ def start(self) -> None:
883888
self._config.rp_ignore_attributes or []
884889
).union({'parametrize'})
885890
)
886-
log.debug('ReportPortal - Init service: endpoint=%s, '
887-
'project=%s, api_key=%s', self._config.rp_endpoint,
888-
self._config.rp_project, self._config.rp_api_key)
891+
LOGGER.debug('ReportPortal - Init service: endpoint=%s, '
892+
'project=%s, api_key=%s', self._config.rp_endpoint,
893+
self._config.rp_project, self._config.rp_api_key)
889894
launch_id = self._launch_id
890895
if self._config.rp_launch_id:
891896
launch_id = self._config.rp_launch_id

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from setuptools import setup
1919

2020

21-
__version__ = '5.4.4'
21+
__version__ = '5.4.5'
2222

2323

2424
def read_file(fname):

tests/integration/test_fixtures.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
1415
import sys
1516
from collections import defaultdict
1617
from unittest import mock
@@ -522,3 +523,30 @@ def test_class_fixture_setup(mock_client_init):
522523
assert teardown_call_args[0] == teardown_step_name
523524
setup_call_kwargs = call_args[-1][1]
524525
assert not setup_call_kwargs['has_stats']
526+
527+
528+
@mock.patch(REPORT_PORTAL_SERVICE)
529+
def test_fixture_setup_skip(mock_client_init):
530+
mock_client = setup_mock_for_logging(mock_client_init)
531+
532+
test_path = 'examples/fixtures/test_fixture_skipped/test_fixture_skipped.py'
533+
run_tests(test_path, False)
534+
535+
call_args = mock_client.start_test_item.call_args_list
536+
setup_call_args = call_args[2][0]
537+
fixture_name = 'skip_fixture'
538+
step_name = f'function fixture setup: {fixture_name}'
539+
assert setup_call_args[0] == step_name
540+
541+
setup_call_kwargs = call_args[2][1]
542+
assert not setup_call_kwargs['has_stats']
543+
544+
log_count = mock_client.log.call_count
545+
assert log_count == 1, 'Incorrect number of "log" calls'
546+
547+
call_args = mock_client.finish_test_item.call_args_list
548+
finish_call_kwargs = call_args[1][1]
549+
assert finish_call_kwargs['status'] == 'PASSED'
550+
551+
finish_call_kwargs = call_args[-1][1]
552+
assert finish_call_kwargs['status'] == 'SKIPPED'

0 commit comments

Comments
 (0)