Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f43a64ae59 | ||
|
|
cd7d8ca42a | ||
|
|
6241167b6c | ||
|
|
eb46f9b642 | ||
|
|
a2881fd8a9 | ||
|
|
d8d9f3684b | ||
|
|
9039807943 | ||
|
|
d498cb3e0f | ||
|
|
1c7eb24a1f | ||
|
|
7d124ecf87 | ||
|
|
e8fa737196 | ||
|
|
305acdd72a | ||
|
|
4fc9cb6e99 | ||
|
|
b4a7a1a8a8 | ||
|
|
c27ac36fca | ||
|
|
9786e3d774 | ||
|
|
8ec8d29cbf | ||
|
|
dd3d180fe3 | ||
|
|
20fe1f9874 | ||
|
|
8954f0d63d | ||
|
|
ba35a3da02 | ||
|
|
6601b5f9ba | ||
|
|
b27301e1d9 | ||
|
|
7e6011541f | ||
|
|
7f8ae3944c | ||
|
|
a11632b5d0 | ||
|
|
f19b804c67 | ||
|
|
96506867d1 | ||
|
|
023226840c | ||
|
|
26abac7a95 |
21
.hgtags
21
.hgtags
@@ -1,21 +0,0 @@
|
|||||||
42c6503ee48fae9c4c96d406afb12bfc86f15803 1.0
|
|
||||||
eca7ce17eabf296983c36812c8b8be901e7055a3 1.1
|
|
||||||
56d8e5280be224a0ad3220a9deed55334710bd23 1.2
|
|
||||||
e6c4ce20db4bf65086ff55807a3c306cad7ca393 1.3
|
|
||||||
e6c4ce20db4bf65086ff55807a3c306cad7ca393 1.3
|
|
||||||
eaf8b1cb7c312883598677231be5bbeea3b5c127 1.3
|
|
||||||
a423748bf17ee778a37853225210257699cad9c1 1.4
|
|
||||||
cd44a941c833c098e4899fe3d42a96703754d0d5 1.5
|
|
||||||
4815040bdad8f182a5487f57a9da385483836e75 1.6
|
|
||||||
20875fed94e7f3dff50bdf762df91153b15ceca6 1.7
|
|
||||||
20875fed94e7f3dff50bdf762df91153b15ceca6 1.7
|
|
||||||
29c38e195526f5f0fdd651fb51f59d6efaaafbb0 1.7
|
|
||||||
0d1c00018008433956aa7d93007bab6ea7de96e4 1.8
|
|
||||||
0d1c00018008433956aa7d93007bab6ea7de96e4 1.8
|
|
||||||
1d27987c267577899350a25ba5828d55d87083ad 1.8
|
|
||||||
5c5cb6d59e12e566fbb0217aea718dc31578bee1 1.9
|
|
||||||
4406fc2a6427fadc021ed7e43e7aa5032b1ea91f 1.10
|
|
||||||
220f6e46eb71a6212ccbe6b67b9e6edcf8ee4fa5 1.11
|
|
||||||
39ef85dbc893cc63dede11601208098a667b58e9 1.12
|
|
||||||
4e25f4c568be2d7cb4d1739638a9e66bbf28f588 v1.13
|
|
||||||
67ff3aa4d294f75ade0ebf03267e5739e1bd9473 v1.13.1
|
|
||||||
45
.travis.yml
45
.travis.yml
@@ -1,46 +1,45 @@
|
|||||||
sudo: false
|
sudo: false
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- '3.5'
|
- '3.5'
|
||||||
# command to install dependencies
|
install: pip install -U tox setuptools_scm
|
||||||
install: "pip install -U tox setuptools_scm"
|
|
||||||
# # command to run tests
|
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
- TESTENV=flakes
|
- TESTENV=py26-pytest26
|
||||||
- TESTENV=readme
|
|
||||||
# matrix was trimmed to skip
|
|
||||||
# some builds that are unnecessary/perceived redundant:
|
|
||||||
# py27 and py35 are tested with all pytest versions we declare to support;
|
|
||||||
# py26 and py34 only with latest pytest versions.
|
|
||||||
# pytest24,25,26 don't work on py35 due to changes in ast module
|
|
||||||
- TESTENV=py26-pytest27
|
- TESTENV=py26-pytest27
|
||||||
- TESTENV=py26-pytest28
|
- TESTENV=py26-pytest28
|
||||||
|
- TESTENV=py26-pytest29
|
||||||
- TESTENV=py27-pytest24
|
|
||||||
- TESTENV=py27-pytest25
|
|
||||||
- TESTENV=py27-pytest26
|
- TESTENV=py27-pytest26
|
||||||
- TESTENV=py27-pytest27
|
- TESTENV=py27-pytest27
|
||||||
- TESTENV=py27-pytest28
|
- TESTENV=py27-pytest28
|
||||||
|
- TESTENV=py27-pytest29
|
||||||
|
- TESTENV=py34-pytest26
|
||||||
- TESTENV=py34-pytest27
|
- TESTENV=py34-pytest27
|
||||||
- TESTENV=py34-pytest28
|
- TESTENV=py34-pytest28
|
||||||
|
- TESTENV=py34-pytest29
|
||||||
- TESTENV=py35-pytest27
|
- TESTENV=py35-pytest27
|
||||||
- TESTENV=py35-pytest28
|
- TESTENV=py35-pytest28
|
||||||
|
- TESTENV=py35-pytest29
|
||||||
- TESTENV=py27-pytest28-pexpect
|
- TESTENV=py27-pytest28-pexpect
|
||||||
- TESTENV=py34-pytest28-pexpect
|
- TESTENV=py35-pytest28-pexpect
|
||||||
- TESTENV=pypy-pytest28
|
- TESTENV=flakes
|
||||||
|
- TESTENV=readme
|
||||||
script: tox --recreate -e $TESTENV
|
script: tox --recreate -e $TESTENV
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
irc:
|
irc:
|
||||||
channels:
|
channels:
|
||||||
- "chat.freenode.net#pytest"
|
- chat.freenode.net#pytest
|
||||||
on_success: change
|
on_success: change
|
||||||
on_failure: change
|
on_failure: change
|
||||||
skip_join: true
|
skip_join: true
|
||||||
email:
|
email:
|
||||||
- pytest-commit@python.org
|
- pytest-commit@python.org
|
||||||
|
deploy:
|
||||||
|
provider: pypi
|
||||||
|
user: ronny
|
||||||
|
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
|
||||||
|
|||||||
13
CHANGELOG
13
CHANGELOG
@@ -1,3 +1,16 @@
|
|||||||
|
1.15.0
|
||||||
|
------
|
||||||
|
|
||||||
|
- new ``worker_id`` fixture, returns the id of the worker in a test or fixture.
|
||||||
|
Thanks Jared Hellman for the PR.
|
||||||
|
|
||||||
|
- display progress during collection only when in a terminal, similar to pytest #1397 issue.
|
||||||
|
Thanks Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix internal error message when ``--maxfail`` is used (#62, #65).
|
||||||
|
Thanks Collin RM Stocks and Bryan A. Jones for reports and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
|
||||||
1.14
|
1.14
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ include README.txt
|
|||||||
include setup.py
|
include setup.py
|
||||||
include tox.ini
|
include tox.ini
|
||||||
graft testing
|
graft testing
|
||||||
prune .hg
|
prune .git
|
||||||
|
|||||||
38
README.rst
38
README.rst
@@ -185,17 +185,47 @@ at once. The specifications strings use the `xspec syntax`_.
|
|||||||
|
|
||||||
.. _`execnet`: http://codespeak.net/execnet
|
.. _`execnet`: http://codespeak.net/execnet
|
||||||
|
|
||||||
|
Identifying the worker process during a test
|
||||||
|
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
|
||||||
|
If you need to determine the identity of a worker process in
|
||||||
|
a test or fixture, you may use the ``worker_id`` fixture to do so:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def user_account(worker_id):
|
||||||
|
""" use a different account in each xdist worker """
|
||||||
|
return "account_%s" % worker_id
|
||||||
|
|
||||||
|
When ``xdist`` is disabled (running with ``-n0`` for example), then
|
||||||
|
``worker_id`` will return ``"master"``.
|
||||||
|
|
||||||
|
Additionally, worker processes have the following environment variables
|
||||||
|
defined:
|
||||||
|
|
||||||
|
* ``PYTEST_XDIST_WORKER``: the name of the worker, e.g., ``"gw2"``.
|
||||||
|
* ``PYTEST_XDIST_WORKER_COUNT``: the total number of workers in this session,
|
||||||
|
e.g., ``"4"`` when ``-n 4`` is given in the command-line.
|
||||||
|
|
||||||
|
*New in version 1.15.*
|
||||||
|
|
||||||
Specifying test exec environments in an ini file
|
Specifying test exec environments in an ini file
|
||||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
pytest (since version 2.0) supports ini-style cofiguration.
|
pytest (since version 2.0) supports ini-style cofiguration.
|
||||||
You can for example make running with three subprocesses
|
You can for example make running with three subprocesses
|
||||||
your default like this::
|
your default like this:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
[pytest]
|
[pytest]
|
||||||
addopts = -n3
|
addopts = -n3
|
||||||
|
|
||||||
You can also add default environments like this::
|
You can also add default environments like this:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
[pytest]
|
[pytest]
|
||||||
addopts = --tx ssh=myhost//python=python2.5 --tx ssh=myhost//python=python2.6
|
addopts = --tx ssh=myhost//python=python2.5 --tx ssh=myhost//python=python2.6
|
||||||
@@ -210,7 +240,9 @@ Specifying "rsync" dirs in an ini-file
|
|||||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
In a ``tox.ini`` or ``setup.cfg`` file in your root project directory
|
In a ``tox.ini`` or ``setup.cfg`` file in your root project directory
|
||||||
you may specify directories to include or to exclude in synchronisation::
|
you may specify directories to include or to exclude in synchronisation:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
[pytest]
|
[pytest]
|
||||||
rsyncdirs = . mypkg helperpkg
|
rsyncdirs = . mypkg helperpkg
|
||||||
|
|||||||
14
appveyor.yml
14
appveyor.yml
@@ -1,17 +1,7 @@
|
|||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- PYTHON: "C:\\Python35"
|
|
||||||
TESTENV: "py35"
|
|
||||||
|
|
||||||
- PYTHON: "C:\\Python27"
|
|
||||||
TESTENV: "py27"
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
- C:\Python35\python -m pip install tox setuptools_scm
|
||||||
- pip install tox setuptools_scm"
|
|
||||||
|
|
||||||
build: false # Not a C# project, build stuff at the test step instead.
|
build: false # Not a C# project, build stuff at the test step instead.
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
# Build the compiled extension and run the project tests
|
- C:\Python35\python -m tox
|
||||||
- tox -e %TESTENV%-pytest27,%TESTENV%-pytest28,readme,flakes
|
|
||||||
|
|||||||
1
setup.py
1
setup.py
@@ -24,6 +24,7 @@ setup(
|
|||||||
setup_requires=['setuptools_scm'],
|
setup_requires=['setuptools_scm'],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
'Framework :: Pytest',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: MIT License',
|
'License :: OSI Approved :: MIT License',
|
||||||
'Operating System :: POSIX',
|
'Operating System :: POSIX',
|
||||||
|
|||||||
@@ -411,7 +411,9 @@ def test_session_testscollected(testdir):
|
|||||||
|
|
||||||
def test_funcarg_teardown_failure(testdir):
|
def test_funcarg_teardown_failure(testdir):
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
def pytest_funcarg__myarg(request):
|
import pytest
|
||||||
|
@pytest.fixture
|
||||||
|
def myarg(request):
|
||||||
def teardown(val):
|
def teardown(val):
|
||||||
raise ValueError(val)
|
raise ValueError(val)
|
||||||
return request.cached_setup(setup=lambda: 42, teardown=teardown,
|
return request.cached_setup(setup=lambda: 42, teardown=teardown,
|
||||||
@@ -620,3 +622,68 @@ class TestNodeFailure:
|
|||||||
"*Slave*crashed while running*",
|
"*Slave*crashed while running*",
|
||||||
"*1 failed*2 passed*",
|
"*1 failed*2 passed*",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('n', [0, 2])
|
||||||
|
def test_worker_id_fixture(testdir, n):
|
||||||
|
import glob
|
||||||
|
f = testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
@pytest.mark.parametrize("run_num", range(2))
|
||||||
|
def test_worker_id1(worker_id, run_num):
|
||||||
|
with open("worker_id%s.txt" % run_num, "w") as f:
|
||||||
|
f.write(worker_id)
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest(f, "-n%d" % n)
|
||||||
|
result.stdout.fnmatch_lines('* 2 passed in *')
|
||||||
|
worker_ids = set()
|
||||||
|
for fname in glob.glob(str(testdir.tmpdir.join("*.txt"))):
|
||||||
|
with open(fname) as f:
|
||||||
|
worker_ids.add(f.read().strip())
|
||||||
|
if n == 0:
|
||||||
|
assert worker_ids == set(['master'])
|
||||||
|
else:
|
||||||
|
assert worker_ids == set(['gw0', 'gw1'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_color_yes_collection_on_non_atty(testdir, request):
|
||||||
|
"""skip collect progress report when working on non-terminals.
|
||||||
|
|
||||||
|
Similar to pytest-dev/pytest#1397
|
||||||
|
"""
|
||||||
|
tr = request.config.pluginmanager.getplugin("terminalreporter")
|
||||||
|
if not hasattr(tr, 'isatty'):
|
||||||
|
pytest.skip('only valid for newer pytest versions')
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
@pytest.mark.parametrize('i', range(10))
|
||||||
|
def test_this(i):
|
||||||
|
assert 1
|
||||||
|
""")
|
||||||
|
args = ['--color=yes', '-n2']
|
||||||
|
result = testdir.runpytest(*args)
|
||||||
|
assert 'test session starts' in result.stdout.str()
|
||||||
|
assert '\x1b[1m' in result.stdout.str()
|
||||||
|
assert 'gw0 [10] / gw1 [10]' in result.stdout.str()
|
||||||
|
assert 'gw0 C / gw1 C' not in result.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
|
def test_internal_error_with_maxfail(testdir):
|
||||||
|
"""
|
||||||
|
Internal error when using --maxfail option (#62, #65).
|
||||||
|
"""
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(params=['1', '2'])
|
||||||
|
def crasher():
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def test_aaa0(crasher):
|
||||||
|
pass
|
||||||
|
def test_aaa1(crasher):
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest_subprocess('--maxfail=1', '-n1')
|
||||||
|
result.stdout.fnmatch_lines(['* 1 error in *'])
|
||||||
|
assert 'INTERNALERROR' not in result.stderr.str()
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ def pytest_addoption(parser):
|
|||||||
help=("add a global test environment, XSpec-syntax. "))
|
help=("add a global test environment, XSpec-syntax. "))
|
||||||
|
|
||||||
|
|
||||||
def pytest_funcarg__specssh(request):
|
@pytest.fixture
|
||||||
|
def specssh(request):
|
||||||
return getspecssh(request.config)
|
return getspecssh(request.config)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,12 @@ def test_dist_options(testdir):
|
|||||||
|
|
||||||
|
|
||||||
def test_auto_detect_cpus(testdir, monkeypatch):
|
def test_auto_detect_cpus(testdir, monkeypatch):
|
||||||
import multiprocessing
|
import os
|
||||||
monkeypatch.setattr(multiprocessing, 'cpu_count', lambda: 99)
|
if hasattr(os, 'cpu_count'):
|
||||||
|
monkeypatch.setattr(os, 'cpu_count', lambda: 99)
|
||||||
|
else:
|
||||||
|
import multiprocessing
|
||||||
|
monkeypatch.setattr(multiprocessing, 'cpu_count', lambda: 99)
|
||||||
|
|
||||||
config = testdir.parseconfigure("-n2")
|
config = testdir.parseconfigure("-n2")
|
||||||
assert config.getoption('numprocesses') == 2
|
assert config.getoption('numprocesses') == 2
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import py
|
import py
|
||||||
|
import pytest
|
||||||
from xdist.slavemanage import SlaveController, unserialize_report
|
from xdist.slavemanage import SlaveController, unserialize_report
|
||||||
from xdist.remote import serialize_report
|
from xdist.remote import serialize_report
|
||||||
import execnet
|
import execnet
|
||||||
queue = py.builtin._tryimport("queue", "Queue")
|
|
||||||
import marshal
|
import marshal
|
||||||
|
|
||||||
|
queue = py.builtin._tryimport("queue", "Queue")
|
||||||
|
|
||||||
WAIT_TIMEOUT = 10.0
|
WAIT_TIMEOUT = 10.0
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +40,12 @@ class SlaveSetup:
|
|||||||
self.gateway = execnet.makegateway()
|
self.gateway = execnet.makegateway()
|
||||||
self.config = config = self.testdir.parseconfigure()
|
self.config = config = self.testdir.parseconfigure()
|
||||||
putevent = self.use_callback and self.events.put or None
|
putevent = self.use_callback and self.events.put or None
|
||||||
self.slp = SlaveController(None, self.gateway, config, putevent)
|
|
||||||
|
class DummyMananger:
|
||||||
|
specs = [0, 1]
|
||||||
|
|
||||||
|
self.slp = SlaveController(DummyMananger, self.gateway, config,
|
||||||
|
putevent)
|
||||||
self.request.addfinalizer(self.slp.ensure_teardown)
|
self.request.addfinalizer(self.slp.ensure_teardown)
|
||||||
self.slp.setup()
|
self.slp.setup()
|
||||||
|
|
||||||
@@ -57,10 +64,12 @@ class SlaveSetup:
|
|||||||
self.slp.sendcommand(name, **kwargs)
|
self.slp.sendcommand(name, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def pytest_funcarg__slave(request):
|
@pytest.fixture
|
||||||
|
def slave(request):
|
||||||
return SlaveSetup(request)
|
return SlaveSetup(request)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(reason='#59')
|
||||||
def test_remoteinitconfig(testdir):
|
def test_remoteinitconfig(testdir):
|
||||||
from xdist.remote import remote_initconfig
|
from xdist.remote import remote_initconfig
|
||||||
config1 = testdir.parseconfig()
|
config1 = testdir.parseconfig()
|
||||||
@@ -174,6 +183,8 @@ class TestSlaveInteractor:
|
|||||||
ev = slave.popevent("slavefinished")
|
ev = slave.popevent("slavefinished")
|
||||||
assert 'slaveoutput' in ev.kwargs
|
assert 'slaveoutput' in ev.kwargs
|
||||||
|
|
||||||
|
@pytest.mark.skipif(pytest.__version__ >= '3.0',
|
||||||
|
reason='skip at module level illegal in pytest 3.0')
|
||||||
def test_remote_collect_skip(self, slave):
|
def test_remote_collect_skip(self, slave):
|
||||||
slave.testdir.makepyfile("""
|
slave.testdir.makepyfile("""
|
||||||
import py
|
import py
|
||||||
@@ -251,3 +262,14 @@ class TestSlaveInteractor:
|
|||||||
("pytest_pycollect_makeitem", "name == 'test_func'"),
|
("pytest_pycollect_makeitem", "name == 'test_func'"),
|
||||||
("pytest_collectreport", "report.collector.fspath == bbb"),
|
("pytest_collectreport", "report.collector.fspath == bbb"),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_env_vars(testdir):
|
||||||
|
testdir.makepyfile('''
|
||||||
|
import os
|
||||||
|
def test():
|
||||||
|
assert os.environ['PYTEST_XDIST_WORKER'] in ('gw0', 'gw1')
|
||||||
|
assert os.environ['PYTEST_XDIST_WORKER_COUNT'] == '2'
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest('-n2', '--max-slave-restart=0')
|
||||||
|
assert result.ret == 0
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ from xdist.slavemanage import HostRSync, NodeManager
|
|||||||
pytest_plugins = "pytester"
|
pytest_plugins = "pytester"
|
||||||
|
|
||||||
|
|
||||||
def pytest_funcarg__hookrecorder(request, config):
|
@pytest.fixture
|
||||||
|
def hookrecorder(request, config):
|
||||||
hookrecorder = HookRecorder(config.pluginmanager)
|
hookrecorder = HookRecorder(config.pluginmanager)
|
||||||
if hasattr(hookrecorder, "start_recording"):
|
if hasattr(hookrecorder, "start_recording"):
|
||||||
hookrecorder.start_recording(newhooks)
|
hookrecorder.start_recording(newhooks)
|
||||||
@@ -16,11 +17,13 @@ def pytest_funcarg__hookrecorder(request, config):
|
|||||||
return hookrecorder
|
return hookrecorder
|
||||||
|
|
||||||
|
|
||||||
def pytest_funcarg__config(testdir):
|
@pytest.fixture
|
||||||
|
def config(testdir):
|
||||||
return testdir.parseconfig()
|
return testdir.parseconfig()
|
||||||
|
|
||||||
|
|
||||||
def pytest_funcarg__mysetup(tmpdir):
|
@pytest.fixture
|
||||||
|
def mysetup(tmpdir):
|
||||||
class mysetup:
|
class mysetup:
|
||||||
source = tmpdir.mkdir("source")
|
source = tmpdir.mkdir("source")
|
||||||
dest = tmpdir.mkdir("dest")
|
dest = tmpdir.mkdir("dest")
|
||||||
|
|||||||
25
tox.ini
25
tox.ini
@@ -1,20 +1,27 @@
|
|||||||
[tox]
|
[tox]
|
||||||
|
# if you change the envlist, please update .travis.yml file as well
|
||||||
envlist=
|
envlist=
|
||||||
py{26,27,34,35}-pytest2{4,5,6,7,8},py{27,34}-pytest28-pexpect,flakes,readme
|
py{26,27,34}-pytest2{6,7,8,9}
|
||||||
|
py35-pytest2{7,8,9}
|
||||||
|
py{27,35}-pytest28-pexpect
|
||||||
|
flakes
|
||||||
|
readme
|
||||||
|
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
changedir=testing
|
changedir=testing
|
||||||
passenv = USER USERNAME
|
passenv = USER USERNAME
|
||||||
deps =
|
deps =
|
||||||
pycmd
|
pycmd
|
||||||
setuptools_scm # to avoid .eggs
|
# to avoid .eggs
|
||||||
pytest24: pytest~=2.4.0
|
setuptools_scm
|
||||||
pytest25: pytest~=2.5.0
|
pytest26: pytest~=2.6.1
|
||||||
pytest26: pytest~=2.6.1
|
pytest27: pytest~=2.7.2
|
||||||
pytest27: pytest~=2.7.2
|
pytest28: pytest~=2.8.7
|
||||||
pytest28: pytest~=2.8.3
|
pytest29: pytest~=2.9.1
|
||||||
pexpect: pexpect
|
pexpect: pexpect
|
||||||
|
platform=
|
||||||
|
pexpect: linux|darwin
|
||||||
commands=
|
commands=
|
||||||
# always clean to avoid code unmarshal mismatch on old python/pytest
|
# always clean to avoid code unmarshal mismatch on old python/pytest
|
||||||
py.cleanup -aq
|
py.cleanup -aq
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
__all__ = ['__version__']
|
|
||||||
from xdist._version import version as __version__
|
from xdist._version import version as __version__
|
||||||
|
|
||||||
|
__all__ = ['__version__']
|
||||||
|
|||||||
@@ -535,6 +535,7 @@ class DSession:
|
|||||||
while not self.session_finished:
|
while not self.session_finished:
|
||||||
self.loop_once()
|
self.loop_once()
|
||||||
if self.shouldstop:
|
if self.shouldstop:
|
||||||
|
self.triggershutdown()
|
||||||
raise Interrupted(str(self.shouldstop))
|
raise Interrupted(str(self.shouldstop))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -722,17 +723,18 @@ class TerminalDistReporter:
|
|||||||
self.tr = config.pluginmanager.getplugin("terminalreporter")
|
self.tr = config.pluginmanager.getplugin("terminalreporter")
|
||||||
self._status = {}
|
self._status = {}
|
||||||
self._lastlen = 0
|
self._lastlen = 0
|
||||||
|
self._isatty = getattr(self.tr, 'isatty', self.tr.hasmarkup)
|
||||||
|
|
||||||
def write_line(self, msg):
|
def write_line(self, msg):
|
||||||
self.tr.write_line(msg)
|
self.tr.write_line(msg)
|
||||||
|
|
||||||
def ensure_show_status(self):
|
def ensure_show_status(self):
|
||||||
if not self.tr.hasmarkup:
|
if not self._isatty:
|
||||||
self.write_line(self.getstatus())
|
self.write_line(self.getstatus())
|
||||||
|
|
||||||
def setstatus(self, spec, status, show=True):
|
def setstatus(self, spec, status, show=True):
|
||||||
self._status[spec.id] = status
|
self._status[spec.id] = status
|
||||||
if show and self.tr.hasmarkup:
|
if show and self._isatty:
|
||||||
self.rewrite(self.getstatus())
|
self.rewrite(self.getstatus())
|
||||||
|
|
||||||
def getstatus(self):
|
def getstatus(self):
|
||||||
|
|||||||
@@ -4,8 +4,15 @@ import pytest
|
|||||||
|
|
||||||
def parse_numprocesses(s):
|
def parse_numprocesses(s):
|
||||||
if s == 'auto':
|
if s == 'auto':
|
||||||
import multiprocessing
|
try:
|
||||||
return multiprocessing.cpu_count()
|
from os import cpu_count
|
||||||
|
except ImportError:
|
||||||
|
from multiprocessing import cpu_count
|
||||||
|
try:
|
||||||
|
n = cpu_count()
|
||||||
|
except NotImplementedError:
|
||||||
|
return 1
|
||||||
|
return n if n else 1
|
||||||
else:
|
else:
|
||||||
return int(s)
|
return int(s)
|
||||||
|
|
||||||
@@ -99,3 +106,15 @@ def pytest_cmdline_main(config):
|
|||||||
if usepdb:
|
if usepdb:
|
||||||
raise pytest.UsageError(
|
raise pytest.UsageError(
|
||||||
"--pdb incompatible with distributing tests.")
|
"--pdb incompatible with distributing tests.")
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# fixtures
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def worker_id(request):
|
||||||
|
if hasattr(request.config, 'slaveinput'):
|
||||||
|
return request.config.slaveinput['slaveid']
|
||||||
|
else:
|
||||||
|
return 'master'
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ class SlaveInteractor:
|
|||||||
self.log("entering main loop")
|
self.log("entering main loop")
|
||||||
torun = []
|
torun = []
|
||||||
while 1:
|
while 1:
|
||||||
name, kwargs = self.channel.receive()
|
try:
|
||||||
|
name, kwargs = self.channel.receive()
|
||||||
|
except EOFError:
|
||||||
|
return True
|
||||||
self.log("received command", name, kwargs)
|
self.log("received command", name, kwargs)
|
||||||
if name == "runtests":
|
if name == "runtests":
|
||||||
torun.extend(kwargs['indices'])
|
torun.extend(kwargs['indices'])
|
||||||
@@ -145,6 +148,8 @@ if __name__ == '__channelexec__':
|
|||||||
os.environ['PYTHONPATH'] = (
|
os.environ['PYTHONPATH'] = (
|
||||||
importpath + os.pathsep +
|
importpath + os.pathsep +
|
||||||
os.environ.get('PYTHONPATH', ''))
|
os.environ.get('PYTHONPATH', ''))
|
||||||
|
os.environ['PYTEST_XDIST_WORKER'] = slaveinput['slaveid']
|
||||||
|
os.environ['PYTEST_XDIST_WORKER_COUNT'] = str(slaveinput['slavecount'])
|
||||||
# os.environ['PYTHONPATH'] = importpath
|
# os.environ['PYTHONPATH'] = importpath
|
||||||
import py
|
import py
|
||||||
config = remote_initconfig(option_dict, args)
|
config = remote_initconfig(option_dict, args)
|
||||||
|
|||||||
@@ -205,7 +205,8 @@ class SlaveController(object):
|
|||||||
self.putevent = putevent
|
self.putevent = putevent
|
||||||
self.gateway = gateway
|
self.gateway = gateway
|
||||||
self.config = config
|
self.config = config
|
||||||
self.slaveinput = {'slaveid': gateway.id}
|
self.slaveinput = {'slaveid': gateway.id,
|
||||||
|
'slavecount': len(nodemanager.specs)}
|
||||||
self._down = False
|
self._down = False
|
||||||
self._shutdown_sent = False
|
self._shutdown_sent = False
|
||||||
self.log = py.log.Producer("slavectl-%s" % gateway.id)
|
self.log = py.log.Producer("slavectl-%s" % gateway.id)
|
||||||
|
|||||||
Reference in New Issue
Block a user