Add unit_tests and drive by assorted
* Add unit tests * Fix path to repo in layers.yaml * Ignore unit_tests etc in layers.yaml * Make set_state calls consistently from conversation * Setup travis (interim step until this interface is in OpenStack gerrit)
This commit is contained in:
parent
3dbb0b0237
commit
2351b3ad56
|
@ -0,0 +1,5 @@
|
|||
.tox
|
||||
.testrepository
|
||||
.unit-state.db
|
||||
.stestr/
|
||||
__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
|
|
@ -0,0 +1,6 @@
|
|||
sudo: false
|
||||
language: python
|
||||
python:
|
||||
- "3.4"
|
||||
install: pip install tox-travis
|
||||
script: tox -e pep8,py3
|
|
@ -1,4 +1,13 @@
|
|||
name: cinder-backend
|
||||
summary: OpenStack Cinder backend interface
|
||||
version: 1
|
||||
repo: https://github.com/mskalka/interface-cinder-backend
|
||||
repo: https://github.com/openstack-charmers/interface-cinder-backend
|
||||
ignore:
|
||||
- 'unit_tests'
|
||||
- 'Makefile'
|
||||
- '.testr.conf'
|
||||
- 'test-requirements.txt'
|
||||
- 'tox.ini'
|
||||
- '.gitignore'
|
||||
- '.gitreview'
|
||||
- '.unit-state.db'
|
||||
|
|
|
@ -15,15 +15,15 @@ class CinderBackendProvides(RelationBase):
|
|||
def cinder_backend_joined(self):
|
||||
conv = self.conversation()
|
||||
conv.set_state('{relation_name}.joined')
|
||||
self.set_state('{relation_name}.connected')
|
||||
self.set_state('{relation_name}.available')
|
||||
conv.set_state('{relation_name}.connected')
|
||||
conv.set_state('{relation_name}.available')
|
||||
|
||||
@hook('{provides:cinder-backend}-relation-{broken, departed}')
|
||||
def cinder_backend_departed(self):
|
||||
conv = self.conversation()
|
||||
conv.remove_state('{relation_name}.joined')
|
||||
self.remove_state('{relation_name}.available')
|
||||
self.remove_state('{relation_name}.connected')
|
||||
conv.remove_state('{relation_name}.available')
|
||||
conv.remove_state('{relation_name}.connected')
|
||||
conv.set_state('{relation_name}.departing')
|
||||
|
||||
def configure_principal(self, backend_name, configuration, stateless=None):
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# Lint and unit test requirements
|
||||
flake8
|
||||
os-testr>=0.4.1
|
||||
charms.reactive
|
||||
mock>=1.2
|
||||
coverage>=3.6
|
|
@ -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 = ostestr {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,0 +1,130 @@
|
|||
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.application_name = application_name
|
||||
self.units = units
|
||||
|
||||
|
||||
class TestCinderBackendProvides(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.cr = provides.CinderBackendProvides('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.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_cinder_backend_joined(self):
|
||||
mock_conv = mock.MagicMock()
|
||||
self.patch_kr('conversation', mock_conv)
|
||||
self.cr.cinder_backend_joined()
|
||||
expected_calls = [
|
||||
mock.call('{relation_name}.joined'),
|
||||
mock.call('{relation_name}.connected'),
|
||||
mock.call('{relation_name}.available')]
|
||||
mock_conv.set_state.assert_has_calls(expected_calls)
|
||||
|
||||
def test_cinder_backend_departed(self):
|
||||
mock_conv = mock.MagicMock()
|
||||
self.patch_kr('conversation', mock_conv)
|
||||
self.cr.cinder_backend_departed()
|
||||
expected_calls = [
|
||||
mock.call('{relation_name}.joined'),
|
||||
mock.call('{relation_name}.available'),
|
||||
mock.call('{relation_name}.connected')]
|
||||
mock_conv.remove_state.assert_has_calls(expected_calls)
|
||||
mock_conv.set_state.assert_called_once_with(
|
||||
'{relation_name}.departing')
|
||||
|
||||
def test_configure_principal(self):
|
||||
mock_conv = mock.MagicMock()
|
||||
self.patch_kr('conversation', mock_conv)
|
||||
self.cr.configure_principal(
|
||||
'cinder-supernas',
|
||||
[('cinder', 'ss')],
|
||||
True)
|
||||
expect = ('{"cinder": {"/etc/cinder/cinder.conf": {"sections": '
|
||||
'{"cinder-supernas": [["cinder", "ss"]]}}}}')
|
||||
mock_conv.set_remote.assert_called_once_with(
|
||||
backend_name='cinder-supernas',
|
||||
stateless=True,
|
||||
subordinate_configuration=expect)
|
Loading…
Reference in New Issue