Fix func27-smoke which fails

This was a combination of the smoke test being incorrectly specified
and there being no assess_status() at the end of the hsm_connected()
function.  Also the assess_status() was removed from the layer-openstack
which meant that the status wasn't updating.

The change adds in an assess_status() call, but also reworks the tests
so that they use the new features in charms.openstack, and also uses
defaults for config-changed and assess-status hooks/events.

The gate that tox.ini is the keystone-v2 version of the tests.

Change-Id: Ib8082a083b05eba872d8a2e5fe477352df25ccbb
Closes-Bug: #1629624
This commit is contained in:
Alex Kavanagh 2016-10-05 12:21:26 +00:00
parent ff0224dbac
commit b00cb733a8
6 changed files with 83 additions and 157 deletions

View File

@ -42,9 +42,19 @@ def install():
def on_hsm_connected(hsm):
"""When SoftHSM connects to Barbican, configure Barbican with the
information necessary to configure the plugin.
:param hsm: the hsm relation object
"""
BarbicanSoftHSMCharm.singleton.on_hsm_connected(hsm)
def assess_status():
"""Call the charm assess_status function"""
BarbicanSoftHSMCharm.singleton.assess_status()
class BarbicanSoftHSMCharm(charms_openstack.charm.OpenStackCharm):
service_name = 'barbican-softhsm'

View File

@ -14,8 +14,15 @@
import charms.reactive as reactive
import charms_openstack.charm
import charm.openstack.softhsm as softhsm
# Use the charms.openstack defaults for common states and hooks
charms_openstack.charm.use_defaults(
'config.changed',
'update-status')
# use a synthetic state to ensure that it get it to be installed independent of
# the install hook.
@ -29,3 +36,4 @@ def install_packages():
def hsm_connected(hsm):
softhsm.on_hsm_connected(hsm)
reactive.set_state('hsm.available')
softhsm.assess_status()

View File

@ -1 +1,3 @@
TODO: write Amulet tests.
Note that gate-basic-xenial-mitaka is the keystone V2 version of the tests.

View File

