Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
577418f28c | ||
|
|
5c46cdf62d | ||
|
|
493ba6cb1d | ||
|
|
d9bb158085 | ||
|
|
0175605c57 | ||
|
|
3ed405f22f | ||
|
|
7b9546b89b | ||
|
|
542111d272 | ||
|
|
2adf810e5e | ||
|
|
f8e138b986 |
34
.travis.yml
34
.travis.yml
@@ -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,25 +21,24 @@ 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
|
install: pip install tox setuptools_scm
|
||||||
matrix:
|
script: tox
|
||||||
|
|
||||||
|
jobs:
|
||||||
include:
|
include:
|
||||||
# note: please use "tox --listenvs" to populate the build matrix
|
- stage: test
|
||||||
|
# python x env above are already included into this stage
|
||||||
- python: "3.6"
|
- python: "3.6"
|
||||||
env: TOXENV=flakes
|
env: TOXENV=flakes
|
||||||
- python: "3.6"
|
- python: "3.6"
|
||||||
env: TOXENV=readme
|
env: TOXENV=readme
|
||||||
|
|
||||||
script: tox
|
- stage: deploy
|
||||||
notifications:
|
python: '3.6'
|
||||||
irc:
|
env:
|
||||||
channels:
|
install: skip
|
||||||
- chat.freenode.net#pytest
|
script: skip
|
||||||
on_success: change
|
|
||||||
on_failure: change
|
|
||||||
skip_join: true
|
|
||||||
email:
|
|
||||||
- pytest-commit@python.org
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: pypi
|
provider: pypi
|
||||||
user: ronny
|
user: ronny
|
||||||
|
|||||||
@@ -1,3 +1,24 @@
|
|||||||
|
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)
|
pytest-xdist 1.19.1 (2017-08-10)
|
||||||
================================
|
================================
|
||||||
|
|
||||||
|
|||||||
@@ -471,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*",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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'],
|
||||||
|
|||||||
Reference in New Issue
Block a user