[svn r46011] Branch merge of session cleanups.

* killed _tryiter usage in rsession
* moved reporter one level up, so it can be reused later for normal session
* a lot of small simplifications

--HG--
branch : trunk
This commit is contained in:
fijal 2007-08-27 11:02:50 +02:00
parent 46fdbe7867
commit 28c5aae67d
27 changed files with 4266 additions and 385 deletions

View File

@ -189,7 +189,7 @@ class Collector(object):
return True return True
return False return False
def _tryiter(self, yieldtype=None, reporterror=None, keyword=None): def _tryiter(self, yieldtype=None):
""" yield stop item instances from flattening the collector. """ yield stop item instances from flattening the collector.
XXX deprecated: this way of iteration is not safe in all XXX deprecated: this way of iteration is not safe in all
cases. cases.
@ -197,28 +197,17 @@ class Collector(object):
if yieldtype is None: if yieldtype is None:
yieldtype = py.test.collect.Item yieldtype = py.test.collect.Item
if isinstance(self, yieldtype): if isinstance(self, yieldtype):
try: yield self
self._skipbykeyword(keyword)
yield self
except Skipped:
if reporterror is not None:
excinfo = py.code.ExceptionInfo()
reporterror((excinfo, self))
else: else:
if not isinstance(self, py.test.collect.Item): if not isinstance(self, py.test.collect.Item):
try: try:
if reporterror is not None:
reporterror((None, self))
for x in self.run(): for x in self.run():
for y in self.join(x)._tryiter(yieldtype, for y in self.join(x)._tryiter(yieldtype):
reporterror, keyword):
yield y yield y
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except:
if reporterror is not None: pass
excinfo = py.code.ExceptionInfo()
reporterror((excinfo, self))
def _getsortvalue(self): def _getsortvalue(self):
return self.name return self.name

View File

@ -1,7 +1,10 @@
""" File defining possible outcomes of running """ File defining possible outcomes of running and also
serialization of outcomes
""" """
import py, sys
class Outcome: class Outcome:
def __init__(self, msg=None, excinfo=None): def __init__(self, msg=None, excinfo=None):
self.msg = msg self.msg = msg
@ -27,3 +30,120 @@ class ExceptionFailure(Failed):
class Skipped(Outcome): class Skipped(Outcome):
pass pass
class SerializableOutcome(object):
def __init__(self, setupfailure=False, excinfo=None, skipped=None,
is_critical=False):
self.passed = not excinfo and not skipped
self.skipped = skipped
self.setupfailure = setupfailure
self.excinfo = excinfo
self.is_critical = is_critical
self.signal = 0
self.stdout = "" # XXX temporary
self.stderr = ""
assert bool(self.passed) + bool(excinfo) + bool(skipped) == 1
def make_excinfo_repr(self, tbstyle):
if self.excinfo is None:
return None
excinfo = self.excinfo
tb_info = [self.traceback_entry_repr(x, tbstyle)
for x in excinfo.traceback]
rec_index = excinfo.traceback.recursionindex()
if hasattr(excinfo, 'type'):
etype = excinfo.type
if hasattr(etype, '__name__'):
etype = etype.__name__
else:
etype = excinfo.typename
val = getattr(excinfo, 'value', None)
if not val:
val = excinfo.exconly()
val = str(val)
return (etype, val, (tb_info, rec_index))
def traceback_entry_repr(self, tb_entry, tb_style):
lineno = tb_entry.lineno
relline = lineno - tb_entry.frame.code.firstlineno
path = str(tb_entry.path)
#try:
try:
if tb_style == 'long':
source = str(tb_entry.getsource())
else:
source = str(tb_entry.getsource()).split("\n")[relline]
except py.error.ENOENT:
source = "[cannot get source]"
name = str(tb_entry.frame.code.name)
# XXX: Bare except. What can getsource() raise anyway?
# SyntaxError, AttributeError, IndentationError for sure, check it
#except:
# source = "<could not get source>"
return (relline, lineno, source, path, name)
def make_repr(self, tbstyle="long"):
return (self.passed, self.setupfailure,
self.make_excinfo_repr(tbstyle),
self.skipped, self.is_critical, 0, self.stdout, self.stderr)
class TracebackEntryRepr(object):
def __init__(self, tbentry):
relline, lineno, self.source, self.path, self.name = tbentry
self.relline = int(relline)
self.path = py.path.local(self.path)
self.lineno = int(lineno)
self.locals = {}
def __repr__(self):
return "line %s in %s\n %s" %(self.lineno, self.path, self.source[100:])
def getsource(self):
return py.code.Source(self.source).strip()
def getfirstlinesource(self):
return self.lineno - self.relline
class TracebackRepr(list):
def recursionindex(self):
return self.recursion_index
class ExcInfoRepr(object):
def __init__(self, excinfo):
self.typename, self.value, tb_i = excinfo
tb, rec_index = tb_i
self.traceback = TracebackRepr([TracebackEntryRepr(x) for x in tb])
self.traceback.recursion_index = rec_index
def __repr__(self):
l = ["%s=%s" %(x, getattr(self, x))
for x in "typename value traceback".split()]
return "<ExcInfoRepr %s>" %(" ".join(l),)
def exconly(self, tryshort=False):
""" Somehow crippled version of original one
"""
return "%s: %s" % (self.typename, self.value)
def errisinstance(self, exc_t):
if not isinstance(exc_t, tuple):
exc_t = (exc_t,)
for exc in exc_t:
if self.typename == str(exc).split('.')[-1]:
return True
return False
class ReprOutcome(object):
def __init__(self, repr_tuple):
(self.passed, self.setupfailure, excinfo, self.skipped,
self.is_critical, self.signal, self.stdout, self.stderr) = repr_tuple
if excinfo is None:
self.excinfo = None
else:
self.excinfo = ExcInfoRepr(excinfo)
def __repr__(self):
l = ["%s=%s" %(x, getattr(self, x))
for x in "signal passed skipped setupfailure excinfo stdout stderr".split()]
return "<ReprOutcome %s>" %(" ".join(l),)

View File

@ -38,6 +38,9 @@ class ReportEvent(object):
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),)
def is_failure(self):
return False
class SendItem(ReportEvent): class SendItem(ReportEvent):
def __init__(self, channel, item): def __init__(self, channel, item):
self.item = item self.item = item
@ -53,6 +56,9 @@ class ReceivedItemOutcome(ReportEvent):
self.item = item self.item = item
self.outcome = outcome self.outcome = outcome
def is_failure(self):
return not (self.outcome.passed or self.outcome.skipped)
class CallEvent(ReportEvent): class CallEvent(ReportEvent):
def __init__(self, func, args, kwargs): def __init__(self, func, args, kwargs):
self.func = func self.func = func
@ -115,6 +121,9 @@ class FailedTryiter(ReportEvent):
self.excinfo = excinfo self.excinfo = excinfo
self.item = item self.item = item
def is_failure(self):
return True
class ItemStart(ReportEvent): class ItemStart(ReportEvent):
""" This class shows most of the start stuff, like directory, module, class """ This class shows most of the start stuff, like directory, module, class
can be used for containers can be used for containers

