[svn r63560] beginning to review/polish test events

* pyevent() now receives args and kwargs as simple arguments
* refactoring event handling in tests

--HG--
branch : trunk
This commit is contained in:
hpk 2009-04-03 12:57:34 +02:00
parent 3ab894cadc
commit 54cc936437
11 changed files with 70 additions and 32 deletions

View File

@ -9,7 +9,7 @@ class EventQueue:
self.queue = queue self.queue = queue
bus.register(self) bus.register(self)
def pyevent(self, eventname, *args, **kwargs): def pyevent(self, eventname, args, kwargs):
self.queue.put((eventname, args, kwargs)) self.queue.put((eventname, args, kwargs))
def geteventargs(self, eventname, timeout=2.0): def geteventargs(self, eventname, timeout=2.0):
@ -48,7 +48,7 @@ class MySetup:
assert not self.node.channel.isclosed() assert not self.node.channel.isclosed()
return self.node return self.node
def finalize(self): def xfinalize(self):
if hasattr(self, 'node'): if hasattr(self, 'node'):
gw = self.node.gateway gw = self.node.gateway
print "exiting:", gw print "exiting:", gw
@ -56,7 +56,7 @@ class MySetup:
def pytest_funcarg__mysetup(pyfuncitem): def pytest_funcarg__mysetup(pyfuncitem):
mysetup = MySetup(pyfuncitem) mysetup = MySetup(pyfuncitem)
pyfuncitem.addfinalizer(mysetup.finalize) #pyfuncitem.addfinalizer(mysetup.finalize)
return mysetup return mysetup
def pytest_funcarg__testdir(__call__, pyfuncitem): def pytest_funcarg__testdir(__call__, pyfuncitem):

View File

@ -22,10 +22,6 @@ class NOP(BaseEvent):
# Basic Live Reporting Events # Basic Live Reporting Events
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
class TestrunStart(BaseEvent):
def __init__(self):
self.timestart = time.time()
class TestrunFinish(BaseEvent): class TestrunFinish(BaseEvent):
def __init__(self, exitstatus=0, excinfo=None): def __init__(self, exitstatus=0, excinfo=None):
self.exitstatus = exitstatus self.exitstatus = exitstatus

View File

@ -55,7 +55,7 @@ class PluginHooks:
class Events: class Events:
# Events # Events
def pyevent(self, eventname, *args, **kwargs): def pyevent(self, eventname, args, kwargs):
""" generically called for each notification event. """ """ generically called for each notification event. """
def pyevent__gateway_init(self, gateway): def pyevent__gateway_init(self, gateway):
@ -76,7 +76,7 @@ class Events:
def pyevent__internalerror(self, event): def pyevent__internalerror(self, event):
""" called for internal errors. """ """ called for internal errors. """
def pyevent__itemstart(self, item, node): def pyevent__itemstart(self, item, node=None):
""" test item gets collected. """ """ test item gets collected. """
def pyevent__itemtestreport(self, event): def pyevent__itemtestreport(self, event):
@ -91,7 +91,7 @@ class Events:
def pyevent__collectionreport(self, event): def pyevent__collectionreport(self, event):
""" collector finished collecting. """ """ collector finished collecting. """
def pyevent__testrunstart(self, event): def pyevent__testrunstart(self):
""" whole test run starts. """ """ whole test run starts. """
def pyevent__testrunfinish(self, event): def pyevent__testrunfinish(self, event):

View File

@ -16,7 +16,7 @@ class EventlogPlugin:
self.eventlogfile.close() self.eventlogfile.close()
del self.eventlogfile del self.eventlogfile
def pyevent(self, eventname, *args, **kwargs): def pyevent(self, eventname, args, kwargs):
if hasattr(self, 'eventlogfile'): if hasattr(self, 'eventlogfile'):
f = self.eventlogfile f = self.eventlogfile
print >>f, eventname, args, kwargs print >>f, eventname, args, kwargs
@ -36,6 +36,6 @@ def test_generic(plugintester):
""") """)
testdir.runpytest("--eventlog=event.log") testdir.runpytest("--eventlog=event.log")
s = testdir.tmpdir.join("event.log").read() s = testdir.tmpdir.join("event.log").read()
assert s.find("TestrunStart") != -1 assert s.find("testrunstart") != -1
assert s.find("ItemTestReport") != -1 assert s.find("ItemTestReport") != -1
assert s.find("TestrunFinish") != -1 assert s.find("TestrunFinish") != -1

View File

@ -21,8 +21,8 @@ class ExecnetcleanupPlugin:
if self._gateways is not None: if self._gateways is not None:
self._gateways.remove(gateway) self._gateways.remove(gateway)
def pyevent__testrunstart(self, event): def pyevent__testrunstart(self):
self.trace("testrunstart", event) self.trace("testrunstart")
self._gateways = [] self._gateways = []
def pyevent__testrunfinish(self, event): def pyevent__testrunfinish(self, event):

View File

