Add unit tests, tidylint
This commit is contained in:
parent
3d154836aa
commit
7a3b026509
|
@ -0,0 +1,6 @@
|
|||
[report]
|
||||
# Regexes for lines to exclude from consideration
|
||||
exclude_lines =
|
||||
if __name__ == .__main__.:
|
||||
include=
|
||||
hooks/ceilometer_*
|
|
@ -2,6 +2,7 @@
|
|||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
<path>/ceilometer/hooks</path>
|
||||
<path>/ceilometer/unit_tests</path>
|
||||
</pydev_pathproperty>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
|
|
1
Makefile
1
Makefile
|
@ -2,6 +2,7 @@
|
|||
|
||||
lint:
|
||||
@flake8 --exclude hooks/charmhelpers hooks
|
||||
@flake8 unit_tests
|
||||
@charm proof
|
||||
|
||||
sync:
|
||||
|
|
|
@ -60,3 +60,15 @@ class CeilometerContext(OSContextGenerator):
|
|||
'metering_secret': get_shared_secret()
|
||||
}
|
||||
return ctxt
|
||||
|
||||
|
||||
class CeilometerServiceContext(OSContextGenerator):
|
||||
interfaces = ['ceilometer-service']
|
||||
|
||||
def __call__(self):
|
||||
for relid in relation_ids('ceilometer-service'):
|
||||
for unit in related_units(relid):
|
||||
conf = relation_get(unit=unit, rid=relid)
|
||||
if context_complete(conf):
|
||||
return conf
|
||||
return {}
|
||||
|
|
|
@ -61,7 +61,7 @@ def register_configs():
|
|||
# just default to earliest supported release. configs dont get touched
|
||||
# till post-install, anyway.
|
||||
release = get_os_codename_package('ceilometer-common', fatal=False) \
|
||||
or 'grizzly'
|
||||
or 'grizzly'
|
||||
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
|
||||
openstack_release=release)
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
[nosetests]
|
||||
verbosity=1
|
||||
with-coverage=1
|
||||
cover-erase=1
|
||||
cover-package=hooks
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import sys
|
||||
sys.path.append('hooks')
|
|
@ -0,0 +1,89 @@
|
|||
from mock import patch
|
||||
|
||||
import ceilometer_contexts as contexts
|
||||
|
||||
from test_utils import CharmTestCase, mock_open
|
||||
|
||||
TO_PATCH = [
|
||||
'relation_get',
|
||||
'relation_ids',
|
||||
'related_units',
|
||||
'config'
|
||||
]
|
||||
|
||||
|
||||
class CeilometerContextsTest(CharmTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CeilometerContextsTest, self).setUp(contexts, TO_PATCH)
|
||||
self.config.side_effect = self.test_config.get
|
||||
self.relation_get.side_effect = self.test_relation.get
|
||||
|
||||
def tearDown(self):
|
||||
super(CeilometerContextsTest, self).tearDown()
|
||||
|
||||
def test_logging_context(self):
|
||||
self.test_config.set('debug', False)
|
||||
self.test_config.set('verbose', False)
|
||||
self.assertEquals(contexts.LoggingConfigContext()(),
|
||||
{'debug': False, 'verbose': False})
|
||||
self.test_config.set('debug', True)
|
||||
self.test_config.set('verbose', False)
|
||||
self.assertEquals(contexts.LoggingConfigContext()(),
|
||||
{'debug': True, 'verbose': False})
|
||||
self.test_config.set('debug', True)
|
||||
self.test_config.set('verbose', True)
|
||||
self.assertEquals(contexts.LoggingConfigContext()(),
|
||||
{'debug': True, 'verbose': True})
|
||||
|
||||
def test_mongodb_context_not_related(self):
|
||||
self.relation_ids.return_value = []
|
||||
self.assertEquals(contexts.MongoDBContext()(), {})
|
||||
|
||||
def test_mongodb_context_related(self):
|
||||
self.relation_ids.return_value = ['shared-db:0']
|
||||
self.related_units.return_value = ['mongodb/0']
|
||||
data = {
|
||||
'hostname': 'mongodb',
|
||||
'port': 8090
|
||||
}
|
||||
self.test_relation.set(data)
|
||||
self.assertEquals(contexts.MongoDBContext()(),
|
||||
{'db_host': 'mongodb', 'db_port': 8090,
|
||||
'db_name': 'ceilometer'})
|
||||
|
||||
@patch.object(contexts, 'get_shared_secret')
|
||||
def test_ceilometer_context(self, secret):
|
||||
secret.return_value = 'mysecret'
|
||||
self.assertEquals(contexts.CeilometerContext()(),
|
||||
{'port': 8777, 'metering_secret': 'mysecret'})
|
||||
|
||||
def test_ceilometer_service_context(self):
|
||||
self.relation_ids.return_value = ['ceilometer-service:0']
|
||||
self.related_units.return_value = ['ceilometer/0']
|
||||
data = {
|
||||
'metering_secret': 'mysecret',
|
||||
'keystone_host': 'test'
|
||||
}
|
||||
self.test_relation.set(data)
|
||||
self.assertEquals(contexts.CeilometerServiceContext()(), data)
|
||||
|
||||
def test_ceilometer_service_context_not_related(self):
|
||||
self.relation_ids.return_value = []
|
||||
self.assertEquals(contexts.CeilometerServiceContext()(), {})
|
||||
|
||||
@patch('os.path.exists')
|
||||
def test_get_shared_secret_existing(self, exists):
|
||||
exists.return_value = True
|
||||
with mock_open(contexts.SHARED_SECRET, u'mysecret'):
|
||||
self.assertEquals(contexts.get_shared_secret(),
|
||||
'mysecret')
|
||||
|
||||
@patch('uuid.uuid4')
|
||||
@patch('os.path.exists')
|
||||
def test_get_shared_secret_new(self, exists, uuid4):
|
||||
exists.return_value = False
|
||||
uuid4.return_value = 'newsecret'
|
||||
with patch('__builtin__.open'):
|
||||
self.assertEquals(contexts.get_shared_secret(),
|
||||
'newsecret')
|
|
@ -0,0 +1,99 @@
|
|||
from mock import patch, MagicMock
|
||||
|
||||
import ceilometer_utils
|
||||
# Patch out register_configs for import of hooks
|
||||
_register_configs = ceilometer_utils.register_configs
|
||||
ceilometer_utils.register_configs = MagicMock()
|
||||
|
||||
import ceilometer_hooks as hooks
|
||||
|
||||
# Renable old function
|
||||
ceilometer_utils.register_configs = _register_configs
|
||||
|
||||
from test_utils import CharmTestCase
|
||||
|
||||
TO_PATCH = [
|
||||
'relation_set',
|
||||
'configure_installation_source',
|
||||
'apt_install',
|
||||
'apt_update',
|
||||
'open_port',
|
||||
'config',
|
||||
'log',
|
||||
'relation_ids',
|
||||
'filter_installed_packages',
|
||||
'CONFIGS',
|
||||
'unit_get',
|
||||
'get_ceilometer_context'
|
||||
]
|
||||
|
||||
|
||||
class CeilometerHooksTest(CharmTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CeilometerHooksTest, self).setUp(hooks, TO_PATCH)
|
||||
self.config.side_effect = self.test_config.get
|
||||
|
||||
def test_configure_source(self):
|
||||
self.test_config.set('openstack-origin', 'cloud:precise-havana')
|
||||
hooks.hooks.execute(['hooks/install'])
|
||||
self.configure_installation_source.\
|
||||
assert_called_with('cloud:precise-havana')
|
||||
|
||||
def test_install_hook(self):
|
||||
self.filter_installed_packages.return_value = hooks.CEILOMETER_PACKAGES
|
||||
hooks.hooks.execute(['hooks/install'])
|
||||
self.assertTrue(self.configure_installation_source.called)
|
||||
self.open_port.assert_called_with(hooks.CEILOMETER_PORT)
|
||||
self.apt_update.assert_called_with(fatal=True)
|
||||
self.apt_install.assert_called_with(hooks.CEILOMETER_PACKAGES,
|
||||
fatal=True)
|
||||
|
||||
def test_amqp_joined(self):
|
||||
hooks.hooks.execute(['hooks/amqp-relation-joined'])
|
||||
self.relation_set.assert_called_with(
|
||||
username=self.test_config.get('rabbit-user'),
|
||||
vhost=self.test_config.get('rabbit-vhost'))
|
||||
|
||||
def test_db_joined(self):
|
||||
hooks.hooks.execute(['hooks/shared-db-relation-joined'])
|
||||
self.relation_set.assert_called_with(
|
||||
ceilometer_database='ceilometer')
|
||||
|
||||
@patch.object(hooks, 'ceilometer_joined')
|
||||
def test_any_changed(self, joined):
|
||||
hooks.hooks.execute(['hooks/shared-db-relation-changed'])
|
||||
self.assertTrue(self.CONFIGS.write_all.called)
|
||||
self.assertTrue(joined.called)
|
||||
|
||||
@patch.object(hooks, 'install')
|
||||
@patch.object(hooks, 'any_changed')
|
||||
def test_upgrade_charm(self, changed, install):
|
||||
hooks.hooks.execute(['hooks/upgrade-charm'])
|
||||
self.assertTrue(changed.called)
|
||||
self.assertTrue(install.called)
|
||||
|
||||
@patch.object(hooks, 'install')
|
||||
@patch.object(hooks, 'any_changed')
|
||||
def test_config_changed(self, changed, install):
|
||||
hooks.hooks.execute(['hooks/config-changed'])
|
||||
self.assertTrue(changed.called)
|
||||
self.assertTrue(install.called)
|
||||
|
||||
def test_keystone_joined(self):
|
||||
self.unit_get.return_value = 'thishost'
|
||||
self.test_config.set('region', 'myregion')
|
||||
hooks.hooks.execute(['hooks/identity-service-relation-joined'])
|
||||
url = "http://{}:{}".format('thishost', hooks.CEILOMETER_PORT)
|
||||
self.relation_set.assert_called_with(
|
||||
service=hooks.CEILOMETER_SERVICE,
|
||||
public_url=url, admin_url=url, internal_url=url,
|
||||
requested_roles=hooks.CEILOMETER_ROLE,
|
||||
region='myregion')
|
||||
|
||||
def test_ceilometer_joined(self):
|
||||
self.relation_ids.return_value = ['ceilometer:0']
|
||||
self.get_ceilometer_context.return_value = {'test': 'data'}
|
||||
hooks.hooks.execute(['hooks/ceilometer-service-relation-joined'])
|
||||
self.relation_set.assert_called_with('ceilometer:0',
|
||||
{'test': 'data'})
|
|
@ -0,0 +1,49 @@
|
|||
from mock import patch, call
|
||||
|
||||
import ceilometer_utils as utils
|
||||
|
||||
from test_utils import CharmTestCase
|
||||
|
||||
TO_PATCH = [
|
||||
'get_os_codename_package',
|
||||
'templating',
|
||||
'LoggingConfigContext',
|
||||
'MongoDBContext',
|
||||
'CeilometerContext',
|
||||
]
|
||||
|
||||
|
||||
class CeilometerUtilsTest(CharmTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CeilometerUtilsTest, self).setUp(utils, TO_PATCH)
|
||||
|
||||
def tearDown(self):
|
||||
super(CeilometerUtilsTest, self).tearDown()
|
||||
|
||||
def test_register_configs(self):
|
||||
configs = utils.register_configs()
|
||||
calls = []
|
||||
for conf in utils.CONFIG_FILES:
|
||||
calls.append(call(conf,
|
||||
utils.CONFIG_FILES[conf]['hook_contexts']))
|
||||
configs.register.assert_has_calls(calls, any_order=True)
|
||||
|
||||
def test_restart_map(self):
|
||||
restart_map = utils.restart_map()
|
||||
self.assertEquals(restart_map,
|
||||
{'/etc/ceilometer/ceilometer.conf': [
|
||||
'ceilometer-agent-central',
|
||||
'ceilometer-collector',
|
||||
'ceilometer-api']})
|
||||
|
||||
def test_get_ceilometer_conf(self):
|
||||
class TestContext():
|
||||
def __call__(self):
|
||||
return {'data': 'test'}
|
||||
with patch.dict(utils.CONFIG_FILES,
|
||||
{'/etc/ceilometer/ceilometer.conf': {
|
||||
'hook_contexts': [TestContext()]
|
||||
}}):
|
||||
self.assertTrue(utils.get_ceilometer_context(),
|
||||
{'data': 'test'})
|
|
@ -0,0 +1,111 @@
|
|||
import logging
|
||||
import unittest
|
||||
import os
|
||||
import yaml
|
||||
import io
|
||||
|
||||
from contextlib import contextmanager
|
||||
from mock import patch
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mock_open(filename, contents=None):
|
||||
''' Slightly simpler mock of open to return contents for filename '''
|
||||
def mock_file(*args):
|
||||
if args[0] == filename:
|
||||
return io.StringIO(contents)
|
||||
else:
|
||||
return open(*args)
|
||||
with patch('__builtin__.open', mock_file):
|
||||
yield
|
||||
|
||||
|
||||
def load_config():
|
||||
'''
|
||||
Walk backwords from __file__ looking for config.yaml, load and return the
|
||||
'options' section'
|
||||
'''
|
||||
config = None
|
||||
f = __file__
|
||||
while config is None:
|
||||
d = os.path.dirname(f)
|
||||
if os.path.isfile(os.path.join(d, 'config.yaml')):
|
||||
config = os.path.join(d, 'config.yaml')
|
||||
break
|
||||
f = d
|
||||
|
||||
if not config:
|
||||
logging.error('Could not find config.yaml in any parent directory '
|
||||
'of %s. ' % file)
|
||||
raise Exception
|
||||
|
||||
return yaml.safe_load(open(config).read())['options']
|
||||
|
||||
|
||||
def get_default_config():
|
||||
'''
|
||||
Load default charm config from config.yaml return as a dict.
|
||||
If no default is set in config.yaml, its value is None.
|
||||
'''
|
||||
default_config = {}
|
||||
config = load_config()
|
||||
for k, v in config.iteritems():
|
||||
if 'default' in v:
|
||||
default_config[k] = v['default']
|
||||
else:
|
||||
default_config[k] = None
|
||||
return default_config
|
||||
|
||||
|
||||
class CharmTestCase(unittest.TestCase):
|
||||
def setUp(self, obj, patches):
|
||||
super(CharmTestCase, self).setUp()
|
||||
self.patches = patches
|
||||
self.obj = obj
|
||||
self.test_config = TestConfig()
|
||||
self.test_relation = TestRelation()
|
||||
self.patch_all()
|
||||
|
||||
def patch(self, method):
|
||||
_m = patch.object(self.obj, method)
|
||||
mock = _m.start()
|
||||
self.addCleanup(_m.stop)
|
||||
return mock
|
||||
|
||||
def patch_all(self):
|
||||
for method in self.patches:
|
||||
setattr(self, method, self.patch(method))
|
||||
|
||||
|
||||
class TestConfig(object):
|
||||
def __init__(self):
|
||||
self.config = get_default_config()
|
||||
|
||||
def get(self, attr):
|
||||
try:
|
||||
return self.config[attr]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def get_all(self):
|
||||
return self.config
|
||||
|
||||
def set(self, attr, value):
|
||||
if attr not in self.config:
|
||||
raise KeyError
|
||||
self.config[attr] = value
|
||||
|
||||
|
||||
class TestRelation(object):
|
||||
def __init__(self, relation_data={}):
|
||||
self.relation_data = relation_data
|
||||
|
||||
def set(self, relation_data):
|
||||
self.relation_data = relation_data
|
||||
|
||||
def get(self, attr=None, unit=None, rid=None):
|
||||
if attr is None:
|
||||
return self.relation_data
|
||||
elif attr in self.relation_data:
|
||||
return self.relation_data[attr]
|
||||
return None
|
Loading…
Reference in New Issue