Refactor notifications
I'm replacing the implementation of notifications with the blinker library. In order to do this properly I wanted to have a more defined interface and less coupling in the tests. Test should be unaware of the implementation of the thing they are testing so that the implementation can be changed later. Change-Id: Icdcbf77944187bc9b2b390420862f700baa179c9
This commit is contained in:
parent
e13641f296
commit
135708488e
@ -28,6 +28,7 @@ from pycadf import resource
|
|||||||
from keystone.openstack.common.gettextutils import _
|
from keystone.openstack.common.gettextutils import _
|
||||||
from keystone.openstack.common import log
|
from keystone.openstack.common import log
|
||||||
|
|
||||||
|
|
||||||
notifier_opts = [
|
notifier_opts = [
|
||||||
cfg.StrOpt('default_publisher_id',
|
cfg.StrOpt('default_publisher_id',
|
||||||
default=None,
|
default=None,
|
||||||
@ -39,7 +40,7 @@ LOG = log.getLogger(__name__)
|
|||||||
# a new action is supported.
|
# a new action is supported.
|
||||||
ACTIONS = frozenset(['created', 'deleted', 'disabled', 'updated'])
|
ACTIONS = frozenset(['created', 'deleted', 'disabled', 'updated'])
|
||||||
# resource types that can be notified
|
# resource types that can be notified
|
||||||
SUBSCRIBERS = {}
|
_SUBSCRIBERS = {}
|
||||||
_notifier = None
|
_notifier = None
|
||||||
|
|
||||||
|
|
||||||
@ -129,8 +130,8 @@ def register_event_callback(event, resource_type, callbacks):
|
|||||||
msg = _('Method not callable: %s') % callback
|
msg = _('Method not callable: %s') % callback
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
SUBSCRIBERS.setdefault(event, {}).setdefault(resource_type, set())
|
_SUBSCRIBERS.setdefault(event, {}).setdefault(resource_type, set())
|
||||||
SUBSCRIBERS[event][resource_type].add(callback)
|
_SUBSCRIBERS[event][resource_type].add(callback)
|
||||||
|
|
||||||
if LOG.logger.getEffectiveLevel() <= logging.INFO:
|
if LOG.logger.getEffectiveLevel() <= logging.INFO:
|
||||||
# Do this only if its going to appear in the logs.
|
# Do this only if its going to appear in the logs.
|
||||||
@ -144,9 +145,9 @@ def register_event_callback(event, resource_type, callbacks):
|
|||||||
|
|
||||||
def notify_event_callbacks(service, resource_type, operation, payload):
|
def notify_event_callbacks(service, resource_type, operation, payload):
|
||||||
"""Sends a notification to registered extensions."""
|
"""Sends a notification to registered extensions."""
|
||||||
if operation in SUBSCRIBERS:
|
if operation in _SUBSCRIBERS:
|
||||||
if resource_type in SUBSCRIBERS[operation]:
|
if resource_type in _SUBSCRIBERS[operation]:
|
||||||
for cb in SUBSCRIBERS[operation][resource_type]:
|
for cb in _SUBSCRIBERS[operation][resource_type]:
|
||||||
subst_dict = {'cb_name': cb.__name__,
|
subst_dict = {'cb_name': cb.__name__,
|
||||||
'service': service,
|
'service': service,
|
||||||
'resource_type': resource_type,
|
'resource_type': resource_type,
|
||||||
@ -181,7 +182,11 @@ def _get_notifier():
|
|||||||
return _notifier
|
return _notifier
|
||||||
|
|
||||||
|
|
||||||
def _reset_notifier():
|
def clear_subscribers():
|
||||||
|
_SUBSCRIBERS.clear()
|
||||||
|
|
||||||
|
|
||||||
|
def reset_notifier():
|
||||||
global _notifier
|
global _notifier
|
||||||
_notifier = None
|
_notifier = None
|
||||||
|
|
||||||
@ -199,19 +204,19 @@ def _send_notification(operation, resource_type, resource_id, public=True):
|
|||||||
if False, the event will only be sent via
|
if False, the event will only be sent via
|
||||||
notify_event_callbacks to in process listeners.
|
notify_event_callbacks to in process listeners.
|
||||||
"""
|
"""
|
||||||
context = {}
|
|
||||||
payload = {'resource_info': resource_id}
|
payload = {'resource_info': resource_id}
|
||||||
service = 'identity'
|
service = 'identity'
|
||||||
event_type = '%(service)s.%(resource_type)s.%(operation)s' % {
|
|
||||||
'service': service,
|
|
||||||
'resource_type': resource_type,
|
|
||||||
'operation': operation}
|
|
||||||
|
|
||||||
notify_event_callbacks(service, resource_type, operation, payload)
|
notify_event_callbacks(service, resource_type, operation, payload)
|
||||||
|
|
||||||
if public:
|
if public:
|
||||||
notifier = _get_notifier()
|
notifier = _get_notifier()
|
||||||
if notifier:
|
if notifier:
|
||||||
|
context = {}
|
||||||
|
event_type = '%(service)s.%(resource_type)s.%(operation)s' % {
|
||||||
|
'service': service,
|
||||||
|
'resource_type': resource_type,
|
||||||
|
'operation': operation}
|
||||||
try:
|
try:
|
||||||
notifier.info(context, event_type, payload)
|
notifier.info(context, event_type, payload)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -412,8 +412,8 @@ class TestCase(BaseTestCase):
|
|||||||
self.addCleanup(kvs.INMEMDB.clear)
|
self.addCleanup(kvs.INMEMDB.clear)
|
||||||
|
|
||||||
# Ensure Notification subscriotions and resource types are empty
|
# Ensure Notification subscriotions and resource types are empty
|
||||||
self.addCleanup(notifications.SUBSCRIBERS.clear)
|
self.addCleanup(notifications.clear_subscribers)
|
||||||
self.addCleanup(notifications._reset_notifier)
|
self.addCleanup(notifications.reset_notifier)
|
||||||
|
|
||||||
# Reset the auth-plugin registry
|
# Reset the auth-plugin registry
|
||||||
self.addCleanup(self.clear_auth_plugin_registry)
|
self.addCleanup(self.clear_auth_plugin_registry)
|
||||||
|
@ -363,7 +363,6 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestEventCallbacks, self).setUp()
|
super(TestEventCallbacks, self).setUp()
|
||||||
notifications.SUBSCRIBERS = {}
|
|
||||||
self.has_been_called = False
|
self.has_been_called = False
|
||||||
|
|
||||||
def _project_deleted_callback(self, service, resource_type, operation,
|
def _project_deleted_callback(self, service, resource_type, operation,
|
||||||
@ -382,7 +381,6 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
|
|||||||
|
|
||||||
def test_notification_method_not_callable(self):
|
def test_notification_method_not_callable(self):
|
||||||
fake_method = None
|
fake_method = None
|
||||||
notifications.SUBSCRIBERS = {}
|
|
||||||
self.assertRaises(TypeError,
|
self.assertRaises(TypeError,
|
||||||
notifications.register_event_callback,
|
notifications.register_event_callback,
|
||||||
UPDATED_OPERATION,
|
UPDATED_OPERATION,
|
||||||
@ -406,11 +404,10 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
|
|||||||
notifications.register_event_callback(DELETED_OPERATION,
|
notifications.register_event_callback(DELETED_OPERATION,
|
||||||
resource_type,
|
resource_type,
|
||||||
self._project_deleted_callback)
|
self._project_deleted_callback)
|
||||||
self.assertIn(DELETED_OPERATION, notifications.SUBSCRIBERS)
|
|
||||||
self.assertIn(resource_type,
|
|
||||||
notifications.SUBSCRIBERS[DELETED_OPERATION])
|
|
||||||
|
|
||||||
def test_provider_event_callbacks_subscription(self):
|
def test_provider_event_callbacks_subscription(self):
|
||||||
|
callback_called = []
|
||||||
|
|
||||||
@dependency.provider('foo_api')
|
@dependency.provider('foo_api')
|
||||||
class Foo:
|
class Foo:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -419,11 +416,13 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
|
|||||||
|
|
||||||
def foo_callback(self, service, resource_type, operation,
|
def foo_callback(self, service, resource_type, operation,
|
||||||
payload):
|
payload):
|
||||||
pass
|
callback_called.append(True) # uses callback_called
|
||||||
|
# from the closure
|
||||||
|
|
||||||
notifications.SUBSCRIBERS = {}
|
|
||||||
Foo()
|
Foo()
|
||||||
self.assertIn(CREATED_OPERATION, notifications.SUBSCRIBERS)
|
project_ref = self.new_project_ref(domain_id=self.domain_id)
|
||||||
|
self.assignment_api.create_project(project_ref['id'], project_ref)
|
||||||
|
self.assertEqual([True], callback_called)
|
||||||
|
|
||||||
def test_invalid_event_callbacks(self):
|
def test_invalid_event_callbacks(self):
|
||||||
@dependency.provider('foo_api')
|
@dependency.provider('foo_api')
|
||||||
@ -431,7 +430,6 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.event_callbacks = 'bogus'
|
self.event_callbacks = 'bogus'
|
||||||
|
|
||||||
notifications.SUBSCRIBERS = {}
|
|
||||||
self.assertRaises(ValueError, Foo)
|
self.assertRaises(ValueError, Foo)
|
||||||
|
|
||||||
def test_invalid_event_callbacks_event(self):
|
def test_invalid_event_callbacks_event(self):
|
||||||
@ -440,7 +438,6 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.event_callbacks = {CREATED_OPERATION: 'bogus'}
|
self.event_callbacks = {CREATED_OPERATION: 'bogus'}
|
||||||
|
|
||||||
notifications.SUBSCRIBERS = {}
|
|
||||||
self.assertRaises(ValueError, Foo)
|
self.assertRaises(ValueError, Foo)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user