]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Refactor RESOURCE_ATTRIBUTE_MAP cleanup
authorBrent Eagles <beagles@redhat.com>
Tue, 17 Feb 2015 17:15:25 +0000 (13:45 -0330)
committerBrent Eagles <beagles@redhat.com>
Wed, 22 Apr 2015 14:32:34 +0000 (12:02 -0230)
This patch adds a AttributeMapMemento class that can be used for
restoring the RESOURCE_ATTRIBUTE_MAP on test tear down. Tests containing
their own cleanup code have been modified to use it instead.

Change-Id: I7ce5182bdfb8f541741a327feada63a29ddac2ae

12 files changed:
neutron/tests/functional/api/test_policies.py
neutron/tests/tools.py
neutron/tests/unit/api/v2/test_base.py
neutron/tests/unit/db/test_db_base_plugin_v2.py
neutron/tests/unit/extensions/base.py
neutron/tests/unit/extensions/test_agent.py
neutron/tests/unit/extensions/test_providernet.py
neutron/tests/unit/extensions/test_quotasv2.py
neutron/tests/unit/plugins/cisco/n1kv/test_n1kv_plugin.py
neutron/tests/unit/plugins/ml2/test_security_group.py
neutron/tests/unit/plugins/oneconvergence/test_security_group.py
neutron/tests/unit/plugins/openvswitch/test_agent_scheduler.py

index c9d4a99dcd848c1bc72e3613ced6b5ac2f1805bd..c73400a269f9bb0f0e8d0ef618f307ce8c1cce8a 100644 (file)
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import copy
 import os.path
 
 from neutron import context
@@ -23,6 +22,7 @@ from neutron.api import extensions
 from neutron.api.v2 import attributes
 
 from neutron.tests import base
+from neutron.tests import tools
 
 TEST_PATH = os.path.dirname(os.path.abspath(__file__))
 
@@ -40,8 +40,7 @@ class APIPolicyTestCase(base.BaseTestCase):
 
     def setUp(self):
         super(APIPolicyTestCase, self).setUp()
-
-        self.ATTRIBUTE_MAP_COPY = copy.copy(attributes.RESOURCE_ATTRIBUTE_MAP)
+        self.useFixture(tools.AttributeMapMemento())
         self.extension_path = os.path.abspath(os.path.join(
             TEST_PATH, "../../../extensions"))
         policy.reset()
@@ -94,6 +93,5 @@ class APIPolicyTestCase(base.BaseTestCase):
                          True)
 
     def tearDown(self):
-        if self.ATTRIBUTE_MAP_COPY:
-            attributes.RESOURCE_ATTRIBUTE_MAP = self.ATTRIBUTE_MAP_COPY
+        policy.reset()
         super(APIPolicyTestCase, self).tearDown()
