[svn r63107] cleanup event handling of dsession

--HG--
branch : trunk
This commit is contained in:
hpk 2009-03-20 03:13:31 +01:00
parent c44764dc51
commit 78495272aa
2 changed files with 48 additions and 39 deletions

View File

@ -13,7 +13,8 @@ from py.__.test import outcome
import Queue import Queue
class LoopState(object): class LoopState(object):
def __init__(self, colitems): def __init__(self, dsession, colitems):
self.dsession = dsession
self.colitems = colitems self.colitems = colitems
self.exitstatus = None self.exitstatus = None
# loopstate.dowork is False after reschedule events # loopstate.dowork is False after reschedule events
@ -23,6 +24,30 @@ class LoopState(object):
self.shuttingdown = False self.shuttingdown = False
self.testsfailed = False self.testsfailed = False
def pyevent_itemtestreport(self, event):
if event.colitem in self.dsession.item2host:
self.dsession.removeitem(event.colitem)
if event.failed:
self.testsfailed = True
def pyevent_collectionreport(self, event):
if event.passed:
self.colitems.extend(event.result)
def pyevent_testnodeready(self, event):
self.dsession.addhost(event.host)
def pyevent_testnodedown(self, event):
pending = self.dsession.removehost(event.host)
if pending:
crashitem = pending[0]
self.dsession.handle_crashitem(crashitem, event.host)
self.colitems.extend(pending[1:])
def pyevent_rescheduleitems(self, event):
self.colitems.extend(event.items)
self.dowork = False # avoid busywait
class DSession(Session): class DSession(Session):
""" """
Session drives the collection and running of tests Session drives the collection and running of tests
@ -36,7 +61,6 @@ class DSession(Session):
self.queue = Queue.Queue() self.queue = Queue.Queue()
self.host2pending = {} self.host2pending = {}
self.item2host = {} self.item2host = {}
self._testsfailed = False
if self.config.getvalue("executable") and \ if self.config.getvalue("executable") and \
not self.config.getvalue("numprocesses"): not self.config.getvalue("numprocesses"):
self.config.option.numprocesses = 1 self.config.option.numprocesses = 1
@ -83,8 +107,8 @@ class DSession(Session):
if loopstate.shuttingdown: if loopstate.shuttingdown:
return self.loop_once_shutdown(loopstate) return self.loop_once_shutdown(loopstate)
colitems = loopstate.colitems colitems = loopstate.colitems
if loopstate.dowork and loopstate.colitems: if loopstate.dowork and colitems:
self.triggertesting(colitems) self.triggertesting(loopstate.colitems)
colitems[:] = [] colitems[:] = []
# we use a timeout here so that control-C gets through # we use a timeout here so that control-C gets through
while 1: while 1:
@ -97,28 +121,6 @@ class DSession(Session):
eventname, args, kwargs = eventcall eventname, args, kwargs = eventcall
self.bus.notify(eventname, *args, **kwargs) self.bus.notify(eventname, *args, **kwargs)
if args:
ev, = args
else:
ev = None
if eventname == "itemtestreport":
self.removeitem(ev.colitem)
if ev.failed:
loopstate.testsfailed = True
elif eventname == "collectionreport":
if ev.passed:
colitems.extend(ev.result)
elif eventname == "testnodeready":
self.addhost(ev.host)
elif eventname == "testnodedown":
pending = self.removehost(ev.host)
if pending:
crashitem = pending.pop(0)
self.handle_crashitem(crashitem, ev.host)
colitems.extend(pending)
elif eventname == "rescheduleitems":
colitems.extend(ev.items)
loopstate.dowork = False # avoid busywait
# termination conditions # termination conditions
if ((loopstate.testsfailed and self.config.option.exitfirst) or if ((loopstate.testsfailed and self.config.option.exitfirst) or
@ -143,9 +145,14 @@ class DSession(Session):
else: else:
loopstate.exitstatus = outcome.EXIT_OK loopstate.exitstatus = outcome.EXIT_OK
def _initloopstate(self, colitems):
loopstate = LoopState(self, colitems)
self.config.bus.register(loopstate)
return loopstate
def loop(self, colitems): def loop(self, colitems):
try: try:
loopstate = LoopState(colitems) loopstate = self._initloopstate(colitems)
loopstate.dowork = False # first receive at least one HostUp events loopstate.dowork = False # first receive at least one HostUp events
while 1: while 1:
self.loop_once(loopstate) self.loop_once(loopstate)
@ -157,6 +164,7 @@ class DSession(Session):
except: except:
self.bus.notify("internalerror", event.InternalException()) self.bus.notify("internalerror", event.InternalException())
exitstatus = outcome.EXIT_INTERNALERROR exitstatus = outcome.EXIT_INTERNALERROR
self.config.bus.unregister(loopstate)
if exitstatus == 0 and self._testsfailed: if exitstatus == 0 and self._testsfailed:
exitstatus = outcome.EXIT_TESTSFAILED exitstatus = outcome.EXIT_TESTSFAILED
return exitstatus return exitstatus

View File

@ -1,4 +1,4 @@
from py.__.test.dsession.dsession import DSession, LoopState from py.__.test.dsession.dsession import DSession
from py.__.test.dsession.masterslave import maketestnodeready from py.__.test.dsession.masterslave import maketestnodeready
from py.__.execnet.gwmanage import GatewaySpec from py.__.execnet.gwmanage import GatewaySpec
from py.__.test.runner import basic_collect_report from py.__.test.runner import basic_collect_report
@ -120,7 +120,7 @@ class TestDSession:
host1.node = MockNode() host1.node = MockNode()
session.addhost(host1) session.addhost(host1)
ev = event.RescheduleItems([item]) ev = event.RescheduleItems([item])
loopstate = LoopState([]) loopstate = session._initloopstate([])
session.queueevent("rescheduleitems", ev) session.queueevent("rescheduleitems", ev)
session.loop_once(loopstate) session.loop_once(loopstate)
# check that RescheduleEvents are not immediately # check that RescheduleEvents are not immediately
@ -148,7 +148,7 @@ class TestDSession:
ev = event.HostDown(host1, None) ev = event.HostDown(host1, None)
session.queueevent("testnodedown", ev) session.queueevent("testnodedown", ev)
loopstate = LoopState([item]) loopstate = session._initloopstate([item])
loopstate.dowork = False loopstate.dowork = False
session.loop_once(loopstate) session.loop_once(loopstate)
dumpqueue(session.queue) dumpqueue(session.queue)
@ -178,7 +178,8 @@ class TestDSession:
ev = event.HostDown(host, None) ev = event.HostDown(host, None)
session.queueevent("testnodedown", ev) session.queueevent("testnodedown", ev)
evrec = EventRecorder(session.bus) evrec = EventRecorder(session.bus)
loopstate = LoopState([]) print session.item2host
loopstate = session._initloopstate([])
session.loop_once(loopstate) session.loop_once(loopstate)
assert loopstate.colitems == [item2] # do not reschedule crash item assert loopstate.colitems == [item2] # do not reschedule crash item
@ -195,7 +196,7 @@ class TestDSession:
host1 = GatewaySpec("localhost") host1 = GatewaySpec("localhost")
testnodeready = maketestnodeready(host1) testnodeready = maketestnodeready(host1)
session.queueevent("testnodeready", testnodeready) session.queueevent("testnodeready", testnodeready)
loopstate = LoopState([item]) loopstate = session._initloopstate([item])
loopstate.dowork = False loopstate.dowork = False
assert len(session.host2pending) == 0 assert len(session.host2pending) == 0
session.loop_once(loopstate) session.loop_once(loopstate)
@ -207,7 +208,7 @@ class TestDSession:
evrec = EventRecorder(session.bus) evrec = EventRecorder(session.bus)
session.queueevent("NOPevent", 42) session.queueevent("NOPevent", 42)
session.loop_once(LoopState([])) session.loop_once(session._initloopstate([]))
assert evrec.getfirstnamed('NOPevent') assert evrec.getfirstnamed('NOPevent')
def runthrough(self, item): def runthrough(self, item):
@ -215,7 +216,7 @@ class TestDSession:
host1 = GatewaySpec("localhost") host1 = GatewaySpec("localhost")
host1.node = MockNode() host1.node = MockNode()
session.addhost(host1) session.addhost(host1)
loopstate = LoopState([item]) loopstate = session._initloopstate([item])
session.queueevent("NOP") session.queueevent("NOP")
session.loop_once(loopstate) session.loop_once(loopstate)
@ -263,7 +264,7 @@ class TestDSession:
session.queueevent("itemtestreport", ev1) # a failing one session.queueevent("itemtestreport", ev1) # a failing one
session.queueevent("itemtestreport", ev2) session.queueevent("itemtestreport", ev2)
# now call the loop # now call the loop
loopstate = LoopState(items) loopstate = session._initloopstate(items)
session.loop_once(loopstate) session.loop_once(loopstate)
assert loopstate.testsfailed assert loopstate.testsfailed
assert loopstate.shuttingdown assert loopstate.shuttingdown
@ -273,7 +274,7 @@ class TestDSession:
session = DSession(item.config) session = DSession(item.config)
host = GatewaySpec("localhost") host = GatewaySpec("localhost")
session.addhost(host) session.addhost(host)
loopstate = LoopState([]) loopstate = session._initloopstate([])
loopstate.shuttingdown = True loopstate.shuttingdown = True
evrec = EventRecorder(session.bus) evrec = EventRecorder(session.bus)
session.queueevent("itemtestreport", run(item)) session.queueevent("itemtestreport", run(item))
@ -322,7 +323,7 @@ class TestDSession:
session.addhost(host) session.addhost(host)
session.senditems([item]) session.senditems([item])
session.queueevent("itemtestreport", run(item)) session.queueevent("itemtestreport", run(item))
loopstate = LoopState([]) loopstate = session._initloopstate([])
session.loop_once(loopstate) session.loop_once(loopstate)
assert host.node._shutdown is True assert host.node._shutdown is True
assert loopstate.exitstatus is None, "loop did not wait for testnodedown" assert loopstate.exitstatus is None, "loop did not wait for testnodedown"
@ -353,7 +354,7 @@ class TestDSession:
# but we have a collection pending # but we have a collection pending
session.queueevent("collectionreport", colreport) session.queueevent("collectionreport", colreport)
loopstate = LoopState([]) loopstate = session._initloopstate([])
session.loop_once(loopstate) session.loop_once(loopstate)
assert loopstate.exitstatus is None, "loop did not care for collection report" assert loopstate.exitstatus is None, "loop did not care for collection report"
assert not loopstate.colitems assert not loopstate.colitems