Add unit tests and fix for _parse bug exposed
* Add unit tests for common.py and requires.py. * Update tox env for above. * Update gitignore to ignore common kruft. * CRM._parse did not add a space when constructing 'results' after each argument of 'data'. This caused each element to run into the last. Change-Id: I2c35820149618aae02171c89b26bf29ee5e22344
This commit is contained in:
parent
ab38cf8b07
commit
ce2aa63653
|
@ -1,2 +1,6 @@
|
|||
.tox
|
||||
.testrepository
|
||||
.stestr
|
||||
.unit-state.db
|
||||
**/__pycache__/
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[DEFAULT]
|
||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
||||
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
|
||||
${PYTHON:-python} -m subunit.run discover -t ./ ./unit_tests $LISTOPT $IDOPTION
|
||||
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
|
@ -139,8 +139,8 @@ class CRM(dict):
|
|||
if first:
|
||||
results = results + ' '
|
||||
first = False
|
||||
results = results + ('%s %s' % (prefix, d))
|
||||
|
||||
results = results + ('%s %s ' % (prefix, d))
|
||||
results = results.rstrip()
|
||||
return results
|
||||
|
||||
def clone(self, name, resource, description=None, **kwargs):
|
||||
|
@ -275,7 +275,7 @@ class CRM(dict):
|
|||
"""
|
||||
specs = ' '.join(resources)
|
||||
if 'description' in kwargs:
|
||||
specs = specs + (' description="' % kwargs['description'])
|
||||
specs = specs + (' description=%s"' % kwargs['description'])
|
||||
|
||||
for key in 'meta', 'params':
|
||||
if key not in kwargs:
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
flake8>=2.2.4,<=2.4.1
|
||||
# Lint and unit test requirements
|
||||
flake8
|
||||
os-testr>=0.4.1
|
||||
charms.reactive
|
||||
mock>=1.2
|
||||
coverage>=3.6
|
||||
netifaces
|
||||
|
|
23
tox.ini
23
tox.ini
|
@ -1,6 +1,7 @@
|
|||
[tox]
|
||||
envlist = pep8,py27
|
||||
envlist = pep8,py35
|
||||
skipsdist = True
|
||||
skip_missing_interpreters = True
|
||||
|
||||
[testenv]
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
|
@ -9,29 +10,15 @@ install_command =
|
|||
pip install {opts} {packages}
|
||||
commands = ostestr {posargs}
|
||||
|
||||
[testenv:py27]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
# TODO: Need to write unit tests then remove the following command.
|
||||
commands = /bin/true
|
||||
|
||||
[testenv:py34]
|
||||
basepython = python3.4
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
# TODO: Need to write unit tests then remove the following command.
|
||||
commands = /bin/true
|
||||
|
||||
[testenv:py35]
|
||||
basepython = python3.5
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
# TODO: Need to write unit tests then remove the following command.
|
||||
commands = /bin/true
|
||||
commands = ostestr {posargs}
|
||||
|
||||
[testenv:py36]
|
||||
basepython = python3.6
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
# TODO: Need to write unit tests then remove the following command.
|
||||
commands = /bin/true
|
||||
commands = ostestr {posargs}
|
||||
|
||||
[testenv:pep8]
|
||||
basepython = python3
|
||||
|
@ -43,4 +30,4 @@ basepython = python3
|
|||
commands = {posargs}
|
||||
|
||||
[flake8]
|
||||
ignore = E402,E226
|
||||
ignore = E402,E226,W504
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import mock
|
||||
import unittest
|
||||
|
||||
import common
|
||||
|
||||
|
||||
class TestHAClusterCommonCRM(unittest.TestCase):
|
||||
|
||||
def test_init(self):
|
||||
crm = common.CRM()
|
||||
expect = {
|
||||
'resources': {},
|
||||
'delete_resources': [],
|
||||
'resource_params': {},
|
||||
'groups': {},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {},
|
||||
'locations': {},
|
||||
'init_services': []}
|
||||
|
||||
self.assertEqual(
|
||||
crm,
|
||||
expect)
|
||||
|
||||
expect['resources'] = {'res1': 'res1'}
|
||||
self.assertEqual(
|
||||
common.CRM(resources={'res1': 'res1'}),
|
||||
expect)
|
||||
self.assertEqual(
|
||||
common.CRM({'resources': {'res1': 'res1'}}),
|
||||
expect)
|
||||
|
||||
def test_primitive(self):
|
||||
crm = common.CRM()
|
||||
crm.primitive('www8', 'apache',
|
||||
params='configfile=/etc/apache/www8.conf',
|
||||
operations='$id-ref=apache_ops')
|
||||
self.assertEqual(
|
||||
crm['resources']['www8'],
|
||||
'apache')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['www8'],
|
||||
(' params configfile=/etc/apache/www8.conf '
|
||||
'operations $id-ref=apache_ops'))
|
||||
|
||||
def test_primitive_description(self):
|
||||
crm = common.CRM()
|
||||
crm.primitive('www8', 'apache',
|
||||
description='super awesome',
|
||||
params='configfile=/etc/apache/www8.conf',
|
||||
operations='$id-ref=apache_ops')
|
||||
self.assertEqual(
|
||||
crm['resources']['www8'],
|
||||
'apache')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['www8'],
|
||||
('description="super awesome"'
|
||||
' params configfile=/etc/apache/www8.conf '
|
||||
'operations $id-ref=apache_ops'))
|
||||
|
||||
def test_primitive_multiops(self):
|
||||
crm = common.CRM()
|
||||
ops = ['monitor role=Master interval=60s',
|
||||
'monitor role=Slave interval=300s']
|
||||
|
||||
crm.primitive('r0', 'ocf:linbit:drbd',
|
||||
params='drbd_resource=r0',
|
||||
op=ops)
|
||||
self.assertEqual(
|
||||
crm['resources']['r0'],
|
||||
'ocf:linbit:drbd')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['r0'],
|
||||
(' params drbd_resource=r0 op monitor role=Master '
|
||||
'interval=60s op monitor role=Slave interval=300s'))
|
||||
|
||||
def test__parse(self):
|
||||
crm = common.CRM()
|
||||
self.assertEqual(
|
||||
crm._parse('prefix', 'var1'),
|
||||
' prefix var1')
|
||||
self.assertEqual(
|
||||
crm._parse('prefix', ['var1']),
|
||||
' prefix var1')
|
||||
self.assertEqual(
|
||||
crm._parse('prefix', ['var1', 'var2']),
|
||||
' prefix var1 prefix var2')
|
||||
|
||||
def test_clone(self):
|
||||
crm = common.CRM()
|
||||
crm.clone(
|
||||
'cl_nova_haproxy',
|
||||
'res_neutron_haproxy',
|
||||
description='FE Haproxy')
|
||||
self.assertEqual(
|
||||
crm['clones']['cl_nova_haproxy'],
|
||||
'res_neutron_haproxy description="FE Haproxy"')
|
||||
|
||||
def test_clone_meta(self):
|
||||
crm = common.CRM()
|
||||
crm.clone(
|
||||
'cl_nova_haproxy',
|
||||
'res_neutron_haproxy',
|
||||
description='FE Haproxy',
|
||||
meta='clone-node-max=1')
|
||||
self.assertEqual(
|
||||
crm['clones']['cl_nova_haproxy'],
|
||||
('res_neutron_haproxy description="FE Haproxy" '
|
||||
'meta clone-node-max=1'))
|
||||
|
||||
def test_colocation(self):
|
||||
crm = common.CRM()
|
||||
crm.colocation('console_with_vip', 'ALWAYS', 'nova-console', 'vip')
|
||||
self.assertEqual(
|
||||
crm['colocations']['console_with_vip'],
|
||||
'ALWAYS: nova-console vip')
|
||||
|
||||
def test_colocation_node_attr(self):
|
||||
crm = common.CRM()
|
||||
crm.colocation(
|
||||
'console_with_vip',
|
||||
'ALWAYS',
|
||||
'nova-console',
|
||||
'vip',
|
||||
node_attribute='attr1')
|
||||
self.assertEqual(
|
||||
crm['colocations']['console_with_vip'],
|
||||
'ALWAYS: nova-console vip node-attribute=attr1')
|
||||
|
||||
def test_group(self):
|
||||
crm = common.CRM()
|
||||
crm.group('grp_mysql', 'res_mysql_rbd', 'res_mysql_fs',
|
||||
'res_mysql_vip', 'res_mysqld')
|
||||
self.assertEqual(
|
||||
crm['groups']['grp_mysql'],
|
||||
'res_mysql_rbd res_mysql_fs res_mysql_vip res_mysqld')
|
||||
|
||||
def test_group_meta(self):
|
||||
crm = common.CRM()
|
||||
crm.group('grp_mysql', 'res_mysql_rbd', 'res_mysql_fs',
|
||||
'res_mysql_vip', 'res_mysqld', meta='container="vm"')
|
||||
self.assertEqual(
|
||||
crm['groups']['grp_mysql'],
|
||||
('res_mysql_rbd res_mysql_fs res_mysql_vip res_mysqld '
|
||||
'meta container="vm"'))
|
||||
|
||||
def test_group_meta_and_params(self):
|
||||
crm = common.CRM()
|
||||
crm.group('grp_mysql', 'res_mysql_rbd', 'res_mysql_fs',
|
||||
'res_mysql_vip', 'res_mysqld', meta='container="vm"',
|
||||
params='config=/etc/mysql/db0.conf')
|
||||
self.assertEqual(
|
||||
crm['groups']['grp_mysql'],
|
||||
('res_mysql_rbd res_mysql_fs res_mysql_vip res_mysqld '
|
||||
'meta container="vm" '
|
||||
'params config=/etc/mysql/db0.conf'))
|
||||
|
||||
def test_group_desc(self):
|
||||
crm = common.CRM()
|
||||
crm.group('grp_mysql', 'res_mysql_rbd', 'res_mysql_fs',
|
||||
'res_mysql_vip', 'res_mysqld', description='useful desc')
|
||||
self.assertEqual(
|
||||
crm['groups']['grp_mysql'],
|
||||
('res_mysql_rbd res_mysql_fs res_mysql_vip res_mysqld '
|
||||
'description=useful desc"'))
|
||||
|
||||
def test_delete_resource(self):
|
||||
crm = common.CRM()
|
||||
crm.delete_resource('res_mysql_vip')
|
||||
self.assertEqual(
|
||||
crm['delete_resources'],
|
||||
('res_mysql_vip',))
|
||||
|
||||
def test_delete_resource_multi(self):
|
||||
crm = common.CRM()
|
||||
crm.delete_resource('res_mysql_vip', 'grp_mysql')
|
||||
self.assertEqual(
|
||||
crm['delete_resources'],
|
||||
('res_mysql_vip', 'grp_mysql'))
|
||||
|
||||
def test_init_services(self):
|
||||
crm = common.CRM()
|
||||
crm.init_services('haproxy')
|
||||
self.assertEqual(
|
||||
crm['init_services'],
|
||||
('haproxy',))
|
||||
|
||||
def test_init_services_multi(self):
|
||||
crm = common.CRM()
|
||||
crm.init_services('haproxy', 'apache2')
|
||||
self.assertEqual(
|
||||
crm['init_services'],
|
||||
('haproxy', 'apache2'))
|
||||
|
||||
def test_ms_meta(self):
|
||||
crm = common.CRM()
|
||||
crm.ms('disk1', 'drbd1', meta='notify=true globally-unique=false')
|
||||
self.assertEqual(
|
||||
crm['ms']['disk1'],
|
||||
'drbd1 meta notify=true globally-unique=false')
|
||||
|
||||
def test_ms_meta_and_params(self):
|
||||
crm = common.CRM()
|
||||
crm.ms('disk1', 'drbd1',
|
||||
meta='notify=true globally-unique=false',
|
||||
params='config=/etc/mysql/db0.conf')
|
||||
self.assertEqual(
|
||||
crm['ms']['disk1'],
|
||||
'drbd1 meta notify=true globally-unique=false '
|
||||
'params config=/etc/mysql/db0.conf')
|
||||
|
||||
def test_ms_desc(self):
|
||||
crm = common.CRM()
|
||||
crm.ms('disk1', 'drbd1', description='useful desc')
|
||||
self.assertEqual(
|
||||
crm['ms']['disk1'],
|
||||
'drbd1 description="useful desc"')
|
||||
|
||||
# The method signature of 'order' seems broken. Leaving out unit tests for
|
||||
# it as they would just confirm broken behaviour.
|
||||
|
||||
def test_add(self):
|
||||
crm = common.CRM()
|
||||
mock1 = mock.MagicMock()
|
||||
mock2 = mock.MagicMock()
|
||||
mock1.configure_resource = mock2
|
||||
crm.add(mock1)
|
||||
mock2.assert_called_once_with(crm)
|
||||
|
||||
|
||||
class TestHAClusterCommonInitService(unittest.TestCase):
|
||||
|
||||
def test_init(self):
|
||||
init_svc = common.InitService('apache', 'apache2')
|
||||
self.assertEqual(
|
||||
init_svc.service_name,
|
||||
'apache')
|
||||
self.assertEqual(
|
||||
init_svc.init_service_name,
|
||||
'apache2')
|
||||
self.assertTrue(init_svc.clone)
|
||||
|
||||
def test_init_no_clone(self):
|
||||
init_svc = common.InitService('apache', 'apache2', clone=False)
|
||||
self.assertFalse(init_svc.clone)
|
||||
|
||||
def test_configure_resource(self):
|
||||
crm = common.CRM()
|
||||
init_svc = common.InitService('apache', 'apache2')
|
||||
init_svc.configure_resource(crm)
|
||||
self.assertEqual(
|
||||
crm['resources']['res_apache_apache2'],
|
||||
'lsb:apache2')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['res_apache_apache2'],
|
||||
(' op monitor interval="5s"'))
|
||||
self.assertEqual(crm['init_services'], ('apache2',))
|
||||
self.assertEqual(
|
||||
crm['clones']['cl_res_apache_apache2'],
|
||||
'res_apache_apache2')
|
||||
|
||||
def test_configure_resource_no_clone(self):
|
||||
crm = common.CRM()
|
||||
init_svc = common.InitService('apache', 'apache2', clone=False)
|
||||
init_svc.configure_resource(crm)
|
||||
self.assertEqual(
|
||||
crm['resources']['res_apache_apache2'],
|
||||
'lsb:apache2')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['res_apache_apache2'],
|
||||
(' op monitor interval="5s"'))
|
||||
self.assertEqual(crm['init_services'], ('apache2',))
|
||||
self.assertFalse(crm['clones'].get('cl_res_apache_apache2'))
|
||||
|
||||
|
||||
class TestHAClusterCommonVirtualIP(unittest.TestCase):
|
||||
|
||||
def test_init(self):
|
||||
vip_svc = common.VirtualIP('apache', '10.110.1.1')
|
||||
self.assertEqual(vip_svc.service_name, 'apache')
|
||||
self.assertEqual(vip_svc.vip, '10.110.1.1')
|
||||
self.assertIsNone(vip_svc.nic)
|
||||
self.assertIsNone(vip_svc.cidr)
|
||||
|
||||
def test_init_no_default(self):
|
||||
vip_svc = common.VirtualIP('apache', '10.110.1.1', 'eth1', '24')
|
||||
self.assertEqual(vip_svc.service_name, 'apache')
|
||||
self.assertEqual(vip_svc.vip, '10.110.1.1')
|
||||
self.assertEqual(vip_svc.nic, 'eth1')
|
||||
self.assertEqual(vip_svc.cidr, '24')
|
||||
|
||||
def test_configure_resource(self):
|
||||
crm = common.CRM()
|
||||
vip_svc = common.VirtualIP('apache', '10.110.1.1', 'eth1', '24')
|
||||
vip_svc.configure_resource(crm)
|
||||
self.assertEqual(
|
||||
crm['resources']['res_apache_eth1_vip'],
|
||||
'ocf:heartbeat:IPaddr2')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['res_apache_eth1_vip'],
|
||||
(' params ip="10.110.1.1" nic="eth1" cidr_netmask="24" '
|
||||
'op monitor depth="0" timeout="20s" interval="10s"'))
|
||||
|
||||
def test_configure_resource_no_nic(self):
|
||||
crm = common.CRM()
|
||||
vip_svc = common.VirtualIP('apache', '10.110.1.1')
|
||||
vip_svc.configure_resource(crm)
|
||||
self.assertEqual(
|
||||
crm['resources']['res_apache_a7815c8_vip'],
|
||||
'ocf:heartbeat:IPaddr2')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['res_apache_a7815c8_vip'],
|
||||
(' params ip="10.110.1.1" '
|
||||
'op monitor depth="0" timeout="20s" interval="10s"'))
|
||||
|
||||
|
||||
class TestHAClusterCommonDNSEntry(unittest.TestCase):
|
||||
|
||||
def test_init(self):
|
||||
dns_svc = common.DNSEntry(
|
||||
'keystone',
|
||||
'10.110.1.1',
|
||||
'keystone.admin',
|
||||
'admin')
|
||||
self.assertEqual(dns_svc.service_name, 'keystone')
|
||||
self.assertEqual(dns_svc.ip, '10.110.1.1')
|
||||
self.assertEqual(dns_svc.fqdn, 'keystone.admin')
|
||||
self.assertEqual(dns_svc.endpoint_type, 'admin')
|
||||
|
||||
def test_configure_resource(self):
|
||||
crm = common.CRM()
|
||||
dns_svc = common.DNSEntry(
|
||||
'keystone',
|
||||
'10.110.1.1',
|
||||
'keystone.admin',
|
||||
'admin')
|
||||
dns_svc.configure_resource(crm)
|
||||
self.assertEqual(
|
||||
crm['resources']['res_keystone_admin_hostname'],
|
||||
'ocf:maas:dns')
|
||||
self.assertEqual(
|
||||
crm['resource_params']['res_keystone_admin_hostname'],
|
||||
' params fqdn="keystone.admin" ip_address="10.110.1.1"')
|
|
@ -0,0 +1,414 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import json
|
||||
import mock
|
||||
import unittest
|
||||
|
||||
import common
|
||||
|
||||
# Deal with the 'relations.hacluster.common' import in requires.py which
|
||||
# is invalid in the unit tests as there is no 'relations'.
|
||||
relations_mock = mock.MagicMock()
|
||||
relations_mock.hacluster.common = common
|
||||
modules = {
|
||||
'relations': relations_mock,
|
||||
'relations.hacluster': mock.MagicMock(),
|
||||
'relations.hacluster.common': common,
|
||||
}
|
||||
module_patcher = mock.patch.dict('sys.modules', modules)
|
||||
module_patcher.start()
|
||||
|
||||
with mock.patch('charmhelpers.core.hookenv.metadata') as _meta:
|
||||
_meta.return_Value = 'ss'
|
||||
import requires
|
||||
|
||||
_hook_args = {}
|
||||
|
||||
TO_PATCH = [
|
||||
'data_changed',
|
||||
]
|
||||
|
||||
|
||||
def mock_hook(*args, **kwargs):
|
||||
|
||||
def inner(f):
|
||||
# remember what we were passed. Note that we can't actually determine
|
||||
# the class we're attached to, as the decorator only gets the function.
|
||||
_hook_args[f.__name__] = dict(args=args, kwargs=kwargs)
|
||||
return f
|
||||
return inner
|
||||
|
||||
|
||||
class TestHAClusterRequires(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls._patched_hook = mock.patch('charms.reactive.when', mock_hook)
|
||||
cls._patched_hook_started = cls._patched_hook.start()
|
||||
# force requires to rerun the mock_hook decorator:
|
||||
# try except is Python2/Python3 compatibility as Python3 has moved
|
||||
# reload to importlib.
|
||||
try:
|
||||
reload(requires)
|
||||
except NameError:
|
||||
import importlib
|
||||
importlib.reload(requires)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls._patched_hook.stop()
|
||||
cls._patched_hook_started = None
|
||||
cls._patched_hook = None
|
||||
# and fix any breakage we did to the module
|
||||
try:
|
||||
reload(requires)
|
||||
except NameError:
|
||||
import importlib
|
||||
importlib.reload(requires)
|
||||
|
||||
def patch(self, method):
|
||||
_m = mock.patch.object(self.obj, method)
|
||||
_mock = _m.start()
|
||||
self.addCleanup(_m.stop)
|
||||
return _mock
|
||||
|
||||
def setUp(self):
|
||||
self.cr = requires.HAClusterRequires('some-relation', [])
|
||||
self._patches = {}
|
||||
self._patches_start = {}
|
||||
self.obj = requires
|
||||
for method in TO_PATCH:
|
||||
setattr(self, method, self.patch(method))
|
||||
|
||||
def tearDown(self):
|
||||
self.cr = None
|
||||
for k, v in self._patches.items():
|
||||
v.stop()
|
||||
setattr(self, k, None)
|
||||
self._patches = None
|
||||
self._patches_start = None
|
||||
|
||||
def patch_kr(self, attr, return_value=None):
|
||||
mocked = mock.patch.object(self.cr, attr)
|
||||
self._patches[attr] = mocked
|
||||
started = mocked.start()
|
||||
started.return_value = return_value
|
||||
self._patches_start[attr] = started
|
||||
setattr(self, attr, started)
|
||||
|
||||
def test_joined(self):
|
||||
self.patch_kr('set_state')
|
||||
self.cr.joined()
|
||||
self.set_state.assert_called_once_with('{relation_name}.connected')
|
||||
|
||||
def test_changed(self):
|
||||
self.patch_kr('is_clustered', True)
|
||||
self.patch_kr('set_state')
|
||||
self.cr.changed()
|
||||
self.set_state.assert_called_once_with('{relation_name}.available')
|
||||
|
||||
def test_changed_not_clustered(self):
|
||||
self.patch_kr('is_clustered', False)
|
||||
self.patch_kr('remove_state')
|
||||
self.cr.changed()
|
||||
self.remove_state.assert_called_once_with('{relation_name}.available')
|
||||
|
||||
def test_departed(self):
|
||||
self.patch_kr('remove_state')
|
||||
self.cr.departed()
|
||||
self.remove_state.assert_has_calls([
|
||||
mock.call('{relation_name}.available'),
|
||||
mock.call('{relation_name}.connected')])
|
||||
|
||||
def test_is_clustered(self):
|
||||
self.patch_kr('get_remote_all')
|
||||
|
||||
self.get_remote_all.return_value = [True]
|
||||
self.assertTrue(self.cr.is_clustered())
|
||||
|
||||
self.get_remote_all.return_value = ['true']
|
||||
self.assertTrue(self.cr.is_clustered())
|
||||
|
||||
self.get_remote_all.return_value = ['yes']
|
||||
self.assertTrue(self.cr.is_clustered())
|
||||
|
||||
self.get_remote_all.return_value = None
|
||||
self.assertFalse(self.cr.is_clustered())
|
||||
|
||||
self.get_remote_all.return_value = [False]
|
||||
self.assertFalse(self.cr.is_clustered())
|
||||
|
||||
self.get_remote_all.return_value = ['false']
|
||||
self.assertFalse(self.cr.is_clustered())
|
||||
|
||||
self.get_remote_all.return_value = ['flump']
|
||||
self.assertFalse(self.cr.is_clustered())
|
||||
|
||||
def jsonify(self, options):
|
||||
json_encode_options = dict(
|
||||
sort_keys=True,
|
||||
)
|
||||
for k, v in options.items():
|
||||
if v:
|
||||
options[k] = json.dumps(v, **json_encode_options)
|
||||
|
||||
def test_manage_resources(self):
|
||||
res = common.CRM()
|
||||
res.primitive('res_neutron_haproxy', 'lsb:haproxy',
|
||||
op='monitor interval="5s"')
|
||||
res.init_services('haproxy')
|
||||
res.clone('cl_nova_haproxy', 'res_neutron_haproxy')
|
||||
expected = {
|
||||
'json_clones': {"cl_nova_haproxy": "res_neutron_haproxy"},
|
||||
'json_init_services': ["haproxy"],
|
||||
'json_resource_params': {
|
||||
"res_neutron_haproxy": ' op monitor interval="5s"'},
|
||||
'json_resources': {"res_neutron_haproxy": "lsb:haproxy"}}
|
||||
self.jsonify(expected)
|
||||
self.data_changed.return_value = True
|
||||
self.patch_kr('set_local')
|
||||
self.patch_kr('set_remote')
|
||||
self.cr.manage_resources(res)
|
||||
self.set_local.assert_called_once_with(**expected)
|
||||
self.set_remote.assert_called_once_with(**expected)
|
||||
|
||||
def test_manage_resources_no_change(self):
|
||||
res = common.CRM()
|
||||
res.primitive('res_neutron_haproxy', 'lsb:haproxy',
|
||||
op='monitor interval="5s"')
|
||||
res.init_services('haproxy')
|
||||
res.clone('cl_nova_haproxy', 'res_neutron_haproxy')
|
||||
self.data_changed.return_value = False
|
||||
self.patch_kr('set_local')
|
||||
self.patch_kr('set_remote')
|
||||
self.cr.manage_resources(res)
|
||||
self.assertFalse(self.set_local.called)
|
||||
self.assertFalse(self.set_remote.called)
|
||||
|
||||
def test_bind_resources(self):
|
||||
self.patch_kr('get_local', 'resources')
|
||||
self.patch_kr('bind_on')
|
||||
self.patch_kr('manage_resources')
|
||||
self.cr.bind_resources()
|
||||
self.bind_on.assert_called_once_with(iface=None, mcastport=4440)
|
||||
self.manage_resources.assert_called_once_with('resources')
|
||||
|
||||
def test_bind_resources_no_defaults(self):
|
||||
self.patch_kr('get_local', 'resources')
|
||||
self.patch_kr('bind_on')
|
||||
self.patch_kr('manage_resources')
|
||||
self.cr.bind_resources(iface='tr34', mcastport=111)
|
||||
self.bind_on.assert_called_once_with(iface='tr34', mcastport=111)
|
||||
self.manage_resources.assert_called_once_with('resources')
|
||||
|
||||
def test_add_vip(self):
|
||||
expected = {
|
||||
'resources': {
|
||||
'res_mysql_4b8ce37_vip': 'ocf:heartbeat:IPaddr2'},
|
||||
'delete_resources': [],
|
||||
'resource_params': {
|
||||
'res_mysql_4b8ce37_vip': (
|
||||
' params ip="10.110.5.43" op monitor depth="0" '
|
||||
'timeout="20s" interval="10s"')},
|
||||
'groups': {},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {},
|
||||
'locations': {},
|
||||
'init_services': []}
|
||||
|
||||
self.patch_kr('get_local', None)
|
||||
self.patch_kr('set_local')
|
||||
self.cr.add_vip('mysql', '10.110.5.43')
|
||||
self.set_local.assert_called_once_with(resources=expected)
|
||||
|
||||
def test_add_additional_vip(self):
|
||||
existing_resource = {
|
||||
'resources': {
|
||||
'res_mysql_4b8ce37_vip': 'ocf:heartbeat:IPaddr2'},
|
||||
'delete_resources': [],
|
||||
'resource_params': {
|
||||
'res_mysql_4b8ce37_vip': (
|
||||
' params ip="10.110.5.43" op monitor depth="0" '
|
||||
'timeout="20s" interval="10s"')},
|
||||
'groups': {},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {},
|
||||
'locations': {},
|
||||
'init_services': []}
|
||||
|
||||
expected = {
|
||||
'resources': {
|
||||
'res_mysql_4b8ce37_vip': 'ocf:heartbeat:IPaddr2',
|
||||
'res_mysql_1993276_vip': 'ocf:heartbeat:IPaddr2'},
|
||||
'delete_resources': [],
|
||||
'resource_params': {
|
||||
'res_mysql_4b8ce37_vip': (
|
||||
' params ip="10.110.5.43" op monitor depth="0" '
|
||||
'timeout="20s" interval="10s"'),
|
||||
'res_mysql_1993276_vip': (
|
||||
' params ip="10.120.5.43" op monitor depth="0" '
|
||||
'timeout="20s" interval="10s"')},
|
||||
'groups': {
|
||||
'grp_mysql_vips': ('res_mysql_1993276_vip '
|
||||
'res_mysql_4b8ce37_vip')},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {},
|
||||
'locations': {},
|
||||
'init_services': []}
|
||||
|
||||
self.patch_kr('get_local', existing_resource)
|
||||
self.patch_kr('set_local')
|
||||
self.cr.add_vip('mysql', '10.120.5.43')
|
||||
self.set_local.assert_called_once_with(resources=expected)
|
||||
|
||||
def test_add_init_service(self):
|
||||
expected = {
|
||||
'resources': {
|
||||
'res_mysql_telnetd': 'lsb:telnetd'},
|
||||
'delete_resources': [],
|
||||
'resource_params': {
|
||||
'res_mysql_telnetd': ' op monitor interval="5s"'},
|
||||
'groups': {},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {'cl_res_mysql_telnetd': 'res_mysql_telnetd'},
|
||||
'locations': {},
|
||||
'init_services': ('telnetd',)}
|
||||
self.patch_kr('get_local', None)
|
||||
self.patch_kr('set_local')
|
||||
self.cr.add_init_service('mysql', 'telnetd')
|
||||
self.set_local.assert_called_once_with(resources=expected)
|
||||
|
||||
def test_add_dnsha(self):
|
||||
expected = {
|
||||
'resources': {
|
||||
'res_keystone_public_hostname': 'ocf:maas:dns'},
|
||||
'delete_resources': [],
|
||||
'resource_params': {
|
||||
'res_keystone_public_hostname': (
|
||||
' params fqdn="keystone.public" '
|
||||
'ip_address="10.110.5.43"')},
|
||||
'groups': {},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {},
|
||||
'locations': {},
|
||||
'init_services': []}
|
||||
|
||||
self.patch_kr('get_local', None)
|
||||
self.patch_kr('set_local')
|
||||
self.cr.add_dnsha(
|
||||
'keystone',
|
||||
'10.110.5.43',
|
||||
'keystone.public',
|
||||
'public')
|
||||
self.set_local.assert_called_once_with(resources=expected)
|
||||
|
||||
def test_add_additional_dnsha(self):
|
||||
existing_resource = {
|
||||
'resources': {
|
||||
'res_keystone_public_hostname': 'ocf:maas:dns'},
|
||||
'delete_resources': [],
|
||||
'resource_params': {
|
||||
'res_keystone_public_hostname': (
|
||||
' params fqdn="keystone.public" '
|
||||
'ip_address="10.110.5.43"')},
|
||||
'groups': {},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {},
|
||||
'locations': {},
|
||||
'init_services': []}
|
||||
expected = {
|
||||
'resources': {
|
||||
'res_keystone_public_hostname': 'ocf:maas:dns',
|
||||
'res_keystone_admin_hostname': 'ocf:maas:dns'},
|
||||
'delete_resources': [],
|
||||
'resource_params': {
|
||||
'res_keystone_public_hostname': (
|
||||
' params fqdn="keystone.public" '
|
||||
'ip_address="10.110.5.43"'),
|
||||
'res_keystone_admin_hostname': (
|
||||
' params fqdn="keystone.admin" '
|
||||
'ip_address="10.120.5.43"')},
|
||||
'groups': {
|
||||
'grp_keystone_hostnames': ('res_keystone_admin_hostname '
|
||||
'res_keystone_public_hostname')},
|
||||
'ms': {},
|
||||
'orders': {},
|
||||
'colocations': {},
|
||||
'clones': {},
|
||||
'locations': {},
|
||||
'init_services': []}
|
||||
|
||||
self.patch_kr('get_local', existing_resource)
|
||||
self.patch_kr('set_local')
|
||||
self.cr.add_dnsha(
|
||||
'keystone',
|
||||
'10.120.5.43',
|
||||
'keystone.admin',
|
||||
'admin')
|
||||
self.set_local.assert_called_once_with(resources=expected)
|
||||
|
||||
@mock.patch.object(requires.hookenv, 'related_units')
|
||||
@mock.patch.object(requires.hookenv, 'relation_get')
|
||||
def test_get_remote_all(self, relation_get, related_units):
|
||||
unit_data = {
|
||||
'rid:1': {
|
||||
'app1/0': {
|
||||
'key1': 'value1',
|
||||
'key2': 'value2'},
|
||||
'app1/1': {
|
||||
'key1': 'value1',
|
||||
'key2': 'value3'}},
|
||||
'rid:2': {
|
||||
'app2/0': {
|
||||
'key1': 'value1',
|
||||
'key2': 'value3'}},
|
||||
'rid:3': {}}
|
||||
|
||||
def get_unit_data(key, unit, relation_id):
|
||||
return unit_data[relation_id].get(unit, {}).get(key, {})
|
||||
conv1 = mock.MagicMock()
|
||||
conv1.relation_ids = ['rid:1', 'rid:2']
|
||||
conv2 = mock.MagicMock()
|
||||
conv2.relation_ids = ['rid:3']
|
||||
self.patch_kr('conversations', [conv1, conv2])
|
||||
related_units.side_effect = lambda x: unit_data[x].keys()
|
||||
relation_get.side_effect = get_unit_data
|
||||
# Check de-duplication:
|
||||
self.assertEqual(
|
||||
self.cr.get_remote_all('key1'),
|
||||
['value1'])
|
||||
# Check multiple values:
|
||||
self.assertEqual(
|
||||
self.cr.get_remote_all('key2'),
|
||||
['value2', 'value3'])
|
||||
# Check missing key
|
||||
self.assertEqual(
|
||||
self.cr.get_remote_all('key100'),
|
||||
[])
|
||||
# Check missing key with default
|
||||
self.assertEqual(
|
||||
self.cr.get_remote_all('key100', default='defaultvalue'),
|
||||
['defaultvalue'])
|
Loading…
Reference in New Issue