Make callback manager Object Oriented friendly
The callback manager was indexing callbacks based on a callback ID generated from oslo utils reflection. This presented two problems. The first was that in py34 get_callable_name would use __qualname__ which returns the class name the function is defined on rather than the class of the object itself. So two classes defined in the same module inheriting from the same parent class could not both subscribe a method defined on the parent. The second more general problem is that two objects which are instances of the same class cannot subscribe the same method because they have the same ID. This adds the hash of the method to the ID to prevent these issues. The hash by itself could have been used but it's not very user-friendly so the name is left on for nice log messages. Change-Id: Iff1ca8c4ddb58ca5907d21fa0de7f0f292b6fc0e
This commit is contained in:
parent
a915f2b690
commit
4d85336ec1
|
@ -166,4 +166,6 @@ def _get_id(callback):
|
|||
# TODO(armax): consider using something other than names
|
||||
# https://www.python.org/dev/peps/pep-3155/, but this
|
||||
# might be okay for now.
|
||||
return reflection.get_callable_name(callback)
|
||||
parts = (reflection.get_callable_name(callback),
|
||||
str(hash(callback)))
|
||||
return '-'.join(parts)
|
||||
|
|
|
@ -22,6 +22,19 @@ from neutron.callbacks import resources
|
|||
from neutron.tests import base
|
||||
|
||||
|
||||
class ObjectWithCallback(object):
|
||||
|
||||
def __init__(self):
|
||||
self.counter = 0
|
||||
|
||||
def callback(self, *args, **kwargs):
|
||||
self.counter += 1
|
||||
|
||||
|
||||
class GloriousObjectWithCallback(ObjectWithCallback):
|
||||
pass
|
||||
|
||||
|
||||
def callback_1(*args, **kwargs):
|
||||
callback_1.counter += 1
|
||||
callback_id_1 = manager._get_id(callback_1)
|
||||
|
@ -214,3 +227,19 @@ class CallBacksManagerTestCase(base.BaseTestCase):
|
|||
resources.ROUTER, events.BEFORE_DELETE, mock.ANY)
|
||||
self.assertEqual(2, callback_1.counter)
|
||||
self.assertEqual(1, callback_2.counter)
|
||||
|
||||
def test_object_instances_as_subscribers(self):
|
||||
"""Ensures that the manager doesn't think these are equivalent."""
|
||||
a = GloriousObjectWithCallback()
|
||||
b = ObjectWithCallback()
|
||||
c = ObjectWithCallback()
|
||||
for o in (a, b, c):
|
||||
self.manager.subscribe(
|
||||
o.callback, resources.PORT, events.BEFORE_CREATE)
|
||||
# ensure idempotency remains for a single object
|
||||
self.manager.subscribe(
|
||||
o.callback, resources.PORT, events.BEFORE_CREATE)
|
||||
self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
|
||||
self.assertEqual(1, a.counter)
|
||||
self.assertEqual(1, b.counter)
|
||||
self.assertEqual(1, c.counter)
|
||||
|
|
|
@ -24,7 +24,6 @@ from oslo_utils import uuidutils
|
|||
from webob import exc
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
||||
from neutron.api.rpc.handlers import dhcp_rpc
|
||||
from neutron.api.rpc.handlers import l3_rpc
|
||||
|
@ -1301,7 +1300,8 @@ class OvsDhcpAgentNotifierTestCase(test_agent.AgentDBTestMixIn,
|
|||
mock.patch.object(
|
||||
self.plugin, 'filter_hosts_with_network_access',
|
||||
side_effect=lambda context, network_id, hosts: hosts).start()
|
||||
self.dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
self.dhcp_notifier = plugin.agent_notifiers[constants.AGENT_TYPE_DHCP]
|
||||
self.dhcp_notifier_cast = mock.patch(
|
||||
'neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.'
|
||||
'DhcpAgentNotifyAPI._cast_message').start()
|
||||
|
|
Loading…
Reference in New Issue