Files
pytest2/testing/conftest.py
holger krekel 715a235b45 remove shutdown logic from PluginManager and add a add_cleanup() API
for the already existing cleanup logic of the config object.
This simplifies lifecycle management as we don't keep two
layers of shutdown functions and also simplifies the pluginmanager
interface.

also add some docstrings.

--HG--
branch : plugin_no_pytest
2015-04-22 16:33:20 +02:00

120 lines
3.9 KiB
Python

import pytest
import sys
pytest_plugins = "pytester",
import os, py
class LsofFdLeakChecker(object):
def get_open_files(self):
out = self._exec_lsof()
open_files = self._parse_lsof_output(out)
return open_files
def _exec_lsof(self):
pid = os.getpid()
return py.process.cmdexec("lsof -Ffn0 -p %d" % pid)
def _parse_lsof_output(self, out):
def isopen(line):
return line.startswith('f') and (
"deleted" not in line and 'mem' not in line and "txt" not in line and 'cwd' not in line)
open_files = []
for line in out.split("\n"):
if isopen(line):
fields = line.split('\0')
fd = fields[0][1:]
filename = fields[1][1:]
if filename.startswith('/'):
open_files.append((fd, filename))
return open_files
def pytest_addoption(parser):
parser.addoption('--lsof',
action="store_true", dest="lsof", default=False,
help=("run FD checks if lsof is available"))
def pytest_runtest_setup(item):
config = item.config
config._basedir = py.path.local()
if config.getvalue("lsof"):
try:
config._fd_leak_checker = LsofFdLeakChecker()
config._openfiles = config._fd_leak_checker.get_open_files()
except py.process.cmdexec.Error:
pass
#def pytest_report_header():
# return "pid: %s" % os.getpid()
def check_open_files(config):
lines2 = config._fd_leak_checker.get_open_files()
new_fds = set([t[0] for t in lines2]) - set([t[0] for t in config._openfiles])
open_files = [t for t in lines2 if t[0] in new_fds]
if open_files:
error = []
error.append("***** %s FD leakage detected" % len(open_files))
error.extend([str(f) for f in open_files])
error.append("*** Before:")
error.extend([str(f) for f in config._openfiles])
error.append("*** After:")
error.extend([str(f) for f in lines2])
error.append(error[0])
raise AssertionError("\n".join(error))
@pytest.mark.trylast
def pytest_runtest_teardown(item, __multicall__):
item.config._basedir.chdir()
if hasattr(item.config, '_openfiles'):
x = __multicall__.execute()
check_open_files(item.config)
return x
# XXX copied from execnet's conftest.py - needs to be merged
winpymap = {
'python2.7': r'C:\Python27\python.exe',
'python2.6': r'C:\Python26\python.exe',
'python3.1': r'C:\Python31\python.exe',
'python3.2': r'C:\Python32\python.exe',
'python3.3': r'C:\Python33\python.exe',
'python3.4': r'C:\Python34\python.exe',
'python3.5': r'C:\Python35\python.exe',
}
def getexecutable(name, cache={}):
try:
return cache[name]
except KeyError:
executable = py.path.local.sysfind(name)
if executable:
if name == "jython":
import subprocess
popen = subprocess.Popen([str(executable), "--version"],
universal_newlines=True, stderr=subprocess.PIPE)
out, err = popen.communicate()
if not err or "2.5" not in err:
executable = None
if "2.5.2" in err:
executable = None # http://bugs.jython.org/issue1790
cache[name] = executable
return executable
@pytest.fixture(params=['python2.6', 'python2.7', 'python3.3', "python3.4",
'pypy', 'pypy3'])
def anypython(request):
name = request.param
executable = getexecutable(name)
if executable is None:
if sys.platform == "win32":
executable = winpymap.get(name, None)
if executable:
executable = py.path.local(executable)
if executable.check():
return executable
pytest.skip("no suitable %s found" % (name,))
return executable