Compare commits

..

16 Commits

Author SHA1 Message Date
Bruno Oliveira
577418f28c Prepare release 1.20.0 2017-08-17 18:34:03 -03:00
Bruno Oliveira
5c46cdf62d Mention flaky in the changelog for #206 2017-08-17 18:33:50 -03:00
Ronny Pfannschmidt
493ba6cb1d Merge pull request #223 from nicoddemus/travis-stages
Change Travis configuration to use stages in CI
2017-08-17 09:39:16 +02:00
Bruno Oliveira
d9bb158085 Change Travis configuration to use stages in CI
Fix #221
2017-08-16 23:54:38 -03:00
Ronny Pfannschmidt
0175605c57 Merge pull request #219 from nicoddemus/worker-id-docstring
Add docstring for worker_id
2017-08-11 15:49:26 +02:00
Bruno Oliveira
3ed405f22f Add docstring for worker_id
Fix #190
2017-08-10 21:51:30 -03:00
Bruno Oliveira
7b9546b89b Merge pull request #218 from nicoddemus/teardown-crash
Identify correct test crashed during teardown and support multiple test logs from plugins
2017-08-10 21:33:08 -03:00
Bruno Oliveira
542111d272 Merge pull request #217 from nicoddemus/release-1.19.1
Prepare release 1.19.1
2017-08-10 12:50:53 -03:00
Bruno Oliveira
2adf810e5e Add acceptance test for plugins which log tests multiple times
Fix #206
2017-08-10 11:18:52 -03:00
Bruno Oliveira
f8e138b986 Fix tests incorrectly identified if worker crashes during teardown stage
Fix #124
2017-08-10 10:43:40 -03:00
Bruno Oliveira
469c8c50d0 Prepare release 1.19.1 2017-08-10 07:17:59 -03:00
Ronny Pfannschmidt
79f1b6dab2 Merge pull request #215 from nicoddemus/logwarning-py-path
Fix crash when transferring internal pytest warnings from workers to the master node
2017-08-10 08:57:21 +02:00
Ronny Pfannschmidt
75e61d86b7 Merge pull request #213 from messa/patch-1
Fix reprcrash check in unserialize_report()
2017-08-10 08:55:51 +02:00
Bruno Oliveira
20a1b9ef11 Fix crash when transferring internal pytest warnings from workers to the master node
Fix #214
2017-08-09 17:55:16 -03:00
Bruno Oliveira
a54f531701 Merge pull request #212 from nicoddemus/release-1.19.0
Prepare release 1.19.0
2017-08-09 12:44:59 -03:00
Petr Messner
4389843dcb Fix reprcrash check in unserialize_report() 2017-08-09 17:44:45 +02:00
7 changed files with 160 additions and 53 deletions

View File

