Skip to content

Commit e0fb0b7

Browse files
authored
Merge pull request #1 from ppapou/master
Pytest-Reportportal client
2 parents 0e2e1e3 + 1c184e2 commit e0fb0b7

File tree

7 files changed

+389
-0
lines changed

7 files changed

+389
-0
lines changed

CONTRIBUTING.rst

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
.. highlight:: shell
2+
3+
============
4+
Contributing
5+
============
6+
7+
Contributions are welcome, and they are greatly appreciated! Every
8+
little bit helps, and credit will always be given.
9+
10+
You can contribute in many ways:
11+
12+
Types of Contributions
13+
----------------------
14+
15+
Report Bugs
16+
~~~~~~~~~~~
17+
18+
Report bugs at https://github.com/reportportal/agent-python-pytest/issues.
19+
20+
If you are reporting a bug, please include:
21+
22+
* Your operating system name and version.
23+
* Any details about your local setup that might be helpful in troubleshooting.
24+
* Detailed steps to reproduce the bug.
25+
26+
Fix Bugs
27+
~~~~~~~~
28+
29+
Look through the GitHub issues for bugs. Anything tagged with "bug"
30+
and "help wanted" is open to whoever wants to implement it.
31+
32+
Implement Features
33+
~~~~~~~~~~~~~~~~~~
34+
35+
Look through the GitHub issues for features. Anything tagged with "enhancement"
36+
and "help wanted" is open to whoever wants to implement it.
37+
38+
Write Documentation
39+
~~~~~~~~~~~~~~~~~~~
40+
41+
agent-python-pytest could always use more documentation, whether as part of the
42+
official agent-python-pytest docs, in docstrings, or even on the web in blog posts,
43+
articles, and such.
44+
45+
Submit Feedback
46+
~~~~~~~~~~~~~~~
47+
48+
The best way to send feedback is to file an issue at https://github.com/reportportal/agent-python-pytest/issues.
49+
50+
If you are proposing a feature:
51+
52+
* Explain in detail how it would work.
53+
* Keep the scope as narrow as possible, to make it easier to implement.
54+
* Remember that this is a volunteer-driven project, and that contributions
55+
are welcome :)
56+
57+
Get Started!
58+
------------
59+
60+
Ready to contribute? Here's how to set up `agent-python-pytest` for local development.
61+
62+
1. Fork the `agent-python-pytest` repo on GitHub.
63+
2. Clone your fork locally::
64+
65+
$ git clone [email protected]:your_name_here/agent-python-pytest
66+
67+
3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
68+
69+
$ mkvirtualenv agent_python_pytest
70+
$ cd agent_python_pytest/
71+
$ python setup.py develop
72+
73+
4. Create a branch for local development::
74+
75+
$ git checkout -b name-of-your-bugfix-or-feature
76+
77+
Now you can make your changes locally.
78+
79+
5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox::
80+
81+
$ flake8 agent_python_pytest tests
82+
$ tox
83+
84+
To get flake8 and tox, just pip install them into your virtualenv.
85+
86+
6. Commit your changes and push your branch to GitHub::
87+
88+
$ git add .
89+
$ git commit -m "Your detailed description of your changes."
90+
$ git push origin name-of-your-bugfix-or-feature
91+
92+
7. Submit a pull request through the GitHub website.
93+

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,24 @@
11
# agent-python-pytest
22
Framework integration with PyTest
3+
4+
Description:
5+
Plugin for reporting items results of Pytest to the 'Reportal Portal'.
6+
7+
Install Plugin
8+
pip install pytest-reportportal
9+
10+
Usage:
11+
12+
Prepare the config file pytest.ini in root dir of tests.
13+
Content of the pytest.ini file:
14+
[pytest]
15+
rp_uuid = uid reportportal
16+
rp_endpoint = http://ip:port
17+
rp_project = Project of ReportPortal
18+
19+
Run tests:
20+
py.test ./tests --rp_launch AnyLaunchName
21+
22+
Features:
23+
- add logging
24+
- add Tags parameter to config file

pytest_reportportal/__init__.py