@ -3,8 +3,10 @@ pytes plugin for easing testing of pytest runs themselves.
""" """
import py import py
import inspect
from py.__.test import event from py.__.test import event
from py.__.test.config import Config as pytestConfig from py.__.test.config import Config as pytestConfig
import api
class PytesterPlugin: class PytesterPlugin:
def pytest_funcarg__linecomp(self, pyfuncitem): def pytest_funcarg__linecomp(self, pyfuncitem):
@ -257,6 +259,13 @@ class Event:
def __repr__(self): def __repr__(self):
return "<Event %r %r>" %(self.name, self.args) return "<Event %r %r>" %(self.name, self.args)
class ParsedEvent:
def __init__(self, locals):
self.__dict__ = locals.copy()
def __repr__(self):
return "<Event %r>" %(self.__dict__,)
class EventRecorder(object): class EventRecorder(object):
def __init__(self, pyplugins, debug=False): # True): def __init__(self, pyplugins, debug=False): # True):
self.events = [] self.events = []
@ -264,7 +273,7 @@ class EventRecorder(object):
self.debug = debug self.debug = debug
pyplugins.register(self) pyplugins.register(self)
def pyevent(self, name, *args, **kwargs): def pyevent(self, name, args, kwargs):
if name == "plugin_registered" and args == (self,): if name == "plugin_registered" and args == (self,):
return return
if self.debug: if self.debug:
@ -278,10 +287,40 @@ class EventRecorder(object):
return event return event
raise KeyError("popevent: %r not found in %r" %(name, self.events)) raise KeyError("popevent: %r not found in %r" %(name, self.events))
def getevents(self, eventname):
method = self.geteventmethod(eventname)
l = []
for event in self.events:
if event.name == eventname:
pevent = method(*event.args, **event.kwargs)
l.append(pevent)
return l
def geteventmethod(self, eventname):
mname = "pyevent__" + eventname
method = getattr(api.Events, mname)
args, varargs, varkw, default = inspect.getargspec(method)
assert args[0] == "self"
args = args[1:]
fspec = inspect.formatargspec(args, varargs, varkw, default)
source = """def %(mname)s%(fspec)s:
return ParsedEvent(locals())""" % locals()
print source
exec source
return locals()[mname]
def firstparsedevent(self, eventname):
return self.parsedevents(eventname)[0]
def get(self, cls): def get(self, cls):
l = [] l = []
for event in self.events: for event in self.events:
try:
value = event.args[0] value = event.args[0]
except IndexError:
continue
else:
if isinstance(value, cls): if isinstance(value, cls):
l.append(value) l.append(value)
return l return l

View File

@ -370,7 +370,7 @@ class TestWithFunctionIntegration:
except ValueError: except ValueError:
excinfo = event.InternalException() excinfo = event.InternalException()
reslog = ResultDB(StringIO.StringIO()) reslog = ResultDB(StringIO.StringIO())
reslog.pyevent("internalerror", excinfo) reslog.pyevent("internalerror", (excinfo,), {})
entry = reslog.logfile.getvalue() entry = reslog.logfile.getvalue()
entry_lines = entry.splitlines() entry_lines = entry.splitlines()

View File

@ -81,7 +81,9 @@ class ResultLog(object):
shortrepr, longrepr = getoutcomecodes(event) shortrepr, longrepr = getoutcomecodes(event)
self.write_log_entry(shortrepr, gpath, longrepr) self.write_log_entry(shortrepr, gpath, longrepr)
def pyevent(self, eventname, event, *args, **kwargs): def pyevent(self, eventname, args, kwargs):
if args:
event = args[0]
if eventname == "itemtestreport": if eventname == "itemtestreport":
self.log_outcome(event) self.log_outcome(event)
elif eventname == "collectionreport": elif eventname == "collectionreport":
@ -91,6 +93,7 @@ class ResultLog(object):
path = event.repr.reprcrash.path # fishing :( path = event.repr.reprcrash.path # fishing :(
self.write_log_entry('!', path, str(event.repr)) self.write_log_entry('!', path, str(event.repr))
# =============================================================================== # ===============================================================================
# #
# plugin tests # plugin tests
@ -223,7 +226,7 @@ class TestWithFunctionIntegration:
except ValueError: except ValueError:
excinfo = event.InternalException() excinfo = event.InternalException()
reslog = ResultLog(StringIO.StringIO()) reslog = ResultLog(StringIO.StringIO())
reslog.pyevent("internalerror", excinfo) reslog.pyevent("internalerror", (excinfo,), {})
entry = reslog.logfile.getvalue() entry = reslog.logfile.getvalue()
entry_lines = entry.splitlines() entry_lines = entry.splitlines()

View File

@ -194,7 +194,7 @@ class TerminalReporter:
self.stats.setdefault("skipped", []).append(event) self.stats.setdefault("skipped", []).append(event)
self.write_fspath_result(event.colitem.fspath, "S") self.write_fspath_result(event.colitem.fspath, "S")
def pyevent__testrunstart(self, event): def pyevent__testrunstart(self):
self.write_sep("=", "test session starts", bold=True) self.write_sep("=", "test session starts", bold=True)
self._sessionstarttime = py.std.time.time() self._sessionstarttime = py.std.time.time()
@ -370,7 +370,7 @@ class TestTerminal:
""") """)
rep = TerminalReporter(modcol.config, file=linecomp.stringio) rep = TerminalReporter(modcol.config, file=linecomp.stringio)
rep.config.bus.register(rep) rep.config.bus.register(rep)
rep.config.bus.notify("testrunstart", event.TestrunStart()) rep.config.bus.notify("testrunstart")
for item in testdir.genitems([modcol]): for item in testdir.genitems([modcol]):
ev = basic_run_report(item) ev = basic_run_report(item)
@ -397,7 +397,7 @@ class TestTerminal:
""", configargs=("-v",)) """, configargs=("-v",))
rep = TerminalReporter(modcol.config, file=linecomp.stringio) rep = TerminalReporter(modcol.config, file=linecomp.stringio)
rep.config.bus.register(rep) rep.config.bus.register(rep)
rep.config.bus.notify("testrunstart", event.TestrunStart()) rep.config.bus.notify("testrunstart")
items = modcol.collect() items = modcol.collect()
rep.config.option.debug = True # rep.config.option.debug = True #
for item in items: for item in items:
@ -422,7 +422,7 @@ class TestTerminal:
modcol = testdir.getmodulecol("import xyz") modcol = testdir.getmodulecol("import xyz")
rep = TerminalReporter(modcol.config, file=linecomp.stringio) rep = TerminalReporter(modcol.config, file=linecomp.stringio)
rep.config.bus.register(rep) rep.config.bus.register(rep)
rep.config.bus.notify("testrunstart", event.TestrunStart()) rep.config.bus.notify("testrunstart")
l = list(testdir.genitems([modcol])) l = list(testdir.genitems([modcol]))
assert len(l) == 0 assert len(l) == 0
linecomp.assert_contains_lines([ linecomp.assert_contains_lines([
@ -518,8 +518,8 @@ class TestTerminal:
""", configargs=("--tb=%s" % tbopt,)) """, configargs=("--tb=%s" % tbopt,))
rep = TerminalReporter(modcol.config, file=linecomp.stringio) rep = TerminalReporter(modcol.config, file=linecomp.stringio)
rep.config.bus.register(rep) rep.config.bus.register(rep)
rep.config.bus.notify("testrunstart", event.TestrunStart()) rep.config.bus.notify("testrunstart")
rep.config.bus.notify("testrunstart", event.TestrunStart()) rep.config.bus.notify("testrunstart")
for item in testdir.genitems([modcol]): for item in testdir.genitems([modcol]):
rep.config.bus.notify("itemtestreport", basic_run_report(item)) rep.config.bus.notify("itemtestreport", basic_run_report(item))
rep.config.bus.notify("testrunfinish", event.TestrunFinish()) rep.config.bus.notify("testrunfinish", event.TestrunFinish())
@ -566,7 +566,7 @@ class TestTerminal:
rep = TerminalReporter(modcol.config, file=linecomp.stringio) rep = TerminalReporter(modcol.config, file=linecomp.stringio)
modcol.config.bus.register(rep) modcol.config.bus.register(rep)
bus = modcol.config.bus bus = modcol.config.bus
bus.notify("testrunstart", event.TestrunStart()) bus.notify("testrunstart")
try: try:
for item in testdir.genitems([modcol]): for item in testdir.genitems([modcol]):
bus.notify("itemtestreport", basic_run_report(item)) bus.notify("itemtestreport", basic_run_report(item))

View File

@ -79,7 +79,7 @@ class Session(object):
def sessionstarts(self): def sessionstarts(self):
""" setup any neccessary resources ahead of the test run. """ """ setup any neccessary resources ahead of the test run. """
self.bus.notify("testrunstart", event.TestrunStart()) self.bus.notify("testrunstart")
def pyevent__itemtestreport(self, rep): def pyevent__itemtestreport(self, rep):
if rep.failed: if rep.failed:

View File

@ -25,11 +25,11 @@ class SessionTests:
assert failed[0].colitem.name == "test_one_one" assert failed[0].colitem.name == "test_one_one"
assert failed[1].colitem.name == "test_other" assert failed[1].colitem.name == "test_other"
assert failed[2].colitem.name == "test_two" assert failed[2].colitem.name == "test_two"
itemstarted = sorter.getnamed("itemstart") itemstarted = sorter.getevents("itemstart")
assert len(itemstarted) == 4 assert len(itemstarted) == 4
colstarted = sorter.getnamed("collectionstart") colstarted = sorter.getevents("collectionstart")
assert len(colstarted) == 1 assert len(colstarted) == 1
col = colstarted[0].collector col = colstarted[0].event.collector
assert isinstance(col, py.test.collect.Module) assert isinstance(col, py.test.collect.Module)
def test_nested_import_error(self, testdir): def test_nested_import_error(self, testdir):