@@ -1,5 +1,16 @@
sudo: false sudo: false
language: python language: python
notifications:
irc:
channels:
- 'chat.freenode.net#pytest'
on_success: change
on_failure: change
skip_join: true
email:
- pytest-commit@python.org
python: python:
- '2.6' - '2.6'
- '2.7' - '2.7'
@@ -10,32 +21,31 @@ env:
- TOXENV=py-pytest30 - TOXENV=py-pytest30
- TOXENV=py-pytest31 - TOXENV=py-pytest31
- TOXENV=py-pytest32 - TOXENV=py-pytest32
install: pip install tox setuptools_scm
matrix:
include:
# note: please use "tox --listenvs" to populate the build matrix
- python: "3.6"
env: TOXENV=flakes
- python: "3.6"
env: TOXENV=readme
install: pip install tox setuptools_scm
script: tox script: tox
notifications:
irc: jobs:
channels: include:
- chat.freenode.net#pytest - stage: test
on_success: change # python x env above are already included into this stage
on_failure: change - python: "3.6"
skip_join: true env: TOXENV=flakes
email: - python: "3.6"
- pytest-commit@python.org env: TOXENV=readme
deploy:
provider: pypi - stage: deploy
user: ronny python: '3.6'
skip_upload_docs: true env:
password: install: skip
secure: cxmSDho5d+PYKEM4ZCg8ms1P4lzhYkrw6fEOm2HtTcsuCyY6aZMSgImWAnEYbJHSkdzgcxlXK9UKJ9B0YenXmBCkAr7UjdnpNXNmkySr0sYzlH/sfqt/dDATCHFaRKxnkOSOVywaDYhT9n8YudbXI77pXwD12i/CeSSJDbHhsu0JYUfAcb+D6YjRYoA2SEGCnzSzg+gDDfwXZx4ZiODCGLVwieNp1klCg88YROUE1BaYYNuUOONvfXX8+TWowbCF6ChH1WL/bZ49OStEYQNuYxZQZr4yClIqu9VJbchrU8j860K9ott2kkGTgfB/dDrQB/XncBubyIX9ikzCQAmmBXWAI3eyvWLPDk2Jz7kW2l2RT7syct80tCq3JhvQ1qdwr5ap7siocTLgnBW0tF4tkHSTFN3510fkc43npnp6FThebESQpnI24vqpwJ9hI/kW5mYi014Og2E/cpCXnz2XO8iZPDbqAMQpDsqEQoyhfGNgPTGp4K30TxRtwZBI5hHhDKnnR16fXtRgt1gYPvz/peUQvvpOm4JzIzGXPzluuutpnCBy75v5+oiwT3YRrLL/Meims9FtDDXL3qQubAE/ezIOOpm0N5XXV8DxIom8EN71yq5ab1tqhM+tBX7owRjy4FR4If2Q8feBdmTuh26DIQt/y+qSG8VkB9Sw/JCjc7c= script: skip
on: deploy:
tags: true provider: pypi
distributions: sdist bdist_wheel user: ronny
repo: pytest-dev/pytest-xdist skip_upload_docs: true
password:
secure: cxmSDho5d+PYKEM4ZCg8ms1P4lzhYkrw6fEOm2HtTcsuCyY6aZMSgImWAnEYbJHSkdzgcxlXK9UKJ9B0YenXmBCkAr7UjdnpNXNmkySr0sYzlH/sfqt/dDATCHFaRKxnkOSOVywaDYhT9n8YudbXI77pXwD12i/CeSSJDbHhsu0JYUfAcb+D6YjRYoA2SEGCnzSzg+gDDfwXZx4ZiODCGLVwieNp1klCg88YROUE1BaYYNuUOONvfXX8+TWowbCF6ChH1WL/bZ49OStEYQNuYxZQZr4yClIqu9VJbchrU8j860K9ott2kkGTgfB/dDrQB/XncBubyIX9ikzCQAmmBXWAI3eyvWLPDk2Jz7kW2l2RT7syct80tCq3JhvQ1qdwr5ap7siocTLgnBW0tF4tkHSTFN3510fkc43npnp6FThebESQpnI24vqpwJ9hI/kW5mYi014Og2E/cpCXnz2XO8iZPDbqAMQpDsqEQoyhfGNgPTGp4K30TxRtwZBI5hHhDKnnR16fXtRgt1gYPvz/peUQvvpOm4JzIzGXPzluuutpnCBy75v5+oiwT3YRrLL/Meims9FtDDXL3qQubAE/ezIOOpm0N5XXV8DxIom8EN71yq5ab1tqhM+tBX7owRjy4FR4If2Q8feBdmTuh26DIQt/y+qSG8VkB9Sw/JCjc7c=
on:
tags: true
distributions: sdist bdist_wheel
repo: pytest-dev/pytest-xdist

View File

@@ -1,3 +1,35 @@
pytest-xdist 1.20.0 (2017-08-17)
================================
Features
--------
- ``xdist`` now supports tests to log results multiple times, improving
integration with plugins which require it like `pytest-rerunfailures
<https://github.com/gocept/pytest-rerunfailures>_` and `flaky
<https://pypi.python.org/pypi/flaky>`_. (`#206 <https://github.com/pytest-
dev/pytest-xdist/issues/206>`_)
Bug Fixes
---------
- Fix issue where tests were being incorrectly identified if a worker crashed
during the ``teardown`` stage of the test. (`#124 <https://github.com/pytest-
dev/pytest-xdist/issues/124>`_)
pytest-xdist 1.19.1 (2017-08-10)
================================
Bug Fixes
---------
- Fix crash when transferring internal pytest warnings from workers to the
master node. (`#214 <https://github.com/pytest-dev/pytest-
xdist/issues/214>`_)
pytest-xdist 1.19.0 (2017-08-09) pytest-xdist 1.19.0 (2017-08-09)
================================ ================================

