# Copyright 2013 eNovance # # 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. from oslo_utils import timeutils import testscenarios import oslo_messaging from oslo_messaging.notify import dispatcher as notify_dispatcher from oslo_messaging.tests import utils as test_utils from unittest import mock load_tests = testscenarios.load_tests_apply_scenarios notification_msg = dict( publisher_id="publisher_id", event_type="compute.start", payload={"info": "fuu"}, message_id="uuid", timestamp=str(timeutils.utcnow()) ) class TestDispatcher(test_utils.BaseTestCase): scenarios = [ ('no_endpoints', dict(endpoints=[], endpoints_expect_calls=[], priority='info', ex=None, return_value=oslo_messaging.NotificationResult.HANDLED)), ('one_endpoints', dict(endpoints=[['warn']], endpoints_expect_calls=['warn'], priority='warn', ex=None, return_value=oslo_messaging.NotificationResult.HANDLED)), ('two_endpoints_only_one_match', dict(endpoints=[['warn'], ['info']], endpoints_expect_calls=[None, 'info'], priority='info', ex=None, return_value=oslo_messaging.NotificationResult.HANDLED)), ('two_endpoints_both_match', dict(endpoints=[['debug', 'info'], ['info', 'debug']], endpoints_expect_calls=['debug', 'debug'], priority='debug', ex=None, return_value=oslo_messaging.NotificationResult.HANDLED)), ('no_return_value', dict(endpoints=[['warn']], endpoints_expect_calls=['warn'], priority='warn', ex=None, return_value=None)), ('requeue', dict(endpoints=[['debug', 'warn']], endpoints_expect_calls=['debug'], priority='debug', msg=notification_msg, ex=None, return_value=oslo_messaging.NotificationResult.REQUEUE)), ('exception', dict(endpoints=[['debug', 'warn']], endpoints_expect_calls=['debug'], priority='debug', msg=notification_msg, ex=Exception, return_value=oslo_messaging.NotificationResult.HANDLED)), ] def test_dispatcher(self): endpoints = [] for endpoint_methods in self.endpoints: e = mock.Mock(spec=endpoint_methods) endpoints.append(e) for m in endpoint_methods: method = getattr(e, m) if self.ex: method.side_effect = self.ex() else: method.return_value = self.return_value msg = notification_msg.copy() msg['priority'] = self.priority dispatcher = notify_dispatcher.NotificationDispatcher(endpoints, None) incoming = mock.Mock(ctxt={}, message=msg) res = dispatcher.dispatch(incoming) expected_res = ( notify_dispatcher.NotificationResult.REQUEUE if (self.return_value == notify_dispatcher.NotificationResult.REQUEUE or self.ex is not None) else notify_dispatcher.NotificationResult.HANDLED ) self.assertEqual(expected_res, res) # check endpoint callbacks are called or not for i, endpoint_methods in enumerate(self.endpoints): for m in endpoint_methods: if m == self.endpoints_expect_calls[i]: method = getattr(endpoints[i], m) method.assert_called_once_with( {}, msg['publisher_id'], msg['event_type'], msg['payload'], { 'timestamp': mock.ANY, 'message_id': mock.ANY }) else: self.assertEqual(0, endpoints[i].call_count) @mock.patch('oslo_messaging.notify.dispatcher.LOG') def test_dispatcher_unknown_prio(self, mylog): msg = notification_msg.copy() msg['priority'] = 'what???' dispatcher = notify_dispatcher.NotificationDispatcher( [mock.Mock()], None) res = dispatcher.dispatch(mock.Mock(ctxt={}, message=msg)) self.assertIsNone(res) mylog.warning.assert_called_once_with('Unknown priority "%s"', 'what???') class TestDispatcherFilter(test_utils.BaseTestCase): scenarios = [ ('publisher_id_match', dict(filter_rule=dict(publisher_id='^compute.*'), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=True)), ('publisher_id_nomatch', dict(filter_rule=dict(publisher_id='^compute.*'), publisher_id='network01.manager', event_type='instance.create.start', context={}, match=False)), ('event_type_match', dict(filter_rule=dict(event_type=r'^instance\.create'), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=True)), ('event_type_nomatch', dict(filter_rule=dict(event_type=r'^instance\.delete'), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=False)), # this is only for simulation ('event_type_not_string', dict(filter_rule=dict(event_type=r'^instance\.delete'), publisher_id='compute01.manager', event_type=['instance.swim', 'instance.fly'], context={}, match=False)), ('context_match', dict(filter_rule=dict(context={'user': '^adm'}), publisher_id='compute01.manager', event_type='instance.create.start', context={'user': 'admin'}, match=True)), ('context_key_missing', dict(filter_rule=dict(context={'user': '^adm'}), publisher_id='compute01.manager', event_type='instance.create.start', context={'project': 'admin'}, metadata={}, match=False)), ('metadata_match', dict(filter_rule=dict(metadata={'message_id': '^99'}), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=True)), ('metadata_key_missing', dict(filter_rule=dict(metadata={'user': '^adm'}), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=False)), ('payload_match', dict(filter_rule=dict(payload={'state': '^active$'}), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=True)), ('payload_no_match', dict(filter_rule=dict(payload={'state': '^deleted$'}), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=False)), ('payload_key_missing', dict(filter_rule=dict(payload={'user': '^adm'}), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=False)), ('payload_value_none', dict(filter_rule=dict(payload={'virtual_size': '2048'}), publisher_id='compute01.manager', event_type='instance.create.start', context={}, match=False)), ('mix_match', dict(filter_rule=dict(event_type=r'^instance\.create', publisher_id='^compute', context={'user': '^adm'}), publisher_id='compute01.manager', event_type='instance.create.start', context={'user': 'admin'}, match=True)), ] def test_filters(self): notification_filter = oslo_messaging.NotificationFilter( **self.filter_rule) endpoint = mock.Mock(spec=['info'], filter_rule=notification_filter) dispatcher = notify_dispatcher.NotificationDispatcher( [endpoint], serializer=None) message = {'payload': {'state': 'active', 'virtual_size': None}, 'priority': 'info', 'publisher_id': self.publisher_id, 'event_type': self.event_type, 'timestamp': '2014-03-03 18:21:04.369234', 'message_id': '99863dda-97f0-443a-a0c1-6ed317b7fd45'} incoming = mock.Mock(ctxt=self.context, message=message) dispatcher.dispatch(incoming) if self.match: self.assertEqual(1, endpoint.info.call_count) else: self.assertEqual(0, endpoint.info.call_count)