View File

@ -8,13 +8,45 @@
import py import py
from py.__.test.terminal.out import getout from py.__.test.terminal.out import getout
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession import outcome from py.__.test import outcome
from py.__.misc.terminal_helper import ansi_print, get_terminal_width from py.__.misc.terminal_helper import ansi_print, get_terminal_width
from py.__.test.representation import Presenter from py.__.test.representation import Presenter
import sys import sys
import thread
def choose_reporter(config):
option = config.option
if option.startserver or option.runbrowser:
from py.__.test.rsession.web import WebReporter
return WebReporter
if option.restreport:
from py.__.test.rsession.rest import RestReporter
return RestReporter
else:
if option.dist:
return RemoteReporter
else:
return LocalReporter
class TestReporter(object):
""" Simple test reporter which tracks failures
and also calls arbitrary provided function,
useful for tests
"""
def __init__(self, reportfun):
self.reportfun = reportfun
self.flag = False
def report(self, event):
if event.is_failure():
self.flag = True
self.reportfun(event)
__call__ = report
def was_failure(self):
return self.flag
class AbstractReporter(object): class AbstractReporter(object):
def __init__(self, config, hosts): def __init__(self, config, hosts):
@ -45,6 +77,11 @@ class AbstractReporter(object):
for i in excinfo.traceback: for i in excinfo.traceback:
print str(i)[2:-1] print str(i)[2:-1]
print excinfo print excinfo
# XXX reenable test before removing below line and
# run it with raise
#raise
__call__ = report
def report_unknown(self, what): def report_unknown(self, what):
if self.config.option.verbose: if self.config.option.verbose:
@ -152,7 +189,7 @@ class AbstractReporter(object):
self.repr_failure(event.item, event.outcome) self.repr_failure(event.item, event.outcome)
else: else:
self.out.sep('_', " ".join(event.item.listnames())) self.out.sep('_', " ".join(event.item.listnames()))
out = outcome.Outcome(excinfo=event.excinfo) out = outcome.SerializableOutcome(excinfo=event.excinfo)
self.repr_failure(event.item, outcome.ReprOutcome(out.make_repr())) self.repr_failure(event.item, outcome.ReprOutcome(out.make_repr()))
def gethost(self, event): def gethost(self, event):
@ -254,13 +291,13 @@ class AbstractReporter(object):
else: else:
self.failed[host] += 1 self.failed[host] += 1
self.failed_tests_outcome.append(event) self.failed_tests_outcome.append(event)
sys.stdout.write("%15s: " % hostrepr) sys.stdout.write("%15s: " % hostrepr)
ansi_print("FAILED", esc=(31,1), newline=False, file=sys.stdout) ansi_print("FAILED", esc=(31,1), newline=False, file=sys.stdout)
sys.stdout.write(" ") sys.stdout.write(" ")
# we should have printed 20 characters to this point # we should have printed 20 characters to this point
itempath = ".".join(event.item.listnames()[1:-1]) itempath = ".".join(event.item.listnames()[1:-1])
funname = event.item.listnames()[-1] funname = event.item.listnames()[-1]
lgt = get_terminal_width() - 25 lgt = get_terminal_width() - 20
# mark the function name, to be sure # mark the function name, to be sure
to_display = len(itempath) + len(funname) + 1 to_display = len(itempath) + len(funname) + 1
if to_display > lgt: if to_display > lgt:
@ -273,6 +310,9 @@ class AbstractReporter(object):
def report_Nodes(self, event): def report_Nodes(self, event):
self.nodes = event.nodes self.nodes = event.nodes
def was_failure(self):
return len(self.failed) > 0
class RemoteReporter(AbstractReporter): class RemoteReporter(AbstractReporter):
def get_item_name(self, event, colitem): def get_item_name(self, event, colitem):
return event.host.hostname + ":" + \ return event.host.hostname + ":" + \

View File

