tests: complain about memory leaks
Currently this detects leaking VM (and all subclasses), Qubes and libvirt-related objects. Usable only with --failfast.
This commit is contained in:
parent
7df8f51011
commit
5aa9fa2db4
@ -374,9 +374,29 @@ class QubesTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
self.addCleanup(self.cleanup_gc)
|
||||||
|
|
||||||
self.loop = asyncio.get_event_loop()
|
self.loop = asyncio.get_event_loop()
|
||||||
self.addCleanup(self.cleanup_loop)
|
self.addCleanup(self.cleanup_loop)
|
||||||
|
|
||||||
|
def cleanup_gc(self):
|
||||||
|
gc.collect()
|
||||||
|
leaked = [obj for obj in gc.get_objects() + gc.garbage
|
||||||
|
if isinstance(obj,
|
||||||
|
(qubes.Qubes, qubes.vm.BaseVM,
|
||||||
|
libvirt.virConnect, libvirt.virDomain))]
|
||||||
|
|
||||||
|
if leaked:
|
||||||
|
try:
|
||||||
|
import objgraph
|
||||||
|
objgraph.show_backrefs(leaked,
|
||||||
|
max_depth=15, extra_info=extra_info,
|
||||||
|
filename='/tmp/objgraph-{}.png'.format(self.id()))
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert not leaked
|
||||||
|
|
||||||
def cleanup_loop(self):
|
def cleanup_loop(self):
|
||||||
'''Check if the loop is empty'''
|
'''Check if the loop is empty'''
|
||||||
# XXX BEWARE this is touching undocumented, implementation-specific
|
# XXX BEWARE this is touching undocumented, implementation-specific
|
||||||
@ -1013,6 +1033,23 @@ def list_templates():
|
|||||||
_templates = ()
|
_templates = ()
|
||||||
return _templates
|
return _templates
|
||||||
|
|
||||||
|
def extra_info(obj):
|
||||||
|
'''Return short info identifying object.
|
||||||
|
|
||||||
|
For example, if obj is a qube, return its name. This is for use with
|
||||||
|
:py:mod:`objgraph` package.
|
||||||
|
'''
|
||||||
|
# Feel free to extend to other cases.
|
||||||
|
|
||||||
|
if isinstance(obj, qubes.vm.qubesvm.QubesVM):
|
||||||
|
try:
|
||||||
|
return obj.name
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
if isinstance(obj, unittest.TestCase):
|
||||||
|
return obj.id()
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
def load_tests(loader, tests, pattern): # pylint: disable=unused-argument
|
def load_tests(loader, tests, pattern): # pylint: disable=unused-argument
|
||||||
# discard any tests from this module, because it hosts base classes
|
# discard any tests from this module, because it hosts base classes
|
||||||
|
Loading…
Reference in New Issue
Block a user