Whitespace-only changes.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# This program is free software: you can redistribute it and/or modify iit under the terms of the GPL licence
2+
import pytest
3+
import logging
4+
from service import PyTestService
5+
6+
7+
class RP_Report_Listener(object):
8+
9+
# Identifier if TestItem is called:
10+
# if setup is failed, pytest will NOT call
11+
# TestItem and Result will not reported!
12+
called = None
13+
# Test Item result
14+
result = None
15+
16+
@pytest.mark.hookwrapper
17+
def pytest_runtest_makereport(self, item, call):
18+
report = (yield).get_result()
19+
if report.when == "setup":
20+
# when function pytest_setup is called,
21+
# test item session is started in RP
22+
PyTestService.start_pytest_item(item)
23+
24+
if report.when == "call":
25+
self.called = True
26+
if report.passed:
27+
item_result = "PASSED"
28+
elif report.failed:
29+
item_result = "FAILED"
30+
else:
31+
item_result = "SKIPPED"
32+
33+
self.result = item_result
34+
35+
if report.when == "teardown":
36+
# If item is called, result of TestItem is reported
37+
if self.called is True:
38+
item_result = self.result
39+
else:
40+
# If setup - failed or skipped,
41+
# the TestItem will reported as SKIPPED
42+
item_result = "SKIPPED"
43+
PyTestService.finish_pytest_item(item_result)
44+
45+
46+
def pytest_sessionstart(session):
47+
config = session.config
48+
if config.option.rp_launch:
49+
# get config parameters if rp_launch option is set
50+
rp_uuid = config.getini('rp_uuid')
51+
rp_project = config.getini('rp_project')
52+
rp_endpoint = config.getini('rp_endpoint')
53+
# initialize PyTest
54+
PyTestService.init_service(
55+
project=rp_project,
56+
endpoint=rp_endpoint,
57+
uuid=rp_uuid)
58+
launch_name = config.getoption('rp_launch')
59+
60+
PyTestService.start_launch(launch_name)
61+
62+
63+
def pytest_sessionfinish(session):
64+
config = session.config
65+
if config.option.rp_launch:
66+
PyTestService.finish_launch("RP_Launch")
67+
68+
69+
def pytest_configure(config):
70+
rp_launch = config.getoption('rp_launch')
71+
if rp_launch:
72+
# set Pytest_Reporter and configure it
73+
config._reporter = RP_Report_Listener()
74+
75+
if hasattr(config, '_reporter'):
76+
config.pluginmanager.register(config._reporter)
77+
78+
79+
def pytest_unconfigure(config):
80+
if hasattr(config, '_reporter'):
81+
reporter = config._reporter
82+
del config._reporter
83+
config.pluginmanager.unregister(reporter)
84+
logging.debug('ReportPortal is unconfigured')
85+
86+
87+
def pytest_addoption(parser):
88+
group = parser.getgroup("reporting")
89+
group.addoption(
90+
'--rp_launch',
91+
action='store',
92+
dest=None,
93+
help="The Launch name for ReportPortal, i.e PyTest")
94+
95+
parser.addini(
96+
'rp_uuid',
97+
help="Uid of RP user")
98+
99+
parser.addini(
100+
'rp_endpoint',
101+
help="Report portal server")
102+
103+
parser.addini(
104+
"rp_project",
105+
help='Report Portal Project')

