Skip to content

Commit

Permalink
restore backwards compatability with pytest-xdist==1.22.0
Browse files Browse the repository at this point in the history
  • Loading branch information
graingert authored and ionelmc committed Aug 29, 2019
1 parent df92550 commit b33126d
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 28 deletions.
19 changes: 19 additions & 0 deletions src/pytest_cov/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,22 @@ def testsfailed(self):
@testsfailed.setter
def testsfailed(self, value):
setattr(self._session, self._attr, value)


def _attrgetter(attr):
"""
Return a callable object that fetches attr from its operand.
Unlike operator.attrgetter, the returned callable supports an extra two
arg form for a default.
"""
def fn(obj, *args):
return getattr(obj, attr, *args)

return fn


worker = 'slave' # for compatability with pytest-xdist<=1.22.0
workerid = worker + 'id'
workerinput = _attrgetter(worker + 'input')
workeroutput = _attrgetter(worker + 'output')
37 changes: 21 additions & 16 deletions src/pytest_cov/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from coverage.data import CoverageData

from .embed import cleanup
from .compat import StringIO
from .compat import StringIO, workeroutput, workerinput


class CovController(object):
Expand Down Expand Up @@ -207,26 +207,29 @@ def start(self):
def configure_node(self, node):
"""Workers need to know if they are collocated and what files have moved."""

node.workerinput['cov_master_host'] = socket.gethostname()
node.workerinput['cov_master_topdir'] = self.topdir
node.workerinput['cov_master_rsync_roots'] = [str(root) for root in node.nodemanager.roots]
workerinput(node).update({
'cov_master_host': socket.gethostname(),
'cov_master_topdir': self.topdir,
'cov_master_rsync_roots': [str(root) for root in node.nodemanager.roots],
})

def testnodedown(self, node, error):
"""Collect data file name from worker."""

# If worker doesn't return any data then it is likely that this
# plugin didn't get activated on the worker side.
if not (hasattr(node, 'workeroutput') and 'cov_worker_node_id' in node.workeroutput):
output = workeroutput(node, {})
if 'cov_worker_node_id' not in output:
self.failed_workers.append(node)
return

# If worker is not collocated then we must save the data file
# that it returns to us.
if 'cov_worker_data' in node.workeroutput:
if 'cov_worker_data' in output:
data_suffix = '%s.%s.%06d.%s' % (
socket.gethostname(), os.getpid(),
random.randint(0, 999999),
node.workeroutput['cov_worker_node_id']
output['cov_worker_node_id']
)

cov = coverage.Coverage(source=self.cov_source,
Expand All @@ -235,11 +238,11 @@ def testnodedown(self, node, error):
config_file=self.cov_config)
cov.start()
data = CoverageData()
data.read_fileobj(StringIO(node.workeroutput['cov_worker_data']))
data.read_fileobj(StringIO(output['cov_worker_data']))
cov.data.update(data)
cov.stop()
cov.save()
path = node.workeroutput['cov_worker_path']
path = output['cov_worker_path']
self.cov.config.paths['source'].append(path)

# Record the worker types that contribute to the data file.
Expand All @@ -266,12 +269,12 @@ def start(self):
cleanup()

# Determine whether we are collocated with master.
self.is_collocated = (socket.gethostname() == self.config.workerinput['cov_master_host'] and
self.topdir == self.config.workerinput['cov_master_topdir'])
self.is_collocated = (socket.gethostname() == workerinput(self.config)['cov_master_host'] and
self.topdir == workerinput(self.config)['cov_master_topdir'])

