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:
Wojtek Porczyk 2017-08-31 20:22:05 +02:00
parent d0f2fdba55
commit 6ff1bfdc16
2 changed files with 8 additions and 42 deletions

View File

@ -345,12 +345,6 @@ class substitute_entry_points(object):
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):
'''Base class for Qubes unit tests.
'''
@ -379,27 +373,15 @@ class QubesTestCase(unittest.TestCase):
super().setUp()
self.loop = asyncio.new_event_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
# some unfinished bussiness. Let's catch that.
with warnings.catch_warnings():
warnings.simplefilter('error')
self.loop.close()
# 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()
del self.loop
def assertNotRaises(self, excClass, callableObj=None, *args, **kwargs):
"""Fail if an exception of class excClass is raised
@ -628,10 +610,12 @@ class SystemTestCase(QubesTestCase):
qubes.api.internal.QubesInternalAPI,
app=self.app, debug=True))
def tearDown(self):
self.addCleanup(self.cleanup_app)
def cleanup_app(self):
self.remove_test_vms()
# close the servers before super(), because that might close the loop
server = None
for server in self.qubesd:
for sock in server.sockets:
@ -674,7 +658,6 @@ class SystemTestCase(QubesTestCase):
'libvirt event impl not clean: callbacks %r descriptors %r',
self.libvirt_event_impl.callbacks,
self.libvirt_event_impl.descriptors)
super(SystemTestCase, self).tearDown()
def init_default_template(self, template=None):
if template is None:

View File

@ -231,10 +231,6 @@ class QubesTestResult(unittest.TestResult):
self.stream.writeln('%s' % err)
class QubesDNCTestResult(QubesTestResult):
do_not_clean = True
def demo(verbosity=2):
class TC_00_Demo(qubes.tests.QubesTestCase):
'''Demo class'''
@ -293,13 +289,6 @@ parser.add_argument('--no-failfast',
action='store_false', dest='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
try:
name_to_level = logging._nameToLevel
@ -387,9 +376,6 @@ def main(args=None):
print(str(test)) # pylint: disable=superfluous-parens
return True
if args.do_not_clean:
args.failfast = True
logging.root.setLevel(args.loglevel)
if args.logfile is not None:
@ -425,10 +411,7 @@ def main(args=None):
verbosity=(args.verbose-args.quiet),
failfast=args.failfast)
unittest.signals.installHandler()
runner.resultclass = QubesDNCTestResult \
if args.do_not_clean else QubesTestResult
runner.resultclass = QubesTestResult
result = runner.run(suite)
if args.break_to_repl: