* introduce explicit pytest_configure_node hook for node configuration,

simplifying implementation of slaveinput/slaveoutput data exchange
* only require the already released execnet-1.0.5
This commit is contained in:
holger krekel
2010-04-22 17:00:03 +02:00
parent 8d6bd3ecde
commit 9abaae8778
4 changed files with 37 additions and 41 deletions

View File

@@ -22,7 +22,7 @@ setup(
packages = ['xdist'], packages = ['xdist'],
entry_points = {'pytest11': ['xdist = xdist.plugin'],}, entry_points = {'pytest11': ['xdist = xdist.plugin'],},
zip_safe=False, zip_safe=False,
install_requires = ['execnet>=1.0.6', 'py>=1.2.2'], install_requires = ['execnet>=1.0.5', 'py>=1.2.2'],
classifiers=[ classifiers=[
'Development Status :: 4 - Beta', 'Development Status :: 4 - Beta',
'Intended Audience :: Developers', 'Intended Audience :: Developers',

View File

@@ -120,30 +120,30 @@ class TestDistribution:
def test_data_exchange(self, testdir): def test_data_exchange(self, testdir):
c1 = testdir.makeconftest(""" c1 = testdir.makeconftest("""
# This hook only called on master. # This hook only called on master.
def pytest_testnodeready(node): def pytest_configure_node(node):
node.slaveinput['a'] = 42 node.slaveinput['a'] = 42
node.slaveinput['b'] = 7 node.slaveinput['b'] = 7
# This hook only take action on slave. # This hook only takes action on slave.
def pytest_sessionstart(session): def pytest_configure(config):
if hasattr(session.config, 'slaveinput'): if hasattr(config, 'slaveinput'):
a = session.config.slaveinput['a'] a = config.slaveinput['a']
b = session.config.slaveinput['b'] b = config.slaveinput['b']
r = a + b r = a + b
session.config.slaveoutput['r'] = r config.slaveoutput['r'] = r
# This hook only called on master. # This hook only called on master.
def pytest_testnodedown(node, error): def pytest_testnodedown(node, error):
node.config.calc_result = node.slaveoutput['r'] node.config.calc_result = node.slaveoutput['r']
# This hook only take action on master. # This hook only takes action on master.
def pytest_terminal_summary(terminalreporter): def pytest_terminal_summary(terminalreporter):
if not hasattr(terminalreporter.config, 'slaveinput'): if not hasattr(terminalreporter.config, 'slaveinput'):
calc_result = terminalreporter.config.calc_result calc_result = terminalreporter.config.calc_result
terminalreporter._tw.sep('-', 'calculated result is %s' % calc_result) terminalreporter._tw.sep('-',
'calculated result is %s' % calc_result)
""") """)
p1 = testdir.makepyfile("def test_func(): pass") p1 = testdir.makepyfile("def test_func(): pass")
result = testdir.runpytest(p1, '-d', '--tx=popen') result = testdir.runpytest(p1, '-d', '--tx=popen')
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines([

View File

@@ -8,6 +8,9 @@ def pytest_gwmanage_rsyncstart(source, gateways):
def pytest_gwmanage_rsyncfinish(source, gateways): def pytest_gwmanage_rsyncfinish(source, gateways):
""" called after rsyncing a directory to remote gateways takes place. """ """ called after rsyncing a directory to remote gateways takes place. """
def pytest_configure_node(node):
""" configure node information before it gets instantiated. """
def pytest_testnodeready(node): def pytest_testnodeready(node):
""" Test Node is ready to operate. """ """ Test Node is ready to operate. """
@@ -19,3 +22,4 @@ def pytest_rescheduleitems(items):
def pytest_looponfailinfo(failreports, rootdirs): def pytest_looponfailinfo(failreports, rootdirs):
""" info for repeating failing tests. """ """ info for repeating failing tests. """

View File

@@ -18,12 +18,10 @@ class TXNode(object):
self.config = config self.config = config
self.putevent = putevent self.putevent = putevent
self.gateway = gateway self.gateway = gateway
self.channel = install_slave(gateway, config) self.slaveinput = {}
self.channel = install_slave(self)
self.channel.setcallback(self.callback, endmarker=self.ENDMARK) self.channel.setcallback(self.callback, endmarker=self.ENDMARK)
self._down = False self._down = False
self.slaveinputsent = False
self.slaveinput = {}
self.slaveoutput = {}
def __repr__(self): def __repr__(self):
id = self.gateway.id id = self.gateway.id
@@ -72,30 +70,22 @@ class TXNode(object):
py.builtin.print_("!" * 20, excinfo) py.builtin.print_("!" * 20, excinfo)
self.config.pluginmanager.notify_exception(excinfo) self.config.pluginmanager.notify_exception(excinfo)
def sendslaveinput(self):
if not self.slaveinputsent:
self.channel.send(self.slaveinput)
self.slaveinputsent = True
def send(self, item): def send(self, item):
assert item is not None assert item is not None
self.sendslaveinput()
self.channel.send(item) self.channel.send(item)
def sendlist(self, itemlist): def sendlist(self, itemlist):
self.sendslaveinput()
self.channel.send(itemlist) self.channel.send(itemlist)
def shutdown(self, kill=False): def shutdown(self, kill=False):
if kill: if kill:
self.gateway.exit() self.gateway.exit()
else: else:
self.sendslaveinput()
self.channel.send(None) self.channel.send(None)
# setting up slave code # configuring and setting up slave node
def install_slave(gateway, config): def install_slave(node):
channel = gateway.remote_exec(source=""" channel = node.gateway.remote_exec(source="""
import os, sys import os, sys
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
from xdist.mypickle import PickleChannel from xdist.mypickle import PickleChannel
@@ -108,12 +98,14 @@ def install_slave(gateway, config):
channel.receive() channel.receive()
channel = PickleChannel(channel) channel = PickleChannel(channel)
basetemp = None basetemp = None
if gateway.spec.popen: config = node.config
config.hook.pytest_configure_node(node=node)
if node.gateway.spec.popen:
popenbase = config.ensuretemp("popen") popenbase = config.ensuretemp("popen")
basetemp = py.path.local.make_numbered_dir(prefix="slave-", basetemp = py.path.local.make_numbered_dir(prefix="slave-",
keep=0, rootdir=popenbase) keep=0, rootdir=popenbase)
basetemp = str(basetemp) basetemp = str(basetemp)
channel.send((config, basetemp, gateway.id)) channel.send((config, node.slaveinput, basetemp, node.gateway.id))
return channel return channel
class SlaveNode(object): class SlaveNode(object):
@@ -134,15 +126,15 @@ class SlaveNode(object):
def run(self): def run(self):
channel = self.channel channel = self.channel
self.config, basetemp, self.nodeid = channel.receive() self.config, slaveinput, basetemp, self.nodeid = channel.receive()
if basetemp: if basetemp:
self.config.basetemp = py.path.local(basetemp) self.config.basetemp = py.path.local(basetemp)
self.config.slaveinput = slaveinput
self.config.slaveoutput = {}
self.config.pluginmanager.do_configure(self.config) self.config.pluginmanager.do_configure(self.config)
self.config.pluginmanager.register(self) self.config.pluginmanager.register(self)
self.runner = self.config.pluginmanager.getplugin("pytest_runner") self.runner = self.config.pluginmanager.getplugin("pytest_runner")
self.sendevent("slaveready") self.sendevent("slaveready")
self.config.slaveinput = channel.receive()
self.config.slaveoutput = {}
try: try:
self.config.hook.pytest_sessionstart(session=self) self.config.hook.pytest_sessionstart(session=self)
while 1: while 1: