[svn r63575] killing yet more test "events" and redundant code
--HG-- branch : trunk
This commit is contained in:
parent
53491b1531
commit
85635e1239
|
@ -131,9 +131,9 @@ class TestDSession:
|
||||||
# check that RescheduleEvents are not immediately
|
# check that RescheduleEvents are not immediately
|
||||||
# rescheduled if there are no nodes
|
# rescheduled if there are no nodes
|
||||||
assert loopstate.dowork == False
|
assert loopstate.dowork == False
|
||||||
session.queueevent("anonymous", event.NOP())
|
session.queueevent("anonymous")
|
||||||
session.loop_once(loopstate)
|
session.loop_once(loopstate)
|
||||||
session.queueevent("anonymous", event.NOP())
|
session.queueevent("anonymous")
|
||||||
session.loop_once(loopstate)
|
session.loop_once(loopstate)
|
||||||
assert node.sent == [[item]]
|
assert node.sent == [[item]]
|
||||||
session.queueevent("itemtestreport", run(item, node))
|
session.queueevent("itemtestreport", run(item, node))
|
||||||
|
|
|
@ -6,20 +6,16 @@ import py
|
||||||
import time
|
import time
|
||||||
from py.__.test.outcome import Skipped
|
from py.__.test.outcome import Skipped
|
||||||
|
|
||||||
class BaseEvent(object):
|
# ----------------------------------------------------------------------
|
||||||
|
# Events related to collecting and executing test Items
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class BaseReport(object):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
l = ["%s=%s" %(key, value)
|
l = ["%s=%s" %(key, value)
|
||||||
for key, value in self.__dict__.items()]
|
for key, value in self.__dict__.items()]
|
||||||
return "<%s %s>" %(self.__class__.__name__, " ".join(l),)
|
return "<%s %s>" %(self.__class__.__name__, " ".join(l),)
|
||||||
|
|
||||||
class NOP(BaseEvent):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Events related to collecting and executing test Items
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
class BaseReport(BaseEvent):
|
|
||||||
def toterminal(self, out):
|
def toterminal(self, out):
|
||||||
longrepr = self.longrepr
|
longrepr = self.longrepr
|
||||||
if hasattr(longrepr, 'toterminal'):
|
if hasattr(longrepr, 'toterminal'):
|
||||||
|
@ -93,16 +89,3 @@ class CollectionReport(BaseReport):
|
||||||
else:
|
else:
|
||||||
out.line(str(longrepr))
|
out.line(str(longrepr))
|
||||||
|
|
||||||
class LooponfailingInfo(BaseEvent):
|
|
||||||
def __init__(self, failreports, rootdirs):
|
|
||||||
self.failreports = failreports
|
|
||||||
self.rootdirs = rootdirs
|
|
||||||
|
|
||||||
# make all eventclasses available on BaseEvent so that
|
|
||||||
# consumers of events can easily filter by
|
|
||||||
# 'isinstance(event, event.Name)' checks
|
|
||||||
|
|
||||||
for name, cls in vars().items():
|
|
||||||
if hasattr(cls, '__bases__') and issubclass(cls, BaseEvent):
|
|
||||||
setattr(BaseEvent, name, cls)
|
|
||||||
#
|
|
||||||
|
|
|
@ -39,7 +39,6 @@ class LooponfailingSession(Session):
|
||||||
colitems = loopstate.colitems
|
colitems = loopstate.colitems
|
||||||
loopstate.wasfailing = colitems and len(colitems)
|
loopstate.wasfailing = colitems and len(colitems)
|
||||||
loopstate.colitems = self.remotecontrol.runsession(colitems or ())
|
loopstate.colitems = self.remotecontrol.runsession(colitems or ())
|
||||||
#ev = event.LooponfailingInfo(loopstate.failreports, self.rootdirs)
|
|
||||||
self.remotecontrol.setup()
|
self.remotecontrol.setup()
|
||||||
|
|
||||||
class LoopState:
|
class LoopState:
|
||||||
|
@ -149,6 +148,7 @@ def slave_runsession(channel, config, fullwidth, hasmarkup):
|
||||||
|
|
||||||
DEBUG("SLAVE: starting session.main()")
|
DEBUG("SLAVE: starting session.main()")
|
||||||
session.main(colitems)
|
session.main(colitems)
|
||||||
ev = event.LooponfailingInfo(list(failreports), [config.topdir])
|
session.bus.notify("looponfailinfo",
|
||||||
session.bus.notify("looponfailinfo", ev)
|
failreports=list(failreports),
|
||||||
channel.send([x.colitem._totrail() for x in failreports if x.failed])
|
rootdirs=[config.topdir])
|
||||||
|
channel.send([x.colitem._totrail() for x in failreports])
|
||||||
|
|
|
@ -108,10 +108,10 @@ class Events:
|
||||||
def pyevent__testnodedown(self, node, error):
|
def pyevent__testnodedown(self, node, error):
|
||||||
""" Test Node is down. """
|
""" Test Node is down. """
|
||||||
|
|
||||||
def pyevent__rescheduleitems(self, event):
|
def pyevent__rescheduleitems(self, items):
|
||||||
""" reschedule Items from a node that went down. """
|
""" reschedule Items from a node that went down. """
|
||||||
|
|
||||||
def pyevent__looponfailinfo(self, event):
|
def pyevent__looponfailinfo(self, failreports, rootdirs):
|
||||||
""" info for repeating failing tests. """
|
""" info for repeating failing tests. """
|
||||||
|
|
||||||
def pyevent__plugin_registered(self, plugin):
|
def pyevent__plugin_registered(self, plugin):
|
||||||
|
|
|
@ -394,7 +394,7 @@ class EventRecorder(object):
|
||||||
def test_eventrecorder():
|
def test_eventrecorder():
|
||||||
bus = py._com.PyPlugins()
|
bus = py._com.PyPlugins()
|
||||||
recorder = EventRecorder(bus)
|
recorder = EventRecorder(bus)
|
||||||
bus.notify("anonymous", event.NOP())
|
bus.notify("anonymous")
|
||||||
assert recorder.events
|
assert recorder.events
|
||||||
assert not recorder.getfailures()
|
assert not recorder.getfailures()
|
||||||
rep = event.ItemTestReport(None, None)
|
rep = event.ItemTestReport(None, None)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import uuid
|
import uuid
|
||||||
import py
|
import py
|
||||||
from pytest_resultlog import generic_path, getoutcomecodes
|
from pytest_resultlog import ResultLog
|
||||||
|
|
||||||
class ResultdbPlugin:
|
class ResultdbPlugin:
|
||||||
"""resultdb plugin for database logging of test results.
|
"""XXX in progress: resultdb plugin for database logging of test results.
|
||||||
|
|
||||||
Saves test results to a datastore.
|
Saves test results to a datastore.
|
||||||
|
|
||||||
|
@ -144,12 +144,12 @@ class SQLiteResultArchive(object):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
class ResultDB(object):
|
class ResultDB(ResultLog):
|
||||||
def __init__(self, cls, db_path):
|
def __init__(self, cls, db_path):
|
||||||
self.archive = cls(db_path)
|
self.archive = cls(db_path)
|
||||||
self.archive.init_db()
|
self.archive.init_db()
|
||||||
|
|
||||||
def write_log_entry(self, event, shortrepr, name, longrepr):
|
def write_log_entry(self, testpath, shortrepr, longrepr):
|
||||||
data = {}
|
data = {}
|
||||||
event_excludes = ['colitem', 'longrepr']
|
event_excludes = ['colitem', 'longrepr']
|
||||||
for item in vars(event).keys():
|
for item in vars(event).keys():
|
||||||
|
@ -159,29 +159,9 @@ class ResultDB(object):
|
||||||
data['longrepr'] = longrepr
|
data['longrepr'] = longrepr
|
||||||
data['shortrepr'] = shortrepr
|
data['shortrepr'] = shortrepr
|
||||||
|
|
||||||
data['fspath'] = unicode(event.colitem.fspath)
|
data['testpath'] = unicode(testpath)
|
||||||
data['itemname'] = event.colitem.name
|
|
||||||
|
|
||||||
data['name'] = name
|
|
||||||
self.archive.append_data([data])
|
self.archive.append_data([data])
|
||||||
|
|
||||||
def log_outcome(self, event):
|
|
||||||
if (not event.passed or isinstance(event, event.ItemTestReport)):
|
|
||||||
gpath = generic_path(event.colitem)
|
|
||||||
shortrepr, longrepr = getoutcomecodes(event)
|
|
||||||
self.write_log_entry(event, shortrepr, gpath, longrepr)
|
|
||||||
|
|
||||||
def pyevent__itemtestreport(self, event):
|
|
||||||
self.log_outcome(event)
|
|
||||||
|
|
||||||
def pyevent__collectionreport(self, event):
|
|
||||||
if not event.passed:
|
|
||||||
self.log_outcome(event)
|
|
||||||
|
|
||||||
def pyevent__internalerror(self, excrepr):
|
|
||||||
path = excrepr.reprcrash.path
|
|
||||||
XXX # we don't have an event
|
|
||||||
self.write_log_entry(event, '!', path, str(excrepr))
|
|
||||||
|
|
||||||
SQL_CREATE_TABLES = """
|
SQL_CREATE_TABLES = """
|
||||||
create table pytest_results (
|
create table pytest_results (
|
||||||
|
@ -370,7 +350,7 @@ class TestWithFunctionIntegration:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
excinfo = py.code.ExceptionInfo()
|
excinfo = py.code.ExceptionInfo()
|
||||||
reslog = ResultDB(StringIO.StringIO())
|
reslog = ResultDB(StringIO.StringIO())
|
||||||
reslog.pyevent("internalerror", (excinfo.getrepr(),), {})
|
reslog.pyevent__internalerror(excinfo.getrepr)
|
||||||
entry = reslog.logfile.getvalue()
|
entry = reslog.logfile.getvalue()
|
||||||
entry_lines = entry.splitlines()
|
entry_lines = entry.splitlines()
|
||||||
|
|
||||||
|
|
|
@ -45,54 +45,42 @@ def generic_path(item):
|
||||||
fspath = newfspath
|
fspath = newfspath
|
||||||
return ''.join(gpath)
|
return ''.join(gpath)
|
||||||
|
|
||||||
def getoutcomecodes(ev):
|
|
||||||
if isinstance(ev, ev.CollectionReport):
|
|
||||||
# encode pass/fail/skip indepedent of terminal reporting semantics
|
|
||||||
# XXX handle collection and item reports more uniformly
|
|
||||||
assert not ev.passed
|
|
||||||
if ev.failed:
|
|
||||||
code = "F"
|
|
||||||
elif ev.skipped:
|
|
||||||
code = "S"
|
|
||||||
longrepr = str(ev.longrepr.reprcrash)
|
|
||||||
else:
|
|
||||||
assert isinstance(ev, ev.ItemTestReport)
|
|
||||||
code = ev.shortrepr
|
|
||||||
if ev.passed:
|
|
||||||
longrepr = ""
|
|
||||||
elif ev.failed:
|
|
||||||
longrepr = str(ev.longrepr)
|
|
||||||
elif ev.skipped:
|
|
||||||
longrepr = str(ev.longrepr.reprcrash.message)
|
|
||||||
return code, longrepr
|
|
||||||
|
|
||||||
class ResultLog(object):
|
class ResultLog(object):
|
||||||
def __init__(self, logfile):
|
def __init__(self, logfile):
|
||||||
self.logfile = logfile # preferably line buffered
|
self.logfile = logfile # preferably line buffered
|
||||||
|
|
||||||
def write_log_entry(self, shortrepr, name, longrepr):
|
def write_log_entry(self, testpath, shortrepr, longrepr):
|
||||||
print >>self.logfile, "%s %s" % (shortrepr, name)
|
print >>self.logfile, "%s %s" % (shortrepr, testpath)
|
||||||
for line in longrepr.splitlines():
|
for line in longrepr.splitlines():
|
||||||
print >>self.logfile, " %s" % line
|
print >>self.logfile, " %s" % line
|
||||||
|
|
||||||
def log_outcome(self, event):
|
def log_outcome(self, event, shortrepr, longrepr):
|
||||||
if (not event.passed or isinstance(event, event.ItemTestReport)):
|
testpath = generic_path(event.colitem)
|
||||||
gpath = generic_path(event.colitem)
|
self.write_log_entry(testpath, shortrepr, longrepr)
|
||||||
shortrepr, longrepr = getoutcomecodes(event)
|
|
||||||
self.write_log_entry(shortrepr, gpath, longrepr)
|
|
||||||
|
|
||||||
def pyevent(self, eventname, args, kwargs):
|
def pyevent__itemtestreport(self, event):
|
||||||
if args:
|
code = event.shortrepr
|
||||||
event = args[0]
|
if event.passed:
|
||||||
if eventname == "itemtestreport":
|
longrepr = ""
|
||||||
self.log_outcome(event)
|
elif event.failed:
|
||||||
elif eventname == "collectionreport":
|
longrepr = str(event.longrepr)
|
||||||
|
elif event.skipped:
|
||||||
|
longrepr = str(event.longrepr.reprcrash.message)
|
||||||
|
self.log_outcome(event, code, longrepr)
|
||||||
|
|
||||||
|
def pyevent__collectionreport(self, event):
|
||||||
if not event.passed:
|
if not event.passed:
|
||||||
self.log_outcome(event)
|
if event.failed:
|
||||||
elif eventname == "internalerror":
|
code = "F"
|
||||||
excrepr = args[0]
|
else:
|
||||||
path = excrepr.reprcrash.path # fishing :(
|
assert event.skipped
|
||||||
self.write_log_entry('!', path, str(excrepr))
|
code = "S"
|
||||||
|
longrepr = str(event.longrepr.reprcrash)
|
||||||
|
self.log_outcome(event, code, longrepr)
|
||||||
|
|
||||||
|
def pyevent__internalerror(self, excrepr):
|
||||||
|
path = excrepr.reprcrash.path
|
||||||
|
self.write_log_entry(path, '!', str(excrepr))
|
||||||
|
|
||||||
|
|
||||||
# ===============================================================================
|
# ===============================================================================
|
||||||
|
@ -127,7 +115,7 @@ def test_generic_path():
|
||||||
def test_write_log_entry():
|
def test_write_log_entry():
|
||||||
reslog = ResultLog(None)
|
reslog = ResultLog(None)
|
||||||
reslog.logfile = StringIO.StringIO()
|
reslog.logfile = StringIO.StringIO()
|
||||||
reslog.write_log_entry('.', 'name', '')
|
reslog.write_log_entry('name', '.', '')
|
||||||
entry = reslog.logfile.getvalue()
|
entry = reslog.logfile.getvalue()
|
||||||
assert entry[-1] == '\n'
|
assert entry[-1] == '\n'
|
||||||
entry_lines = entry.splitlines()
|
entry_lines = entry.splitlines()
|
||||||
|
@ -135,7 +123,7 @@ def test_write_log_entry():
|
||||||
assert entry_lines[0] == '. name'
|
assert entry_lines[0] == '. name'
|
||||||
|
|
||||||
reslog.logfile = StringIO.StringIO()
|
reslog.logfile = StringIO.StringIO()
|
||||||
reslog.write_log_entry('s', 'name', 'Skipped')
|
reslog.write_log_entry('name', 's', 'Skipped')
|
||||||
entry = reslog.logfile.getvalue()
|
entry = reslog.logfile.getvalue()
|
||||||
assert entry[-1] == '\n'
|
assert entry[-1] == '\n'
|
||||||
entry_lines = entry.splitlines()
|
entry_lines = entry.splitlines()
|
||||||
|
@ -144,7 +132,7 @@ def test_write_log_entry():
|
||||||
assert entry_lines[1] == ' Skipped'
|
assert entry_lines[1] == ' Skipped'
|
||||||
|
|
||||||
reslog.logfile = StringIO.StringIO()
|
reslog.logfile = StringIO.StringIO()
|
||||||
reslog.write_log_entry('s', 'name', 'Skipped\n')
|
reslog.write_log_entry('name', 's', 'Skipped\n')
|
||||||
entry = reslog.logfile.getvalue()
|
entry = reslog.logfile.getvalue()
|
||||||
assert entry[-1] == '\n'
|
assert entry[-1] == '\n'
|
||||||
entry_lines = entry.splitlines()
|
entry_lines = entry.splitlines()
|
||||||
|
@ -154,7 +142,7 @@ def test_write_log_entry():
|
||||||
|
|
||||||
reslog.logfile = StringIO.StringIO()
|
reslog.logfile = StringIO.StringIO()
|
||||||
longrepr = ' tb1\n tb 2\nE tb3\nSome Error'
|
longrepr = ' tb1\n tb 2\nE tb3\nSome Error'
|
||||||
reslog.write_log_entry('F', 'name', longrepr)
|
reslog.write_log_entry('name', 'F', longrepr)
|
||||||
entry = reslog.logfile.getvalue()
|
entry = reslog.logfile.getvalue()
|
||||||
assert entry[-1] == '\n'
|
assert entry[-1] == '\n'
|
||||||
entry_lines = entry.splitlines()
|
entry_lines = entry.splitlines()
|
||||||
|
@ -227,7 +215,7 @@ class TestWithFunctionIntegration:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
excinfo = py.code.ExceptionInfo()
|
excinfo = py.code.ExceptionInfo()
|
||||||
reslog = ResultLog(StringIO.StringIO())
|
reslog = ResultLog(StringIO.StringIO())
|
||||||
reslog.pyevent("internalerror", (excinfo.getrepr(),), {})
|
reslog.pyevent__internalerror(excinfo.getrepr())
|
||||||
entry = reslog.logfile.getvalue()
|
entry = reslog.logfile.getvalue()
|
||||||
entry_lines = entry.splitlines()
|
entry_lines = entry.splitlines()
|
||||||
|
|
||||||
|
|
|
@ -154,9 +154,9 @@ class TerminalReporter:
|
||||||
#self.write_fspath_result(fspath, "")
|
#self.write_fspath_result(fspath, "")
|
||||||
self.write_ensure_prefix(line, "")
|
self.write_ensure_prefix(line, "")
|
||||||
|
|
||||||
def pyevent__rescheduleitems(self, event):
|
def pyevent__rescheduleitems(self, items):
|
||||||
if self.config.option.debug:
|
if self.config.option.debug:
|
||||||
self.write_sep("!", "RESCHEDULING %s " %(event.items,))
|
self.write_sep("!", "RESCHEDULING %s " %(items,))
|
||||||
|
|
||||||
def pyevent__deselected(self, items):
|
def pyevent__deselected(self, items):
|
||||||
self.stats.setdefault('deselected', []).append(items)
|
self.stats.setdefault('deselected', []).append(items)
|
||||||
|
@ -232,17 +232,17 @@ class TerminalReporter:
|
||||||
self.summary_deselected()
|
self.summary_deselected()
|
||||||
self.summary_stats()
|
self.summary_stats()
|
||||||
|
|
||||||
def pyevent__looponfailinfo(self, event):
|
def pyevent__looponfailinfo(self, failreports, rootdirs):
|
||||||
if event.failreports:
|
if failreports:
|
||||||
self.write_sep("#", "LOOPONFAILING", red=True)
|
self.write_sep("#", "LOOPONFAILING", red=True)
|
||||||
for report in event.failreports:
|
for report in failreports:
|
||||||
try:
|
try:
|
||||||
loc = report.longrepr.reprcrash
|
loc = report.longrepr.reprcrash
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
loc = str(report.longrepr)[:50]
|
loc = str(report.longrepr)[:50]
|
||||||
self.write_line(loc, red=True)
|
self.write_line(loc, red=True)
|
||||||
self.write_sep("#", "waiting for changes")
|
self.write_sep("#", "waiting for changes")
|
||||||
for rootdir in event.rootdirs:
|
for rootdir in rootdirs:
|
||||||
self.write_line("### Watching: %s" %(rootdir,), bold=True)
|
self.write_line("### Watching: %s" %(rootdir,), bold=True)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -496,7 +496,7 @@ class TestTerminal:
|
||||||
""")
|
""")
|
||||||
rep = TerminalReporter(modcol.config, file=linecomp.stringio)
|
rep = TerminalReporter(modcol.config, file=linecomp.stringio)
|
||||||
reports = [basic_run_report(x) for x in modcol.collect()]
|
reports = [basic_run_report(x) for x in modcol.collect()]
|
||||||
rep.pyevent__looponfailinfo(event.LooponfailingInfo(reports, [modcol.config.topdir]))
|
rep.pyevent__looponfailinfo(reports, [modcol.config.topdir])
|
||||||
linecomp.assert_contains_lines([
|
linecomp.assert_contains_lines([
|
||||||
"*test_looponfailreport.py:2: assert 0",
|
"*test_looponfailreport.py:2: assert 0",
|
||||||
"*test_looponfailreport.py:4: ValueError*",
|
"*test_looponfailreport.py:4: ValueError*",
|
||||||
|
|
Loading…
Reference in New Issue