@ -3,9 +3,9 @@
import py, os, sys import py, os, sys
from py.__.test.rsession.outcome import Outcome, ReprOutcome from py.__.test.outcome import SerializableOutcome, ReprOutcome
from py.__.test.rsession.box import Box from py.__.test.rsession.box import Box
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.outcome import Skipped, Failed from py.__.test.outcome import Skipped, Failed
class RunExecutor(object): class RunExecutor(object):
@ -33,9 +33,9 @@ class RunExecutor(object):
def execute(self, capture=True): def execute(self, capture=True):
try: try:
self.run(capture) self.run(capture)
outcome = Outcome() outcome = SerializableOutcome()
except Skipped, e: except Skipped, e:
outcome = Outcome(skipped=str(e)) outcome = SerializableOutcome(skipped=str(e))
except (SystemExit, KeyboardInterrupt): except (SystemExit, KeyboardInterrupt):
raise raise
except: except:
@ -49,7 +49,7 @@ class RunExecutor(object):
code = py.code.Code(fun) code = py.code.Code(fun)
excinfo.traceback = excinfo.traceback.cut( excinfo.traceback = excinfo.traceback.cut(
path=code.path, firstlineno=code.firstlineno) path=code.path, firstlineno=code.firstlineno)
outcome = Outcome(excinfo=excinfo, setupfailure=False) outcome = SerializableOutcome(excinfo=excinfo, setupfailure=False)
if self.usepdb: if self.usepdb:
if self.reporter is not None: if self.reporter is not None:
self.reporter(repevent.ImmediateFailure(self.item, self.reporter(repevent.ImmediateFailure(self.item,

View File

@ -5,7 +5,7 @@ import thread, threading
from py.__.test.rsession.master import MasterNode from py.__.test.rsession.master import MasterNode
from py.__.test.rsession.slave import setup_slave from py.__.test.rsession.slave import setup_slave
from py.__.test.rsession import repevent from py.__.test import repevent
class HostInfo(object): class HostInfo(object):
""" Class trying to store all necessary attributes """ Class trying to store all necessary attributes

View File

@ -5,8 +5,8 @@
import py import py
from py.__.test.rsession.executor import BoxExecutor, RunExecutor,\ from py.__.test.rsession.executor import BoxExecutor, RunExecutor,\
ApigenExecutor ApigenExecutor
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession.outcome import ReprOutcome from py.__.test.outcome import ReprOutcome
# XXX copied from session.py # XXX copied from session.py
def startcapture(session): def startcapture(session):

View File

@ -2,8 +2,9 @@
Node code for Master. Node code for Master.
""" """
import py import py
from py.__.test.rsession.outcome import ReprOutcome from py.__.test.outcome import ReprOutcome
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.outcome import Skipped
class MasterNode(object): class MasterNode(object):
def __init__(self, channel, reporter): def __init__(self, channel, reporter):
@ -39,12 +40,30 @@ class MasterNode(object):
# of hanging nodes and such # of hanging nodes and such
raise raise
def itemgen(colitems, reporter, keyword, reporterror): def itemgen(colitems, reporter, keyword=None):
def rep(x): stopitems = py.test.collect.Item # XXX should be generator here as well
reporterror(reporter, x) for next in colitems:
for x in colitems: if isinstance(next, stopitems):
for y in x._tryiter(reporterror=rep, keyword=keyword): try:
yield y next._skipbykeyword(keyword)
yield next
except Skipped:
excinfo = py.code.ExceptionInfo()
reporter(repevent.SkippedTryiter(excinfo, next))
else:
reporter(repevent.ItemStart(next))
try:
for x in itemgen([next.join(x) for x in next.run()], reporter,
keyword):
yield x
except (KeyboardInterrupt, SystemExit, GeneratorExit):
raise
except:
excinfo = py.code.ExceptionInfo()
if excinfo.type is Skipped:
reporter(repevent.SkippedTryiter(excinfo, next))
else:
reporter(repevent.FailedTryiter(excinfo, next))
def dispatch_loop(masternodes, itemgenerator, shouldstop, def dispatch_loop(masternodes, itemgenerator, shouldstop,
waiter = lambda: py.std.time.sleep(0.1), waiter = lambda: py.std.time.sleep(0.1),

View File

@ -1,126 +0,0 @@
""" Classes for representing outcomes on master and slavenode sides
"""
# WARNING! is_critical is debugging flag which means something
# wrong went on a different level. Usually that means
# internal bug.
import sys
import py
class Outcome(object):
def __init__(self, setupfailure=False, excinfo=None, skipped=None,
is_critical=False):
self.passed = not excinfo and not skipped
self.skipped = skipped
self.setupfailure = setupfailure
self.excinfo = excinfo
self.is_critical = is_critical
self.signal = 0
self.stdout = "" # XXX temporary
self.stderr = ""
assert bool(self.passed) + bool(excinfo) + bool(skipped) == 1
def make_excinfo_repr(self, tbstyle):
if self.excinfo is None:
return None
excinfo = self.excinfo
tb_info = [self.traceback_entry_repr(x, tbstyle)
for x in excinfo.traceback]
rec_index = excinfo.traceback.recursionindex()
if hasattr(excinfo, 'type'):
etype = excinfo.type
if hasattr(etype, '__name__'):
etype = etype.__name__
else:
etype = excinfo.typename
val = getattr(excinfo, 'value', None)
if not val:
val = excinfo.exconly()
val = str(val)
return (etype, val, (tb_info, rec_index))
def traceback_entry_repr(self, tb_entry, tb_style):
lineno = tb_entry.lineno
relline = lineno - tb_entry.frame.code.firstlineno
path = str(tb_entry.path)
#try:
try:
if tb_style == 'long':
source = str(tb_entry.getsource())
else:
source = str(tb_entry.getsource()).split("\n")[relline]
except py.error.ENOENT:
source = "[cannot get source]"
name = str(tb_entry.frame.code.name)
# XXX: Bare except. What can getsource() raise anyway?
# SyntaxError, AttributeError, IndentationError for sure, check it
#except:
# source = "<could not get source>"
return (relline, lineno, source, path, name)
def make_repr(self, tbstyle="long"):
return (self.passed, self.setupfailure,
self.make_excinfo_repr(tbstyle),
self.skipped, self.is_critical, 0, self.stdout, self.stderr)
class TracebackEntryRepr(object):
def __init__(self, tbentry):
relline, lineno, self.source, self.path, self.name = tbentry
self.relline = int(relline)
self.path = py.path.local(self.path)
self.lineno = int(lineno)
self.locals = {}
def __repr__(self):
return "line %s in %s\n %s" %(self.lineno, self.path, self.source[100:])
def getsource(self):
return py.code.Source(self.source).strip()
def getfirstlinesource(self):
return self.lineno - self.relline
class TracebackRepr(list):
def recursionindex(self):
return self.recursion_index
class ExcInfoRepr(object):
def __init__(self, excinfo):
self.typename, self.value, tb_i = excinfo
tb, rec_index = tb_i
self.traceback = TracebackRepr([TracebackEntryRepr(x) for x in tb])
self.traceback.recursion_index = rec_index
def __repr__(self):
l = ["%s=%s" %(x, getattr(self, x))
for x in "typename value traceback".split()]
return "<ExcInfoRepr %s>" %(" ".join(l),)
def exconly(self, tryshort=False):
""" Somehow crippled version of original one
"""
return "%s: %s" % (self.typename, self.value)
def errisinstance(self, exc_t):
if not isinstance(exc_t, tuple):
exc_t = (exc_t,)
for exc in exc_t:
if self.typename == str(exc).split('.')[-1]:
return True
return False
class ReprOutcome(object):
def __init__(self, repr_tuple):
(self.passed, self.setupfailure, excinfo, self.skipped,
self.is_critical, self.signal, self.stdout, self.stderr) = repr_tuple
if excinfo is None:
self.excinfo = None
else:
self.excinfo = ExcInfoRepr(excinfo)
def __repr__(self):
l = ["%s=%s" %(x, getattr(self, x))
for x in "signal passed skipped setupfailure excinfo stdout stderr".split()]
return "<ReprOutcome %s>" %(" ".join(l),)

View File

@ -5,8 +5,8 @@
import py import py
import sys import sys
from StringIO import StringIO from StringIO import StringIO
from py.__.test.rsession.reporter import AbstractReporter from py.__.test.reporter import AbstractReporter
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.rest.rst import * from py.__.rest.rst import *
class RestReporter(AbstractReporter): class RestReporter(AbstractReporter):

View File

@ -8,101 +8,15 @@ import sys
import re import re
import time import time
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession.master import MasterNode, dispatch_loop, itemgen from py.__.test.rsession.master import MasterNode, dispatch_loop, itemgen
from py.__.test.rsession.hostmanage import HostInfo, HostManager from py.__.test.rsession.hostmanage import HostInfo, HostManager
from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\ from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\
box_runner box_runner
from py.__.test.rsession.reporter import LocalReporter, RemoteReporter from py.__.test.reporter import LocalReporter, RemoteReporter, TestReporter
from py.__.test.session import Session from py.__.test.session import AbstractSession
from py.__.test.outcome import Skipped, Failed from py.__.test.outcome import Skipped, Failed
class AbstractSession(Session):
"""
An abstract session executes collectors/items through a runner.
"""
def fixoptions(self):
option = self.config.option
if option.runbrowser and not option.startserver:
#print "--runbrowser implies --startserver"
option.startserver = True
if self.config.getvalue("dist_boxed"):
option.boxed = True
super(AbstractSession, self).fixoptions()
def init_reporter(self, reporter, hosts, reporter_class, arg=""):
""" This initialises so called `reporter` class, which will
handle all event presenting to user. Does not get called
if main received custom reporter
"""
startserverflag = self.config.option.startserver
restflag = self.config.option.restreport
if startserverflag and reporter is None:
from py.__.test.rsession.web import start_server, exported_methods
if self.config.option.runbrowser:
from socket import INADDR_ANY
port = INADDR_ANY # pick a random port when starting browser
else:
port = 8000 # stick to a fixed port otherwise
reporter = exported_methods.report
httpd = start_server(server_address = ('', port))
port = httpd.server_port
if self.config.option.runbrowser:
import webbrowser, thread
# webbrowser.open() may block until the browser finishes or not
url = "http://localhost:%d" % (port,)
thread.start_new_thread(webbrowser.open, (url,))
elif reporter is None:
if restflag:
from py.__.test.rsession.rest import RestReporter
reporter_class = RestReporter
if arg:
reporter_instance = reporter_class(self.config, hosts)
else:
reporter_instance = reporter_class(self.config, hosts)
reporter = reporter_instance.report
else:
startserverflag = False
return reporter, startserverflag
def reporterror(reporter, data):
excinfo, item = data
if excinfo is None:
reporter(repevent.ItemStart(item))
elif excinfo.type is Skipped:
reporter(repevent.SkippedTryiter(excinfo, item))
else:
reporter(repevent.FailedTryiter(excinfo, item))
reporterror = staticmethod(reporterror)
def kill_server(self, startserverflag):
""" Kill web server
"""
if startserverflag:
from py.__.test.rsession.web import kill_server
kill_server()
def wrap_reporter(self, reporter):
""" We wrap reporter around, which makes it possible to us to track
existance of failures
"""
self.was_failure = False
def new_reporter(event):
if isinstance(event, repevent.ReceivedItemOutcome) and \
not event.outcome.passed and \
not event.outcome.skipped:
self.was_failure = True
return reporter(event)
checkfun = lambda : self.config.option.exitfirst and \
self.was_failure
# for tests
self.checkfun = checkfun
return new_reporter, checkfun
class RSession(AbstractSession): class RSession(AbstractSession):
""" Remote version of session """ Remote version of session
""" """
@ -129,12 +43,9 @@ class RSession(AbstractSession):
def main(self, reporter=None): def main(self, reporter=None):
""" main loop for running tests. """ """ main loop for running tests. """
args = self.config.args config = self.config
hm = HostManager(config)
hm = HostManager(self.config) reporter, checkfun = self.init_reporter(reporter, config, hm.hosts)
reporter, startserverflag = self.init_reporter(reporter,
hm.hosts, RemoteReporter)
reporter, checkfun = self.wrap_reporter(reporter)
reporter(repevent.TestStarted(hm.hosts, self.config.topdir, reporter(repevent.TestStarted(hm.hosts, self.config.topdir,
hm.roots)) hm.roots))
@ -157,22 +68,18 @@ class RSession(AbstractSession):
exitfirst=self.config.option.exitfirst) exitfirst=self.config.option.exitfirst)
reporter(repevent.Nodes(nodes)) reporter(repevent.Nodes(nodes))
retval = reporter(repevent.TestFinished()) retval = reporter(repevent.TestFinished())
self.kill_server(startserverflag)
return retval return retval
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
reporter(repevent.InterruptedExecution()) reporter(repevent.InterruptedExecution())
self.kill_server(startserverflag)
raise raise
except: except:
reporter(repevent.CrashedExecution()) reporter(repevent.CrashedExecution())
self.kill_server(startserverflag)
raise raise
def dispatch_tests(self, nodes, reporter, checkfun): def dispatch_tests(self, nodes, reporter, checkfun):
colitems = self.config.getcolitems() colitems = self.config.getcolitems()
keyword = self.config.option.keyword keyword = self.config.option.keyword
itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) itemgenerator = itemgen(colitems, reporter, keyword)
all_tests = dispatch_loop(nodes, itemgenerator, checkfun) all_tests = dispatch_loop(nodes, itemgenerator, checkfun)
class LSession(AbstractSession): class LSession(AbstractSession):
@ -180,16 +87,13 @@ class LSession(AbstractSession):
""" """
def main(self, reporter=None, runner=None): def main(self, reporter=None, runner=None):
# check out if used options makes any sense # check out if used options makes any sense
args = self.config.args config = self.config
hm = HostManager(config, hosts=[HostInfo('localhost')])
hm = HostManager(self.config, hosts=[HostInfo('localhost')])
hosts = hm.hosts hosts = hm.hosts
if not self.config.option.nomagic: if not self.config.option.nomagic:
py.magic.invoke(assertion=1) py.magic.invoke(assertion=1)
reporter, startserverflag = self.init_reporter(reporter, reporter, checkfun = self.init_reporter(reporter, config, hosts)
hosts, LocalReporter, args[0])
reporter, checkfun = self.wrap_reporter(reporter)
reporter(repevent.TestStarted(hosts, self.config.topdir, [])) reporter(repevent.TestStarted(hosts, self.config.topdir, []))
colitems = self.config.getcolitems() colitems = self.config.getcolitems()
@ -200,11 +104,10 @@ class LSession(AbstractSession):
keyword = self.config.option.keyword keyword = self.config.option.keyword
itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) itemgenerator = itemgen(colitems, reporter, keyword)
local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner) local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner)
retval = reporter(repevent.TestFinished()) retval = reporter(repevent.TestFinished())
self.kill_server(startserverflag)
if not self.config.option.nomagic: if not self.config.option.nomagic:
py.magic.revoke(assertion=1) py.magic.revoke(assertion=1)