index 16aa49680536490cccfa3c0f480f31a4d04dc159..449dd574ae5870a3204b24df2de14ac554bbb2f7 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
+
+from neutron.api.v2 import attributes
+
+
+class AttributeMapMemento(fixtures.Fixture):
+    """Create a copy of the resource attribute map so it can be restored during
+    test cleanup.
+
+    There are a few reasons why this is not included in a class derived
+    from BaseTestCase:
+
+        - Test cases may need more control about when the backup is
+        made, especially if they are not direct descendants of
+        BaseTestCase.
+
+        - Inheritance is a bit of overkill for this facility and it's a
+        stretch to rationalize the "is a" criteria.
+    """
+    def setUp(self):
+        # Shallow copy is not a proper choice for keeping a backup copy as
+        # the RESOURCE_ATTRIBUTE_MAP map is modified in place through the
+        # 0th level keys. Ideally deepcopy() would be used but this seems
+        # to result in test failures. A compromise is to copy one level
+        # deeper than a shallow copy.
+        super(AttributeMapMemento, self).setUp()
+        self.contents_backup = {}
+        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
+            self.contents_backup[resource] = attrs.copy()
+        self.addCleanup(self.restore)
+
+    def restore(self):
+        attributes.RESOURCE_ATTRIBUTE_MAP = self.contents_backup
+
 
 """setup_mock_calls and verify_mock_calls are convenient methods
 to setup a sequence of mock calls.
index 6630781fe11dc1a5beacae74a14323071ef32ee2..fb7828b7b3e869c6b14f85f79bda75494d5303de 100644 (file)
@@ -37,6 +37,7 @@ from neutron import policy
 from neutron import quota
 from neutron.tests import base
 from neutron.tests import fake_notifier
+from neutron.tests import tools
 from neutron.tests.unit import testlib_api
 
 
@@ -1106,10 +1107,7 @@ class SubresourceTest(base.BaseTestCase):
         plugin = 'neutron.tests.unit.api.v2.test_base.TestSubresourcePlugin'
         extensions.PluginAwareExtensionManager._instance = None
 
-        # Save the global RESOURCE_ATTRIBUTE_MAP
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
 
         self.config_parse()
         self.setup_coreplugin(plugin)
@@ -1136,8 +1134,6 @@ class SubresourceTest(base.BaseTestCase):
 
     def tearDown(self):
         router.SUB_RESOURCES = {}
-        # Restore the global RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
         super(SubresourceTest, self).tearDown()
 
     def test_index_sub_resource(self):
@@ -1382,10 +1378,7 @@ class ExtensionTestCase(base.BaseTestCase):
         # Ensure existing ExtensionManager is not used
         extensions.PluginAwareExtensionManager._instance = None
 
-        # Save the global RESOURCE_ATTRIBUTE_MAP
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
 
         # Create the default configurations
         self.config_parse()
@@ -1412,8 +1405,6 @@ class ExtensionTestCase(base.BaseTestCase):
         super(ExtensionTestCase, self).tearDown()
         self.api = None
         self.plugin = None
-        # Restore the global RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
 
     def test_extended_create(self):
         net_id = _uuid()
index e8ef97e8fdb353e6dc107a49f152ed9e2462c57e..e262887af8322ed26e5022d2560ced9c41de9a6a 100644 (file)
@@ -41,6 +41,7 @@ from neutron.db import db_base_plugin_v2
 from neutron.db import models_v2
 from neutron import manager
 from neutron.tests import base
+from neutron.tests import tools
 from neutron.tests.unit.api import test_extensions
 from neutron.tests.unit import testlib_api
 
@@ -93,14 +94,7 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase):
         extensions.PluginAwareExtensionManager._instance = None
         # Save the attributes map in case the plugin will alter it
         # loading extensions
-        # Note(salvatore-orlando): shallow copy is not good enough in
-        # this case, but copy.deepcopy does not seem to work, since it
-        # causes test failures
-        self._attribute_map_bk = {}
-        for item in attributes.RESOURCE_ATTRIBUTE_MAP:
-            self._attribute_map_bk[item] = (attributes.
-                                            RESOURCE_ATTRIBUTE_MAP[item].
-                                            copy())
+        self.useFixture(tools.AttributeMapMemento())
         self._tenant_id = 'test-tenant'
 
         if not plugin:
@@ -162,8 +156,6 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase):
         self._skip_native_pagination = None
         self._skip_native_sortin = None
         self.ext_api = None
-        # Restore the original attribute map
-        attributes.RESOURCE_ATTRIBUTE_MAP = self._attribute_map_bk
         super(NeutronDbPluginV2TestCase, self).tearDown()
 
     def setup_config(self):
index 2fa03024e861efd9f4b8ba6def83a164dc5e9728..a4d0206918c70f2437eb9bb39feea2acc9bf847d 100644 (file)
@@ -26,14 +26,13 @@ import webtest
 from neutron.api import extensions
 from neutron.api.v2 import attributes
 from neutron import quota
+from neutron.tests import tools
 from neutron.tests.unit.api import test_extensions
 from neutron.tests.unit.api.v2 import test_base
 from neutron.tests.unit import testlib_api
 
 
 class ExtensionTestCase(testlib_api.WebTestCase):
-    def _resotre_attr_map(self):
-        attributes.RESOURCE_ATTRIBUTE_MAP = self._saved_attr_map
 
     def _setUpExtension(self, plugin, service_type,
                         resource_attribute_map, extension_class,
@@ -51,10 +50,7 @@ class ExtensionTestCase(testlib_api.WebTestCase):
         # Ensure existing ExtensionManager is not used
         extensions.PluginAwareExtensionManager._instance = None
 
-        # Save the global RESOURCE_ATTRIBUTE_MAP
-        self._saved_attr_map = attributes.RESOURCE_ATTRIBUTE_MAP.copy()
-        # Restore the global RESOURCE_ATTRIBUTE_MAP
-        self.addCleanup(self._resotre_attr_map)
+        self.useFixture(tools.AttributeMapMemento())
 
         # Create the default configurations
         self.config_parse()
index f3bcb5c34556705d8a22e0346b24e37a75f36591..39e48e98e95c699275c4f615cc308698853b8c91 100644 (file)
@@ -29,6 +29,7 @@ from neutron.db import agents_db
 from neutron.db import db_base_plugin_v2
 from neutron.extensions import agent
 from neutron.openstack.common import uuidutils
+from neutron.tests import tools
 from neutron.tests.unit.api.v2 import test_base
 from neutron.tests.unit.db import test_db_base_plugin_v2
 
@@ -187,19 +188,11 @@ class AgentDBTestCase(AgentDBTestMixIn,
         plugin = 'neutron.tests.unit.extensions.test_agent.TestAgentPlugin'
         # for these tests we need to enable overlapping ips
         cfg.CONF.set_default('allow_overlapping_ips', True)
-        # Save the original RESOURCE_ATTRIBUTE_MAP
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
         ext_mgr = AgentTestExtensionManager()
-        self.addCleanup(self.restore_resource_attribute_map)
         super(AgentDBTestCase, self).setUp(plugin=plugin, ext_mgr=ext_mgr)
         self.adminContext = context.get_admin_context()
 
-    def restore_resource_attribute_map(self):
-        # Restore the originak RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
-
     def test_create_agent(self):
         data = {'agent': {}}
         _req = self.new_create_request('agents', data, self.fmt)
index a1645e21feffecf9afff5a8e6035aae3575e816d..d17f93909a73fb152c955837a4bce2d05ca0bae6 100644 (file)
@@ -19,13 +19,13 @@ from webob import exc as web_exc
 import webtest
 
 from neutron.api import extensions
-from neutron.api.v2 import attributes
 from neutron.api.v2 import router
 from neutron import context
 from neutron.extensions import providernet as pnet
 from neutron import manager
 from neutron.openstack.common import uuidutils
 from neutron import quota
+from neutron.tests import tools
 from neutron.tests.unit.api import test_extensions
 from neutron.tests.unit.api.v2 import test_base
 from neutron.tests.unit import testlib_api
@@ -57,10 +57,7 @@ class ProvidernetExtensionTestCase(testlib_api.WebTestCase):
         # Ensure existing ExtensionManager is not used
         extensions.PluginAwareExtensionManager._instance = None
 
-        # Save the global RESOURCE_ATTRIBUTE_MAP
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
 
         # Update the plugin and extensions path
         self.setup_coreplugin(plugin)
@@ -77,17 +74,12 @@ class ProvidernetExtensionTestCase(testlib_api.WebTestCase):
         ext_mgr = ProviderExtensionManager()
         self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
         self.addCleanup(self._plugin_patcher.stop)
-        self.addCleanup(self._restore_attribute_map)
         self.api = webtest.TestApp(router.APIRouter())
 
         quota.QUOTAS._driver = None
         cfg.CONF.set_override('quota_driver', 'neutron.quota.ConfDriver',
                               group='QUOTAS')
 
-    def _restore_attribute_map(self):
-        # Restore the global RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
-
     def _prepare_net_data(self):
         return {'name': 'net1',
                 pnet.NETWORK_TYPE: 'sometype',
index 349706b5580639bb1604ff6a232fc5d29ee14031..af87c4a76992005957478c3e1ed383a2602b14d4 100644 (file)
@@ -22,7 +22,6 @@ from webob import exc
 import webtest
 
 from neutron.api import extensions
-from neutron.api.v2 import attributes
 from neutron.common import config
 from neutron.common import constants
 from neutron.common import exceptions
@@ -30,6 +29,7 @@ from neutron import context
 from neutron.db import quota_db
 from neutron import quota
 from neutron.tests import base
+from neutron.tests import tools
 from neutron.tests.unit.api.v2 import test_base
 from neutron.tests.unit import testlib_api
 
@@ -45,10 +45,7 @@ class QuotaExtensionTestCase(testlib_api.WebTestCase):
         # Ensure existing ExtensionManager is not used
         extensions.PluginAwareExtensionManager._instance = None
 
-        # Save the global RESOURCE_ATTRIBUTE_MAP
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
 
         # Create the default configurations
         self.config_parse()
@@ -75,8 +72,6 @@ class QuotaExtensionTestCase(testlib_api.WebTestCase):
     def tearDown(self):
         self.api = None
         self.plugin = None
-        # Restore the global RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
         super(QuotaExtensionTestCase, self).tearDown()
 
     def _test_quota_default_values(self, expected_values):
index b388e083fc9f935ce5d4391ba39f7840195d8571..787f0345d9bb3a6b3af828e018b5443716e41d57 100644 (file)
@@ -33,6 +33,7 @@ from neutron.plugins.cisco.extensions import network_profile
 from neutron.plugins.cisco.extensions import policy_profile
 from neutron.plugins.cisco.n1kv import n1kv_client
 from neutron.plugins.cisco.n1kv import n1kv_neutron_plugin
+from neutron.tests import tools
 from neutron.tests.unit import _test_extension_portbindings as test_bindings
 from neutron.tests.unit.api.v2 import test_base
 from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
@@ -225,26 +226,18 @@ class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
 
         neutron_extensions.append_api_extensions_path(extensions.__path__)
 
-        # Save the original RESOURCE_ATTRIBUTE_MAP
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.items():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
         # Update the RESOURCE_ATTRIBUTE_MAP with n1kv specific extended attrs.
         attributes.RESOURCE_ATTRIBUTE_MAP["networks"].update(
             n1kv.EXTENDED_ATTRIBUTES_2_0["networks"])
         attributes.RESOURCE_ATTRIBUTE_MAP["ports"].update(
             n1kv.EXTENDED_ATTRIBUTES_2_0["ports"])
-        self.addCleanup(self.restore_resource_attribute_map)
         super(N1kvPluginTestCase, self).setUp(self._plugin_name,
                                               ext_mgr=ext_mgr)
         # Create some of the database entries that we require.
         self._make_test_profile()
         self._make_test_policy_profile()
 
-    def restore_resource_attribute_map(self):
-        # Restore the original RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
-
 
 class TestN1kvNetworkProfiles(N1kvPluginTestCase):
     def _prepare_net_profile_data(self,
index 6b1c3d016954c1006723b1096310501c9acfd9fb..75f2a41089b952e6536a1b48f53da681d29cf6d5 100644 (file)
@@ -18,10 +18,10 @@ import contextlib
 import math
 import mock
 
-from neutron.api.v2 import attributes
 from neutron.common import constants as const
 from neutron.extensions import securitygroup as ext_sg
 from neutron import manager
+from neutron.tests import tools
 from neutron.tests.unit.agent import test_securitygroups_rpc as test_sg_rpc
 from neutron.tests.unit.api.v2 import test_base
 from neutron.tests.unit.extensions import test_securitygroup as test_sg
@@ -39,16 +39,11 @@ class Ml2SecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase):
         notifier_cls = notifier_p.start()
         self.notifier = mock.Mock()
         notifier_cls.return_value = self.notifier
-        self._attribute_map_bk_ = {}
-        for item in attributes.RESOURCE_ATTRIBUTE_MAP:
-            self._attribute_map_bk_[item] = (attributes.
-                                             RESOURCE_ATTRIBUTE_MAP[item].
-                                             copy())
+        self.useFixture(tools.AttributeMapMemento())
         super(Ml2SecurityGroupsTestCase, self).setUp(PLUGIN_NAME)
 
     def tearDown(self):
         super(Ml2SecurityGroupsTestCase, self).tearDown()
-        attributes.RESOURCE_ATTRIBUTE_MAP = self._attribute_map_bk_
 
 
 class TestMl2SecurityGroups(Ml2SecurityGroupsTestCase,
index 9820f9cfdf36c1598f55836071717d6962690b95..dcde1915a9b67ae298f55453cd58274811694e95 100644 (file)
@@ -16,10 +16,10 @@ import uuid
 
 import mock
 
-from neutron.api.v2 import attributes
 from neutron.extensions import securitygroup as ext_sg
 from neutron import manager
 from neutron.plugins.oneconvergence import plugin as nvsd_plugin
+from neutron.tests import tools
 from neutron.tests.unit.agent import test_securitygroups_rpc as test_sg_rpc
 from neutron.tests.unit.extensions import test_securitygroup as test_sg
 
@@ -49,11 +49,7 @@ class OneConvergenceSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase):
         notifier_cls = mock.patch(AGENTNOTIFIER).start()
         self.notifier = mock.Mock()
         notifier_cls.return_value = self.notifier
-        self._attribute_map_bk_ = {}
-        for item in attributes.RESOURCE_ATTRIBUTE_MAP:
-            self._attribute_map_bk_[item] = (attributes.
-                                             RESOURCE_ATTRIBUTE_MAP[item].
-                                             copy())
+        self.useFixture(tools.AttributeMapMemento())
         with mock.patch.object(nvsd_plugin.OneConvergencePluginV2,
                                'oneconvergence_init',
                                new=mocked_oneconvergence_init):
@@ -62,7 +58,6 @@ class OneConvergenceSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase):
 
     def tearDown(self):
         super(OneConvergenceSecurityGroupsTestCase, self).tearDown()
-        attributes.RESOURCE_ATTRIBUTE_MAP = self._attribute_map_bk_
 
 
 class TestOneConvergenceSGServerRpcCallBack(
index 6a21e3b2d71814dcf79bbdf5f61f029df9af3dba..20be55287ac8de39378bae69981ae9375fdb01ee 100644 (file)
@@ -41,6 +41,7 @@ from neutron import manager
 from neutron.openstack.common import uuidutils
 from neutron.plugins.common import constants as service_constants
 from neutron.tests import fake_notifier
+from neutron.tests import tools
 from neutron.tests.unit.api import test_extensions
 from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
 from neutron.tests.unit.extensions import test_agent
@@ -245,10 +246,7 @@ class OvsAgentSchedulerTestCaseBase(test_l3.L3NatTestCaseMixin,
                  'TestL3NatAgentSchedulingServicePlugin')
 
     def setUp(self):
-        # Save the global RESOURCE_ATTRIBUTE_MAP before loading plugin
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
         if self.l3_plugin:
             service_plugins = {'l3_plugin_name': self.l3_plugin}
         else:
@@ -264,7 +262,6 @@ class OvsAgentSchedulerTestCaseBase(test_l3.L3NatTestCaseMixin,
         # the global attribute map
         attributes.RESOURCE_ATTRIBUTE_MAP.update(
             agent.RESOURCE_ATTRIBUTE_MAP)
-        self.addCleanup(self.restore_attribute_map)
         self.l3agentscheduler_dbMinxin = (
             manager.NeutronManager.get_service_plugins().get(
                 service_constants.L3_ROUTER_NAT))
@@ -279,10 +276,6 @@ class OvsAgentSchedulerTestCaseBase(test_l3.L3NatTestCaseMixin,
             'neutron.extensions.dhcpagentscheduler.notify')
         self.patched_dhcp_notify = self.dhcp_notify_p.start()
 
-    def restore_attribute_map(self):
-        # Restore the original RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
-
 
 class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase):
 
@@ -1307,10 +1300,7 @@ class OvsDhcpAgentNotifierTestCase(test_l3.L3NatTestCaseMixin,
     plugin_str = 'neutron.plugins.ml2.plugin.Ml2Plugin'
 
     def setUp(self):
-        # Save the global RESOURCE_ATTRIBUTE_MAP before loading plugin
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+        self.useFixture(tools.AttributeMapMemento())
         super(OvsDhcpAgentNotifierTestCase, self).setUp(self.plugin_str)
         self.dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
         self.dhcp_notifier_cast = mock.patch(
@@ -1325,13 +1315,8 @@ class OvsDhcpAgentNotifierTestCase(test_l3.L3NatTestCaseMixin,
         # the global attribute map
         attributes.RESOURCE_ATTRIBUTE_MAP.update(
             agent.RESOURCE_ATTRIBUTE_MAP)
-        self.addCleanup(self.restore_attribute_map)
         fake_notifier.reset()
 
-    def restore_attribute_map(self):
-        # Restore the original RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
-
     def test_network_add_to_dhcp_agent_notification(self):
         with self.network() as net1:
             network_id = net1['network']['id']
@@ -1474,10 +1459,9 @@ class OvsL3AgentNotifierTestCase(test_l3.L3NatTestCaseMixin,
         self.dhcp_notifier = mock.Mock(name='dhcp_notifier')
         self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
         self.dhcp_notifier_cls.return_value = self.dhcp_notifier
-        # Save the global RESOURCE_ATTRIBUTE_MAP
-        self.saved_attr_map = {}
-        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
-            self.saved_attr_map[resource] = attrs.copy()
+
+        self.useFixture(tools.AttributeMapMemento())
+
         if self.l3_plugin:
             service_plugins = {'l3_plugin_name': self.l3_plugin}
         else:
@@ -1493,13 +1477,8 @@ class OvsL3AgentNotifierTestCase(test_l3.L3NatTestCaseMixin,
         # the global attribute map
         attributes.RESOURCE_ATTRIBUTE_MAP.update(
             agent.RESOURCE_ATTRIBUTE_MAP)
-        self.addCleanup(self.restore_attribute_map)
         fake_notifier.reset()
 
-    def restore_attribute_map(self):
-        # Restore the original RESOURCE_ATTRIBUTE_MAP
-        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
-
     def test_router_add_to_l3_agent_notification(self):
         l3_plugin = (manager.NeutronManager.get_service_plugins()
                      [service_constants.L3_ROUTER_NAT])