# If we are not collocated then rewrite master paths to worker paths.
if not self.is_collocated:
master_topdir = self.config.workerinput['cov_master_topdir']
master_topdir = workerinput(self.config)['cov_master_topdir']
worker_topdir = self.topdir
if self.cov_source is not None:
self.cov_source = [source.replace(master_topdir, worker_topdir)
Expand Down Expand Up @@ -303,7 +306,7 @@ def finish(self):

# If we are collocated then just inform the master of our
# data file to indicate that we have finished.
self.config.workeroutput['cov_worker_node_id'] = self.nodeid
workeroutput(self.config)['cov_worker_node_id'] = self.nodeid
else:
self.cov.combine()
self.cov.save()
Expand All @@ -312,11 +315,13 @@ def finish(self):
# it on the master node.

# Send all the data to the master over the channel.
self.config.workeroutput['cov_worker_path'] = self.topdir
self.config.workeroutput['cov_worker_node_id'] = self.nodeid
buff = StringIO()
self.cov.data.write_fileobj(buff)
self.config.workeroutput['cov_worker_data'] = buff.getvalue()
workeroutput(self.config).update({
'cov_worker_path': self.topdir,
'cov_worker_node_id': self.nodeid,
'cov_worker_data': buff.getvalue(),
})

def summary(self, stream):
"""Only the master reports so do nothing."""
Expand Down
8 changes: 5 additions & 3 deletions src/pytest_cov/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class Config(object):
self.options.cov_fail_under = cov_config.fail_under

def _is_worker(self, session):
return hasattr(session.config, 'workerinput')
return compat.workerinput(session.config, None) is not None

def pytest_sessionstart(self, session):
"""At session start determine our implementation and delegate to it."""
Expand All @@ -182,8 +182,10 @@ def pytest_sessionstart(self, session):

self.pid = os.getpid()
if self._is_worker(session):
nodeid = session.config.workerinput.get('workerid',
getattr(session, 'nodeid'))
nodeid = (
compat.workerinput(session.config)
.get(compat.workerid, getattr(session, 'nodeid'))
)
self.start(engine.DistWorker, session.config, nodeid)
elif not self._started:
self.start(engine.Central)
Expand Down
21 changes: 12 additions & 9 deletions tests/test_pytest_cov.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
from io import StringIO

import pytest_cov.plugin
from pytest_cov import compat

coverage, platform, StrictVersion # required for skipif mark on test_cov_min_from_coveragerc

max_worker_restart_0 = "--max-" + compat.worker + "-restart=0"

SCRIPT = '''
import sys, helper
Expand Down Expand Up @@ -605,7 +608,7 @@ def test_dist_collocated(testdir, prop):
'--cov-report=term-missing',
'--dist=load',
'--tx=2*popen',
'--max-worker-restart=0',
max_worker_restart_0,
script, *prop.args)

result.stdout.fnmatch_lines([
Expand Down Expand Up @@ -638,7 +641,7 @@ def test_dist_not_collocated(testdir, prop):
'--tx=popen//chdir=%s' % dir2,
'--rsyncdir=%s' % script.basename,
'--rsyncdir=.coveragerc',
'--max-worker-restart=0', '-s',
max_worker_restart_0, '-s',
script, *prop.args)

result.stdout.fnmatch_lines([
Expand Down Expand Up @@ -672,7 +675,7 @@ def test_dist_not_collocated_coveragerc_source(testdir, prop):
'--tx=popen//chdir=%s' % dir2,
'--rsyncdir=%s' % script.basename,
'--rsyncdir=.coveragerc',
'--max-worker-restart=0', '-s',
max_worker_restart_0, '-s',
script, *prop.args)

result.stdout.fnmatch_lines([
Expand Down Expand Up @@ -784,7 +787,7 @@ def test_dist_subprocess_collocated(testdir):
'--cov-report=term-missing',
'--dist=load',
'--tx=2*popen',
'--max-worker-restart=0',
max_worker_restart_0,
parent_script)

result.stdout.fnmatch_lines([
Expand Down Expand Up @@ -819,7 +822,7 @@ def test_dist_subprocess_not_collocated(testdir, tmpdir):
'--rsyncdir=%s' % child_script,
'--rsyncdir=%s' % parent_script,
'--rsyncdir=.coveragerc',
'--max-worker-restart=0',
max_worker_restart_0,
parent_script)

result.stdout.fnmatch_lines([
Expand Down Expand Up @@ -885,7 +888,7 @@ def test_dist_missing_data(testdir):
'--cov-report=term-missing',
'--dist=load',
'--tx=popen//python=%s' % exe,
'--max-worker-restart=0',
max_worker_restart_0,
script)

assert result.ret == 0
Expand Down Expand Up @@ -1422,7 +1425,7 @@ def test_cover_conftest_dist(testdir):
'--cov-report=term-missing',
'--dist=load',
'--tx=2*popen',
'--max-worker-restart=0',
max_worker_restart_0,
script)
assert result.ret == 0
result.stdout.fnmatch_lines([CONF_RESULT])
Expand Down Expand Up @@ -1511,7 +1514,7 @@ def test_coveragerc_dist(testdir):
'--cov=%s' % script.dirpath(),
'--cov-report=term-missing',
'-n', '2',
'--max-worker-restart=0',
max_worker_restart_0,
script)
assert result.ret == 0
result.stdout.fnmatch_lines(
Expand Down Expand Up @@ -1707,7 +1710,7 @@ def test_external_data_file_xdist(testdir):
result = testdir.runpytest('-v',
'--cov=%s' % script.dirpath(),
'-n', '1',
'--max-worker-restart=0',
max_worker_restart_0,
script)
assert result.ret == 0
assert glob.glob(str(testdir.tmpdir.join('some/special/place/coverage-data*')))
Expand Down

0 comments on commit b33126d

Please sign in to comment.