Add unit tests

This commit is contained in:
Liam Young 2019-03-20 07:31:55 +00:00
parent eb7291590b
commit f1297f72a5
8 changed files with 205 additions and 4 deletions

3
.gitignore vendored
View File

@ -1,2 +1,5 @@
.tox
.testrepository
.unit-state.db
.stestr/
__pycache__/

3
.stestr.conf Normal file
View File

@ -0,0 +1,3 @@
[DEFAULT]
test_path=./unit_tests
top_dir=./

View File

@ -1,3 +1,12 @@
name: pacemaker-remote
summary: Basic pacemaker-remote interface
version: 1
ignore:
- 'unit_tests'
- 'Makefile'
- '.testr.conf'
- 'test-requirements.txt'
- 'tox.ini'
- '.gitignore'
- '.gitreview'
- '.unit-state.db'

View File

@ -2,23 +2,28 @@ import base64
from charms.reactive import Endpoint
class PacemakerProvides(Endpoint):
class PacemakerRemoteProvides(Endpoint):
def publish_info(self, stonith_hostname=None):
def publish_info(self, remote_hostname, stonith_hostname=None,
enable_resources=True):
"""
Publish the stonith info
"""
for relation in self.relations:
relation.to_publish['stonith-hostname'] = stonith_hostname
relation.to_publish['remote-hostname'] = remote_hostname
relation.to_publish['enable-resources'] = enable_resources
def get_pacemaker_key(self):
for relation in self.relations:
pacemaker_keys = []
for unit in relation.units:
pacemaker_keys.append(unit.received['pacemaker-key'])
key = unit.received.get('pacemaker-key')
if key:
pacemaker_keys.append(key)
unique_keys = len(set(pacemaker_keys))
if unique_keys > 1:
raise Exception("Inconsistent keys")
elif unique_keys == 1:
return base64.decode(unique_keys[0])
return base64.b64decode(pacemaker_keys[0])
return None

6
test-requirements.txt Normal file
View File

@ -0,0 +1,6 @@
# Lint and unit test requirements
flake8
os-testr>=0.4.1
charms.reactive
mock>=1.2
coverage>=3.6

28
tox.ini Normal file
View File

@ -0,0 +1,28 @@
[tox]
skipsdist = True
envlist = pep8,py3
skip_missing_interpreters = True
[testenv]
setenv = VIRTUAL_ENV={envdir}
PYTHONHASHSEED=0
TERM=linux
install_command =
pip install {opts} {packages}
[testenv:py3]
basepython = python3
deps = -r{toxinidir}/test-requirements.txt
commands = stestr run {posargs}
[testenv:pep8]
basepython = python3
deps = -r{toxinidir}/test-requirements.txt
commands = flake8 {posargs} .
[testenv:venv]
commands = {posargs}
[flake8]
# E402 ignore necessary for path append before sys module import in actions
ignore = E402

0
unit_tests/__init__.py Normal file
View File

147
unit_tests/test_provides.py Normal file
View File

@ -0,0 +1,147 @@
import unittest
import mock
with mock.patch('charmhelpers.core.hookenv.metadata') as _meta:
_meta.return_Value = 'ss'
import provides
_hook_args = {}
TO_PATCH = [
]
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 _unit_mock:
def __init__(self, unit_name, received=None):
self.unit_name = unit_name
self.received = received or {}
class _relation_mock:
def __init__(self, application_name=None, units=None):
self.to_publish_raw = {}
self.to_publish = {}
self.application_name = application_name
self.units = units
class TestPacemakerRemoteProvides(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 provides to rerun the mock_hook decorator:
# try except is Python2/Python3 compatibility as Python3 has moved
# reload to importlib.
try:
reload(provides)
except NameError:
import importlib
importlib.reload(provides)
@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(provides)
except NameError:
import importlib
importlib.reload(provides)
def patch(self, method):
_m = mock.patch.object(self.obj, method)
_mock = _m.start()
self.addCleanup(_m.stop)
return _mock
def setUp(self):
self.relation_obj = provides.PacemakerRemoteProvides(
'some-relation',
[])
self._patches = {}
self._patches_start = {}
self.obj = provides
for method in TO_PATCH:
setattr(self, method, self.patch(method))
def tearDown(self):
self.relation_obj = None
for k, v in self._patches.items():
v.stop()
setattr(self, k, None)
self._patches = None
self._patches_start = None
def patch_relation_obj(self, attr, return_value=None):
mocked = mock.patch.object(self.relation_obj, attr)
self._patches[attr] = mocked
started = mocked.start()
started.return_value = return_value
self._patches_start[attr] = started
setattr(self, attr, started)
def test_publish_info(self):
mock_rel = _relation_mock()
self.relation_obj._relations = [mock_rel]
self.relation_obj.publish_info(
'node1.az1.local',
stonith_hostname='node1.stonith',
enable_resources=True)
expect = {
'remote-hostname': 'node1.az1.local',
'stonith-hostname': 'node1.stonith',
'enable-resources': True}
self.assertEqual(
mock_rel.to_publish,
expect)
def test_get_pacemaker_key(self):
unit1 = _unit_mock(
'unit1',
received={'pacemaker-key': 'cG1ha2Vya2V5MQo='})
mock_rel = _relation_mock(units=[unit1])
self.relation_obj._relations = [mock_rel]
self.assertEqual(
self.relation_obj.get_pacemaker_key(),
b'pmakerkey1\n')
def test_get_pacemaker_key_inconsistent(self):
unit1 = _unit_mock(
'unit1',
received={'pacemaker-key': 'cG1ha2Vya2V5MQo='})
unit2 = _unit_mock(
'unit2',
received={'pacemaker-key': 'cG1ha2Vya2V5Mgo='})
mock_rel = _relation_mock(units=[unit1, unit2])
self.relation_obj._relations = [mock_rel]
with self.assertRaises(Exception):
self.relation_obj.get_pacemaker_key()
def test_get_pacemaker_key_missing(self):
unit1 = _unit_mock(
'unit1',
received={})
unit2 = _unit_mock(
'unit2',
received={})
mock_rel = _relation_mock(units=[unit1, unit2])
self.relation_obj._relations = [mock_rel]
self.assertEqual(
self.relation_obj.get_pacemaker_key(),
None)