2011-01-03 18:19:29 +03:00
|
|
|
#!/usr/bin/env python
|
|
|
|
"""Detect reference leaks after several unit test runs.
|
|
|
|
|
|
|
|
The script runs the unit test and counts the objects alive after the run. If
|
|
|
|
the object count differs between the last two runs, a report is printed and the
|
|
|
|
script exits with error 1.
|
|
|
|
"""
|
|
|
|
|
2019-02-17 04:34:52 +03:00
|
|
|
# Copyright (C) 2011-2019 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
2020-01-18 00:10:44 +03:00
|
|
|
# Copyright (C) 2020 The Psycopg Team
|
2011-01-03 18:19:29 +03:00
|
|
|
#
|
2014-05-20 20:50:53 +04:00
|
|
|
# psycopg2 is free software: you can redistribute it and/or modify it
|
|
|
|
# under the terms of the GNU Lesser General Public License as published
|
|
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
2011-01-03 18:19:29 +03:00
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
2014-05-20 20:50:53 +04:00
|
|
|
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
|
|
# License for more details.
|
2011-01-03 18:19:29 +03:00
|
|
|
|
2018-10-10 15:15:57 +03:00
|
|
|
import argparse
|
2011-01-03 18:19:29 +03:00
|
|
|
import gc
|
|
|
|
import sys
|
|
|
|
import difflib
|
|
|
|
import unittest
|
|
|
|
from pprint import pprint
|
|
|
|
from collections import defaultdict
|
|
|
|
|
2016-10-11 02:10:53 +03:00
|
|
|
|
2011-01-03 18:19:29 +03:00
|
|
|
def main():
|
|
|
|
opt = parse_args()
|
|
|
|
|
2017-12-04 05:47:19 +03:00
|
|
|
import tests
|
|
|
|
test = tests
|
2011-01-03 18:19:29 +03:00
|
|
|
if opt.suite:
|
|
|
|
test = getattr(test, opt.suite)
|
|
|
|
|
2020-11-18 00:52:11 +03:00
|
|
|
sys.stdout.write(f"test suite {test.__name__}\n")
|
2011-01-03 18:19:29 +03:00
|
|
|
|
|
|
|
for i in range(1, opt.nruns + 1):
|
2020-11-18 19:09:08 +03:00
|
|
|
sys.stdout.write(f"test suite run {i} of {opt.nruns}\n")
|
2011-01-03 18:19:29 +03:00
|
|
|
runner = unittest.TextTestRunner()
|
|
|
|
runner.run(test.test_suite())
|
|
|
|
dump(i, opt)
|
|
|
|
|
2020-11-18 19:09:08 +03:00
|
|
|
f1 = open(f'debug-{(opt.nruns - 1):02}.txt').readlines()
|
|
|
|
f2 = open(f'debug-{opt.nruns:02}.txt').readlines()
|
2011-01-03 18:19:29 +03:00
|
|
|
for line in difflib.unified_diff(f1, f2,
|
2020-11-18 19:09:08 +03:00
|
|
|
f"run {opt.nruns - 1}", f"run {opt.nruns}"):
|
2011-01-03 18:19:29 +03:00
|
|
|
sys.stdout.write(line)
|
|
|
|
|
|
|
|
rv = f1 != f2 and 1 or 0
|
|
|
|
|
|
|
|
if opt.objs:
|
2020-11-18 19:09:08 +03:00
|
|
|
f1 = open(f'objs-{(opt.nruns - 1):02}.txt').readlines()
|
|
|
|
f2 = open(f'objs-{opt.nruns:02}.txt').readlines()
|
2011-01-03 18:19:29 +03:00
|
|
|
for line in difflib.unified_diff(f1, f2,
|
2020-11-18 19:09:08 +03:00
|
|
|
f"run {opt.nruns - 1}", f"run {opt.nruns}"):
|
2011-01-03 18:19:29 +03:00
|
|
|
sys.stdout.write(line)
|
|
|
|
|
|
|
|
return rv
|
|
|
|
|
2016-10-11 02:10:53 +03:00
|
|
|
|
2011-01-03 18:19:29 +03:00
|
|
|
def parse_args():
|
2018-10-10 15:15:57 +03:00
|
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
|
|
parser.add_argument('--nruns', type=int, metavar="N", default=3,
|
|
|
|
help="number of test suite runs [default: %(default)d]")
|
|
|
|
parser.add_argument('--suite', metavar="NAME",
|
2011-01-03 18:19:29 +03:00
|
|
|
help="the test suite to run (e.g. 'test_cursor'). [default: all]")
|
2018-10-10 15:15:57 +03:00
|
|
|
parser.add_argument('--objs', metavar="TYPE",
|
2011-01-03 18:19:29 +03:00
|
|
|
help="in case of leaks, print a report of object TYPE "
|
|
|
|
"(support still incomplete)")
|
|
|
|
|
2018-10-10 15:15:57 +03:00
|
|
|
return parser.parse_args()
|
2011-01-03 18:19:29 +03:00
|
|
|
|
|
|
|
|
|
|
|
def dump(i, opt):
|
|
|
|
gc.collect()
|
|
|
|
objs = gc.get_objects()
|
|
|
|
|
|
|
|
c = defaultdict(int)
|
|
|
|
for o in objs:
|
|
|
|
c[type(o)] += 1
|
|
|
|
|
|
|
|
pprint(
|
2016-10-11 02:10:53 +03:00
|
|
|
sorted(((v, str(k)) for k, v in c.items()), reverse=True),
|
2020-11-18 19:09:08 +03:00
|
|
|
stream=open(f"debug-{i:02}.txt", "w"))
|
2011-01-03 18:19:29 +03:00
|
|
|
|
|
|
|
if opt.objs:
|
|
|
|
co = []
|
|
|
|
t = getattr(__builtins__, opt.objs)
|
|
|
|
for o in objs:
|
|
|
|
if type(o) is t:
|
|
|
|
co.append(o)
|
|
|
|
|
|
|
|
# TODO: very incomplete
|
|
|
|
if t is dict:
|
2016-10-11 02:10:53 +03:00
|
|
|
co.sort(key=lambda d: d.items())
|
2011-01-03 18:19:29 +03:00
|
|
|
else:
|
|
|
|
co.sort()
|
|
|
|
|
2020-11-18 19:09:08 +03:00
|
|
|
pprint(co, stream=open(f"objs-{i:02}.txt", "w"))
|
2011-01-03 18:19:29 +03:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
sys.exit(main())
|