Compare commits

...

30 Commits

Author SHA1 Message Date
Ronny Pfannschmidt
f43a64ae59 remove .dev version tag from changelog 2016-08-12 16:22:14 +02:00
Bruno Oliveira
cd7d8ca42a Merge pull request #83 from RonnyPfannschmidt/travis
add travis deploy for pypi release publishing
2016-08-12 11:18:23 -03:00
Ronny Pfannschmidt
6241167b6c add travis deploy for pypi release publishing 2016-08-12 15:48:50 +02:00
Bruno Oliveira
eb46f9b642 Merge pull request #80 from nicoddemus/cpu-auto-errors
Cpu auto errors
2016-08-06 17:21:09 -03:00
Bruno Oliveira
a2881fd8a9 Fix test_auto_detect_cpus 2016-08-06 17:06:37 -03:00
Bruno Oliveira
d8d9f3684b Merge remote-tracking branch 'upstream/master' into cpu-auto-errors 2016-08-06 17:03:06 -03:00
Ronny Pfannschmidt
9039807943 Merge pull request #78 from nicoddemus/env-vars
Add env variables to identify workers
2016-08-05 09:16:38 +02:00
Bruno Oliveira
d498cb3e0f Add env variables to identify workers 2016-08-04 21:53:13 -03:00
Bruno Oliveira
1c7eb24a1f Merge pull request #77 from nicoddemus/funcarg
Replace "pytest_funcarg__" by @pytest.fixture
2016-08-04 20:35:25 -03:00
Bruno Oliveira
7d124ecf87 Replace "pytest_funcarg__" by @pytest.fixture 2016-08-04 20:26:08 -03:00
Ronny Pfannschmidt
e8fa737196 Merge pull request #67 from nicoddemus/issue-66-clean-shutdown
Cleanly shutdown workers if session should be interrupted
2016-06-21 18:12:17 +02:00
Bruno Oliveira
305acdd72a Cleanly shutdown workers if session should be interrupted
As discussed in #66
2016-06-07 19:35:08 -03:00
Ronny Pfannschmidt
4fc9cb6e99 Merge pull request #66 from nicoddemus/issue-65-internal-error
Fix internal error when a fixture raises an exception
2016-06-07 08:29:19 +02:00
Bruno Oliveira
b4a7a1a8a8 Fix internal error when using --maxfail option
Fix #65
Fix #62
2016-06-06 20:55:54 -03:00
Ronny Pfannschmidt
c27ac36fca Merge pull request #55 from nicoddemus/collect-report-atty
Skip progress display when in non-terminal
2016-05-13 02:53:00 +02:00
Bruno Oliveira
9786e3d774 Move comment in tox.ini
Latest tox seems to be broken in this regard, it is not stripping the
comment from the dependency line
2016-05-11 22:28:22 -03:00
Bruno Oliveira
8ec8d29cbf Mark test_remoteinitconfig as xfail
#59
2016-05-11 22:25:12 -03:00
Bruno Oliveira
dd3d180fe3 Add pytest 2.9 and drop pytest 2.4 and 2.5 from build matrix 2016-05-11 22:15:33 -03:00
Bruno Oliveira
20fe1f9874 Skip progress display when in non-terminal (pytest >= 2.9)
See pytest-dev/pytest#1397
2016-05-11 22:15:25 -03:00
Bruno Oliveira
8954f0d63d Add Framework::Pytest to list of classifiers 2016-03-22 20:53:07 -03:00
Bruno Oliveira
ba35a3da02 Add syntax highlight in README 2016-02-23 22:36:42 -03:00
Bruno Oliveira
6601b5f9ba Merge pull request #49 from nicoddemus/worker-id-fixture
Worker id fixture
2016-02-23 22:11:52 -03:00
Bruno Oliveira
b27301e1d9 Improve test a bit and add CHANGELOG entry 2016-02-23 20:53:46 -03:00
Bruno Oliveira
7e6011541f Fix flakes 2016-02-23 20:39:41 -03:00
hellmanj
7f8ae3944c worker_id fixture as shown in #47 2016-02-23 17:58:33 -05:00
Bruno Oliveira
a11632b5d0 Remove old .hgtags file 2016-01-30 21:37:16 -02:00
Ronny Pfannschmidt
f19b804c67 Merge pull request #43 from nicoddemus/ci-refactorings
Refactor tox and ci scripts
2016-01-30 22:53:39 +01:00
Bruno Oliveira
96506867d1 Refactor tox and ci scripts
Make sure a plain "tox" command works in all platforms without failures,
which facilitates making releases using a "devpi upload/test" workflow

* Fix small flakes failures
* Limit py35 testing to pytest>=2.7, as pytest<2.7 does not work on py35
* pexpect environments only work on Linux platforms and should be skipped on Windows
* Simplify AppVeyor script by running all tox environments: no need to have a build matrix
  because AppVeyor does not execute builds in parallel
* Add all environments to travis.yml, obtained from "tox --listenvs"
2016-01-30 16:47:07 -02:00
Bruno Oliveira
023226840c Prepare CHANGELOG for next release 2016-01-30 12:03:55 -02:00
Omer Katz
26abac7a95 Added error handling to -n auto. 2015-11-09 12:30:10 +02:00
18 changed files with 232 additions and 86 deletions

21
.hgtags
View File

@@ -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

View File

@@ -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

View File

@@ -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
---- ----

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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',

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -1,2 +1,3 @@
__all__ = ['__version__']
from xdist._version import version as __version__ from xdist._version import version as __version__
__all__ = ['__version__']

View File

@@ -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):

View File

@@ -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'

View File

@@ -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)

View File

@@ -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)