Lint tidyup and unit tests
This commit is contained in:
parent
55de68b794
commit
3c85d2249a
1
.bzrignore
Normal file
1
.bzrignore
Normal file
@ -0,0 +1 @@
|
||||
.coverage
|
14
Makefile
Normal file
14
Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/make
|
||||
PYTHON := /usr/bin/env python
|
||||
|
||||
lint:
|
||||
@flake8 --exclude hooks/charmhelpers hooks
|
||||
@flake8 --exclude hooks/charmhelpers unit_tests
|
||||
@charm proof
|
||||
|
||||
test:
|
||||
@echo Starting tests...
|
||||
@$(PYTHON) /usr/bin/nosetests --nologcapture unit_tests
|
||||
|
||||
sync:
|
||||
@charm-helper-sync -c charm-helpers-sync.yaml
|
10
charm-helpers-sync.yaml
Normal file
10
charm-helpers-sync.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
branch: lp:charm-helpers
|
||||
destination: hooks/charmhelpers
|
||||
include:
|
||||
- core
|
||||
- fetch
|
||||
- contrib.openstack
|
||||
- contrib.hahelpers
|
||||
- contrib.network.ovs
|
||||
- contrib.storage.linux
|
||||
- payload.execd
|
@ -1,9 +1,9 @@
|
||||
from charmhelpers.core.hookenv import (
|
||||
relation_ids,
|
||||
related_units,
|
||||
relation_get,
|
||||
config,
|
||||
unit_get,
|
||||
relation_ids,
|
||||
related_units,
|
||||
relation_get,
|
||||
config,
|
||||
unit_get,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.openstack import context
|
||||
@ -12,6 +12,7 @@ from charmhelpers.contrib.network.ovs import add_bridge
|
||||
from charmhelpers.contrib.openstack.utils import get_host_ip
|
||||
OVS_BRIDGE = 'br-int'
|
||||
|
||||
|
||||
def _neutron_security_groups():
|
||||
'''
|
||||
Inspects current neutron-plugin relation and determine if nova-c-c has
|
||||
@ -19,11 +20,14 @@ def _neutron_security_groups():
|
||||
'''
|
||||
for rid in relation_ids('neutron-plugin-api'):
|
||||
for unit in related_units(rid):
|
||||
sec_group=relation_get('neutron_security_groups',rid=rid, unit=unit)
|
||||
sec_group = relation_get('neutron_security_groups',
|
||||
rid=rid,
|
||||
unit=unit)
|
||||
if sec_group is not None:
|
||||
return sec_group
|
||||
return False
|
||||
|
||||
|
||||
class OVSPluginContext(context.NeutronContext):
|
||||
interfaces = []
|
||||
|
||||
|
@ -34,6 +34,7 @@ def install():
|
||||
apt_update()
|
||||
apt_install(determine_packages(), fatal=True)
|
||||
|
||||
|
||||
@hooks.hook('upgrade-charm')
|
||||
@hooks.hook('neutron-plugin-relation-changed')
|
||||
@hooks.hook('config-changed')
|
||||
@ -41,6 +42,7 @@ def install():
|
||||
def config_changed():
|
||||
CONFIGS.write_all()
|
||||
|
||||
|
||||
@hooks.hook('amqp-relation-joined')
|
||||
def amqp_joined(relation_id=None):
|
||||
relation_set(relation_id=relation_id,
|
||||
@ -57,6 +59,7 @@ def amqp_changed():
|
||||
return
|
||||
CONFIGS.write(NEUTRON_CONF)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
hooks.execute(sys.argv)
|
||||
|
@ -4,10 +4,9 @@ from copy import deepcopy
|
||||
from charmhelpers.contrib.openstack import context, templating
|
||||
from collections import OrderedDict
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
os_release,
|
||||
os_release,
|
||||
)
|
||||
import neutron_ovs_context
|
||||
from charmhelpers.core.hookenv import is_relation_made
|
||||
|
||||
NOVA_CONF_DIR = "/etc/nova"
|
||||
NEUTRON_CONF_DIR = "/etc/neutron"
|
||||
@ -28,6 +27,7 @@ BASE_RESOURCE_MAP = OrderedDict([
|
||||
])
|
||||
TEMPLATES = 'templates/'
|
||||
|
||||
|
||||
def determine_packages():
|
||||
ovs_pkgs = []
|
||||
pkgs = neutron_plugin_attribute('ovs', 'packages',
|
||||
@ -37,6 +37,7 @@ def determine_packages():
|
||||
|
||||
return set(ovs_pkgs)
|
||||
|
||||
|
||||
def register_configs(release=None):
|
||||
release = release or os_release('nova-common')
|
||||
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
|
||||
@ -45,6 +46,7 @@ def register_configs(release=None):
|
||||
configs.register(cfg, rscs['contexts'])
|
||||
return configs
|
||||
|
||||
|
||||
def resource_map():
|
||||
'''
|
||||
Dynamically generate a map of resources that will be managed for a single
|
||||
@ -53,6 +55,7 @@ def resource_map():
|
||||
resource_map = deepcopy(BASE_RESOURCE_MAP)
|
||||
return resource_map
|
||||
|
||||
|
||||
def restart_map():
|
||||
'''
|
||||
Constructs a restart map based on charm config settings and relation
|
||||
|
2
unit_tests/__init__.py
Normal file
2
unit_tests/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
import sys
|
||||
sys.path.append('hooks/')
|
71
unit_tests/test_neutron_ovs_context.py
Normal file
71
unit_tests/test_neutron_ovs_context.py
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
from test_utils import CharmTestCase
|
||||
from mock import patch
|
||||
import neutron_ovs_context as context
|
||||
import charmhelpers
|
||||
TO_PATCH = [
|
||||
'relation_get',
|
||||
'relation_ids',
|
||||
'related_units',
|
||||
'config',
|
||||
'unit_get',
|
||||
'add_bridge',
|
||||
'service_running',
|
||||
'service_start',
|
||||
'get_host_ip',
|
||||
]
|
||||
|
||||
|
||||
class OVSPluginContextTest(CharmTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(OVSPluginContextTest, self).setUp(context, TO_PATCH)
|
||||
self.relation_get.side_effect = self.test_relation.get
|
||||
self.config.side_effect = self.test_config.get
|
||||
self.test_config.set('debug', True)
|
||||
self.test_config.set('verbose', True)
|
||||
self.test_config.set('use-syslog', True)
|
||||
|
||||
def tearDown(self):
|
||||
super(OVSPluginContextTest, self).tearDown()
|
||||
|
||||
@patch.object(charmhelpers.contrib.openstack.context, 'config')
|
||||
@patch.object(charmhelpers.contrib.openstack.context, 'unit_get')
|
||||
@patch.object(charmhelpers.contrib.openstack.context, 'is_clustered')
|
||||
@patch.object(charmhelpers.contrib.openstack.context, 'https')
|
||||
@patch.object(context.OVSPluginContext, '_save_flag_file')
|
||||
@patch.object(context.OVSPluginContext, '_ensure_packages')
|
||||
@patch.object(charmhelpers.contrib.openstack.context, 'neutron_plugin_attribute')
|
||||
@patch.object(charmhelpers.contrib.openstack.context, 'unit_private_ip')
|
||||
def test_neutroncc_context_api_rel(self, _unit_priv_ip, _npa, _ens_pkgs, _save_ff, _https, _is_clus, _unit_get, _config):
|
||||
def mock_npa(plugin, section, manager):
|
||||
if section == "driver":
|
||||
return "neutron.randomdriver"
|
||||
if section == "config":
|
||||
return "neutron.randomconfig"
|
||||
_npa.side_effect = mock_npa
|
||||
_config.return_value = 'ovs'
|
||||
_unit_get.return_value = '127.0.0.13'
|
||||
_unit_priv_ip.return_value = '127.0.0.14'
|
||||
_is_clus.return_value = False
|
||||
self.related_units.return_value = ['unit1']
|
||||
self.relation_ids.return_value = ['rid2']
|
||||
self.test_relation.set({'neutron_security_groups': 'yes'})
|
||||
self.get_host_ip.return_value = '127.0.0.15'
|
||||
self.service_running.return_value = False
|
||||
napi_ctxt = context.OVSPluginContext()
|
||||
expect = {
|
||||
'neutron_alchemy_flags': {},
|
||||
'neutron_security_groups': 'yes',
|
||||
'verbose': True,
|
||||
'local_ip': '127.0.0.15',
|
||||
'config': 'neutron.randomconfig',
|
||||
'use_syslog': True,
|
||||
'network_manager': 'neutron',
|
||||
'debug': True,
|
||||
'core_plugin': 'neutron.randomdriver',
|
||||
'neutron_plugin': 'ovs',
|
||||
'neutron_url': 'https://127.0.0.13:9696'
|
||||
}
|
||||
self.assertEquals(expect, napi_ctxt())
|
||||
self.service_start.assertCalled()
|
75
unit_tests/test_neutron_ovs_hooks.py
Normal file
75
unit_tests/test_neutron_ovs_hooks.py
Normal file
@ -0,0 +1,75 @@
|
||||
|
||||
from mock import MagicMock, patch, call
|
||||
from test_utils import CharmTestCase
|
||||
|
||||
|
||||
with patch('charmhelpers.core.hookenv.config') as config:
|
||||
config.return_value = 'neutron'
|
||||
import neutron_ovs_utils as utils
|
||||
|
||||
_reg = utils.register_configs
|
||||
_map = utils.restart_map
|
||||
|
||||
utils.register_configs = MagicMock()
|
||||
utils.restart_map = MagicMock()
|
||||
|
||||
import neutron_ovs_hooks as hooks
|
||||
|
||||
utils.register_configs = _reg
|
||||
utils.restart_map = _map
|
||||
|
||||
TO_PATCH = [
|
||||
'apt_update',
|
||||
'apt_install',
|
||||
'config',
|
||||
'CONFIGS',
|
||||
'determine_packages',
|
||||
'log',
|
||||
'relation_set',
|
||||
]
|
||||
NEUTRON_CONF_DIR = "/etc/neutron"
|
||||
|
||||
NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR
|
||||
|
||||
class NeutronOVSHooksTests(CharmTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(NeutronOVSHooksTests, self).setUp(hooks, TO_PATCH)
|
||||
|
||||
self.config.side_effect = self.test_config.get
|
||||
|
||||
def _call_hook(self, hookname):
|
||||
hooks.hooks.execute([
|
||||
'hooks/{}'.format(hookname)])
|
||||
|
||||
def test_install_hook(self):
|
||||
_pkgs = ['foo', 'bar']
|
||||
self.determine_packages.return_value = _pkgs
|
||||
self._call_hook('install')
|
||||
self.apt_update.assert_called_with()
|
||||
self.apt_install.assert_has_calls([
|
||||
call(_pkgs, fatal=True),
|
||||
])
|
||||
|
||||
def test_config_changed(self):
|
||||
self._call_hook('config-changed')
|
||||
self.assertTrue(self.CONFIGS.write_all.called)
|
||||
|
||||
def test_amqp_joined(self):
|
||||
self._call_hook('amqp-relation-joined')
|
||||
self.relation_set.assert_called_with(
|
||||
username='neutron',
|
||||
vhost='openstack',
|
||||
relation_id=None
|
||||
)
|
||||
|
||||
def test_amqp_changed(self):
|
||||
self.CONFIGS.complete_contexts.return_value = ['amqp']
|
||||
self._call_hook('amqp-relation-changed')
|
||||
self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))
|
||||
|
||||
def test_amqp_departed(self):
|
||||
self._call_hook('amqp-relation-departed')
|
||||
self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))
|
||||
|
||||
|
95
unit_tests/test_neutron_ovs_utils.py
Normal file
95
unit_tests/test_neutron_ovs_utils.py
Normal file
@ -0,0 +1,95 @@
|
||||
|
||||
from mock import MagicMock, call, patch
|
||||
from collections import OrderedDict
|
||||
import charmhelpers.contrib.openstack.templating as templating
|
||||
|
||||
templating.OSConfigRenderer = MagicMock()
|
||||
|
||||
import neutron_ovs_utils as nutils
|
||||
|
||||
from test_utils import (
|
||||
CharmTestCase,
|
||||
patch_open,
|
||||
)
|
||||
import charmhelpers
|
||||
import charmhelpers.core.hookenv as hookenv
|
||||
|
||||
|
||||
TO_PATCH = [
|
||||
'os_release',
|
||||
'neutron_plugin_attribute',
|
||||
]
|
||||
|
||||
head_pkg = 'linux-headers-3.15.0-5-generic'
|
||||
def _mock_npa(plugin, attr, net_manager=None):
|
||||
plugins = {
|
||||
'ovs': {
|
||||
'config': '/etc/neutron/plugins/ml2/ml2_conf.ini',
|
||||
'driver': 'neutron.plugins.ml2.plugin.Ml2Plugin',
|
||||
'contexts': [],
|
||||
'services': ['neutron-plugin-openvswitch-agent'],
|
||||
'packages': [[head_pkg], ['neutron-plugin-openvswitch-agent']],
|
||||
'server_packages': ['neutron-server',
|
||||
'neutron-plugin-ml2'],
|
||||
'server_services': ['neutron-server']
|
||||
},
|
||||
}
|
||||
return plugins[plugin][attr]
|
||||
|
||||
class TestNeutronOVSUtils(CharmTestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
super(TestNeutronOVSUtils, self).setUp(nutils, TO_PATCH)
|
||||
self.neutron_plugin_attribute.side_effect = _mock_npa
|
||||
|
||||
def tearDown(self):
|
||||
# Reset cached cache
|
||||
hookenv.cache = {}
|
||||
|
||||
@patch.object(charmhelpers.contrib.openstack.neutron,'os_release')
|
||||
@patch.object(charmhelpers.contrib.openstack.neutron,'headers_package')
|
||||
def test_determine_packages(self, _head_pkgs, _os_rel):
|
||||
_os_rel.return_value = 'trusty'
|
||||
_head_pkgs.return_value = head_pkg
|
||||
pkg_list = nutils.determine_packages()
|
||||
expect = ['neutron-plugin-openvswitch-agent', head_pkg]
|
||||
self.assertItemsEqual(pkg_list, expect)
|
||||
|
||||
def test_register_configs(self):
|
||||
class _mock_OSConfigRenderer():
|
||||
def __init__(self, templates_dir=None, openstack_release=None):
|
||||
self.configs = []
|
||||
self.ctxts = []
|
||||
|
||||
def register(self, config, ctxt):
|
||||
self.configs.append(config)
|
||||
self.ctxts.append(ctxt)
|
||||
|
||||
self.os_release.return_value = 'trusty'
|
||||
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
|
||||
_regconfs = nutils.register_configs()
|
||||
confs = ['/etc/neutron/neutron.conf',
|
||||
'/etc/neutron/plugins/ml2/ml2_conf.ini']
|
||||
self.assertItemsEqual(_regconfs.configs, confs)
|
||||
|
||||
def test_resource_map(self):
|
||||
_map = nutils.resource_map()
|
||||
confs = [nutils.NEUTRON_CONF]
|
||||
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
|
||||
|
||||
def test_restart_map(self):
|
||||
_restart_map = nutils.restart_map()
|
||||
ML2CONF = "/etc/neutron/plugins/ml2/ml2_conf.ini"
|
||||
expect = OrderedDict([
|
||||
(nutils.NEUTRON_CONF,
|
||||
['neutron-plugin-openvswitch-agent'],
|
||||
),
|
||||
(ML2CONF,
|
||||
['neutron-plugin-openvswitch-agent'],
|
||||
),
|
||||
])
|
||||
self.assertTrue(len(expect) == len(_restart_map))
|
||||
for item in _restart_map:
|
||||
self.assertTrue(item in _restart_map)
|
||||
self.assertTrue(expect[item] == _restart_map[item])
|
121
unit_tests/test_utils.py
Normal file
121
unit_tests/test_utils.py
Normal file
@ -0,0 +1,121 @@
|
||||
import logging
|
||||
import unittest
|
||||
import os
|
||||
import yaml
|
||||
|
||||
from contextlib import contextmanager
|
||||
from mock import patch, MagicMock
|
||||
|
||||
|
||||
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=None):
|
||||
if not attr:
|
||||
return self.get_all()
|
||||
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, attribute=None, unit=None, rid=None):
|
||||
if attribute is None:
|
||||
return self.relation_data
|
||||
elif attribute in self.relation_data:
|
||||
return self.relation_data[attribute]
|
||||
return None
|
||||
|
||||
|
||||
@contextmanager
|
||||
def patch_open():
|
||||
'''Patch open() to allow mocking both open() itself and the file that is
|
||||
yielded.
|
||||
|
||||
Yields the mock for "open" and "file", respectively.'''
|
||||
mock_open = MagicMock(spec=open)
|
||||
mock_file = MagicMock(spec=file)
|
||||
|
||||
@contextmanager
|
||||
def stub_open(*args, **kwargs):
|
||||
mock_open(*args, **kwargs)
|
||||
yield mock_file
|
||||
|
||||
with patch('__builtin__.open', stub_open):
|
||||
yield mock_open, mock_file
|
Loading…
Reference in New Issue
Block a user