tests: even more agressive cleanup in tearDown

Remove some more references to objects holding (possibly indirectly)
reference to libvirt connection:
 - local variables in tearDown function
 - running Admin API calls (especially admin.Events)
 - vmm._libvirt_conn directly, in case some reference to Qubes()
   is still there
 - any instance attribute that is an object from 'qubes' python package
   (instead of just those descending from BaseVM)
 - do not create new Qubes() instance for removing VMs - if we already
   have one in self.app

Then trigger garbage collector to really cleanup those objects (and
close relevant file descriptors). It's important do do this before
closing event loop, because some of descructors may try to use it (for
example remove registered handlers).
This commit is contained in:
Marek Marczykowski-Górecki 2017-07-26 02:59:05 +02:00
parent d57120d809
commit c53582b285
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -48,6 +48,7 @@ import unittest
import warnings import warnings
from distutils import spawn from distutils import spawn
import gc
import lxml.etree import lxml.etree
import pkg_resources import pkg_resources
@ -661,25 +662,42 @@ class SystemTestCase(QubesTestCase):
self.remove_test_vms() self.remove_test_vms()
# close the servers before super(), because that might close the loop # close the servers before super(), because that might close the loop
server = None
for server in self.qubesd: for server in self.qubesd:
for sock in server.sockets: for sock in server.sockets:
os.unlink(sock.getsockname()) os.unlink(sock.getsockname())
server.close() server.close()
del server
# close all existing connections, especially this will interrupt
# running admin.Events calls, which do keep reference to Qubes() and
# libvirt connection
conn = None
for conn in qubes.api.QubesDaemonProtocol.connections:
if conn.transport:
conn.transport.abort()
del conn
self.loop.run_until_complete(asyncio.wait([ self.loop.run_until_complete(asyncio.wait([
server.wait_closed() for server in self.qubesd])) server.wait_closed() for server in self.qubesd]))
del self.qubesd
super(SystemTestCase, self).tearDown() # remove all references to any complex qubes objects, to release
# remove all references to VM objects, to release resources - most # resources - most importantly file descriptors; this object will live
# importantly file descriptors; this object will live
# during the whole test run, but all the file descriptors would be # during the whole test run, but all the file descriptors would be
# depleted earlier # depleted earlier
self.app.vmm._libvirt_conn = None
del self.app del self.app
del self.host_app del self.host_app
for attr in dir(self): for attr in dir(self):
if isinstance(getattr(self, attr), qubes.vm.BaseVM): obj_type = type(getattr(self, attr))
if obj_type.__module__.startswith('qubes'):
delattr(self, attr) delattr(self, attr)
# then trigger garbage collector to really destroy those objects
gc.collect()
super(SystemTestCase, self).tearDown()
def _remove_vm_qubes(self, vm): def _remove_vm_qubes(self, vm):
vmname = vm.name vmname = vm.name
@ -689,7 +707,7 @@ class SystemTestCase(QubesTestCase):
# XXX .is_running() may throw libvirtError if undefined # XXX .is_running() may throw libvirtError if undefined
if vm.is_running(): if vm.is_running():
self.loop.run_until_complete(vm.kill()) self.loop.run_until_complete(vm.kill())
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
pass pass
try: try:
@ -776,12 +794,14 @@ class SystemTestCase(QubesTestCase):
# first, remove them Qubes-way # first, remove them Qubes-way
if os.path.exists(xmlpath): if os.path.exists(xmlpath):
try: try:
self.remove_vms(vm for vm in qubes.Qubes(xmlpath).domains try:
app = self.app
except AttributeError:
app = qubes.Qubes(xmlpath)
self.remove_vms(vm for vm in app.domains
if vm.name.startswith(prefix)) if vm.name.startswith(prefix))
except (qubes.exc.QubesException, lxml.etree.XMLSyntaxError): del app
# If qubes-test.xml is broken that much it doesn't even load, except qubes.exc.QubesException:
# simply remove it. VMs will be cleaned up the hard way.
# TODO logging?
pass pass
os.unlink(xmlpath) os.unlink(xmlpath)