View File

@ -4,7 +4,7 @@ Node code for slaves.
import py import py
from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor
from py.__.test.rsession.outcome import Outcome from py.__.test.outcome import SerializableOutcome
from py.__.test.outcome import Skipped from py.__.test.outcome import Skipped
import thread import thread
import os import os
@ -53,10 +53,10 @@ def slave_main(receive, send, path, config):
node = getnode(nextitem) node = getnode(nextitem)
res = node.run(nextitem) res = node.run(nextitem)
except Skipped, s: except Skipped, s:
send(Outcome(skipped=str(s)).make_repr()) send(SerializableOutcome(skipped=str(s)).make_repr())
except: except:
excinfo = py.code.ExceptionInfo() excinfo = py.code.ExceptionInfo()
send(Outcome(excinfo=excinfo, is_critical=True).make_repr()) send(SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr())
else: else:
if not res[0] and not res[3] and config.option.exitfirst: if not res[0] and not res[3] and config.option.exitfirst:
# we're finished, but need to eat what we can # we're finished, but need to eat what we can

View File

@ -4,7 +4,7 @@ import example1
from py.__.test.rsession.executor import RunExecutor, BoxExecutor,\ from py.__.test.rsession.executor import RunExecutor, BoxExecutor,\
AsyncExecutor, ApigenExecutor AsyncExecutor, ApigenExecutor
from py.__.test.rsession.outcome import ReprOutcome from py.__.test.outcome import ReprOutcome
from py.__.test.rsession.testing.basetest import BasicRsessionTest from py.__.test.rsession.testing.basetest import BasicRsessionTest
from py.__.test.outcome import Failed from py.__.test.outcome import Failed

