13647: Use cluster config instead of custom keepstore config.
[arvados.git] / services / fuse / tests / integration_test.py
index 5a45bfc103f34df2ae928ed5bcd305d100c408fa..89b39dbc87e10677c3024d4566c9325cae756048 100644 (file)
@@ -1,14 +1,30 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+from __future__ import absolute_import
 import arvados
 import arvados_fuse
 import arvados_fuse.command
+import atexit
 import functools
 import inspect
+import logging
 import multiprocessing
 import os
+from . import run_test_server
+import signal
 import sys
 import tempfile
 import unittest
-import run_test_server
+
+@atexit.register
+def _pool_cleanup():
+    if _pool is None:
+        return
+    _pool.close()
+    _pool.join()
+
 
 def wrap_static_test_method(modName, clsName, funcName, args, kwargs):
     class Test(unittest.TestCase):
@@ -17,6 +33,17 @@ def wrap_static_test_method(modName, clsName, funcName, args, kwargs):
     Test().runTest(*args, **kwargs)
 
 
+# To avoid Python's threading+multiprocessing=deadlock problems, we
+# use a single global pool with maxtasksperchild=None for the entire
+# test suite.
+_pool = None
+def workerPool():
+    global _pool
+    if _pool is None:
+        _pool = multiprocessing.Pool(processes=1, maxtasksperchild=None)
+    return _pool
+
+
 class IntegrationTest(unittest.TestCase):
     def pool_test(self, *args, **kwargs):
         """Run a static method as a unit test, in a different process.
@@ -27,19 +54,14 @@ class IntegrationTest(unittest.TestCase):
         modName = inspect.getmodule(self).__name__
         clsName = self.__class__.__name__
         funcName = inspect.currentframe().f_back.f_code.co_name
-        pool = multiprocessing.Pool(1)
-        try:
-            pool.apply(
-                wrap_static_test_method,
-                (modName, clsName, '_'+funcName, args, kwargs))
-        finally:
-            pool.terminate()
-            pool.join()
+        workerPool().apply(
+            wrap_static_test_method,
+            (modName, clsName, '_'+funcName, args, kwargs))
 
     @classmethod
     def setUpClass(cls):
         run_test_server.run()
-        run_test_server.run_keep(enforce_permissions=True, num_servers=2)
+        run_test_server.run_keep(blob_signing=True, num_servers=2)
 
     @classmethod
     def tearDownClass(cls):
@@ -48,7 +70,6 @@ class IntegrationTest(unittest.TestCase):
     def setUp(self):
         self.mnt = tempfile.mkdtemp()
         run_test_server.authorize_with('active')
-        self.api = arvados.safeapi.ThreadSafeApiCache(arvados.config.settings())
 
     def tearDown(self):
         os.rmdir(self.mnt)
@@ -60,11 +81,19 @@ class IntegrationTest(unittest.TestCase):
         def decorator(func):
             @functools.wraps(func)
             def wrapper(self, *args, **kwargs):
-                with arvados_fuse.command.Mount(
-                        arvados_fuse.command.ArgumentParser().parse_args(
-                            argv + ['--foreground',
-                                    '--unmount-timeout=0.1',
-                                    self.mnt])):
-                    return func(self, *args, **kwargs)
+                self.mount = None
+                try:
+                    with arvados_fuse.command.Mount(
+                            arvados_fuse.command.ArgumentParser().parse_args(
+                                argv + ['--foreground',
+                                        '--unmount-timeout=2',
+                                        self.mnt])) as self.mount:
+                        return func(self, *args, **kwargs)
+                finally:
+                    if self.mount and self.mount.llfuse_thread.is_alive():
+                        logging.warning("IntegrationTest.mount:"
+                                            " llfuse thread still alive after umount"
+                                            " -- killing test suite to avoid deadlock")
+                        os.kill(os.getpid(), signal.SIGKILL)
             return wrapper
         return decorator