[svn r63153] refactoring almost complete, apart from testnodeready info
--HG-- branch : trunk
This commit is contained in:
parent
10fb32ad37
commit
afca655202
|
@ -25,7 +25,7 @@ class LoopState(object):
|
|||
self.testsfailed = False
|
||||
|
||||
def pyevent_itemtestreport(self, event):
|
||||
if event.colitem in self.dsession.item2host:
|
||||
if event.colitem in self.dsession.item2node:
|
||||
self.dsession.removeitem(event.colitem)
|
||||
if event.failed:
|
||||
self.testsfailed = True
|
||||
|
@ -34,14 +34,14 @@ class LoopState(object):
|
|||
if event.passed:
|
||||
self.colitems.extend(event.result)
|
||||
|
||||
def pyevent_testnodeready(self, event):
|
||||
self.dsession.addhost(event.host)
|
||||
def pyevent_testnodeready(self, node):
|
||||
self.dsession.addnode(node)
|
||||
|
||||
def pyevent_testnodedown(self, event):
|
||||
pending = self.dsession.removehost(event.host)
|
||||
def pyevent_testnodedown(self, node, error=None):
|
||||
pending = self.dsession.removenode(node)
|
||||
if pending:
|
||||
crashitem = pending[0]
|
||||
self.dsession.handle_crashitem(crashitem, event.host)
|
||||
self.dsession.handle_crashitem(crashitem, node)
|
||||
self.colitems.extend(pending[1:])
|
||||
|
||||
def pyevent_rescheduleitems(self, event):
|
||||
|
@ -59,8 +59,8 @@ class DSession(Session):
|
|||
super(DSession, self).__init__(config=config)
|
||||
|
||||
self.queue = Queue.Queue()
|
||||
self.host2pending = {}
|
||||
self.item2host = {}
|
||||
self.node2pending = {}
|
||||
self.item2node = {}
|
||||
if self.config.getvalue("executable") and \
|
||||
not self.config.getvalue("numprocesses"):
|
||||
self.config.option.numprocesses = 1
|
||||
|
@ -84,7 +84,7 @@ class DSession(Session):
|
|||
if config.option.numprocesses:
|
||||
return
|
||||
try:
|
||||
config.getvalue('hosts')
|
||||
config.getvalue('xspecs')
|
||||
except KeyError:
|
||||
print "Please specify test environments for distribution of tests:"
|
||||
print "py.test --tx ssh=user@somehost --tx popen//python=python2.5"
|
||||
|
@ -97,9 +97,9 @@ class DSession(Session):
|
|||
def main(self, colitems=None):
|
||||
colitems = self.getinitialitems(colitems)
|
||||
self.sessionstarts()
|
||||
self.setup_hosts()
|
||||
self.setup_nodes()
|
||||
exitstatus = self.loop(colitems)
|
||||
self.teardown_hosts()
|
||||
self.teardown_nodes()
|
||||
self.sessionfinishes()
|
||||
return exitstatus
|
||||
|
||||
|
@ -124,10 +124,10 @@ class DSession(Session):
|
|||
|
||||
# termination conditions
|
||||
if ((loopstate.testsfailed and self.config.option.exitfirst) or
|
||||
(not self.item2host and not colitems and not self.queue.qsize())):
|
||||
(not self.item2node and not colitems and not self.queue.qsize())):
|
||||
self.triggershutdown()
|
||||
loopstate.shuttingdown = True
|
||||
elif not self.host2pending:
|
||||
elif not self.node2pending:
|
||||
loopstate.exitstatus = outcome.EXIT_NOHOSTS
|
||||
|
||||
def loop_once_shutdown(self, loopstate):
|
||||
|
@ -135,10 +135,10 @@ class DSession(Session):
|
|||
# events other than HostDown upstream
|
||||
eventname, args, kwargs = self.queue.get()
|
||||
if eventname == "testnodedown":
|
||||
ev, = args
|
||||
self.bus.notify("testnodedown", ev)
|
||||
self.removehost(ev.host)
|
||||
if not self.host2pending:
|
||||
node, error = args[0], args[1]
|
||||
self.bus.notify("testnodedown", node, error)
|
||||
self.removenode(node)
|
||||
if not self.node2pending:
|
||||
# finished
|
||||
if loopstate.testsfailed:
|
||||
loopstate.exitstatus = outcome.EXIT_TESTSFAILED
|
||||
|
@ -170,21 +170,21 @@ class DSession(Session):
|
|||
return exitstatus
|
||||
|
||||
def triggershutdown(self):
|
||||
for host in self.host2pending:
|
||||
host.node.shutdown()
|
||||
for node in self.node2pending:
|
||||
node.shutdown()
|
||||
|
||||
def addhost(self, host):
|
||||
assert host not in self.host2pending
|
||||
self.host2pending[host] = []
|
||||
def addnode(self, node):
|
||||
assert node not in self.node2pending
|
||||
self.node2pending[node] = []
|
||||
|
||||
def removehost(self, host):
|
||||
def removenode(self, node):
|
||||
try:
|
||||
pending = self.host2pending.pop(host)
|
||||
pending = self.node2pending.pop(node)
|
||||
except KeyError:
|
||||
# this happens if we didn't receive a testnodeready event yet
|
||||
return []
|
||||
for item in pending:
|
||||
del self.item2host[item]
|
||||
del self.item2node[item]
|
||||
return pending
|
||||
|
||||
def triggertesting(self, colitems):
|
||||
|
@ -204,17 +204,17 @@ class DSession(Session):
|
|||
def senditems(self, tosend):
|
||||
if not tosend:
|
||||
return
|
||||
for host, pending in self.host2pending.items():
|
||||
for node, pending in self.node2pending.items():
|
||||
room = self.MAXITEMSPERHOST - len(pending)
|
||||
if room > 0:
|
||||
sending = tosend[:room]
|
||||
host.node.sendlist(sending)
|
||||
node.sendlist(sending)
|
||||
for item in sending:
|
||||
#assert item not in self.item2host, (
|
||||
# "sending same item %r to multiple hosts "
|
||||
#assert item not in self.item2node, (
|
||||
# "sending same item %r to multiple "
|
||||
# "not implemented" %(item,))
|
||||
self.item2host[item] = host
|
||||
self.bus.notify("itemstart", event.ItemStart(item, host))
|
||||
self.item2node[item] = node
|
||||
self.bus.notify("itemstart", event.ItemStart(item, node))
|
||||
pending.extend(sending)
|
||||
tosend[:] = tosend[room:] # update inplace
|
||||
if not tosend:
|
||||
|
@ -224,24 +224,24 @@ class DSession(Session):
|
|||
self.queueevent("rescheduleitems", event.RescheduleItems(tosend))
|
||||
|
||||
def removeitem(self, item):
|
||||
if item not in self.item2host:
|
||||
raise AssertionError(item, self.item2host)
|
||||
host = self.item2host.pop(item)
|
||||
self.host2pending[host].remove(item)
|
||||
if item not in self.item2node:
|
||||
raise AssertionError(item, self.item2node)
|
||||
node = self.item2node.pop(item)
|
||||
self.node2pending[node].remove(item)
|
||||
#self.config.bus.notify("removeitem", item, host.hostid)
|
||||
|
||||
def handle_crashitem(self, item, host):
|
||||
longrepr = "!!! Host %r crashed during running of test %r" %(host, item)
|
||||
def handle_crashitem(self, item, node):
|
||||
longrepr = "!!! Node %r crashed during running of test %r" %(node, item)
|
||||
rep = event.ItemTestReport(item, when="???", excinfo=longrepr)
|
||||
self.bus.notify("itemtestreport", rep)
|
||||
|
||||
def setup_hosts(self):
|
||||
def setup_nodes(self):
|
||||
""" setup any neccessary resources ahead of the test run. """
|
||||
from py.__.test.dsession.hostmanage import HostManager
|
||||
self.hm = HostManager(self.config)
|
||||
self.hm.setup_hosts(putevent=self.queue.put)
|
||||
|
||||
def teardown_hosts(self):
|
||||
def teardown_nodes(self):
|
||||
""" teardown any resources after a test run. """
|
||||
self.hm.teardown_hosts()
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ class HostManager(object):
|
|||
hosts = getxspecs(self.config)
|
||||
self.roots = getconfigroots(config)
|
||||
self.gwmanager = GatewayManager(hosts)
|
||||
self.nodes = []
|
||||
|
||||
def makegateways(self):
|
||||
# we change to the topdir sot that
|
||||
|
@ -116,11 +117,9 @@ class HostManager(object):
|
|||
""").waitclose()
|
||||
|
||||
for gateway in self.gwmanager.gateways:
|
||||
host = gateway.spec
|
||||
host.node = MasterNode(host,
|
||||
gateway,
|
||||
self.config,
|
||||
putevent)
|
||||
node = MasterNode(gateway, self.config, putevent)
|
||||
self.nodes.append(node)
|
||||
|
||||
def teardown_hosts(self):
|
||||
# XXX teardown nodes?
|
||||
self.gwmanager.exit()
|
||||
|
|
|
@ -6,13 +6,14 @@ from py.__.test import event
|
|||
from py.__.test.dsession.mypickle import PickleChannel
|
||||
|
||||
class MasterNode(object):
|
||||
""" Install slave code, manage sending test tasks & receiving results """
|
||||
ENDMARK = -1
|
||||
|
||||
def __init__(self, host, gateway, config, putevent):
|
||||
self.host = host
|
||||
def __init__(self, gateway, config, putevent):
|
||||
self.config = config
|
||||
self.putevent = putevent
|
||||
self.channel = install_slave(host, gateway, config)
|
||||
self.gateway = gateway
|
||||
self.channel = install_slave(gateway, config)
|
||||
self.channel.setcallback(self.callback, endmarker=self.ENDMARK)
|
||||
self._down = False
|
||||
|
||||
|
@ -32,23 +33,25 @@ class MasterNode(object):
|
|||
err = self.channel._getremoteerror()
|
||||
if not self._down:
|
||||
if not err:
|
||||
err = "TERMINATED"
|
||||
self.notify("testnodedown", event.HostDown(self.host, err))
|
||||
err = "Not properly terminated"
|
||||
self.notify("testnodedown", self, err)
|
||||
self._down = True
|
||||
return
|
||||
elif eventcall is None:
|
||||
eventname, args, kwargs = eventcall
|
||||
if eventname == "slaveready":
|
||||
self.notify("testnodeready", self)
|
||||
elif eventname == "slavefinished":
|
||||
self._down = True
|
||||
self.notify("testnodedown", event.HostDown(self.host, None))
|
||||
return
|
||||
except KeyboardInterrupt:
|
||||
self.notify("testnodedown", self, None)
|
||||
else:
|
||||
self.notify(eventname, *args, **kwargs)
|
||||
except KeyboardInterrupt:
|
||||
# should not land in receiver-thread
|
||||
raise
|
||||
except:
|
||||
excinfo = py.code.ExceptionInfo()
|
||||
print "!" * 20, excinfo
|
||||
self.notify("internalerror", event.InternalException(excinfo))
|
||||
else:
|
||||
# XXX we need to have the proper event name
|
||||
eventname, args, kwargs = eventcall
|
||||
self.notify(eventname, *args, **kwargs)
|
||||
|
||||
def send(self, item):
|
||||
assert item is not None
|
||||
|
@ -61,7 +64,7 @@ class MasterNode(object):
|
|||
self.channel.send(None)
|
||||
|
||||
# setting up slave code
|
||||
def install_slave(host, gateway, config):
|
||||
def install_slave(gateway, config):
|
||||
channel = gateway.remote_exec(source="""
|
||||
from py.__.test.dsession.mypickle import PickleChannel
|
||||
from py.__.test.dsession.masterslave import SlaveNode
|
||||
|
@ -71,12 +74,12 @@ def install_slave(host, gateway, config):
|
|||
""")
|
||||
channel = PickleChannel(channel)
|
||||
basetemp = None
|
||||
if host.popen:
|
||||
if gateway.spec.popen:
|
||||
popenbase = config.ensuretemp("popen")
|
||||
basetemp = py.path.local.make_numbered_dir(prefix="slave-",
|
||||
keep=0, rootdir=popenbase)
|
||||
basetemp = str(basetemp)
|
||||
channel.send((host, config, basetemp))
|
||||
channel.send((config, basetemp))
|
||||
return channel
|
||||
|
||||
class SlaveNode(object):
|
||||
|
@ -91,17 +94,16 @@ class SlaveNode(object):
|
|||
|
||||
def run(self):
|
||||
channel = self.channel
|
||||
host, self.config, basetemp = channel.receive()
|
||||
self.config, basetemp = channel.receive()
|
||||
if basetemp:
|
||||
self.config.basetemp = py.path.local(basetemp)
|
||||
self.config.pytestplugins.do_configure(self.config)
|
||||
self.sendevent("testnodeready", maketestnodeready(host))
|
||||
self.sendevent("slaveready")
|
||||
try:
|
||||
while 1:
|
||||
task = channel.receive()
|
||||
self.config.bus.notify("masterslave_receivedtask", task)
|
||||
if task is None: # shutdown
|
||||
self.channel.send(None)
|
||||
if task is None:
|
||||
self.sendevent("slavefinished")
|
||||
break
|
||||
if isinstance(task, list):
|
||||
for item in task:
|
||||
|
@ -119,10 +121,3 @@ class SlaveNode(object):
|
|||
testrep = runner(item)
|
||||
self.sendevent("itemtestreport", testrep)
|
||||
|
||||
|
||||
def maketestnodeready(host="INPROCESS"):
|
||||
import sys
|
||||
platinfo = {}
|
||||
for name in 'platform', 'executable', 'version_info':
|
||||
platinfo["sys."+name] = getattr(sys, name)
|
||||
return event.HostUp(host, platinfo)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from py.__.test.dsession.dsession import DSession
|
||||
from py.__.test.dsession.masterslave import maketestnodeready
|
||||
from py.__.test.runner import basic_collect_report
|
||||
from py.__.test import event
|
||||
from py.__.test import outcome
|
||||
import py
|
||||
|
||||
XSpec = py.execnet.XSpec
|
||||
|
||||
def run(item):
|
||||
runner = item._getrunner()
|
||||
return runner(item)
|
||||
|
@ -33,35 +34,33 @@ class TestDSession:
|
|||
config.initsession().fixoptions()
|
||||
assert config.option.numprocesses == 3
|
||||
|
||||
def test_add_remove_host(self, testdir):
|
||||
def test_add_remove_node(self, testdir):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
rep = run(item)
|
||||
session = DSession(item.config)
|
||||
host = py.execnet.XSpec("popen")
|
||||
host.node = MockNode()
|
||||
assert not session.host2pending
|
||||
session.addhost(host)
|
||||
assert len(session.host2pending) == 1
|
||||
node = MockNode()
|
||||
assert not session.node2pending
|
||||
session.addnode(node)
|
||||
assert len(session.node2pending) == 1
|
||||
session.senditems([item])
|
||||
pending = session.removehost(host)
|
||||
pending = session.removenode(node)
|
||||
assert pending == [item]
|
||||
assert item not in session.item2host
|
||||
l = session.removehost(host)
|
||||
assert item not in session.item2node
|
||||
l = session.removenode(node)
|
||||
assert not l
|
||||
|
||||
def test_senditems_removeitems(self, testdir):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
rep = run(item)
|
||||
session = DSession(item.config)
|
||||
host = py.execnet.XSpec("popen")
|
||||
host.node = MockNode()
|
||||
session.addhost(host)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
session.senditems([item])
|
||||
assert session.host2pending[host] == [item]
|
||||
assert session.item2host[item] == host
|
||||
assert session.node2pending[node] == [item]
|
||||
assert session.item2node[item] == node
|
||||
session.removeitem(item)
|
||||
assert not session.host2pending[host]
|
||||
assert not session.item2host
|
||||
assert not session.node2pending[node]
|
||||
assert not session.item2node
|
||||
|
||||
def test_triggertesting_collect(self, testdir):
|
||||
modcol = testdir.getmodulecol("""
|
||||
|
@ -78,19 +77,17 @@ class TestDSession:
|
|||
def test_triggertesting_item(self, testdir):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
session = DSession(item.config)
|
||||
host1 = py.execnet.XSpec("popen")
|
||||
host1.node = MockNode()
|
||||
host2 = py.execnet.XSpec("popen")
|
||||
host2.node = MockNode()
|
||||
session.addhost(host1)
|
||||
session.addhost(host2)
|
||||
node1 = MockNode()
|
||||
node2 = MockNode()
|
||||
session.addnode(node1)
|
||||
session.addnode(node2)
|
||||
session.triggertesting([item] * (session.MAXITEMSPERHOST*2 + 1))
|
||||
host1_sent = host1.node.sent[0]
|
||||
host2_sent = host2.node.sent[0]
|
||||
assert host1_sent == [item] * session.MAXITEMSPERHOST
|
||||
assert host2_sent == [item] * session.MAXITEMSPERHOST
|
||||
assert session.host2pending[host1] == host1_sent
|
||||
assert session.host2pending[host2] == host2_sent
|
||||
sent1 = node1.sent[0]
|
||||
sent2 = node2.sent[0]
|
||||
assert sent1 == [item] * session.MAXITEMSPERHOST
|
||||
assert sent2 == [item] * session.MAXITEMSPERHOST
|
||||
assert session.node2pending[node1] == sent1
|
||||
assert session.node2pending[node2] == sent2
|
||||
name, args, kwargs = session.queue.get(block=False)
|
||||
assert name == "rescheduleitems"
|
||||
ev, = args
|
||||
|
@ -115,37 +112,34 @@ class TestDSession:
|
|||
def test_rescheduleevent(self, testdir):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
session = DSession(item.config)
|
||||
host1 = GatewaySpec("localhost")
|
||||
host1.node = MockNode()
|
||||
session.addhost(host1)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
ev = event.RescheduleItems([item])
|
||||
loopstate = session._initloopstate([])
|
||||
session.queueevent("rescheduleitems", ev)
|
||||
session.loop_once(loopstate)
|
||||
# check that RescheduleEvents are not immediately
|
||||
# rescheduled if there are no hosts
|
||||
# rescheduled if there are no nodes
|
||||
assert loopstate.dowork == False
|
||||
session.queueevent("anonymous", event.NOP())
|
||||
session.loop_once(loopstate)
|
||||
session.queueevent("anonymous", event.NOP())
|
||||
session.loop_once(loopstate)
|
||||
assert host1.node.sent == [[item]]
|
||||
assert node.sent == [[item]]
|
||||
session.queueevent("itemtestreport", run(item))
|
||||
session.loop_once(loopstate)
|
||||
assert loopstate.shuttingdown
|
||||
assert not loopstate.testsfailed
|
||||
|
||||
def test_no_hosts_remaining_for_tests(self, testdir):
|
||||
def test_no_node_remaining_for_tests(self, testdir):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
# setup a session with one host
|
||||
# setup a session with one node
|
||||
session = DSession(item.config)
|
||||
host1 = GatewaySpec("localhost")
|
||||
host1.node = MockNode()
|
||||
session.addhost(host1)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
|
||||
# setup a HostDown event
|
||||
ev = event.HostDown(host1, None)
|
||||
session.queueevent("testnodedown", ev)
|
||||
session.queueevent("testnodedown", node, None)
|
||||
|
||||
loopstate = session._initloopstate([item])
|
||||
loopstate.dowork = False
|
||||
|
@ -162,22 +156,18 @@ class TestDSession:
|
|||
""")
|
||||
item1, item2 = modcol.collect()
|
||||
|
||||
# setup a session with two hosts
|
||||
# setup a session with two nodes
|
||||
session = DSession(item1.config)
|
||||
host1 = GatewaySpec("localhost")
|
||||
host1.node = MockNode()
|
||||
session.addhost(host1)
|
||||
host2 = GatewaySpec("localhost")
|
||||
host2.node = MockNode()
|
||||
session.addhost(host2)
|
||||
node1, node2 = MockNode(), MockNode()
|
||||
session.addnode(node1)
|
||||
session.addnode(node2)
|
||||
|
||||
# have one test pending for a host that goes down
|
||||
# have one test pending for a node that goes down
|
||||
session.senditems([item1, item2])
|
||||
host = session.item2host[item1]
|
||||
ev = event.HostDown(host, None)
|
||||
session.queueevent("testnodedown", ev)
|
||||
node = session.item2node[item1]
|
||||
session.queueevent("testnodedown", node, None)
|
||||
evrec = EventRecorder(session.bus)
|
||||
print session.item2host
|
||||
print session.item2node
|
||||
loopstate = session._initloopstate([])
|
||||
session.loop_once(loopstate)
|
||||
|
||||
|
@ -186,20 +176,19 @@ class TestDSession:
|
|||
assert testrep.failed
|
||||
assert testrep.colitem == item1
|
||||
assert str(testrep.longrepr).find("crashed") != -1
|
||||
assert str(testrep.longrepr).find(host.address) != -1
|
||||
#assert str(testrep.longrepr).find(node.gateway.spec) != -1
|
||||
|
||||
def test_testnodeready_adds_to_available(self, testdir):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
# setup a session with two hosts
|
||||
# setup a session with two nodes
|
||||
session = DSession(item.config)
|
||||
host1 = GatewaySpec("localhost")
|
||||
testnodeready = maketestnodeready(host1)
|
||||
session.queueevent("testnodeready", testnodeready)
|
||||
node1 = MockNode()
|
||||
session.queueevent("testnodeready", node1)
|
||||
loopstate = session._initloopstate([item])
|
||||
loopstate.dowork = False
|
||||
assert len(session.host2pending) == 0
|
||||
assert len(session.node2pending) == 0
|
||||
session.loop_once(loopstate)
|
||||
assert len(session.host2pending) == 1
|
||||
assert len(session.node2pending) == 1
|
||||
|
||||
def test_event_propagation(self, testdir, EventRecorder):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
|
@ -212,20 +201,19 @@ class TestDSession:
|
|||
|
||||
def runthrough(self, item):
|
||||
session = DSession(item.config)
|
||||
host1 = GatewaySpec("localhost")
|
||||
host1.node = MockNode()
|
||||
session.addhost(host1)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
loopstate = session._initloopstate([item])
|
||||
|
||||
session.queueevent("NOP")
|
||||
session.loop_once(loopstate)
|
||||
|
||||
assert host1.node.sent == [[item]]
|
||||
assert node.sent == [[item]]
|
||||
ev = run(item)
|
||||
session.queueevent("itemtestreport", ev)
|
||||
session.loop_once(loopstate)
|
||||
assert loopstate.shuttingdown
|
||||
session.queueevent("testnodedown", event.HostDown(host1, None))
|
||||
session.queueevent("testnodedown", node, None)
|
||||
session.loop_once(loopstate)
|
||||
dumpqueue(session.queue)
|
||||
return session, loopstate.exitstatus
|
||||
|
@ -249,12 +237,11 @@ class TestDSession:
|
|||
""")
|
||||
modcol.config.option.exitfirst = True
|
||||
session = DSession(modcol.config)
|
||||
host1 = GatewaySpec("localhost")
|
||||
host1.node = MockNode()
|
||||
session.addhost(host1)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
items = basic_collect_report(modcol).result
|
||||
|
||||
# trigger testing - this sends tests to host1
|
||||
# trigger testing - this sends tests to the node
|
||||
session.triggertesting(items)
|
||||
|
||||
# run tests ourselves and produce reports
|
||||
|
@ -271,18 +258,17 @@ class TestDSession:
|
|||
def test_shuttingdown_filters_events(self, testdir, EventRecorder):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
session = DSession(item.config)
|
||||
host = GatewaySpec("localhost")
|
||||
session.addhost(host)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
loopstate = session._initloopstate([])
|
||||
loopstate.shuttingdown = True
|
||||
evrec = EventRecorder(session.bus)
|
||||
session.queueevent("itemtestreport", run(item))
|
||||
session.loop_once(loopstate)
|
||||
assert not evrec.getfirstnamed("testnodedown")
|
||||
ev = event.HostDown(host)
|
||||
session.queueevent("testnodedown", ev)
|
||||
session.queueevent("testnodedown", node, None)
|
||||
session.loop_once(loopstate)
|
||||
assert evrec.getfirstnamed('testnodedown') == ev
|
||||
assert evrec.getfirstnamed('testnodedown') == node
|
||||
|
||||
def test_filteritems(self, testdir, EventRecorder):
|
||||
modcol = testdir.getmodulecol("""
|
||||
|
@ -317,17 +303,16 @@ class TestDSession:
|
|||
item = testdir.getitem("def test_func(): pass")
|
||||
session = DSession(item.config)
|
||||
|
||||
host = GatewaySpec("localhost")
|
||||
host.node = MockNode()
|
||||
session.addhost(host)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
session.senditems([item])
|
||||
session.queueevent("itemtestreport", run(item))
|
||||
loopstate = session._initloopstate([])
|
||||
session.loop_once(loopstate)
|
||||
assert host.node._shutdown is True
|
||||
assert node._shutdown is True
|
||||
assert loopstate.exitstatus is None, "loop did not wait for testnodedown"
|
||||
assert loopstate.shuttingdown
|
||||
session.queueevent("testnodedown", event.HostDown(host, None))
|
||||
session.queueevent("testnodedown", node, None)
|
||||
session.loop_once(loopstate)
|
||||
assert loopstate.exitstatus == 0
|
||||
|
||||
|
@ -339,15 +324,13 @@ class TestDSession:
|
|||
pass
|
||||
""")
|
||||
session = DSession(modcol.config)
|
||||
host = GatewaySpec("localhost")
|
||||
host.node = MockNode()
|
||||
session.addhost(host)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
|
||||
colreport = basic_collect_report(modcol)
|
||||
item1, item2 = colreport.result
|
||||
session.senditems([item1])
|
||||
# host2pending will become empty when the loop sees
|
||||
# the report
|
||||
# node2pending will become empty when the loop sees the report
|
||||
session.queueevent("itemtestreport", run(item1))
|
||||
|
||||
# but we have a collection pending
|
||||
|
|
|
@ -52,10 +52,10 @@ class TestAsyncFunctional:
|
|||
assert ev.skipped
|
||||
ev, = eq.geteventargs("itemtestreport")
|
||||
assert ev.failed
|
||||
# see that the host is really down
|
||||
ev, = eq.geteventargs("testnodedown")
|
||||
assert ev.host.popen
|
||||
ev, = eq.geteventargs("testrunfinish")
|
||||
# see that the node is really down
|
||||
node, error = eq.geteventargs("testnodedown")
|
||||
assert node.gateway.spec.popen
|
||||
eq.geteventargs("testrunfinish")
|
||||
|
||||
def test_distribution_rsyncdirs_example(self, testdir):
|
||||
source = testdir.mkdir("source")
|
||||
|
|
|
@ -47,7 +47,7 @@ class TestHostManager:
|
|||
assert dest.join("dir1", "dir2").check()
|
||||
assert dest.join("dir1", "dir2", 'hello').check()
|
||||
|
||||
def test_hostmanager_init_rsync_roots(self, source, dest):
|
||||
def test_init_rsync_roots(self, source, dest):
|
||||
dir2 = source.ensure("dir1", "dir2", dir=1)
|
||||
source.ensure("dir1", "somefile", dir=1)
|
||||
dir2.ensure("hello")
|
||||
|
@ -63,7 +63,7 @@ class TestHostManager:
|
|||
assert not dest.join("dir1").check()
|
||||
assert not dest.join("bogus").check()
|
||||
|
||||
def test_hostmanager_rsyncignore(self, source, dest):
|
||||
def test_rsyncignore(self, source, dest):
|
||||
dir2 = source.ensure("dir1", "dir2", dir=1)
|
||||
dir5 = source.ensure("dir5", "dir6", "bogus")
|
||||
dirf = source.ensure("dir5", "file")
|
||||
|
@ -81,7 +81,7 @@ class TestHostManager:
|
|||
assert dest.join("dir5","file").check()
|
||||
assert not dest.join("dir6").check()
|
||||
|
||||
def test_hostmanage_optimise_popen(self, source, dest):
|
||||
def test_optimise_popen(self, source, dest):
|
||||
hosts = ["popen"] * 3
|
||||
source.join("conftest.py").write("rsyncdirs = ['a']")
|
||||
source.ensure('a', dir=1)
|
||||
|
@ -92,7 +92,7 @@ class TestHostManager:
|
|||
assert gwspec._samefilesystem()
|
||||
assert not gwspec.chdir
|
||||
|
||||
def test_hostmanage_setup_hosts_DEBUG(self, source, EventRecorder):
|
||||
def test_setup_hosts_DEBUG(self, source, EventRecorder):
|
||||
hosts = ["popen"] * 2
|
||||
source.join("conftest.py").write("rsyncdirs = ['a']")
|
||||
source.ensure('a', dir=1)
|
||||
|
@ -107,7 +107,7 @@ class TestHostManager:
|
|||
assert l
|
||||
hm.teardown_hosts()
|
||||
|
||||
def test_hostmanage_ssh_setup_hosts(self, specssh, testdir):
|
||||
def test_ssh_setup_hosts(self, specssh, testdir):
|
||||
testdir.makepyfile(__init__="", test_x="""
|
||||
def test_one():
|
||||
pass
|
||||
|
|
|
@ -42,9 +42,9 @@ class MySetup:
|
|||
config = py.test.config._reparse([])
|
||||
self.config = config
|
||||
self.queue = py.std.Queue.Queue()
|
||||
self.host = py.execnet.XSpec("popen")
|
||||
self.gateway = py.execnet.makegateway(self.host)
|
||||
self.node = MasterNode(self.host, self.gateway, self.config, putevent=self.queue.put)
|
||||
self.xspec = py.execnet.XSpec("popen")
|
||||
self.gateway = py.execnet.makegateway(self.xspec)
|
||||
self.node = MasterNode(self.gateway, self.config, putevent=self.queue.put)
|
||||
assert not self.node.channel.isclosed()
|
||||
return self.node
|
||||
|
||||
|
@ -64,14 +64,20 @@ def pytest_pyfuncarg_testdir(__call__, pyfuncitem):
|
|||
testdir.chdir()
|
||||
return testdir
|
||||
|
||||
class TestMasterSlaveConnection:
|
||||
def test_node_hash_equality(mysetup):
|
||||
node = mysetup.makenode()
|
||||
node2 = mysetup.makenode()
|
||||
assert node != node2
|
||||
assert node == node
|
||||
assert not (node != node)
|
||||
|
||||
class TestMasterSlaveConnection:
|
||||
def test_crash_invalid_item(self, mysetup):
|
||||
node = mysetup.makenode()
|
||||
node.send(123) # invalid item
|
||||
ev, = mysetup.geteventargs("testnodedown")
|
||||
assert ev.host == mysetup.host
|
||||
assert str(ev.error).find("AttributeError") != -1
|
||||
n, error = mysetup.geteventargs("testnodedown")
|
||||
assert n is node
|
||||
assert str(error).find("AttributeError") != -1
|
||||
|
||||
def test_crash_killed(self, testdir, mysetup):
|
||||
if not hasattr(py.std.os, 'kill'):
|
||||
|
@ -83,16 +89,16 @@ class TestMasterSlaveConnection:
|
|||
""")
|
||||
node = mysetup.makenode(item.config)
|
||||
node.send(item)
|
||||
ev, = mysetup.geteventargs("testnodedown")
|
||||
assert ev.host == mysetup.host
|
||||
assert str(ev.error).find("TERMINATED") != -1
|
||||
n, error = mysetup.geteventargs("testnodedown")
|
||||
assert n is node
|
||||
assert str(error).find("Not properly terminated") != -1
|
||||
|
||||
def test_node_down(self, mysetup):
|
||||
node = mysetup.makenode()
|
||||
node.shutdown()
|
||||
ev, = mysetup.geteventargs("testnodedown")
|
||||
assert ev.host == mysetup.host
|
||||
assert not ev.error
|
||||
n, error = mysetup.geteventargs("testnodedown")
|
||||
assert n is node
|
||||
assert not error
|
||||
node.callback(node.ENDMARK)
|
||||
excinfo = py.test.raises(IOError,
|
||||
"mysetup.geteventargs('testnodedown', timeout=0.01)")
|
||||
|
|
|
@ -146,20 +146,10 @@ class RescheduleItems(BaseEvent):
|
|||
def __init__(self, items):
|
||||
self.items = items
|
||||
|
||||
class HostGatewayReady(BaseEvent):
|
||||
def __init__(self, host, roots):
|
||||
self.host = host
|
||||
self.roots = roots
|
||||
|
||||
class HostUp(BaseEvent):
|
||||
def __init__(self, host, platinfo):
|
||||
self.host = host
|
||||
self.platinfo = platinfo
|
||||
|
||||
class HostDown(BaseEvent):
|
||||
def __init__(self, host, error=None):
|
||||
self.host = host
|
||||
self.error = error
|
||||
#class HostGatewayReady(BaseEvent):
|
||||
# def __init__(self, host, roots):
|
||||
# self.host = host
|
||||
# self.roots = roots
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Events related to rsyncing
|
||||
|
|
|
@ -200,11 +200,11 @@ class PytestPluginHooks:
|
|||
within the gateway manager context.
|
||||
"""
|
||||
|
||||
def pyevent_testnodeready(self, event):
|
||||
""" Host is up. """
|
||||
def pyevent_testnodeready(self, node):
|
||||
""" Node is ready to operate. """
|
||||
|
||||
def pyevent_testnodedown(self, event):
|
||||
""" Host is down. """
|
||||
def pyevent_testnodedown(self, node, error):
|
||||
""" Node is down. """
|
||||
|
||||
def pyevent_rescheduleitems(self, event):
|
||||
""" Items from a host that went down. """
|
||||
|
|
|
@ -103,19 +103,20 @@ class TerminalReporter:
|
|||
# which garbles our output if we use self.write_line
|
||||
self.write_line(msg)
|
||||
|
||||
def pyevent_testnodeready(self, event):
|
||||
d = event.platinfo.copy()
|
||||
d['host'] = getattr(event.host, 'address', event.host)
|
||||
d['version'] = repr_pythonversion(d['sys.version_info'])
|
||||
self.write_line("HOSTUP: %(host)s %(sys.platform)s "
|
||||
"%(sys.executable)s - Python %(version)s" %
|
||||
d)
|
||||
def pyevent_testnodeready(self, node):
|
||||
# XXX
|
||||
self.write_line("Node Ready: %r, spec %r" % (node,node.gateway.spec))
|
||||
|
||||
#d = event.platinfo.copy()
|
||||
#d['host'] = getattr(event.host, 'address', event.host)
|
||||
#d['version'] = repr_pythonversion(d['sys.version_info'])
|
||||
#self.write_line("HOSTUP: %(host)s %(sys.platform)s "
|
||||
# "%(sys.executable)s - Python %(version)s" %
|
||||
# d)
|
||||
|
||||
def pyevent_testnodedown(self, event):
|
||||
host = event.host
|
||||
error = event.error
|
||||
def pyevent_testnodedown(self, node, error):
|
||||
if error:
|
||||
self.write_line("HostDown %s: %s" %(host, error))
|
||||
self.write_line("Node Down: %r: %r" %(node, error))
|
||||
|
||||
def pyevent_trace(self, category, msg):
|
||||
if self.config.option.debug or \
|
||||
|
@ -323,13 +324,13 @@ def repr_pythonversion(v=None):
|
|||
|
||||
from py.__.test import event
|
||||
from py.__.test.runner import basic_run_report
|
||||
from py.__.test.dsession.masterslave import maketestnodeready
|
||||
|
||||
class TestTerminal:
|
||||
@py.test.mark.xfail
|
||||
def test_testnodeready(self, testdir, linecomp):
|
||||
item = testdir.getitem("def test_func(): pass")
|
||||
rep = TerminalReporter(item.config, linecomp.stringio)
|
||||
rep.pyevent_testnodeready(maketestnodeready())
|
||||
XXX # rep.pyevent_testnodeready(maketestnodeready())
|
||||
linecomp.assert_contains_lines([
|
||||
"*INPROCESS* %s %s - Python %s" %(sys.platform,
|
||||
sys.executable, repr_pythonversion(sys.version_info))
|
||||
|
@ -428,10 +429,10 @@ class TestTerminal:
|
|||
rep = TerminalReporter(modcol.config, file=linecomp.stringio)
|
||||
class gw1:
|
||||
id = "X1"
|
||||
spec = py.execnet.GatewaySpec("popen")
|
||||
spec = py.execnet.XSpec("popen")
|
||||
class gw2:
|
||||
id = "X2"
|
||||
spec = py.execnet.GatewaySpec("popen")
|
||||
spec = py.execnet.XSpec("popen")
|
||||
rep.pyevent_gwmanage_newgateway(gateway=gw1)
|
||||
linecomp.assert_contains_lines([
|
||||
"X1 instantiated gateway from spec*",
|
||||
|
|
|
@ -12,7 +12,6 @@ from py.__.test import event, outcome
|
|||
Item = py.test.collect.Item
|
||||
Collector = py.test.collect.Collector
|
||||
from runner import basic_collect_report
|
||||
from py.__.test.dsession.masterslave import maketestnodeready
|
||||
|
||||
class Session(object):
|
||||
"""
|
||||
|
@ -117,7 +116,7 @@ class Session(object):
|
|||
colitems = self.getinitialitems(colitems)
|
||||
self.shouldstop = False
|
||||
self.sessionstarts()
|
||||
self.bus.notify("testnodeready", maketestnodeready())
|
||||
#self.bus.notify("testnodeready", maketestnodeready())
|
||||
exitstatus = outcome.EXIT_OK
|
||||
captured_excinfo = None
|
||||
try:
|
||||
|
|
Loading…
Reference in New Issue