View File

@ -5,7 +5,7 @@
import py import py
from py.__.test.rsession.hostmanage import HostRSync, HostInfo, HostManager from py.__.test.rsession.hostmanage import HostRSync, HostInfo, HostManager
from py.__.test.rsession.hostmanage import sethomedir, gethomedir, getpath_relto_home from py.__.test.rsession.hostmanage import sethomedir, gethomedir, getpath_relto_home
from py.__.test.rsession import repevent from py.__.test import repevent
class DirSetup: class DirSetup:
def setup_method(self, method): def setup_method(self, method):

View File

@ -4,7 +4,7 @@
import py import py
from py.__.test.rsession.rsession import LSession from py.__.test.rsession.rsession import LSession
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession.local import box_runner, plain_runner, apigen_runner from py.__.test.rsession.local import box_runner, plain_runner, apigen_runner
def setup_module(mod): def setup_module(mod):

View File

@ -11,8 +11,8 @@ if sys.platform == 'win32':
from py.__.test.rsession.master import dispatch_loop, MasterNode from py.__.test.rsession.master import dispatch_loop, MasterNode
from py.__.test.rsession.slave import setup_slave from py.__.test.rsession.slave import setup_slave
from py.__.test.rsession.outcome import ReprOutcome, Outcome from py.__.test.outcome import ReprOutcome, SerializableOutcome
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession.hostmanage import HostInfo from py.__.test.rsession.hostmanage import HostInfo
def setup_module(mod): def setup_module(mod):
@ -64,8 +64,8 @@ def test_masternode():
mnode = MasterNode(ch, reportlist.append) mnode = MasterNode(ch, reportlist.append)
mnode.send(Item("ok")) mnode.send(Item("ok"))
mnode.send(Item("notok")) mnode.send(Item("notok"))
ch.callback(Outcome().make_repr()) ch.callback(SerializableOutcome().make_repr())
ch.callback(Outcome(excinfo=excinfo).make_repr()) ch.callback(SerializableOutcome(excinfo=excinfo).make_repr())
assert len(reportlist) == 4 assert len(reportlist) == 4
received = [i for i in reportlist received = [i for i in reportlist
if isinstance(i, repevent.ReceivedItemOutcome)] if isinstance(i, repevent.ReceivedItemOutcome)]
@ -91,12 +91,12 @@ def test_sending_two_noes():
mnode = MasterNode(ch, reportlist.append) mnode = MasterNode(ch, reportlist.append)
mnode.send(Item("ok")) mnode.send(Item("ok"))
mnode.send(Item("ok")) mnode.send(Item("ok"))
ch.callback(Outcome().make_repr()) ch.callback(SerializableOutcome().make_repr())
ch.callback(Outcome().make_repr()) ch.callback(SerializableOutcome().make_repr())
assert len(reportlist) == 4 assert len(reportlist) == 4
def test_outcome_repr(): def test_outcome_repr():
out = ReprOutcome(Outcome(skipped=True).make_repr()) out = ReprOutcome(SerializableOutcome(skipped=True).make_repr())
s = repr(out) s = repr(out)
assert s.lower().find("skip") != -1 assert s.lower().find("skip") != -1

View File

@ -3,13 +3,13 @@
""" """
import py import py
from py.__.test.rsession.testing.test_reporter import AbstractTestReporter,\ from py.__.test.testing.test_reporter import AbstractTestReporter,\
DummyChannel DummyChannel
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession.rest import RestReporter, NoLinkWriter from py.__.test.rsession.rest import RestReporter, NoLinkWriter
from py.__.rest.rst import * from py.__.rest.rst import *
from py.__.test.rsession.hostmanage import HostInfo from py.__.test.rsession.hostmanage import HostInfo
from py.__.test.rsession.outcome import Outcome from py.__.test.outcome import SerializableOutcome
class Container(object): class Container(object):
def __init__(self, **args): def __init__(self, **args):
@ -109,7 +109,7 @@ Testing module foo/bar.py (2 items)
""" """
def test_ReceivedItemOutcome_PASSED(self): def test_ReceivedItemOutcome_PASSED(self):
outcome = Outcome() outcome = SerializableOutcome()
item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item)
reporter.report(event) reporter.report(event)
@ -117,7 +117,7 @@ Testing module foo/bar.py (2 items)
'foo.py/bar()/baz\n\n') 'foo.py/bar()/baz\n\n')
def test_ReceivedItemOutcome_SKIPPED(self): def test_ReceivedItemOutcome_SKIPPED(self):
outcome = Outcome(skipped="reason") outcome = SerializableOutcome(skipped="reason")
item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item)
reporter.report(event) reporter.report(event)
@ -125,7 +125,7 @@ Testing module foo/bar.py (2 items)
'foo.py/bar()/baz\n\n') 'foo.py/bar()/baz\n\n')
def test_ReceivedItemOutcome_FAILED(self): def test_ReceivedItemOutcome_FAILED(self):
outcome = Outcome(excinfo="xxx") outcome = SerializableOutcome(excinfo="xxx")
item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item)
reporter.report(event) reporter.report(event)
@ -153,7 +153,7 @@ Testing module foo/bar.py (2 items)
), ),
] ]
) )
outcome = Outcome(excinfo=excinfo) outcome = SerializableOutcome(excinfo=excinfo)
outcome.stdout = '<printed>' outcome.stdout = '<printed>'
outcome.stderr = '' outcome.stderr = ''
parent = Container(parent=None, fspath=py.path.local('.')) parent = Container(parent=None, fspath=py.path.local('.'))
@ -336,18 +336,15 @@ class TestRestReporter(AbstractTestReporter):
py.test.skip("Not implemented") py.test.skip("Not implemented")
def test_report_received_item_outcome(self): def test_report_received_item_outcome(self):
py.test.skip("Relying on exact output matching")
val = self.report_received_item_outcome() val = self.report_received_item_outcome()
expected = """\ expected_list = [
* localhost\: **FAILED** `traceback0`_\n py/test/rsession/testing/test\_slave.py/funcpass "**FAILED**",
"**SKIPPED**",
"**PASSED**",
"* localhost\:",
"`traceback0`_ test\_one.py/funcpass",
"test\_one.py/funcpass"]
for expected in expected_list:
assert val.find(expected) != -1
* localhost\: **SKIPPED** py/test/rsession/testing/test\_slave.py/funcpass
* localhost\: **FAILED** `traceback1`_\n py/test/rsession/testing/test\_slave.py/funcpass
* localhost\: **PASSED** py/test/rsession/testing/test\_slave.py/funcpass
"""
print val
assert val == expected

