139 lines
4.8 KiB
Python
139 lines
4.8 KiB
Python
|
""" Remote executor
|
||
|
"""
|
||
|
|
||
|
import py, os, sys
|
||
|
|
||
|
from py.__.test.outcome import SerializableOutcome, ReprOutcome
|
||
|
from py.__.test.box import Box
|
||
|
from py.__.test import repevent
|
||
|
from py.__.test.outcome import Skipped, Failed
|
||
|
import py.__.test.custompdb
|
||
|
|
||
|
class RunExecutor(object):
|
||
|
""" Same as in executor, but just running run
|
||
|
"""
|
||
|
wraps = False
|
||
|
|
||
|
def __init__(self, item, usepdb=False, reporter=None, config=None):
|
||
|
self.item = item
|
||
|
self.usepdb = usepdb
|
||
|
self.reporter = reporter
|
||
|
self.config = config
|
||
|
assert self.config
|
||
|
|
||
|
def run(self, capture=True):
|
||
|
if capture:
|
||
|
self.item.startcapture()
|
||
|
try:
|
||
|
self.item.run()
|
||
|
finally:
|
||
|
self.item.finishcapture()
|
||
|
else:
|
||
|
self.item.run()
|
||
|
|
||
|
def execute(self, capture=True):
|
||
|
try:
|
||
|
self.run(capture)
|
||
|
outcome = SerializableOutcome()
|
||
|
outcome.stdout, outcome.stderr = self.item._getouterr()
|
||
|
except Skipped:
|
||
|
e = py.code.ExceptionInfo()
|
||
|
outcome = SerializableOutcome(skipped=e)
|
||
|
outcome.stdout, outcome.stderr = self.item._getouterr()
|
||
|
except (SystemExit, KeyboardInterrupt):
|
||
|
raise
|
||
|
except:
|
||
|
e = sys.exc_info()[1]
|
||
|
if isinstance(e, Failed) and e.excinfo:
|
||
|
excinfo = e.excinfo
|
||
|
else:
|
||
|
excinfo = py.code.ExceptionInfo()
|
||
|
if isinstance(self.item, py.test.collect.Function):
|
||
|
fun = self.item.obj # hope this is stable
|
||
|
code = py.code.Code(fun)
|
||
|
excinfo.traceback = excinfo.traceback.cut(
|
||
|
path=code.path, firstlineno=code.firstlineno)
|
||
|
outcome = SerializableOutcome(excinfo=excinfo, setupfailure=False)
|
||
|
outcome.stdout, outcome.stderr = self.item._getouterr()
|
||
|
if self.usepdb:
|
||
|
if self.reporter is not None:
|
||
|
self.reporter(repevent.ImmediateFailure(self.item,
|
||
|
ReprOutcome(outcome.make_repr
|
||
|
(self.config.option.tbstyle))))
|
||
|
py.__.test.custompdb.post_mortem(excinfo._excinfo[2])
|
||
|
# XXX hmm, we probably will not like to continue from that
|
||
|
# point
|
||
|
raise SystemExit()
|
||
|
return outcome
|
||
|
|
||
|
class ApigenExecutor(RunExecutor):
|
||
|
""" Same as RunExecutor, but takes tracer to trace calls as
|
||
|
an argument to execute
|
||
|
"""
|
||
|
def execute(self, tracer):
|
||
|
self.tracer = tracer
|
||
|
return super(ApigenExecutor, self).execute()
|
||
|
|
||
|
def wrap_underlaying(self, target, *args):
|
||
|
try:
|
||
|
self.tracer.start_tracing()
|
||
|
return target(*args)
|
||
|
finally:
|
||
|
self.tracer.end_tracing()
|
||
|
|
||
|
def run(self, capture):
|
||
|
""" We want to trace *only* function objects here. Unsure
|
||
|
what to do with custom collectors at all
|
||
|
"""
|
||
|
if hasattr(self.item, 'obj') and type(self.item) is py.test.collect.Function:
|
||
|
self.item.execute = self.wrap_underlaying
|
||
|
self.item.run()
|
||
|
|
||
|
class BoxExecutor(RunExecutor):
|
||
|
""" Same as RunExecutor, but boxes test instead
|
||
|
"""
|
||
|
wraps = True
|
||
|
|
||
|
def execute(self):
|
||
|
def fun():
|
||
|
outcome = RunExecutor.execute(self, False)
|
||
|
return outcome.make_repr(self.config.option.tbstyle)
|
||
|
b = Box(fun, config=self.config)
|
||
|
pid = b.run()
|
||
|
assert pid
|
||
|
if b.retval is not None:
|
||
|
passed, setupfailure, excinfo, skipped, critical, _, _, _\
|
||
|
= b.retval
|
||
|
return (passed, setupfailure, excinfo, skipped, critical, 0,
|
||
|
b.stdoutrepr, b.stderrrepr)
|
||
|
else:
|
||
|
return (False, False, None, None, False, b.signal,
|
||
|
b.stdoutrepr, b.stderrrepr)
|
||
|
|
||
|
class AsyncExecutor(RunExecutor):
|
||
|
""" same as box executor, but instead it returns function to continue
|
||
|
computations (more async mode)
|
||
|
"""
|
||
|
wraps = True
|
||
|
|
||
|
def execute(self):
|
||
|
def fun():
|
||
|
outcome = RunExecutor.execute(self, False)
|
||
|
return outcome.make_repr(self.config.option.tbstyle)
|
||
|
|
||
|
b = Box(fun, config=self.config)
|
||
|
parent, pid = b.run(continuation=True)
|
||
|
|
||
|
def cont(waiter=os.waitpid):
|
||
|
parent(pid, waiter=waiter)
|
||
|
if b.retval is not None:
|
||
|
passed, setupfailure, excinfo, skipped,\
|
||
|
critical, _, _, _ = b.retval
|
||
|
return (passed, setupfailure, excinfo, skipped, critical, 0,
|
||
|
b.stdoutrepr, b.stderrrepr)
|
||
|
else:
|
||
|
return (False, False, None, False, False,
|
||
|
b.signal, b.stdoutrepr, b.stderrrepr)
|
||
|
|
||
|
return cont, pid
|