@ -15,118 +15,44 @@
from __future__ import absolute_import
from __future__ import print_function
import unittest
import mock
import reactive.handlers as handlers
_when_args = {}
_when_not_args = {}
import charms_openstack.test_utils as test_utils
def mock_hook_factory(d):
class TestRegisteredHooks(test_utils.TestRegisteredHooks):
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.
try:
d[f.__name__].append(dict(args=args, kwargs=kwargs))
except KeyError:
d[f.__name__] = [dict(args=args, kwargs=kwargs)]
return f
return inner
return mock_hook
class TestBarbicanHandlers(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._patched_when = mock.patch('charms.reactive.when',
mock_hook_factory(_when_args))
cls._patched_when_started = cls._patched_when.start()
cls._patched_when_not = mock.patch('charms.reactive.when_not',
mock_hook_factory(_when_not_args))
cls._patched_when_not_started = cls._patched_when_not.start()
# force requires to rerun the mock_hook decorator:
# try except is Python2/Python3 compatibility as Python3 has moved
# reload to importlib.
try:
reload(handlers)
except NameError:
import importlib
importlib.reload(handlers)
@classmethod
def tearDownClass(cls):
cls._patched_when.stop()
cls._patched_when_started = None
cls._patched_when = None
cls._patched_when_not.stop()
cls._patched_when_not_started = None
cls._patched_when_not = None
# and fix any breakage we did to the module
try:
reload(handlers)
except NameError:
import importlib
importlib.reload(handlers)
def setUp(self):
self._patches = {}
self._patches_start = {}
def tearDown(self):
for k, v in self._patches.items():
v.stop()
setattr(self, k, None)
self._patches = None
self._patches_start = None
def patch(self, obj, attr, return_value=None):
mocked = mock.patch.object(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_registered_hooks(self):
# test that the hooks actually registered the relation expressions that
# are meaningful for this interface: this is to handle regressions.
# The keys are the function names that the hook attaches to.
when_patterns = {
'hsm_connected': ('hsm.connected', ),
def test_hooks(self):
defaults = [
'config.changed',
'update-status']
hook_set = {
'when': {
'hsm_connected': ('hsm.connected', ),
},
'when_not': {
'install_packages': ('charm.installed', ),
}
}
when_not_patterns = {
'install_packages': ('charm.installed', ),
}
# check the when hooks are attached to the expected functions
for t, p in [(_when_args, when_patterns),
(_when_not_args, when_not_patterns)]:
for f, args in t.items():
# check that function is in patterns
# print("f: {}, args: {}".format(f, args))
self.assertTrue(f in p.keys())
# check that the lists are equal
l = [a['args'][0] for a in args]
self.assertEqual(l, sorted(p[f]))
# test that the hooks were registered via the
# reactive.barbican_handlers
self.registered_hooks_test_helper(handlers, hook_set, defaults)
class TestBarbicanHandlers(test_utils.PatchHelper):
def test_install_packages(self):
self.patch(handlers.softhsm, 'install')
self.patch(handlers.reactive, 'set_state')
self.patch_object(handlers.softhsm, 'install')
self.patch_object(handlers.reactive, 'set_state')
handlers.install_packages()
self.install.assert_called_once_with()
self.set_state.assert_called_once_with('charm.installed')
def test_hsm_connected(self):
self.patch(handlers.softhsm, 'on_hsm_connected')
self.patch(handlers.reactive, 'set_state')
self.patch_object(handlers.softhsm, 'on_hsm_connected')
self.patch_object(handlers.reactive, 'set_state')
self.patch_object(handlers.softhsm, 'assess_status')
handlers.hsm_connected('hsm-thing')
self.on_hsm_connected.assert_called_once_with('hsm-thing')
self.set_state.assert_called_once_with('hsm.available')
self.assess_status.assert_called_once_with()

View File

@ -16,53 +16,33 @@ from __future__ import absolute_import
from __future__ import print_function
import textwrap
import unittest
import mock
import charm.openstack.softhsm as softhsm
class Helper(unittest.TestCase):
def setUp(self):
self._patches = {}
self._patches_start = {}
# patch out the select_release to always return 'mitaka'
# self.patch(softhsm.unitdata, 'kv')
# _getter = mock.MagicMock()
# _getter.get.return_value = softhsm.BarbicanSoftHSMCharm.release
# self.kv.return_value = _getter
def tearDown(self):
for k, v in self._patches.items():
v.stop()
setattr(self, k, None)
self._patches = None
self._patches_start = None
def patch(self, obj, attr, return_value=None, **kwargs):
mocked = mock.patch.object(obj, attr, **kwargs)
self._patches[attr] = mocked
started = mocked.start()
started.return_value = return_value
self._patches_start[attr] = started
setattr(self, attr, started)
import charms_openstack.test_utils as test_utils
class TestSoftHSM(Helper):
class TestSoftHSM(test_utils.PatchHelper):
def test_install(self):
self.patch(softhsm.BarbicanSoftHSMCharm.singleton, 'install')
self.patch_object(softhsm.BarbicanSoftHSMCharm.singleton, 'install')
softhsm.install()
self.install.assert_called_once_with()
def test_on_hsm_connected(self):
self.patch(softhsm.BarbicanSoftHSMCharm.singleton,
'on_hsm_connected')
self.patch_object(softhsm.BarbicanSoftHSMCharm.singleton,
'on_hsm_connected')
softhsm.on_hsm_connected('hsm-thing')
self.on_hsm_connected.assert_called_once_with('hsm-thing')
def test_assess_status(self):
self.patch_object(softhsm.BarbicanSoftHSMCharm.singleton,
'assess_status')
softhsm.assess_status()
self.assess_status.assert_called_once_with()
def test_read_pins_from_store(self):
# test with no file (patch open so that it raises an error)
mock_open = mock.MagicMock(return_value=mock.sentinel.file_handle)
@ -84,9 +64,9 @@ class TestSoftHSM(Helper):
def test_write_pins_to_store(self):
f = mock.MagicMock()
self.patch(softhsm.os, 'fdopen', return_value=f)
self.patch(softhsm.os, 'open', return_value='opener')
self.patch(softhsm.json, 'dump')
self.patch_object(softhsm.os, 'fdopen', return_value=f)
self.patch_object(softhsm.os, 'open', return_value='opener')
self.patch_object(softhsm.json, 'dump')
softhsm.write_pins_to_store('1234', '5678')
self.open.assert_called_once_with(
softhsm.STORED_PINS_FILE,
@ -115,23 +95,23 @@ class TestSoftHSM(Helper):
User PIN init.: yes
Label: barbican_token
""")
self.patch(softhsm.subprocess, 'check_output',
return_value=result.encode())
self.patch_object(softhsm.subprocess, 'check_output',
return_value=result.encode())
self.assertEqual(softhsm.read_slot_id('barbican_token'), '5')
self.check_output.assert_called_once_with(
[softhsm.SOFTHSM2_UTIL_CMD, '--show-slots'])
self.assertEqual(softhsm.read_slot_id('not_found'), None)
class TestBarbicanSoftHSMCharm(Helper):
class TestBarbicanSoftHSMCharm(test_utils.PatchHelper):
def test_install(self):
self.patch(softhsm.charms_openstack.charm.OpenStackCharm,
'install')
self.patch(softhsm.ch_core_host, 'add_user_to_group')
self.patch_object(softhsm.charms_openstack.charm.OpenStackCharm,
'install')
self.patch_object(softhsm.ch_core_host, 'add_user_to_group')
c = softhsm.BarbicanSoftHSMCharm()
self.patch(c, 'setup_token_store')
self.patch(softhsm.hookenv, 'status_set')
self.patch_object(c, 'setup_token_store')
self.patch_object(softhsm.hookenv, 'status_set')
c.install()
self.install.assert_called_once_with()
self.add_user_to_group.assert_called_once_with('barbican', 'softhsm')
@ -140,17 +120,17 @@ class TestBarbicanSoftHSMCharm(Helper):
'waiting', 'Charm installed and token store configured')
def test_setup_token_store(self):
self.patch(softhsm, 'read_pins_from_store')
self.patch(softhsm.os.path, 'exists')
self.patch(softhsm.os.path, 'isdir')
self.patch(softhsm.shutil, 'rmtree')
self.patch(softhsm.os, 'remove')
self.patch(softhsm.os, 'makedirs')
self.patch(softhsm.os, 'chmod')
self.patch(softhsm.ch_core_host, 'pwgen')
self.patch(softhsm, 'write_pins_to_store')
self.patch(softhsm.subprocess, 'check_call')
self.patch(softhsm.hookenv, 'log')
self.patch_object(softhsm, 'read_pins_from_store')
self.patch_object(softhsm.os.path, 'exists')
self.patch_object(softhsm.os.path, 'isdir')
self.patch_object(softhsm.shutil, 'rmtree')
self.patch_object(softhsm.os, 'remove')
self.patch_object(softhsm.os, 'makedirs')
self.patch_object(softhsm.os, 'chmod')
self.patch_object(softhsm.ch_core_host, 'pwgen')
self.patch_object(softhsm, 'write_pins_to_store')
self.patch_object(softhsm.subprocess, 'check_call')
self.patch_object(softhsm.hookenv, 'log')
# first, pretend that the token store is already setup.
self.read_pins_from_store.return_value = ('1234', '5678', )
c = softhsm.BarbicanSoftHSMCharm()
@ -183,12 +163,12 @@ class TestBarbicanSoftHSMCharm(Helper):
def test_on_hsm_connected(self):
hsm = mock.MagicMock()
self.patch(softhsm, 'read_pins_from_store')
self.patch(softhsm, 'read_slot_id')
self.patch(softhsm.hookenv, 'status_set')
self.patch(softhsm.hookenv, 'log')
self.patch_object(softhsm, 'read_pins_from_store')
self.patch_object(softhsm, 'read_slot_id')
self.patch_object(softhsm.hookenv, 'status_set')
self.patch_object(softhsm.hookenv, 'log')
c = softhsm.BarbicanSoftHSMCharm()
self.patch(c, 'setup_token_store')
self.patch_object(c, 'setup_token_store')
# simulate not being able to set up the token store
self.read_pins_from_store.return_value = None, None
with self.assertRaises(RuntimeError):