View File

@ -3,7 +3,7 @@
""" """
import py import py
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession.rsession import RSession from py.__.test.rsession.rsession import RSession
from py.__.test.rsession.hostmanage import HostManager, HostInfo from py.__.test.rsession.hostmanage import HostManager, HostInfo
from py.__.test.rsession.testing.basetest import BasicRsessionTest from py.__.test.rsession.testing.basetest import BasicRsessionTest
@ -14,23 +14,6 @@ def setup_module(mod):
if py.std.sys.platform == "win32": if py.std.sys.platform == "win32":
py.test.skip("rsession tests disabled for win32") py.test.skip("rsession tests disabled for win32")
def test_example_tryiter():
events = []
tmpdir = py.test.ensuretemp("tryitertest")
tmpdir.ensure("a", "__init__.py")
tmpdir.ensure("conftest.py").write(py.code.Source("""
import py
py.test.skip("Reason")
"""))
tmpdir.ensure("a", "test_empty.py").write(py.code.Source("""
def test_empty():
pass
"""))
rootcol = py.test.collect.Directory(tmpdir)
data = list(rootcol._tryiter(reporterror=events.append))
assert len(events) == 2
assert str(events[1][0].value).find("Reason") != -1
class TestRSessionRemote(DirSetup, BasicRsessionTest): class TestRSessionRemote(DirSetup, BasicRsessionTest):
def test_example_distribution_minus_x(self): def test_example_distribution_minus_x(self):
self.source.ensure("sub", "conftest.py").write(py.code.Source(""" self.source.ensure("sub", "conftest.py").write(py.code.Source("""
@ -57,7 +40,6 @@ class TestRSessionRemote(DirSetup, BasicRsessionTest):
testevents = [x for x in allevents testevents = [x for x in allevents
if isinstance(x, repevent.ReceivedItemOutcome)] if isinstance(x, repevent.ReceivedItemOutcome)]
assert len(testevents) == 3 assert len(testevents) == 3
assert rsession.checkfun()
def test_distribution_rsync_roots_example(self): def test_distribution_rsync_roots_example(self):
destdir = py.test.ensuretemp("example_dist_destdir") destdir = py.test.ensuretemp("example_dist_destdir")

View File

@ -1,7 +1,7 @@
""" Testing the slave side node code (in a local way). """ """ Testing the slave side node code (in a local way). """
from py.__.test.rsession.slave import SlaveNode, slave_main, setup from py.__.test.rsession.slave import SlaveNode, slave_main, setup
from py.__.test.rsession.outcome import ReprOutcome from py.__.test.outcome import ReprOutcome
import py, sys import py, sys
from py.__.test.rsession.testing.basetest import BasicRsessionTest from py.__.test.rsession.testing.basetest import BasicRsessionTest

View File

@ -15,7 +15,7 @@ import socket
import py import py
from py.__.test.rsession.rsession import RSession from py.__.test.rsession.rsession import RSession
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test import collect from py.__.test import collect
from py.__.test.rsession.webdata import json from py.__.test.rsession.webdata import json
@ -305,9 +305,8 @@ class ExportedMethods(BasicExternal):
if not self.to_rsync[item.host]: if not self.to_rsync[item.host]:
self._host_ready(item) self._host_ready(item)
def report_TestStarted(self, event): def report_TestStarted(self, event):
# XXX: It overrides out self.hosts # XXX: It overrides our self.hosts
self.hosts = {} self.hosts = {}
self.ready_hosts = {} self.ready_hosts = {}
for host in event.hosts: for host in event.hosts:
@ -315,6 +314,13 @@ class ExportedMethods(BasicExternal):
self.ready_hosts[host] = False self.ready_hosts[host] = False
self.start_event.set() self.start_event.set()
self.pending_events.put(event) self.pending_events.put(event)
def report_TestFinished(self, event):
self.pending_events.put(event)
kill_server()
report_InterruptedExecution = report_TestFinished
report_CrashedExecution = report_TestFinished
def report(self, what): def report(self, what):
repfun = getattr(self, "report_" + what.__class__.__name__, repfun = getattr(self, "report_" + what.__class__.__name__,
@ -330,13 +336,6 @@ class ExportedMethods(BasicExternal):
print str(i)[2:-1] print str(i)[2:-1]
print excinfo print excinfo
## try:
## self.wait_flag.acquire()
## self.pending_events.insert(0, event)
## self.wait_flag.notify()
## finally:
## self.wait_flag.release()
exported_methods = ExportedMethods() exported_methods = ExportedMethods()
class TestHandler(BaseHTTPRequestHandler): class TestHandler(BaseHTTPRequestHandler):
@ -400,7 +399,7 @@ class TestHandler(BaseHTTPRequestHandler):
js_name = py.path.local(__file__).dirpath("webdata").join("source.js") js_name = py.path.local(__file__).dirpath("webdata").join("source.js")
web_name = py.path.local(__file__).dirpath().join("webjs.py") web_name = py.path.local(__file__).dirpath().join("webjs.py")
if IMPORTED_PYPY and web_name.mtime() > js_name.mtime() or \ if IMPORTED_PYPY and web_name.mtime() > js_name.mtime() or \
(not js_name.check()) or 1: (not js_name.check()):
from py.__.test.rsession import webjs from py.__.test.rsession import webjs
javascript_source = rpython2javascript(webjs, javascript_source = rpython2javascript(webjs,
@ -418,6 +417,34 @@ class TestHandler(BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(data) self.wfile.write(data)
class WebReporter(object):
""" A simple wrapper, this file needs ton of refactoring
anyway, so this is just to satisfy things below
(and start to create saner interface as well)
"""
def __init__(self, config, hosts):
start_server_from_config(config)
# rebind
report = exported_methods.report
__call__ = report
def start_server_from_config(config):
if config.option.runbrowser:
port = socket.INADDR_ANY
else:
port = 8000
httpd = start_server(server_address = ('', port))
port = httpd.server_port
if config.option.runbrowser:
import webbrowser, thread
# webbrowser.open() may block until the browser finishes or not
url = "http://localhost:%d" % (port,)
thread.start_new_thread(webbrowser.open, (url,))
return exported_methods.report
def start_server(server_address = ('', 8000), handler=TestHandler, start_new=True): def start_server(server_address = ('', 8000), handler=TestHandler, start_new=True):
httpd = HTTPServer(server_address, handler) httpd = HTTPServer(server_address, handler)

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,23 @@
import py import py
from py.__.test.outcome import Outcome, Failed, Passed, Skipped from py.__.test.outcome import Outcome, Failed, Passed, Skipped
from py.__.test.reporter import choose_reporter, TestReporter
class Session(object): class AbstractSession(object):
""" """ An abstract session executes collectors/items through a runner.
A Session gets test Items from Collectors, # executes the
Items and sends the Outcome to the Reporter.
""" """
def __init__(self, config): def __init__(self, config):
self._memo = [] self._memo = []
self.config = config self.config = config
self._keyword = config.option.keyword self._keyword = config.option.keyword
def shouldclose(self):
return False
def header(self, colitems):
""" setup any neccessary resources ahead of the test run. """
if not self.config.option.nomagic:
py.magic.invoke(assertion=1)
def footer(self, colitems):
""" teardown any resources after a test run. """
py.test.collect.Function._state.teardown_all()
if not self.config.option.nomagic:
py.magic.revoke(assertion=1)
def fixoptions(self): def fixoptions(self):
""" check, fix and determine conflicting options. """ """ check, fix and determine conflicting options. """
option = self.config.option option = self.config.option
if option.runbrowser and not option.startserver:
#print "--runbrowser implies --startserver"
option.startserver = True
if self.config.getvalue("dist_boxed") and option.dist:
option.boxed = True
# implied options # implied options
if option.usepdb: if option.usepdb:
if not option.nocapture: if not option.nocapture:
@ -43,6 +33,34 @@ class Session(object):
if option.keyword_oneshot and not option.keyword: if option.keyword_oneshot and not option.keyword:
raise ValueError, "--keyword-oneshot makes sense only when --keyword is supplied" raise ValueError, "--keyword-oneshot makes sense only when --keyword is supplied"
def init_reporter(self, reporter, config, hosts):
if reporter is None:
reporter = choose_reporter(config)(config, hosts)
else:
reporter = TestReporter(reporter)
checkfun = lambda : self.config.option.exitfirst and \
reporter.was_failure()
return reporter, checkfun
class Session(AbstractSession):
"""
A Session gets test Items from Collectors, # executes the
Items and sends the Outcome to the Reporter.
"""
def shouldclose(self):
return False
def header(self, colitems):
""" setup any neccessary resources ahead of the test run. """
if not self.config.option.nomagic:
py.magic.invoke(assertion=1)
def footer(self, colitems):
""" teardown any resources after a test run. """
py.test.collect.Function._state.teardown_all()
if not self.config.option.nomagic:
py.magic.revoke(assertion=1)
def start(self, colitem): def start(self, colitem):
""" hook invoked before each colitem.run() invocation. """ """ hook invoked before each colitem.run() invocation. """

View File

@ -7,10 +7,6 @@ def setup_module(mod):
mod.datadir = setupdatadir() mod.datadir = setupdatadir()
mod.tmpdir = py.test.ensuretemp('test_collect') mod.tmpdir = py.test.ensuretemp('test_collect')
def skipboxed():
if py.test.config.option.boxed:
py.test.skip("test does not work with boxed tests")
def test_failing_import_execfile(): def test_failing_import_execfile():
dest = datadir / 'failingimport.py' dest = datadir / 'failingimport.py'
col = py.test.collect.Module(dest) col = py.test.collect.Module(dest)
@ -375,10 +371,6 @@ def test__tryiter_ignores_failing_collectors():
py.test.fail("should not have raised: %s" %(exc,)) py.test.fail("should not have raised: %s" %(exc,))
l = [] l = []
list(col._tryiter(reporterror=l.append))
assert len(l) == 2
excinfo, item = l[-1]
assert isinstance(excinfo, py.code.ExceptionInfo)
def test_tryiter_handles_keyboardinterrupt(): def test_tryiter_handles_keyboardinterrupt():
tmp = py.test.ensuretemp("tryiterkeyboard") tmp = py.test.ensuretemp("tryiterkeyboard")
@ -416,9 +408,25 @@ def test_check_generator_collect_problems():
""")) """))
tmp.ensure("__init__.py") tmp.ensure("__init__.py")
col = py.test.collect.Module(tmp.join("test_one.py")) col = py.test.collect.Module(tmp.join("test_one.py"))
errors = [] assert len(col.join('test_one').run()) == 3
l = list(col._tryiter(reporterror=errors.append))
assert len(errors) == 2 def test_generator_setup_invoked_twice():
py.test.skip("Test for generators not invoking setup, needs thinking")
tmp = py.test.ensuretemp("generator_setup_invoke")
tmp.ensure("test_one.py").write(py.code.Source("""
def setup_module(mod):
mod.x = []
def setup_function(fun):
x.append(1)
def test_one():
yield lambda: None
"""))
tmp.ensure("__init__.py")
col = py.test.collect.Module(tmp.join("test_one.py"))
l = list(col._tryiter())
assert not hasattr(col.obj, 'x')
def test_check_collect_hashes(): def test_check_collect_hashes():
tmp = py.test.ensuretemp("check_collect_hashes") tmp = py.test.ensuretemp("check_collect_hashes")

View File

@ -2,7 +2,6 @@ from __future__ import generators
import py import py
from py.__.test.config import gettopdir from py.__.test.config import gettopdir
from py.__.test.testing.test_collect import skipboxed
def test_tmpdir(): def test_tmpdir():
d1 = py.test.ensuretemp('hello') d1 = py.test.ensuretemp('hello')

View File

@ -1,11 +1,11 @@
import py import py
from py.__.test.rsession.outcome import Outcome, ReprOutcome, ExcInfoRepr from py.__.test.outcome import SerializableOutcome, ReprOutcome, ExcInfoRepr
import marshal import marshal
def test_critical_debugging_flag(): def test_critical_debugging_flag():
outcome = Outcome(is_critical=True) outcome = SerializableOutcome(is_critical=True)
r = ReprOutcome(outcome.make_repr()) r = ReprOutcome(outcome.make_repr())
assert r.is_critical assert r.is_critical
@ -26,7 +26,7 @@ def test_exception_info_repr():
try: try:
f3() f3()
except: except:
outcome = Outcome(excinfo=py.code.ExceptionInfo()) outcome = SerializableOutcome(excinfo=py.code.ExceptionInfo())
repr = outcome.make_excinfo_repr("long") repr = outcome.make_excinfo_repr("long")
assert marshal.dumps(repr) assert marshal.dumps(repr)

View File

@ -1,7 +1,7 @@
""" test reporting functionality. """ """ test reporting functionality. """
import py import py
from py.__.test.rsession import repevent from py.__.test import repevent
def test_wrapcall_ok(): def test_wrapcall_ok():
l = [] l = []
@ -27,10 +27,27 @@ def test_wrapcall_exception():
def test_reporter_methods_sanity(): def test_reporter_methods_sanity():
""" Checks if all the methods of reporter are sane """ Checks if all the methods of reporter are sane
""" """
from py.__.test.rsession.rsession import RemoteReporter from py.__.test.reporter import RemoteReporter
from py.__.test.rsession import repevent
for method in dir(RemoteReporter): for method in dir(RemoteReporter):
if method.startswith("report_") and method != "report_unknown": if method.startswith("report_") and method != "report_unknown":
assert method[len('report_'):] in repevent.__dict__ assert method[len('report_'):] in repevent.__dict__
def test_repevent_failures():
from py.__.test.outcome import SerializableOutcome, ReprOutcome
assert not repevent.ReportEvent().is_failure()
assert not repevent.CallEvent(None, None, None).is_failure()
assert repevent.FailedTryiter(None, None).is_failure()
out = ReprOutcome(SerializableOutcome().make_repr())
assert not repevent.ReceivedItemOutcome(None, None, out).is_failure()
out = ReprOutcome(SerializableOutcome(skipped=True).make_repr())
assert not repevent.ReceivedItemOutcome(None, None, out).is_failure()
try:
1/0
except:
exc = py.code.ExceptionInfo()
out = ReprOutcome(SerializableOutcome(excinfo=exc).make_repr())
assert repevent.ReceivedItemOutcome(None, None, out).is_failure()

View File

@ -18,13 +18,14 @@ etc.
import py, os import py, os
from py.__.test.rsession.rsession import LocalReporter, AbstractSession,\ from py.__.test.session import AbstractSession
RemoteReporter from py.__.test.reporter import RemoteReporter, LocalReporter, choose_reporter
from py.__.test.rsession import repevent from py.__.test import repevent
from py.__.test.rsession.outcome import ReprOutcome, Outcome from py.__.test.outcome import ReprOutcome, SerializableOutcome
from py.__.test.rsession.hostmanage import HostInfo from py.__.test.rsession.hostmanage import HostInfo
from py.__.test.rsession.box import Box from py.__.test.rsession.box import Box
from py.__.test.rsession.testing.basetest import BasicRsessionTest from py.__.test.rsession.testing.basetest import BasicRsessionTest
from py.__.test.rsession.master import itemgen
import sys import sys
from StringIO import StringIO from StringIO import StringIO
@ -44,10 +45,10 @@ class AbstractTestReporter(BasicRsessionTest):
except: except:
exc = py.code.ExceptionInfo() exc = py.code.ExceptionInfo()
outcomes = [Outcome(()), outcomes = [SerializableOutcome(()),
Outcome(skipped=True), SerializableOutcome(skipped=True),
Outcome(excinfo=exc), SerializableOutcome(excinfo=exc),
Outcome()] SerializableOutcome()]
outcomes = [ReprOutcome(outcome.make_repr()) for outcome in outcomes] outcomes = [ReprOutcome(outcome.make_repr()) for outcome in outcomes]
outcomes[3].signal = 11 outcomes[3].signal = 11
@ -111,7 +112,7 @@ class AbstractTestReporter(BasicRsessionTest):
rootcol = py.test.collect.Directory(tmpdir) rootcol = py.test.collect.Directory(tmpdir)
hosts = [HostInfo('localhost')] hosts = [HostInfo('localhost')]
r = self.reporter(config, hosts) r = self.reporter(config, hosts)
list(rootcol._tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x))) list(itemgen([rootcol], r.report))
cap = py.io.StdCaptureFD() cap = py.io.StdCaptureFD()
boxfun() boxfun()
@ -132,7 +133,7 @@ class AbstractTestReporter(BasicRsessionTest):
r = self.reporter(config, [host]) r = self.reporter(config, [host])
r.report(repevent.TestStarted([host], config.topdir, ["a"])) r.report(repevent.TestStarted([host], config.topdir, ["a"]))
r.report(repevent.RsyncFinished()) r.report(repevent.RsyncFinished())
list(rootcol._tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x))) list(itemgen([rootcol], r.report))
r.report(repevent.TestFinished()) r.report(repevent.TestFinished())
return r return r
@ -149,6 +150,8 @@ class AbstractTestReporter(BasicRsessionTest):
cap = py.io.StdCaptureFD() cap = py.io.StdCaptureFD()
config = py.test.config._reparse([str(tmpdir)]) config = py.test.config._reparse([str(tmpdir)])
hosts = [HostInfo(i) for i in ["host1", "host2", "host3"]] hosts = [HostInfo(i) for i in ["host1", "host2", "host3"]]
for host in hosts:
host.gw_remotepath = ''
r = self.reporter(config, hosts) r = self.reporter(config, hosts)
r.report(repevent.TestStarted(hosts, config.topdir, ["a", "b", "c"])) r.report(repevent.TestStarted(hosts, config.topdir, ["a", "b", "c"]))
for host in hosts: for host in hosts:
@ -214,3 +217,17 @@ class TestRemoteReporter(AbstractTestReporter):
val = self._test_full_module() val = self._test_full_module()
assert val.find("FAILED TO LOAD MODULE: repmod/test_three.py\n"\ assert val.find("FAILED TO LOAD MODULE: repmod/test_three.py\n"\
"\nSkipped ('reason') repmod/test_two.py") != -1 "\nSkipped ('reason') repmod/test_two.py") != -1
def test_reporter_choice():
from py.__.test.rsession.web import WebReporter
from py.__.test.rsession.rest import RestReporter
choices = [
(['-d'], RemoteReporter),
(['-d', '--rest'], RestReporter),
([], LocalReporter),
(['-w'], WebReporter),
(['-r'], WebReporter)]
for opts, reporter in choices:
config = py.test.config._reparse(['xxx'] + opts)
assert choose_reporter(config) is reporter