Bladeren bron

qubes/tests: fix some of the fd leaks

This is WIP, there are more fds leaking.
Wojtek Porczyk 6 jaren geleden
bovenliggende
commit
d0f2fdba55
3 gewijzigde bestanden met toevoegingen van 54 en 44 verwijderingen
  1. 51 43
      qubes/tests/__init__.py
  2. 2 1
      qubes/tests/app.py
  3. 1 0
      qubes/tests/storage.py

+ 51 - 43
qubes/tests/__init__.py

@@ -605,7 +605,8 @@ class SystemTestCase(QubesTestCase):
         if not in_dom0:
             self.skipTest('outside dom0')
         super(SystemTestCase, self).setUp()
-        libvirtaio.virEventRegisterAsyncIOImpl(loop=self.loop)
+        self.libvirt_event_impl = libvirtaio.virEventRegisterAsyncIOImpl(
+            loop=self.loop)
         self.remove_test_vms()
 
         # need some information from the real qubes.xml - at least installed
@@ -619,7 +620,7 @@ class SystemTestCase(QubesTestCase):
             shutil.copy(self.host_app.store, XMLPATH)
         self.app = qubes.Qubes(XMLPATH)
         os.environ['QUBES_XML_PATH'] = XMLPATH
-        self.app.vmm.register_event_handlers(self.app)
+        self.app.register_event_handlers()
 
         self.qubesd = self.loop.run_until_complete(
             qubes.api.create_servers(
@@ -627,6 +628,54 @@ class SystemTestCase(QubesTestCase):
                 qubes.api.internal.QubesInternalAPI,
                 app=self.app, debug=True))
 
+    def tearDown(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:
+                os.unlink(sock.getsockname())
+            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([
+            server.wait_closed() for server in self.qubesd]))
+        del self.qubesd
+
+        # remove all references to any complex qubes objects, to release
+        # resources - most importantly file descriptors; this object will live
+        # during the whole test run, but all the file descriptors would be
+        # depleted earlier
+        self.app.close()
+        self.host_app.close()
+        del self.app
+        del self.host_app
+        for attr in dir(self):
+            obj_type = type(getattr(self, attr))
+            if obj_type.__module__.startswith('qubes'):
+                delattr(self, attr)
+
+        # then trigger garbage collector to really destroy those objects
+        gc.collect()
+
+        self.loop.run_until_complete(self.libvirt_event_impl.drain())
+        if not self.libvirt_event_impl.is_idle():
+            self.log.warning(
+                '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:
             template = self.host_app.default_template
@@ -675,47 +724,6 @@ class SystemTestCase(QubesTestCase):
             self.pool = self.app.add_pool(**POOL_CONF)
             self.created_pool = True
 
-    def tearDown(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:
-                os.unlink(sock.getsockname())
-            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([
-            server.wait_closed() for server in self.qubesd]))
-        del self.qubesd
-
-        # remove all references to any complex qubes objects, to release
-        # resources - most importantly file descriptors; this object will live
-        # during the whole test run, but all the file descriptors would be
-        # depleted earlier
-        self.app.vmm._libvirt_conn = None
-        del self.app
-        del self.host_app
-        for attr in dir(self):
-            obj_type = type(getattr(self, attr))
-            if obj_type.__module__.startswith('qubes'):
-                delattr(self, attr)
-
-        # then trigger garbage collector to really destroy those objects
-        gc.collect()
-
-        super(SystemTestCase, self).tearDown()
-
     def _remove_vm_qubes(self, vm):
         vmname = vm.name
         app = vm.app

+ 2 - 1
qubes/tests/app.py

@@ -275,7 +275,7 @@ class TC_90_Qubes(qubes.tests.QubesTestCase):
             os.unlink('/tmp/qubestest.xml')
         except FileNotFoundError:
             pass
-        qubes.Qubes.create_empty_store('/tmp/qubestest.xml')
+        qubes.Qubes.create_empty_store('/tmp/qubestest.xml').close()
 
     def test_100_clockvm(self):
         app = qubes.Qubes('/tmp/qubestest.xml', load=False, offline_mode=True)
@@ -295,6 +295,7 @@ class TC_90_Qubes(qubes.tests.QubesTestCase):
         self.assertNotIn('service.clocksync', appvm.features)
         self.assertIn('service.clocksync', template.features)
         self.assertTrue(template.features['service.clocksync'])
+        app.close()
 
     @qubes.tests.skipUnlessGit
     def test_900_example_xml_in_doc(self):

+ 1 - 0
qubes/tests/storage.py

@@ -92,6 +92,7 @@ class TC_00_Pool(SystemTestCase):
 
     def setUp(self):
         super(TC_00_Pool, self).setUp()
+        self.app.close()
         self.app = TestApp()
 
     def test_000_unknown_pool_driver(self):