pytest_reportportal/service.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import logging
2+
from time import time
3+
from reportportal_client import (
4+
ReportPortalService, FinishExecutionRQ, StartLaunchRQ, StartTestItemRQ,
5+
FinishTestItemRQ, SaveLogRQ)
6+
7+
8+
def timestamp():
9+
return str(int(time() * 1000))
10+
11+
12+
class PyTestService(object):
13+
14+
RP = None
15+
TEST_ITEM_STACK = []
16+
launch_id = None
17+
18+
@staticmethod
19+
def init_service(endpoint, project, uuid):
20+
21+
if PyTestService.RP is None:
22+
logging.debug(
23+
msg="ReportPortal - Init service: "
24+
"endpoint={0}, project={1}, uuid={2}".
25+
format(endpoint, project, uuid))
26+
PyTestService.RP = ReportPortalService(
27+
endpoint=endpoint,
28+
project=project,
29+
token=uuid)
30+
else:
31+
raise Exception("PyTest is initialized")
32+
return PyTestService.RP
33+
34+
@staticmethod
35+
def start_launch(launch_name=None, mode=None):
36+
# TODO: Tags, values could be moved to separated module like helper
37+
tags = ["PyTest"]
38+
sl_pt = StartLaunchRQ(
39+
name=launch_name,
40+
start_time=timestamp(),
41+
description="PyTest_Launch",
42+
mode=mode,
43+
tags=tags)
44+
logging.debug(msg="ReportPortal - Start launch: "
45+
"request_body={0}".format(sl_pt.data))
46+
req_data = PyTestService.RP.start_launch(sl_pt)
47+
logging.debug(msg="ReportPortal - Launch started: "
48+
"response_body={0}".format(req_data.raw))
49+
PyTestService.launch_id = req_data.id
50+
51+
PyTestService.TEST_ITEM_STACK.append((None, "SUITE"))
52+
logging.debug(
53+
msg="ReportPortal - Stack: {0}".
54+
format(PyTestService.TEST_ITEM_STACK))
55+
56+
@staticmethod
57+
def start_pytest_item(test_item=None):
58+
try:
59+
# for common items
60+
item_description = test_item.function.__doc__
61+
except AttributeError:
62+
# doctest has no `function` attribute
63+
item_description = test_item.reportinfo()[2]
64+
65+
start_rq = StartTestItemRQ(
66+
name=test_item.name,
67+
description=item_description,
68+
tags=['PyTest Item Tag'],
69+
start_time=timestamp(),
70+
launch_id=PyTestService.launch_id,
71+
type="TEST")
72+
73+
parent_item_id = PyTestService._get_top_id_from_stack()
74+
75+
logging.debug(
76+
msg="ReportPortal - Start TestItem: "
77+
"request_body={0}, parent_item={1}".format(
78+
start_rq.data, parent_item_id))
79+
80+
req_data = PyTestService.RP.start_test_item(
81+
parent_item_id=parent_item_id, start_test_item_rq=start_rq)
82+
83+
PyTestService.TEST_ITEM_STACK.append((req_data.id, "TEST"))
84+
logging.debug(
85+
msg="ReportPortal - Stack: {0}".
86+
format(PyTestService.TEST_ITEM_STACK))
87+
88+
@staticmethod
89+
def finish_pytest_item(status, issue=None):
90+
fta_rq = FinishTestItemRQ(end_time=timestamp(),
91+
status=status,
92+
issue=issue)
93+
94+
test_item_id = PyTestService._get_top_id_from_stack()
95+
logging.debug(
96+
msg="ReportPortal - Finish TetsItem:"
97+
" request_body={0}, test_id={1}".
98+
format(fta_rq.data, test_item_id))
99+
PyTestService.RP.finish_test_item(
100+
item_id=test_item_id,
101+
finish_test_item_rq=fta_rq)
102+
PyTestService.TEST_ITEM_STACK.pop()
103+
logging.debug(
104+
msg="ReportPortal - Stack: {0}".
105+
format(PyTestService.TEST_ITEM_STACK))
106+
107+
@staticmethod
108+
def finish_launch(status):
109+
fl_rq = FinishExecutionRQ(
110+
end_time=timestamp(),
111+
status=status)
112+
launch_id = PyTestService.launch_id
113+
logging.debug(msg="ReportPortal - Finish launch: "
114+
"request_body={0}, launch_id={1}".format(fl_rq.data,
115+
launch_id))
116+
PyTestService.RP.finish_launch(launch_id, fl_rq)
117+
PyTestService.TEST_ITEM_STACK.pop()
118+
logging.debug(
119+
msg="ReportPortal - Stack: {0}".
120+
format(PyTestService.TEST_ITEM_STACK))
121+
122+
@staticmethod
123+
def _get_top_id_from_stack():
124+
try:
125+
return PyTestService.TEST_ITEM_STACK[-1][0]
126+
except IndexError:
127+
return None
128+
129+
@staticmethod
130+
def post_log(message, log_level="DEBUG"):
131+
sl_rq = SaveLogRQ(item_id=PyTestService._get_top_id_from_stack(),
132+
time=timestamp(), message=message,
133+
level=log_level)
134+
PyTestService.RP.log(sl_rq)
135+

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[metadata]
2+
description-file = README.md

setup.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from setuptools import setup
2+
3+
with open('README.md') as readme_file:
4+
readme = readme_file.read()
5+
6+
version = '0.2.1'
7+
requirements = [
8+
"reportportal_client"
9+
]
10+
11+
setup(
12+
name='pytest-reportportal',
13+
version=version,
14+
description="Framework integration with PyTest",
15+
long_description=readme + '\n\n',
16+
author="Pavel Papou",
17+
author_email='[email protected]',
18+
url='https://github.com/reportportal/agent-python-pytest',
19+
packages=['pytest_reportportal'],
20+
install_requires=requirements,
21+
license="GNU General Public License v3",
22+
keywords=['testing', 'reporting', 'reportportal', 'pytest'],
23+
classifiers=[
24+
"Programming Language :: Python :: 2",
25+
'Programming Language :: Python :: 2.6',
26+
'Programming Language :: Python :: 2.7'],
27+
entry_points={
28+
'pytest11': [
29+
'pytest_reportportal = pytest_reportportal.pytest_rp_plugin',
30+
]
31+
},
32+
)

0 commit comments

Comments
 (0)