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:
parent
d57120d809
commit
c53582b285
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user