View File

@@ -340,18 +340,28 @@ class TestTerminalReporting:
]) ])
@pytest.mark.parametrize('n', ['-n0', '-n1']) @pytest.mark.parametrize('n', ['-n0', '-n1'])
def test_logwarning(self, testdir, n): @pytest.mark.parametrize('warn_type', ['pytest', 'builtin'])
def test_logwarning(self, testdir, n, warn_type):
from pkg_resources import parse_version from pkg_resources import parse_version
if parse_version(pytest.__version__) < parse_version('3.1'): if parse_version(pytest.__version__) < parse_version('3.1'):
pytest.skip('pytest warnings requires >= 3.1') pytest.skip('pytest warnings requires >= 3.1')
if warn_type == 'builtin':
warn_code = """warnings.warn(UserWarning('this is a warning'))"""
elif warn_type == 'pytest':
warn_code = """request.config.warn('', 'this is a warning',
fslocation=py.path.local())"""
else:
assert False
testdir.makepyfile(""" testdir.makepyfile("""
import warnings import warnings, py
def test_func(): def test_func(request):
warnings.warn('this is a warning') {warn_code}
""") """.format(warn_code=warn_code))
result = testdir.runpytest(n) result = testdir.runpytest(n)
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines([
"*this is a warning*", "*this is a warning*",
"*1 passed, 1 warnings*",
]) ])
@@ -461,18 +471,60 @@ def test_funcarg_teardown_failure(testdir):
assert result.ret assert result.ret
def test_crashing_item(testdir): @pytest.mark.parametrize('when', ['setup', 'call', 'teardown'])
def test_crashing_item(testdir, when):
"""Ensure crashing item is correctly reported during all testing stages"""
code = dict(setup='', call='', teardown='')
code[when] = 'py.process.kill(os.getpid())'
p = testdir.makepyfile(""" p = testdir.makepyfile("""
import py
import os import os
def test_crash(): import py
py.process.kill(os.getpid()) import pytest
def test_noncrash():
@pytest.fixture
def fix():
{setup}
yield
{teardown}
def test_crash(fix):
{call}
pass pass
""")
def test_ok():
pass
""".format(**code))
passes = 2 if when == 'teardown' else 1
result = testdir.runpytest("-n2", p) result = testdir.runpytest("-n2", p)
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines([
"*crashed*test_crash*", "*1 failed*1 passed*" "*crashed*test_crash*",
"*1 failed*%d passed*" % passes,
])
def test_multiple_log_reports(testdir):
"""
Ensure that pytest-xdist supports plugins that emit multiple logreports
(#206).
Inspired by pytest-rerunfailures.
"""
testdir.makeconftest("""
from _pytest.runner import runtestprotocol
def pytest_runtest_protocol(item, nextitem):
item.ihook.pytest_runtest_logstart(nodeid=item.nodeid,
location=item.location)
reports = runtestprotocol(item, nextitem=nextitem)
for report in reports:
item.ihook.pytest_runtest_logreport(report=report)
return True
""")
testdir.makepyfile("""
def test():
pass
""")
result = testdir.runpytest("-n1")
result.stdout.fnmatch_lines([
"*2 passed*",
]) ])

View File

@@ -230,18 +230,19 @@ class DSession:
nodeid=nodeid, location=location) nodeid=nodeid, location=location)
def slave_testreport(self, node, rep): def slave_testreport(self, node, rep):
"""Emitted when a node calls the pytest_runtest_logreport hook. """Emitted when a node calls the pytest_runtest_logreport hook."""
If the node indicates it is finished with a test item, remove
the item from the pending list in the scheduler.
"""
if rep.when == "call" or (rep.when == "setup" and not rep.passed):
self.sched.mark_test_complete(node, rep.item_index, rep.duration)
# self.report_line("testreport %s: %s" %(rep.id, rep.status))
rep.node = node rep.node = node
self.config.hook.pytest_runtest_logreport(report=rep) self.config.hook.pytest_runtest_logreport(report=rep)
self._handlefailures(rep) self._handlefailures(rep)
def slave_runtest_protocol_complete(self, node, item_index, duration):
"""
Emitted when a node fires the 'runtest_protocol_complete' event,
signalling that a test has completed the runtestprotocol and should be
removed from the pending list in the scheduler.
"""
self.sched.mark_test_complete(node, item_index, duration)
def slave_collectreport(self, node, rep): def slave_collectreport(self, node, rep):
"""Emitted when a node calls the pytest_collectreport hook.""" """Emitted when a node calls the pytest_collectreport hook."""
if rep.failed: if rep.failed:

