qubes/tests: convert some tearDown into addCleanup
This is because .tearDown() is not executed if the exception occurs in setUp() [for example self.skipTest() raises an exception]. The lower levels of .tearDown() being executed are critical to not leaking file descriptors.
This commit is contained in:
parent
d0f2fdba55
commit
6ff1bfdc16
@ -345,12 +345,6 @@ class substitute_entry_points(object):
|
|||||||
self._orig_iter_entry_points = None
|
self._orig_iter_entry_points = None
|
||||||
|
|
||||||
|
|
||||||
class BeforeCleanExit(BaseException):
|
|
||||||
'''Raised from :py:meth:`QubesTestCase.tearDown` when
|
|
||||||
:py:attr:`qubes.tests.run.QubesDNCTestResult.do_not_clean` is set.'''
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class QubesTestCase(unittest.TestCase):
|
class QubesTestCase(unittest.TestCase):
|
||||||
'''Base class for Qubes unit tests.
|
'''Base class for Qubes unit tests.
|
||||||
'''
|
'''
|
||||||
@ -379,27 +373,15 @@ class QubesTestCase(unittest.TestCase):
|
|||||||
super().setUp()
|
super().setUp()
|
||||||
self.loop = asyncio.new_event_loop()
|
self.loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(self.loop)
|
asyncio.set_event_loop(self.loop)
|
||||||
|
self.addCleanup(self.cleanup_loop)
|
||||||
|
|
||||||
def tearDown(self):
|
def cleanup_loop(self):
|
||||||
# The loop, when closing, throws a warning if there is
|
# The loop, when closing, throws a warning if there is
|
||||||
# some unfinished bussiness. Let's catch that.
|
# some unfinished bussiness. Let's catch that.
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.simplefilter('error')
|
warnings.simplefilter('error')
|
||||||
self.loop.close()
|
self.loop.close()
|
||||||
|
del self.loop
|
||||||
# TODO: find better way in py3
|
|
||||||
try:
|
|
||||||
result = self._outcome.result
|
|
||||||
except:
|
|
||||||
result = self._resultForDoCleanups
|
|
||||||
failed_test_cases = result.failures \
|
|
||||||
+ result.errors \
|
|
||||||
+ [(tc, None) for tc in result.unexpectedSuccesses]
|
|
||||||
|
|
||||||
if getattr(result, 'do_not_clean', False) \
|
|
||||||
and any(tc is self for tc, exc in failed_test_cases):
|
|
||||||
raise BeforeCleanExit()
|
|
||||||
|
|
||||||
|
|
||||||
def assertNotRaises(self, excClass, callableObj=None, *args, **kwargs):
|
def assertNotRaises(self, excClass, callableObj=None, *args, **kwargs):
|
||||||
"""Fail if an exception of class excClass is raised
|
"""Fail if an exception of class excClass is raised
|
||||||
@ -628,10 +610,12 @@ class SystemTestCase(QubesTestCase):
|
|||||||
qubes.api.internal.QubesInternalAPI,
|
qubes.api.internal.QubesInternalAPI,
|
||||||
app=self.app, debug=True))
|
app=self.app, debug=True))
|
||||||
|
|
||||||
def tearDown(self):
|
self.addCleanup(self.cleanup_app)
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_app(self):
|
||||||
self.remove_test_vms()
|
self.remove_test_vms()
|
||||||
|
|
||||||
# close the servers before super(), because that might close the loop
|
|
||||||
server = None
|
server = None
|
||||||
for server in self.qubesd:
|
for server in self.qubesd:
|
||||||
for sock in server.sockets:
|
for sock in server.sockets:
|
||||||
@ -674,7 +658,6 @@ class SystemTestCase(QubesTestCase):
|
|||||||
'libvirt event impl not clean: callbacks %r descriptors %r',
|
'libvirt event impl not clean: callbacks %r descriptors %r',
|
||||||
self.libvirt_event_impl.callbacks,
|
self.libvirt_event_impl.callbacks,
|
||||||
self.libvirt_event_impl.descriptors)
|
self.libvirt_event_impl.descriptors)
|
||||||
super(SystemTestCase, self).tearDown()
|
|
||||||
|
|
||||||
def init_default_template(self, template=None):
|
def init_default_template(self, template=None):
|
||||||
if template is None:
|
if template is None:
|
||||||
|
@ -231,10 +231,6 @@ class QubesTestResult(unittest.TestResult):
|
|||||||
self.stream.writeln('%s' % err)
|
self.stream.writeln('%s' % err)
|
||||||
|
|
||||||
|
|
||||||
class QubesDNCTestResult(QubesTestResult):
|
|
||||||
do_not_clean = True
|
|
||||||
|
|
||||||
|
|
||||||
def demo(verbosity=2):
|
def demo(verbosity=2):
|
||||||
class TC_00_Demo(qubes.tests.QubesTestCase):
|
class TC_00_Demo(qubes.tests.QubesTestCase):
|
||||||
'''Demo class'''
|
'''Demo class'''
|
||||||
@ -293,13 +289,6 @@ parser.add_argument('--no-failfast',
|
|||||||
action='store_false', dest='failfast',
|
action='store_false', dest='failfast',
|
||||||
help='disable --failfast')
|
help='disable --failfast')
|
||||||
|
|
||||||
parser.add_argument('--do-not-clean', '--dnc', '-D',
|
|
||||||
action='store_true', dest='do_not_clean',
|
|
||||||
help='do not execute tearDown on failed tests. Implies --failfast.')
|
|
||||||
parser.add_argument('--do-clean', '-C',
|
|
||||||
action='store_false', dest='do_not_clean',
|
|
||||||
help='do execute tearDown even on failed tests.')
|
|
||||||
|
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
try:
|
try:
|
||||||
name_to_level = logging._nameToLevel
|
name_to_level = logging._nameToLevel
|
||||||
@ -387,9 +376,6 @@ def main(args=None):
|
|||||||
print(str(test)) # pylint: disable=superfluous-parens
|
print(str(test)) # pylint: disable=superfluous-parens
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if args.do_not_clean:
|
|
||||||
args.failfast = True
|
|
||||||
|
|
||||||
logging.root.setLevel(args.loglevel)
|
logging.root.setLevel(args.loglevel)
|
||||||
|
|
||||||
if args.logfile is not None:
|
if args.logfile is not None:
|
||||||
@ -425,10 +411,7 @@ def main(args=None):
|
|||||||
verbosity=(args.verbose-args.quiet),
|
verbosity=(args.verbose-args.quiet),
|
||||||
failfast=args.failfast)
|
failfast=args.failfast)
|
||||||
unittest.signals.installHandler()
|
unittest.signals.installHandler()
|
||||||
|
runner.resultclass = QubesTestResult
|
||||||
runner.resultclass = QubesDNCTestResult \
|
|
||||||
if args.do_not_clean else QubesTestResult
|
|
||||||
|
|
||||||
result = runner.run(suite)
|
result = runner.run(suite)
|
||||||
|
|
||||||
if args.break_to_repl:
|
if args.break_to_repl:
|
||||||
|
Loading…
Reference in New Issue
Block a user