cubicweb/test/unittest_cwconfig.py
changeset 11899 bf6106b91633
parent 11744 a6dc650bc230
child 11900 8496135b6dc1
equal deleted inserted replaced
11898:c5d3382f14e9 11899:bf6106b91633
    15 #
    15 #
    16 # You should have received a copy of the GNU Lesser General Public License along
    16 # You should have received a copy of the GNU Lesser General Public License along
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    18 """cubicweb.cwconfig unit tests"""
    18 """cubicweb.cwconfig unit tests"""
    19 
    19 
       
    20 import contextlib
       
    21 import compileall
       
    22 import functools
    20 import sys
    23 import sys
    21 import os
    24 import os
       
    25 import pkgutil
    22 from os.path import dirname, join, abspath
    26 from os.path import dirname, join, abspath
    23 from pkg_resources import EntryPoint, Distribution
    27 from pkg_resources import EntryPoint, Distribution
    24 import unittest
    28 import unittest
    25 
    29 
    26 from mock import patch
    30 from mock import patch
    29 from logilab.common.modutils import cleanup_sys_modules
    33 from logilab.common.modutils import cleanup_sys_modules
    30 from logilab.common.changelog import Version
    34 from logilab.common.changelog import Version
    31 
    35 
    32 from cubicweb.devtools import ApptestConfiguration
    36 from cubicweb.devtools import ApptestConfiguration
    33 from cubicweb.devtools.testlib import BaseTestCase, TemporaryDirectory
    37 from cubicweb.devtools.testlib import BaseTestCase, TemporaryDirectory
    34 from cubicweb.cwconfig import _find_prefix
    38 from cubicweb.cwconfig import (
       
    39     CubicWebConfiguration, _find_prefix, _expand_modname)
    35 
    40 
    36 
    41 
    37 def unabsolutize(path):
    42 def unabsolutize(path):
    38     parts = path.split(os.sep)
    43     parts = path.split(os.sep)
    39     for i, part in reversed(tuple(enumerate(parts))):
    44     for i, part in reversed(tuple(enumerate(parts))):
    40         if part.startswith('cubicweb_'):
    45         if part.startswith('cubicweb_'):
    41             return os.sep.join([part[len('cubicweb_'):]] + parts[i+1:])
    46             return os.sep.join([part[len('cubicweb_'):]] + parts[i+1:])
    42         if part.startswith('cubicweb') or part == 'legacy_cubes':
    47         if part.startswith('cubicweb') or part == 'legacy_cubes':
    43             return os.sep.join(parts[i+1:])
    48             return os.sep.join(parts[i+1:])
    44     raise Exception('duh? %s' % path)
    49     raise Exception('duh? %s' % path)
       
    50 
       
    51 
       
    52 def templibdir(func):
       
    53     """create a temporary directory and insert it in sys.path"""
       
    54     @functools.wraps(func)
       
    55     def wrapper(*args, **kwargs):
       
    56         with TemporaryDirectory() as libdir:
       
    57             sys.path.insert(0, libdir)
       
    58             try:
       
    59                 args = args + (libdir,)
       
    60                 return func(*args, **kwargs)
       
    61             finally:
       
    62                 sys.path.remove(libdir)
       
    63     return wrapper
       
    64 
       
    65 
       
    66 def create_filepath(filepath):
       
    67     filedir = dirname(filepath)
       
    68     if not os.path.exists(filedir):
       
    69         os.makedirs(filedir)
       
    70     with open(filepath, 'a'):
       
    71         pass
       
    72 
       
    73 
       
    74 @contextlib.contextmanager
       
    75 def temp_config(appid, instance_dir, cubes_dir, cubes):
       
    76     """context manager that create a config object with specified appid,
       
    77     instance_dir, cubes_dir and cubes"""
       
    78     cls = CubicWebConfiguration
       
    79     old = (cls._INSTANCES_DIR, cls.CUBES_DIR, cls.CUBES_PATH,
       
    80            sys.path[:], sys.meta_path[:])
       
    81     old_modules = set(sys.modules)
       
    82     try:
       
    83         cls._INSTANCES_DIR, cls.CUBES_DIR, cls.CUBES_PATH = (
       
    84             instance_dir, cubes_dir, [])
       
    85         config = cls(appid)
       
    86         config._cubes = cubes
       
    87         config.adjust_sys_path()
       
    88         yield config
       
    89     finally:
       
    90         (cls._INSTANCES_DIR, cls.CUBES_DIR, cls.CUBES_PATH,
       
    91          sys.path[:], sys.meta_path[:]) = old
       
    92         for module in set(sys.modules) - old_modules:
       
    93             del sys.modules[module]
    45 
    94 
    46 
    95 
    47 class CubicWebConfigurationTC(BaseTestCase):
    96 class CubicWebConfigurationTC(BaseTestCase):
    48 
    97 
    49     @classmethod
    98     @classmethod
   311         finally:
   360         finally:
   312             if venv:
   361             if venv:
   313                 os.environ['VIRTUAL_ENV'] = venv
   362                 os.environ['VIRTUAL_ENV'] = venv
   314 
   363 
   315 
   364 
       
   365 class ModnamesTC(unittest.TestCase):
       
   366 
       
   367     @templibdir
       
   368     def test_expand_modnames(self, libdir):
       
   369         tempdir = join(libdir, 'lib')
       
   370         filepaths = [
       
   371             join(tempdir, '__init__.py'),
       
   372             join(tempdir, 'a.py'),
       
   373             join(tempdir, 'b.py'),
       
   374             join(tempdir, 'c.py'),
       
   375             join(tempdir, 'b', '__init__.py'),
       
   376             join(tempdir, 'b', 'a.py'),
       
   377             join(tempdir, 'b', 'c.py'),
       
   378             join(tempdir, 'b', 'd', '__init__.py'),
       
   379             join(tempdir, 'e', 'e.py'),
       
   380         ]
       
   381         for filepath in filepaths:
       
   382             create_filepath(filepath)
       
   383         # not importable
       
   384         self.assertEqual(list(_expand_modname('isnotimportable')), [])
       
   385         # not a python package
       
   386         self.assertEqual(list(_expand_modname('lib.e')), [])
       
   387         self.assertEqual(list(_expand_modname('lib.a')), [
       
   388             ('lib.a', join(tempdir, 'a.py')),
       
   389         ])
       
   390         # lib.b.d (subpackage) not to be imported
       
   391         self.assertEqual(list(_expand_modname('lib.b')), [
       
   392             ('lib.b', join(tempdir, 'b', '__init__.py')),
       
   393             ('lib.b.a', join(tempdir, 'b', 'a.py')),
       
   394             ('lib.b.c', join(tempdir, 'b', 'c.py')),
       
   395         ])
       
   396         self.assertEqual(list(_expand_modname('lib')), [
       
   397             ('lib', join(tempdir, '__init__.py')),
       
   398             ('lib.a', join(tempdir, 'a.py')),
       
   399             ('lib.c', join(tempdir, 'c.py')),
       
   400         ])
       
   401         for source in (
       
   402             join(tempdir, 'c.py'),
       
   403             join(tempdir, 'b', 'c.py'),
       
   404         ):
       
   405             if not PY3:
       
   406                 # ensure pyc file exists.
       
   407                 # Doesn't required for PY3 since it create __pycache__
       
   408                 # directory and will not import if source file doesn't
       
   409                 # exists.
       
   410                 compileall.compile_file(source, force=True)
       
   411                 self.assertTrue(os.path.exists(source + 'c'))
       
   412             # remove source file
       
   413             os.remove(source)
       
   414         self.assertEqual(list(_expand_modname('lib.c')), [])
       
   415         self.assertEqual(list(_expand_modname('lib.b')), [
       
   416             ('lib.b', join(tempdir, 'b', '__init__.py')),
       
   417             ('lib.b.a', join(tempdir, 'b', 'a.py')),
       
   418         ])
       
   419         self.assertEqual(list(_expand_modname('lib')), [
       
   420             ('lib', join(tempdir, '__init__.py')),
       
   421             ('lib.a', join(tempdir, 'a.py')),
       
   422         ])
       
   423 
       
   424     @templibdir
       
   425     def test_schema_modnames(self, libdir):
       
   426         for filepath in (
       
   427             join(libdir, 'schema.py'),
       
   428             join(libdir, 'cubicweb_foo', '__init__.py'),
       
   429             join(libdir, 'cubicweb_foo', 'schema', '__init__.py'),
       
   430             join(libdir, 'cubicweb_foo', 'schema', 'a.py'),
       
   431             join(libdir, 'cubicweb_foo', 'schema', 'b.py'),
       
   432             join(libdir, 'cubes', '__init__.py'),
       
   433             join(libdir, 'cubes', 'bar', '__init__.py'),
       
   434             join(libdir, 'cubes', 'bar', 'schema.py'),
       
   435             join(libdir, '_instance_dir', 'data1', 'schema.py'),
       
   436             join(libdir, '_instance_dir', 'data2', 'noschema.py'),
       
   437         ):
       
   438             create_filepath(filepath)
       
   439         expected = [
       
   440             ('cubicweb', 'cubicweb.schemas.bootstrap'),
       
   441             ('cubicweb', 'cubicweb.schemas.base'),
       
   442             ('cubicweb', 'cubicweb.schemas.workflow'),
       
   443             ('cubicweb', 'cubicweb.schemas.Bookmark'),
       
   444             ('bar', 'cubes.bar.schema'),
       
   445             ('foo', 'cubes.foo.schema'),
       
   446             ('foo', 'cubes.foo.schema.a'),
       
   447             ('foo', 'cubes.foo.schema.b'),
       
   448         ]
       
   449         # app has schema file
       
   450         instance_dir, cubes_dir = (
       
   451             join(libdir, '_instance_dir'), join(libdir, 'cubes'))
       
   452         with temp_config('data1', instance_dir, cubes_dir,
       
   453                          ('foo', 'bar')) as config:
       
   454             self.assertEqual(pkgutil.find_loader('schema').get_filename(),
       
   455                              join(libdir, '_instance_dir',
       
   456                                   'data1', 'schema.py'))
       
   457             self.assertEqual(config.schema_modnames(),
       
   458                              expected + [('data', 'schema')])
       
   459         # app doesn't have schema file
       
   460         with temp_config('data2', instance_dir, cubes_dir,
       
   461                          ('foo', 'bar')) as config:
       
   462             self.assertEqual(pkgutil.find_loader('schema').get_filename(),
       
   463                              join(libdir, 'schema.py'))
       
   464             self.assertEqual(config.schema_modnames(), expected)
       
   465 
       
   466 
       
   467 
       
   468 
   316 if __name__ == '__main__':
   469 if __name__ == '__main__':
   317     unittest.main()
   470     unittest.main()