Improve LsofFdLeakChecker; more reliable and useful leak checking

* Make it invoke lsof with options for machine-readable output
* Parse out file descriptor and filename from lsof output
* Draw attention to file descriptors now open that weren't open before

--HG--
branch : refactor_LsofFdLeakChecker
This commit is contained in:
Marc Abramowitz 2014-04-01 13:41:35 -07:00
parent f7713c47e8
commit 064e79761c
1 changed files with 24 additions and 8 deletions

View File

@ -13,13 +13,24 @@ class LsofFdLeakChecker(object):
def _exec_lsof(self): def _exec_lsof(self):
pid = os.getpid() pid = os.getpid()
return py.process.cmdexec("lsof -p %d" % pid) return py.process.cmdexec("lsof -Ffn0 -p %d" % pid)
def _parse_lsof_output(self, out): def _parse_lsof_output(self, out):
def isopen(line): def isopen(line):
return ("REG" in line or "CHR" in line) and ( return line.startswith('f') and (
"deleted" not in line and 'mem' not in line and "txt" not in line) "deleted" not in line and 'mem' not in line and "txt" not in line and 'cwd' not in line)
return [x for x in out.split("\n") if isopen(x)]
open_files = []
for line in out.split("\n"):
if isopen(line):
fields = line.split('\0')
fd = int(fields[0][1:])
filename = fields[1][1:]
if filename.startswith('/'):
open_files.append((fd, filename))
return open_files
def pytest_addoption(parser): def pytest_addoption(parser):
@ -49,11 +60,16 @@ def getopenfiles(out):
def check_open_files(config): def check_open_files(config):
lines2 = config._fd_leak_checker.get_open_files() lines2 = config._fd_leak_checker.get_open_files()
if len(lines2) > config._numfiles + 3: new_fds = sorted(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 = []
error.append("***** %s FD leackage detected" % error.append("***** %s FD leackage detected" % len(open_files))
(len(lines2)-config._numfiles)) error.extend([str(f) for f in open_files])
error.extend(lines2) 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]) error.append(error[0])
# update numfile so that the overall test run continuess # update numfile so that the overall test run continuess
config._numfiles = len(lines2) config._numfiles = len(lines2)