Skip to content

Commit 53adcc3

Browse files
author
Ivan Ivanou
committed
Fix reporting of an issue marker.
1 parent 32361bb commit 53adcc3

File tree

8 files changed

+175
-135
lines changed

8 files changed

+175
-135
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ stages:
55
language: python
66
python:
77
- "2.7"
8-
- "3.4"
98
- "3.5"
109
- "3.6"
10+
- "3.7"
11+
- "3.8"
1112
script:
1213
- python setup.py test
1314
- python setup.py -q install

pytest_reportportal/listener.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def _add_issue_info(self, item, report):
150150
(issue_type in getattr(self.PyTestService, 'issue_types', ())):
151151
if comment:
152152
self.issue['comment'] = comment
153-
self.issue['issue_type'] = self.PyTestService.issue_types[issue_type]
153+
self.issue['issueType'] = self.PyTestService.issue_types[issue_type]
154154
# self.issue['ignoreAnalyzer'] = True ???
155155
elif (report.when == 'setup') and report.skipped:
156-
self.issue['issue_type'] = 'NOT_ISSUE'
156+
self.issue['issueType'] = 'NOT_ISSUE'

pytest_reportportal/service.py

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -72,36 +72,57 @@ def __call__(cls, *args, **kwargs):
7272

7373

7474
class PyTestServiceClass(with_metaclass(Singleton, object)):
75+
"""Pytest service class for reporting test results to the Report Portal."""
7576

7677
def __init__(self):
78+
"""Initialize instance attributes."""
79+
self._agent_name = 'pytest-reportportal'
80+
self._errors = queue.Queue()
81+
self._hier_parts = {}
82+
self._issue_types = {}
83+
self._item_parts = {}
84+
self._loglevels = ('TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR')
85+
self.ignore_errors = True
86+
self.ignored_tags = []
87+
self.log_batch_size = 20
88+
self.log_item_id = None
89+
self.parent_item_id = None
7790
self.rp = None
7891
self.rp_supports_parameters = True
7992
try:
8093
pkg_resources.get_distribution('reportportal_client >= 3.2.0')
8194
except pkg_resources.VersionConflict:
8295
self.rp_supports_parameters = False
8396

