147 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Python
		
	
	
	
""" 
 | 
						|
    internal classes for
 | 
						|
 | 
						|
    * executing test items 
 | 
						|
    * running collectors 
 | 
						|
    * and generating report events about it 
 | 
						|
"""
 | 
						|
 | 
						|
import py, os, sys
 | 
						|
 | 
						|
from py.__.test import event
 | 
						|
from py.__.test.outcome import Skipped, Exit
 | 
						|
from py.__.test.dsession.mypickle import ImmutablePickler
 | 
						|
import py.__.test.custompdb
 | 
						|
 | 
						|
class RobustRun(object):
 | 
						|
    """ a robust setup/execute/teardown protocol. """
 | 
						|
    def __init__(self, colitem, pdb=None):
 | 
						|
        self.colitem = colitem 
 | 
						|
        self.getcapture = colitem._config._getcapture 
 | 
						|
        self.pdb = pdb 
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "<%s colitem=%s>" %(self.__class__.__name__, self.colitem)
 | 
						|
 | 
						|
    def run(self):
 | 
						|
        """ return result of running setup, execution, teardown procedures. """ 
 | 
						|
        excinfo = None
 | 
						|
        res = NORESULT
 | 
						|
        capture = self.getcapture()
 | 
						|
        try:
 | 
						|
            try:
 | 
						|
                when = "setup"
 | 
						|
                self.setup()
 | 
						|
                try:
 | 
						|
                    res = self.execute()
 | 
						|
                finally:
 | 
						|
                    when = "teardown"
 | 
						|
                    self.teardown()
 | 
						|
                    when = "execute"
 | 
						|
            finally:
 | 
						|
                outerr = capture.reset()
 | 
						|
        except (Exit, KeyboardInterrupt):
 | 
						|
            raise
 | 
						|
        except: 
 | 
						|
            excinfo = py.code.ExceptionInfo()
 | 
						|
        return self.makereport(res, when, excinfo, outerr)
 | 
						|
 | 
						|
    def getkw(self, when, excinfo, outerr):
 | 
						|
        if excinfo.errisinstance(Skipped):
 | 
						|
            outcome = "skipped"
 | 
						|
            shortrepr = "s"
 | 
						|
            longrepr = excinfo._getreprcrash()
 | 
						|
        else:
 | 
						|
            outcome = "failed"
 | 
						|
            if when == "execute":
 | 
						|
                longrepr = self.colitem.repr_failure(excinfo, outerr)
 | 
						|
                shortrepr = self.colitem.shortfailurerepr
 | 
						|
            else:
 | 
						|
                longrepr = self.colitem._repr_failure_py(excinfo, outerr)
 | 
						|
                shortrepr = self.colitem.shortfailurerepr.lower()
 | 
						|
        kw = { outcome: OutcomeRepr(when, shortrepr, longrepr)}
 | 
						|
        return kw
 | 
						|
 | 
						|
class ItemRunner(RobustRun):
 | 
						|
    def setup(self):
 | 
						|
        self.colitem._setupstate.prepare(self.colitem)
 | 
						|
    def teardown(self):
 | 
						|
        self.colitem._setupstate.teardown_exact(self.colitem)
 | 
						|
    def execute(self):
 | 
						|
        self.colitem.runtest()
 | 
						|
    def makereport(self, res, when, excinfo, outerr):
 | 
						|
        if excinfo: 
 | 
						|
            kw = self.getkw(when, excinfo, outerr)
 | 
						|
            if self.pdb and kw.get('failed', 0):
 | 
						|
                self.pdb(excinfo)
 | 
						|
        else:
 | 
						|
            kw = {'passed': OutcomeRepr(when, '.', "")}
 | 
						|
        return event.ItemTestReport(self.colitem, **kw)
 | 
						|
 | 
						|
class CollectorRunner(RobustRun):
 | 
						|
    def setup(self):
 | 
						|
        pass
 | 
						|
    def teardown(self):
 | 
						|
        pass
 | 
						|
    def execute(self):
 | 
						|
        return self.colitem._memocollect()
 | 
						|
    def makereport(self, res, when, excinfo, outerr):
 | 
						|
        if excinfo: 
 | 
						|
            kw = self.getkw(when, excinfo, outerr)
 | 
						|
        else:
 | 
						|
            kw = {'passed': OutcomeRepr(when, '', "")}
 | 
						|
        return event.CollectionReport(self.colitem, res, **kw)
 | 
						|
 | 
						|
NORESULT = object()
 | 
						|
# 
 | 
						|
# public entrypoints / objects 
 | 
						|
#
 | 
						|
 | 
						|
class OutcomeRepr(object):
 | 
						|
    def __init__(self, when, shortrepr, longrepr):
 | 
						|
        self.when = when
 | 
						|
        self.shortrepr = shortrepr 
 | 
						|
        self.longrepr = longrepr 
 | 
						|
    def __str__(self):
 | 
						|
        return "<OutcomeRepr when=%r, shortrepr=%r, len-longrepr=%s" %(
 | 
						|
            self.when, self.shortrepr, len(str(self.longrepr)))
 | 
						|
 | 
						|
def basic_collect_report(item):
 | 
						|
    return CollectorRunner(item).run()
 | 
						|
    
 | 
						|
def basic_run_report(item, pdb=None):
 | 
						|
    return ItemRunner(item, pdb=pdb).run()
 | 
						|
 | 
						|
from cPickle import Pickler, Unpickler
 | 
						|
from cStringIO import StringIO
 | 
						|
 | 
						|
def forked_run_report(item, pdb=None):
 | 
						|
    EXITSTATUS_TESTEXIT = 4
 | 
						|
 | 
						|
    ipickle = ImmutablePickler(uneven=0)
 | 
						|
    ipickle.selfmemoize(item._config)
 | 
						|
    def runforked():
 | 
						|
        try:
 | 
						|
            testrep = basic_run_report(item)
 | 
						|
        except (KeyboardInterrupt, Exit): 
 | 
						|
            os._exit(EXITSTATUS_TESTEXIT)
 | 
						|
        return ipickle.dumps(testrep)
 | 
						|
 | 
						|
    ff = py.process.ForkedFunc(runforked)
 | 
						|
    result = ff.waitfinish()
 | 
						|
    if result.retval is not None:
 | 
						|
        return ipickle.loads(result.retval)
 | 
						|
    else:
 | 
						|
        if result.exitstatus == EXITSTATUS_TESTEXIT:
 | 
						|
            raise Exit("forked test item %s raised Exit" %(item,))
 | 
						|
        return report_crash(item, result)
 | 
						|
 | 
						|
def report_crash(item, result):
 | 
						|
    path, lineno = item.getfslineno()
 | 
						|
    longrepr = [
 | 
						|
        ("X", "CRASHED"), 
 | 
						|
        ("%s:%s: CRASHED with signal %d" %(path, lineno, result.signal)),
 | 
						|
    ]
 | 
						|
    outcomerepr = OutcomeRepr(when="???", shortrepr="X", longrepr=longrepr)
 | 
						|
    return event.ItemTestReport(item, failed=outcomerepr)
 |