Charmed-Kubernetes/nrpe/mod/charmhelpers/tests/tools/test_charm_helper_sync.py

305 lines
12 KiB
Python

import unittest
from mock import call, patch
import yaml
import tools.charm_helpers_sync.charm_helpers_sync as sync
import six
if not six.PY3:
builtin_open = '__builtin__.open'
else:
builtin_open = 'builtins.open'
INCLUDE = """
include:
- core
- contrib.openstack
- contrib.storage
- contrib.hahelpers:
- utils
- ceph_utils
- cluster_utils
- haproxy_utils
"""
class HelperSyncTests(unittest.TestCase):
def test_clone_helpers(self):
'''It properly branches the correct helpers branch'''
with patch('subprocess.check_call') as check_call:
sync.clone_helpers(work_dir='/tmp/foo', repo='git:charm-helpers')
check_call.assert_called_with(['git',
'clone', '--depth=1',
'git:charm-helpers',
'/tmp/foo/charm-helpers'])
def test_module_path(self):
'''It converts a python module path to a filesystem path'''
self.assertEquals(sync._module_path('some.test.module'),
'some/test/module')
def test_src_path(self):
'''It renders the correct path to module within charm-helpers tree'''
path = sync._src_path(src='/tmp/charm-helpers',
module='contrib.openstack')
self.assertEquals('/tmp/charm-helpers/charmhelpers/contrib/openstack',
path)
def test_dest_path(self):
'''It correctly finds the correct install path within a charm'''
path = sync._dest_path(dest='/tmp/mycharm/hooks/charmhelpers',
module='contrib.openstack')
self.assertEquals('/tmp/mycharm/hooks/charmhelpers/contrib/openstack',
path)
@patch(builtin_open)
@patch('os.path.exists')
@patch('os.walk')
def test_ensure_init(self, walk, exists, _open):
'''It ensures all subdirectories of a parent are python importable'''
# os walk
# os.path.join
# os.path.exists
# open
def _walk(path):
yield ('/tmp/hooks/', ['helpers'], [])
yield ('/tmp/hooks/helpers', ['foo'], [])
yield ('/tmp/hooks/helpers/foo', [], [])
walk.side_effect = _walk
exists.return_value = False
sync.ensure_init('hooks/helpers/foo/')
ex = [call('/tmp/hooks/__init__.py', 'wb'),
call('/tmp/hooks/helpers/__init__.py', 'wb'),
call('/tmp/hooks/helpers/foo/__init__.py', 'wb')]
for c in ex:
self.assertIn(c, _open.call_args_list)
@patch('tools.charm_helpers_sync.charm_helpers_sync.ensure_init')
@patch('os.path.isfile')
@patch('shutil.copy')
@patch('os.makedirs')
@patch('os.path.exists')
def test_sync_pyfile(self, exists, mkdirs, copy, isfile, ensure_init):
'''It correctly syncs a py src file from src to dest'''
exists.return_value = False
isfile.return_value = True
sync.sync_pyfile('/tmp/charm-helpers/core/host',
'hooks/charmhelpers/core')
mkdirs.assert_called_with('hooks/charmhelpers/core')
copy_f = call('/tmp/charm-helpers/core/host.py',
'hooks/charmhelpers/core')
copy_i = call('/tmp/charm-helpers/core/__init__.py',
'hooks/charmhelpers/core')
self.assertIn(copy_f, copy.call_args_list)
self.assertIn(copy_i, copy.call_args_list)
ensure_init.assert_called_with('hooks/charmhelpers/core')
def _test_filter_dir(self, opts, isfile, isdir):
'''It filters non-python files and non-module dirs from source'''
files = {
'bad_file.bin': 'f',
'some_dir': 'd',
'good_helper.py': 'f',
'good_helper2.py': 'f',
'good_helper3.py': 'f',
'bad_file.img': 'f',
}
def _isfile(f):
try:
return files[f.split('/').pop()] == 'f'
except KeyError:
return False
def _isdir(f):
try:
return files[f.split('/').pop()] == 'd'
except KeyError:
return False
isfile.side_effect = _isfile
isdir.side_effect = _isdir
result = sync.get_filter(opts)(dir='/tmp/charm-helpers/core',
ls=six.iterkeys(files))
return result
@patch('os.path.isdir')
@patch('os.path.isfile')
def test_filter_dir_no_opts(self, isfile, isdir):
'''It filters out all non-py files by default'''
result = self._test_filter_dir(opts=None, isfile=isfile, isdir=isdir)
ex = ['bad_file.bin', 'bad_file.img', 'some_dir']
self.assertEquals(sorted(ex), sorted(result))
@patch('os.path.isdir')
@patch('os.path.isfile')
def test_filter_dir_with_include(self, isfile, isdir):
'''It includes non-py files if specified as an include opt'''
result = sorted(self._test_filter_dir(opts=['inc=*.img'],
isfile=isfile, isdir=isdir))
ex = sorted(['bad_file.bin', 'some_dir'])
self.assertEquals(ex, result)
@patch('os.path.isdir')
@patch('os.path.isfile')
def test_filter_dir_include_all(self, isfile, isdir):
'''It does not filter anything if option specified to include all'''
self.assertEquals(sync.get_filter(opts=['inc=*']), None)
@patch('tools.charm_helpers_sync.charm_helpers_sync.get_filter')
@patch('tools.charm_helpers_sync.charm_helpers_sync.ensure_init')
@patch('shutil.copytree')
@patch('shutil.rmtree')
@patch('os.path.exists')
def test_sync_directory(self, exists, rmtree, copytree, ensure_init,
_filter):
'''It correctly syncs src directory to dest directory'''
_filter.return_value = None
sync.sync_directory('/tmp/charm-helpers/charmhelpers/core',
'hooks/charmhelpers/core')
exists.return_value = True
rmtree.assert_called_with('hooks/charmhelpers/core')
copytree.assert_called_with('/tmp/charm-helpers/charmhelpers/core',
'hooks/charmhelpers/core', ignore=None)
ensure_init.assert_called_with('hooks/charmhelpers/core')
@patch('os.path.isfile')
def test_is_pyfile(self, isfile):
'''It correctly identifies incomplete path to a py src file as such'''
sync._is_pyfile('/tmp/charm-helpers/charmhelpers/core/host')
isfile.assert_called_with(
'/tmp/charm-helpers/charmhelpers/core/host.py'
)
@patch('tools.charm_helpers_sync.charm_helpers_sync.sync_pyfile')
@patch('tools.charm_helpers_sync.charm_helpers_sync.sync_directory')
@patch('os.path.isdir')
def test_syncs_directory(self, is_dir, sync_dir, sync_pyfile):
'''It correctly syncs a module directory'''
is_dir.return_value = True
sync.sync(src='/tmp/charm-helpers',
dest='hooks/charmhelpers',
module='contrib.openstack')
sync_dir.assert_called_with(
'/tmp/charm-helpers/charmhelpers/contrib/openstack',
'hooks/charmhelpers/contrib/openstack', None)
# __init__.py files leading to the directory were also synced.
sync_pyfile.assert_has_calls([
call('/tmp/charm-helpers/charmhelpers/__init__',
'hooks/charmhelpers'),
call('/tmp/charm-helpers/charmhelpers/contrib/__init__',
'hooks/charmhelpers/contrib')])
@patch('tools.charm_helpers_sync.charm_helpers_sync.sync_pyfile')
@patch('tools.charm_helpers_sync.charm_helpers_sync._is_pyfile')
@patch('os.path.isdir')
def test_syncs_file(self, is_dir, is_pyfile, sync_pyfile):
'''It correctly syncs a module file'''
is_dir.return_value = False
is_pyfile.return_value = True
sync.sync(src='/tmp/charm-helpers',
dest='hooks/charmhelpers',
module='contrib.openstack.utils')
sync_pyfile.assert_has_calls([
call('/tmp/charm-helpers/charmhelpers/__init__',
'hooks/charmhelpers'),
call('/tmp/charm-helpers/charmhelpers/contrib/__init__',
'hooks/charmhelpers/contrib'),
call('/tmp/charm-helpers/charmhelpers/contrib/openstack/__init__',
'hooks/charmhelpers/contrib/openstack'),
call('/tmp/charm-helpers/charmhelpers/contrib/openstack/utils',
'hooks/charmhelpers/contrib/openstack')])
@patch('tools.charm_helpers_sync.charm_helpers_sync.sync')
@patch('os.path.isdir')
@patch('os.path.exists')
def test_sync_helpers_from_config(self, exists, isdir, _sync):
'''It correctly syncs a list of included helpers'''
include = yaml.safe_load(INCLUDE)['include']
isdir.return_value = True
exists.return_value = False
sync.sync_helpers(include=include,
src='/tmp/charm-helpers',
dest='hooks/charmhelpers')
mods = [
'core',
'contrib.openstack',
'contrib.storage',
'contrib.hahelpers.utils',
'contrib.hahelpers.ceph_utils',
'contrib.hahelpers.cluster_utils',
'contrib.hahelpers.haproxy_utils'
]
ex_calls = []
[ex_calls.append(
call('/tmp/charm-helpers', 'hooks/charmhelpers', c, [])
) for c in mods]
self.assertEquals(ex_calls, _sync.call_args_list)
@patch('tools.charm_helpers_sync.charm_helpers_sync.sync')
@patch('os.path.isdir')
@patch('os.path.exists')
@patch('shutil.rmtree')
def test_sync_helpers_from_config_cleanup(self, _rmtree, _exists,
isdir, _sync):
'''It correctly syncs a list of included helpers'''
include = yaml.safe_load(INCLUDE)['include']
isdir.return_value = True
_exists.return_value = True
sync.sync_helpers(include=include,
src='/tmp/charm-helpers',
dest='hooks/charmhelpers')
_rmtree.assert_called_with('hooks/charmhelpers')
mods = [
'core',
'contrib.openstack',
'contrib.storage',
'contrib.hahelpers.utils',
'contrib.hahelpers.ceph_utils',
'contrib.hahelpers.cluster_utils',
'contrib.hahelpers.haproxy_utils'
]
ex_calls = []
[ex_calls.append(
call('/tmp/charm-helpers', 'hooks/charmhelpers', c, [])
) for c in mods]
self.assertEquals(ex_calls, _sync.call_args_list)
def test_extract_option_no_globals(self):
'''It extracts option from an included item with no global options'''
inc = 'contrib.openstack.templates|inc=*.template'
result = sync.extract_options(inc)
ex = ('contrib.openstack.templates', ['inc=*.template'])
self.assertEquals(ex, result)
def test_extract_option_with_global_as_string(self):
'''It extracts option for include with global options as str'''
inc = 'contrib.openstack.templates|inc=*.template'
result = sync.extract_options(inc, global_options='inc=foo.*')
ex = ('contrib.openstack.templates',
['inc=*.template', 'inc=foo.*'])
self.assertEquals(ex, result)
def test_extract_option_with_globals(self):
'''It extracts option from an included item with global options'''
inc = 'contrib.openstack.templates|inc=*.template'
result = sync.extract_options(inc, global_options=['inc=*.cfg'])
ex = ('contrib.openstack.templates', ['inc=*.template', 'inc=*.cfg'])
self.assertEquals(ex, result)
def test_extract_multiple_options_with_globals(self):
'''It extracts multiple options from an included item'''
inc = 'contrib.openstack.templates|inc=*.template,inc=foo.*'
result = sync.extract_options(inc, global_options=['inc=*.cfg'])
ex = ('contrib.openstack.templates',
['inc=*.template', 'inc=foo.*', 'inc=*.cfg'])
self.assertEquals(ex, result)