84-
self.log_item_id = None
85-
self.parent_item_id = None
86-
87-
self.ignore_errors = True
88-
self.ignored_tags = []
89-
90-
self._errors = queue.Queue()
91-
self._loglevels = ('TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR')
92-
self._hier_parts = {}
93-
self._item_parts = {}
94-
95-
def init_service(self, endpoint, project, uuid, log_batch_size,
96-
ignore_errors, ignored_tags, verify_ssl=True,
97+
@property
98+
def issue_types(self):
99+
"""Issue types for the Report Portal project."""
100+
if not self._issue_types:
101+
if not self.project_settings:
102+
return self._issue_types
103+
for item_type in ("AUTOMATION_BUG", "PRODUCT_BUG", "SYSTEM_ISSUE",
104+
"NO_DEFECT", "TO_INVESTIGATE"):
105+
for item in self.project_settings["subTypes"][item_type]:
106+
self._issue_types[item["shortName"]] = item["locator"]
107+
return self._issue_types
108+
109+
def init_service(self,
110+
endpoint,
111+
project,
112+
uuid,
113+
log_batch_size,
114+
ignore_errors,
115+
ignored_tags,
116+
verify_ssl=True,
97117
retries=0):
118+
"""Update self.rp with the instance of the ReportPortalService."""
98119
self._errors = queue.Queue()
99120
if self.rp is None:
100121
self.ignore_errors = ignore_errors
122+
self.ignored_tags = ignored_tags
101123
if self.rp_supports_parameters:
102-
self.ignored_tags = list(set(ignored_tags).union({'parametrize'}))
103-
else:
104-
self.ignored_tags = ignored_tags
124+
self.ignored_tags = list(
125+
set(ignored_tags).union({'parametrize'}))
105126
log.debug('ReportPortal - Init service: endpoint=%s, '
106127
'project=%s, uuid=%s', endpoint, project, uuid)
107128
self.rp = ReportPortalService(
@@ -111,19 +132,13 @@ def init_service(self, endpoint, project, uuid, log_batch_size,
111132
retries=retries,
112133
verify_ssl=verify_ssl
113134
)
135+
self.project_settings = None
114136
if self.rp and hasattr(self.rp, "get_project_settings"):
115137
self.project_settings = self.rp.get_project_settings()
116-
else:
117-
self.project_settings = None
118-
self.issue_types = self.get_issue_types()
119138
else:
120139
log.debug('The pytest is already initialized')
121140
return self.rp
122141

123-
def async_error_handler(self, exc_info):
124-
self.rp = None
125-
self._errors.put_nowait(exc_info)
126-
127142
def start_launch(self,
128143
launch_name,
129144
mode=None,
@@ -133,7 +148,10 @@ def start_launch(self,
133148
if self.rp is None:
134149
return
135150

151+
system_info = self.rp.get_system_information(self._agent_name)
152+
system_info['system'] = True
136153
sl_pt = {
154+
'attributes': system_info,
137155
'name': launch_name,
138156
'start_time': timestamp(),
139157
'description': description,
@@ -281,8 +299,7 @@ def finish_pytest_item(self, test_item, item_id, status, issue=None):
281299
log.debug('ReportPortal - Finish TestItem: request_body=%s', fta_rq)
282300

283301
parts = self._item_parts[test_item]
284-
if not parts:
285-
self.rp.finish_test_item(**fta_rq)
302+
self.rp.finish_test_item(**fta_rq)
286303
while len(parts) > 0:
287304
part = parts.pop()
288305
if status == "FAILED":
@@ -323,12 +340,13 @@ def post_log(self, message, loglevel='INFO', attachment=None):
323340
loglevel = 'INFO'
324341

325342
sl_rq = {
343+
'item_id': self.log_item_id,
326344
'time': timestamp(),
327345
'message': message,
328346
'level': loglevel,
329-
'attachment': attachment,
347+
'attachment': attachment
330348
}
331-
self.rp.log_batch((sl_rq,), item_id=self.log_item_id)
349+
self.rp.log(**sl_rq)
332350

333351
def _stop_if_necessary(self):
334352
try:
@@ -340,17 +358,6 @@ def _stop_if_necessary(self):
340358
except queue.Empty:
341359
pass
342360

343-
def get_issue_types(self):
344-
issue_types = {}
345-
if not self.project_settings:
346-
return issue_types
347-
348-
for item_type in ("AUTOMATION_BUG", "PRODUCT_BUG", "SYSTEM_ISSUE", "NO_DEFECT", "TO_INVESTIGATE"):
349-
for item in self.project_settings["subTypes"][item_type]:
350-
issue_types[item["shortName"]] = item["locator"]
351-
352-
return issue_types
353-
354361
@staticmethod
355362
def _add_item_hier_parts_dirs(item, hier_flag, dirs_level, report_parts, dirs_parts, rp_name=""):
356363

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def read_file(fname):
88
return f.read()
99

1010

11-
version = '5.0.0'
11+
version = '5.0.1'
1212

1313

1414
requirements = [
@@ -34,9 +34,10 @@ def read_file(fname):
3434
classifiers=[
3535
'Framework :: Pytest',
3636
'Programming Language :: Python :: 2.7',
37-
'Programming Language :: Python :: 3.4',
3837
'Programming Language :: Python :: 3.5',
39-
'Programming Language :: Python :: 3.6'
38+
'Programming Language :: Python :: 3.6',
39+
'Programming Language :: Python :: 3.7',
40+
'Programming Language :: Python :: 3.8'
4041
],
4142
entry_points={
4243
'pytest11': [

test_mocks.py

Whitespace-only changes.

tests/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"""This package contains unit tests for the project."""
2+
3+
from six import add_move, MovedModule
4+
add_move(MovedModule('mock', 'mock', 'unittest.mock'))

tests/conftest.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""This module contains common Pytest fixtures and hooks for unit tests."""
2+
3+
from six.moves import mock
4+
5+
from _pytest.config import Config
6+
from pytest import fixture
7+
8+
from pytest_reportportal import RPLogger
9+
from pytest_reportportal.listener import RPReportListener
10+
from pytest_reportportal.service import PyTestServiceClass
11+
12+
13+
@fixture
14+
def logger():
15+
"""Prepare instance of the RPLogger for testing."""
16+
return RPLogger('pytest_reportportal.test')
17+
18+
19+
@fixture()
20+
def mocked_item(mocked_session):
21+
"""Mock Pytest item for testing."""
22+
test_item = mock.Mock()
23+
test_item.session = mocked_session
24+
return test_item
25+
26+
27+
@fixture()
28+
def mocked_config():
29+
"""Mock Pytest config for testing."""
30+
mocked_config = mock.create_autospec(Config)
31+
mocked_config._reportportal_configured = True
32+
return mocked_config
33+
34+
35+
@fixture()
36+
def mocked_session(mocked_config):
37+
"""Mock Pytest session for testing."""
38+
mocked_session = mock.Mock()
39+
mocked_session.config = mocked_config
40+
return mocked_session
41+
42+
43+
@fixture(scope='session')
44+
def rp_listener(rp_service):
45+
"""Prepare instance of the RPReportListener for testing."""
46+
return RPReportListener(rp_service)
47+
48+
49+
@fixture(scope='session')
50+
def rp_service():
51+
"""Prepare instance of the PyTestServiceClass for testing."""
52+
service = PyTestServiceClass()
53+
with mock.patch('reportportal_client.service.'
54+
'ReportPortalService.get_project_settings'):
55+
service.init_service("endpoint", "project", "uuid", 20, False, [])
56+
return service

0 commit comments

Comments
 (0)