View File

@@ -124,6 +124,9 @@ def pytest_cmdline_main(config):
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def worker_id(request): def worker_id(request):
"""Return the id of the current worker ('gw0', 'gw1', etc) or 'master'
if running on the master node.
"""
if hasattr(request.config, 'slaveinput'): if hasattr(request.config, 'slaveinput'):
return request.config.slaveinput['slaveid'] return request.config.slaveinput['slaveid']
else: else:

View File

@@ -8,6 +8,7 @@
import sys import sys
import os import os
import time
import pytest import pytest
@@ -59,23 +60,29 @@ class SlaveInteractor:
self.log("items to run:", torun) self.log("items to run:", torun)
# only run if we have an item and a next item # only run if we have an item and a next item
while len(torun) >= 2: while len(torun) >= 2:
self.run_tests(torun) self.run_one_test(torun)
if name == "shutdown": if name == "shutdown":
if torun: if torun:
self.run_tests(torun) self.run_one_test(torun)
break break
return True return True
def run_tests(self, torun): def run_one_test(self, torun):
items = self.session.items items = self.session.items
self.item_index = torun.pop(0) self.item_index = torun.pop(0)
item = items[self.item_index]
if torun: if torun:
nextitem = items[torun[0]] nextitem = items[torun[0]]
else: else:
nextitem = None nextitem = None
start = time.time()
self.config.hook.pytest_runtest_protocol( self.config.hook.pytest_runtest_protocol(
item=items[self.item_index], item=item,
nextitem=nextitem) nextitem=nextitem)
duration = time.time() - start
self.sendevent("runtest_protocol_complete", item_index=self.item_index,
duration=duration)
def pytest_collection_finish(self, session): def pytest_collection_finish(self, session):
self.sendevent( self.sendevent(
@@ -99,7 +106,7 @@ class SlaveInteractor:
def pytest_logwarning(self, message, code, nodeid, fslocation): def pytest_logwarning(self, message, code, nodeid, fslocation):
self.sendevent("logwarning", message=message, code=code, nodeid=nodeid, self.sendevent("logwarning", message=message, code=code, nodeid=nodeid,
fslocation=fslocation) fslocation=str(fslocation))
def serialize_report(rep): def serialize_report(rep):

View File

@@ -315,6 +315,8 @@ class SlaveController(object):
self.notify_inproc(eventname, node=self, rep=rep) self.notify_inproc(eventname, node=self, rep=rep)
elif eventname == "collectionfinish": elif eventname == "collectionfinish":
self.notify_inproc(eventname, node=self, ids=kwargs['ids']) self.notify_inproc(eventname, node=self, ids=kwargs['ids'])
elif eventname == "runtest_protocol_complete":
self.notify_inproc(eventname, node=self, **kwargs)
elif eventname == "logwarning": elif eventname == "logwarning":
self.notify_inproc(eventname, message=kwargs['message'], self.notify_inproc(eventname, message=kwargs['message'],
code=kwargs['code'], nodeid=kwargs['nodeid'], code=kwargs['code'], nodeid=kwargs['nodeid'],
@@ -344,7 +346,7 @@ def unserialize_report(name, reportdict):
ReprTraceback ReprTraceback
) )
if reportdict['longrepr']: if reportdict['longrepr']:
if 'reprcrash' and 'reprtraceback' in reportdict['longrepr']: if 'reprcrash' in reportdict['longrepr'] and 'reprtraceback' in reportdict['longrepr']:
reprtraceback = reportdict['longrepr']['reprtraceback'] reprtraceback = reportdict['longrepr']['reprtraceback']
reprcrash = reportdict['longrepr']['reprcrash'] reprcrash = reportdict['longrepr']['reprcrash']