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
	 Wojtek Porczyk
						Wojtek Porczyk