Merge "Introduce new helper: call_and_ignore_notfound_exc()"
diff --git a/releasenotes/notes/new-test-utils-module-adf34468c4d52719.yaml b/releasenotes/notes/new-test-utils-module-adf34468c4d52719.yaml
new file mode 100644
index 0000000..55df2b3
--- /dev/null
+++ b/releasenotes/notes/new-test-utils-module-adf34468c4d52719.yaml
@@ -0,0 +1,11 @@
+---
+features:
+  - A new `test_utils` module has been added to tempest.lib.common.utils. It
+    should hold any common utility functions that help writing Tempest tests.
+  - A new utility function called `call_and_ignore_notfound_exc` has been
+    added to the `test_utils` module. That function call another function
+    passed as parameter and ignore the NotFound exception if it raised.
+deprecations:
+  - tempest.lib.common.utils.misc.find_test_caller has been moved into the
+    tempest.lib.common.utils.test_utils module. Calling the find_test_caller
+    function with its old location is deprecated.
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 671b139..4f48ad0 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -16,7 +16,7 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 from tempest import test
 
 LOG = log.getLogger(__name__)
@@ -41,9 +41,8 @@
 
     def tearDown(self):
         try:
-            self.client.delete_agent(self.agent_id)
-        except lib_exc.NotFound:
-            pass
+            test_utils.call_and_ignore_notfound_exc(
+                self.client.delete_agent, self.agent_id)
         except Exception:
             LOG.exception('Exception raised deleting agent %s', self.agent_id)
         super(AgentsAdminTestJSON, self).tearDown()
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index a2b1e2f..25efd2e 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -16,7 +16,7 @@
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 from tempest import test
 
 
@@ -41,21 +41,14 @@
                     filter(lambda y: y['service'] == 'compute', hosts_all))
         cls.host = hosts[0]
 
-    def _try_delete_aggregate(self, aggregate_id):
-        # delete aggregate, if it exists
-        try:
-            self.client.delete_aggregate(aggregate_id)
-        # if aggregate not found, it depict it was deleted in the test
-        except lib_exc.NotFound:
-            pass
-
     @test.idempotent_id('0d148aa3-d54c-4317-aa8d-42040a475e20')
     def test_aggregate_create_delete(self):
         # Create and delete an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         aggregate = (self.client.create_aggregate(name=aggregate_name)
                      ['aggregate'])
-        self.addCleanup(self._try_delete_aggregate, aggregate['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.client.delete_aggregate, aggregate['id'])
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertIsNone(aggregate['availability_zone'])
 
@@ -69,7 +62,8 @@
         az_name = data_utils.rand_name(self.az_name_prefix)
         aggregate = self.client.create_aggregate(
             name=aggregate_name, availability_zone=az_name)['aggregate']
-        self.addCleanup(self._try_delete_aggregate, aggregate['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.client.delete_aggregate, aggregate['id'])
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertEqual(az_name, aggregate['availability_zone'])
 
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 77ed7cd..37aa5ac 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -24,6 +24,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import api_version_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 import tempest.test
 
@@ -134,11 +135,8 @@
             server['id'] for server in cls.servers))
         for server in cls.servers:
             try:
-                cls.servers_client.delete_server(server['id'])
-            except lib_exc.NotFound:
-                # Something else already cleaned up the server, nothing to be
-                # worried about
-                pass
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.servers_client.delete_server, server['id'])
             except Exception:
                 LOG.exception('Deleting server %s failed' % server['id'])
 
@@ -177,10 +175,8 @@
         LOG.debug('Clearing images: %s', ','.join(cls.images))
         for image_id in cls.images:
             try:
-                cls.compute_images_client.delete_image(image_id)
-            except lib_exc.NotFound:
-                # The image may have already been deleted which is OK.
-                pass
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.compute_images_client.delete_image, image_id)
             except Exception:
                 LOG.exception('Exception raised deleting image %s' % image_id)
 
@@ -190,10 +186,8 @@
             str(sg['id']) for sg in cls.security_groups))
         for sg in cls.security_groups:
             try:
-                cls.security_groups_client.delete_security_group(sg['id'])
-            except lib_exc.NotFound:
-                # The security group may have already been deleted which is OK.
-                pass
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.security_groups_client.delete_security_group, sg['id'])
             except Exception as exc:
                 LOG.info('Exception raised deleting security group %s',
                          sg['id'])
@@ -204,10 +198,10 @@
         LOG.debug('Clearing server groups: %s', ','.join(cls.server_groups))
         for server_group_id in cls.server_groups:
             try:
-                cls.server_groups_client.delete_server_group(server_group_id)
-            except lib_exc.NotFound:
-                # The server-group may have already been deleted which is OK.
-                pass
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.server_groups_client.delete_server_group,
+                    server_group_id
+                )
             except Exception:
                 LOG.exception('Exception raised deleting server-group %s',
                               server_group_id)
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index 3d7f4f8..3508ba9 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -17,6 +17,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -53,14 +54,6 @@
             cls.client.delete_floating_ip(cls.floating_ip_id)
         super(FloatingIPsTestJSON, cls).resource_cleanup()
 
-    def _try_delete_floating_ip(self, floating_ip_id):
-        # delete floating ip, if it exists
-        try:
-            self.client.delete_floating_ip(floating_ip_id)
-        # if not found, it depicts it was deleted in the test
-        except lib_exc.NotFound:
-            pass
-
     @test.idempotent_id('f7bfb946-297e-41b8-9e8c-aba8e9bb5194')
     @test.services('network')
     def test_allocate_floating_ip(self):
@@ -85,7 +78,8 @@
         # Creating the floating IP that is to be deleted in this method
         floating_ip_body = self.client.create_floating_ip(
             pool=CONF.network.floating_network_name)['floating_ip']
-        self.addCleanup(self._try_delete_floating_ip, floating_ip_body['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.client.delete_floating_ip, floating_ip_body['id'])
         # Deleting the floating IP from the project
         self.client.delete_floating_ip(floating_ip_body['id'])
         # Check it was really deleted.
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index 164caaf..decccf3 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -19,7 +19,7 @@
 
 from tempest import config
 from tempest import exceptions
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 import tempest.test
 
 
@@ -238,11 +238,7 @@
     @staticmethod
     def cleanup_resources(resource_id_list, method):
         for resource_id in resource_id_list:
-            try:
-                method(resource_id)
-            except lib_exc.NotFound:
-                # ignore errors while auto removing created resource
-                pass
+            test_utils.call_and_ignore_notfound_exc(method, resource_id)
 
     @classmethod
     def create_node_group_template(cls, name, plugin_name, hadoop_version,
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 3bcae17..2d4ff17 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -17,7 +17,7 @@
 
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 import tempest.test
 
 CONF = config.CONF
@@ -225,9 +225,7 @@
     @staticmethod
     def _try_wrapper(func, item, **kwargs):
         try:
-            func(item['id'], **kwargs)
-        except lib_exc.NotFound:
-            pass
+            test_utils.call_and_ignore_notfound_exc(func, item['id'], **kwargs)
         except Exception:
             LOG.exception("Unexpected exception occurred in %s deletion. "
                           "But ignored here." % item['id'])
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 0683936..bd04c0d 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -16,7 +16,7 @@
 
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 import tempest.test
 
 CONF = config.CONF
@@ -47,10 +47,8 @@
     @classmethod
     def resource_cleanup(cls):
         for image_id in cls.created_images:
-            try:
-                cls.client.delete_image(image_id)
-            except lib_exc.NotFound:
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                cls.client.delete_image, image_id)
 
         for image_id in cls.created_images:
                 cls.client.wait_for_resource_deletion(image_id)
diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py
index de8299e..da0f4c1 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespaces.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespaces.py
@@ -15,6 +15,7 @@
 
 from tempest.api.image import base
 from tempest.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -36,7 +37,8 @@
                                             display_name=namespace_name,
                                             resource_type_associations=name,
                                             protected=True)
-        self.addCleanup(self._cleanup_namespace, namespace_name)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self._cleanup_namespace, namespace_name)
         # get namespace details
         body = self.client.show_namespace(namespace_name)
         self.assertEqual(namespace_name, body['namespace'])
@@ -56,15 +58,11 @@
         self.client.delete_namespace(namespace_name)
 
     def _cleanup_namespace(self, namespace_name):
-        # this is used to cleanup the resources
-        try:
-            body = self.client.show_namespace(namespace_name)
-            self.assertEqual(namespace_name, body['namespace'])
-            body = self.client.update_namespace(namespace=namespace_name,
-                                                description='Tempest',
-                                                visibility='private',
-                                                display_name=namespace_name,
-                                                protected=False)
-            self.client.delete_namespace(namespace_name)
-        except lib_exc.NotFound:
-            pass
+        body = self.client.show_namespace(namespace_name)
+        self.assertEqual(namespace_name, body['namespace'])
+        body = self.client.update_namespace(namespace=namespace_name,
+                                            description='Tempest',
+                                            visibility='private',
+                                            display_name=namespace_name,
+                                            protected=False)
+        self.client.delete_namespace(namespace_name)
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index a32bfbc..2d53265 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -12,6 +12,7 @@
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest import test
 
 
@@ -97,7 +98,7 @@
         body = self.admin_networks_client.create_network(
             **{'router:external': True})
         external_network = body['network']
-        self.addCleanup(self._try_delete_resource,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.admin_networks_client.delete_network,
                         external_network['id'])
         subnet = self.create_subnet(
@@ -106,7 +107,7 @@
         body = self.admin_floating_ips_client.create_floatingip(
             floating_network_id=external_network['id'])
         created_floating_ip = body['floatingip']
-        self.addCleanup(self._try_delete_resource,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.admin_floating_ips_client.delete_floatingip,
                         created_floating_ip['id'])
         floatingip_list = self.admin_floating_ips_client.list_floatingips(
diff --git a/tempest/api/network/admin/test_external_networks_negative.py b/tempest/api/network/admin/test_external_networks_negative.py
index 57b144a..94d65c3 100644
--- a/tempest/api/network/admin/test_external_networks_negative.py
+++ b/tempest/api/network/admin/test_external_networks_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.network import base
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -34,7 +35,7 @@
         body = self.admin_floating_ips_client.create_floatingip(
             floating_network_id=CONF.network.public_network_id)
         created_floating_ip = body['floatingip']
-        self.addCleanup(self._try_delete_resource,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.admin_floating_ips_client.delete_floatingip,
                         created_floating_ip['id'])
         floating_ip_address = created_floating_ip['floating_ip_address']
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index ea3d59a..2ff31e0 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -17,7 +17,7 @@
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 from tempest import test
 
 
@@ -60,7 +60,8 @@
         # Change quotas for project
         quota_set = self.admin_quotas_client.update_quotas(
             project_id, **new_quotas)['quota']
-        self.addCleanup(self._cleanup_quotas, project_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_quotas_client.reset_quotas, project_id)
         for key, value in six.iteritems(new_quotas):
             self.assertEqual(value, quota_set[key])
 
@@ -88,12 +89,3 @@
     def test_quotas(self):
         new_quotas = {'network': 0, 'security_group': 0}
         self._check_quotas(new_quotas)
-
-    def _cleanup_quotas(self, project_id):
-        # try to clean up the resources.If it fails, then
-        # assume that everything was already deleted, so
-        # it is OK to continue.
-        try:
-            self.admin_quotas_client.reset_quotas(project_id)
-        except lib_exc.NotFound:
-            pass
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 9823345..89fa576 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -18,6 +18,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 import tempest.test
 
@@ -97,7 +98,7 @@
         if CONF.service_available.neutron:
             # Clean up floating IPs
             for floating_ip in cls.floating_ips:
-                cls._try_delete_resource(
+                test_utils.call_and_ignore_notfound_exc(
                     cls.floating_ips_client.delete_floatingip,
                     floating_ip['id'])
 
@@ -106,53 +107,33 @@
             if len(cls.metering_label_rules) > 0:
                 label_rules_client = cls.admin_metering_label_rules_client
             for metering_label_rule in cls.metering_label_rules:
-                cls._try_delete_resource(
+                test_utils.call_and_ignore_notfound_exc(
                     label_rules_client.delete_metering_label_rule,
                     metering_label_rule['id'])
             # Clean up metering labels
             for metering_label in cls.metering_labels:
-                cls._try_delete_resource(
+                test_utils.call_and_ignore_notfound_exc(
                     cls.admin_metering_labels_client.delete_metering_label,
                     metering_label['id'])
             # Clean up ports
             for port in cls.ports:
-                cls._try_delete_resource(cls.ports_client.delete_port,
-                                         port['id'])
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.ports_client.delete_port, port['id'])
             # Clean up routers
             for router in cls.routers:
-                cls._try_delete_resource(cls.delete_router,
-                                         router)
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.delete_router, router)
             # Clean up subnets
             for subnet in cls.subnets:
-                cls._try_delete_resource(cls.subnets_client.delete_subnet,
-                                         subnet['id'])
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.subnets_client.delete_subnet, subnet['id'])
             # Clean up networks
             for network in cls.networks:
-                cls._try_delete_resource(cls.networks_client.delete_network,
-                                         network['id'])
+                test_utils.call_and_ignore_notfound_exc(
+                    cls.networks_client.delete_network, network['id'])
         super(BaseNetworkTest, cls).resource_cleanup()
 
     @classmethod
-    def _try_delete_resource(self, delete_callable, *args, **kwargs):
-        """Cleanup resources in case of test-failure
-
-        Some resources are explicitly deleted by the test.
-        If the test failed to delete a resource, this method will execute
-        the appropriate delete methods. Otherwise, the method ignores NotFound
-        exceptions thrown for resources that were correctly deleted by the
-        test.
-
-        :param delete_callable: delete method
-        :param args: arguments for delete method
-        :param kwargs: keyword arguments for delete method
-        """
-        try:
-            delete_callable(*args, **kwargs)
-        # if resource is not found, this means it was deleted in the test
-        except lib_exc.NotFound:
-            pass
-
-    @classmethod
     def create_network(cls, network_name=None):
         """Wrapper utility that returns a test network."""
         network_name = network_name or data_utils.rand_name('test-network-')
@@ -259,12 +240,9 @@
         body = cls.ports_client.list_ports(device_id=router['id'])
         interfaces = body['ports']
         for i in interfaces:
-            try:
-                cls.routers_client.remove_router_interface(
-                    router['id'],
-                    subnet_id=i['fixed_ips'][0]['subnet_id'])
-            except lib_exc.NotFound:
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                cls.routers_client.remove_router_interface, router['id'],
+                subnet_id=i['fixed_ips'][0]['subnet_id'])
         cls.routers_client.delete_router(router['id'])
 
 
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index a5fb25c..1d96439 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -20,6 +20,7 @@
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -273,14 +274,6 @@
         for subnet in subnets:
             self.assertEqual(sorted(subnet.keys()), sorted(fields))
 
-    def _try_delete_network(self, net_id):
-        # delete network, if it exists
-        try:
-            self.networks_client.delete_network(net_id)
-        # if network is not found, this means it was deleted in the test
-        except lib_exc.NotFound:
-            pass
-
     @test.idempotent_id('f04f61a9-b7f3-4194-90b2-9bcf660d1bfe')
     def test_delete_network_with_subnet(self):
         # Creates a network
@@ -288,7 +281,8 @@
         body = self.networks_client.create_network(name=name)
         network = body['network']
         net_id = network['id']
-        self.addCleanup(self._try_delete_network, net_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, net_id)
 
         # Find a cidr that is not in use yet and create a subnet with it
         subnet = self.create_subnet(network)
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index c6cc8e2..d574d72 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -15,6 +15,7 @@
 from tempest.api.network import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -53,7 +54,9 @@
         body = self.subnetpools_client.create_subnetpool(name=subnetpool_name,
                                                          prefixes=prefix)
         subnetpool_id = body["subnetpool"]["id"]
-        self.addCleanup(self._cleanup_subnetpools, subnetpool_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.subnetpools_client.delete_subnetpool,
+                        subnetpool_id)
         self.assertEqual(subnetpool_name, body["subnetpool"]["name"])
         # get detail about subnet pool
         body = self.subnetpools_client.show_subnetpool(subnetpool_id)
@@ -68,10 +71,3 @@
         self.assertRaises(lib_exc.NotFound,
                           self.subnetpools_client.show_subnetpool,
                           subnetpool_id)
-
-    def _cleanup_subnetpools(self, subnetpool_id):
-        # this is used to cleanup the resources
-        try:
-            self.subnetpools_client.delete_subnetpool(subnetpool_id)
-        except lib_exc.NotFound:
-            pass
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 044e8c1..97d9eed 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -15,6 +15,7 @@
 
 from tempest.common import custom_matchers
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 import tempest.test
 
@@ -80,10 +81,8 @@
                 objlist = container_client.list_all_container_objects(cont)
                 # delete every object in the container
                 for obj in objlist:
-                    try:
-                        object_client.delete_object(cont, obj['name'])
-                    except lib_exc.NotFound:
-                        pass
+                    test_utils.call_and_ignore_notfound_exc(
+                        object_client.delete_object, cont, obj['name'])
                 container_client.delete_container(cont)
             except lib_exc.NotFound:
                 pass
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 752f0b4..867159b 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -19,7 +19,7 @@
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 from tempest import test
 
 # Each segment, except for the final one, must be at least 1 megabyte
@@ -36,12 +36,9 @@
 
     def tearDown(self):
         for obj in self.objects:
-            try:
-                self.object_client.delete_object(
-                    self.container_name,
-                    obj)
-            except lib_exc.NotFound:
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                self.object_client.delete_object,
+                self.container_name, obj)
         self.container_client.delete_container(self.container_name)
         super(ObjectSloTest, self).tearDown()
 
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index d813263..3701b55 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -16,7 +16,7 @@
 
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 import tempest.test
 
 CONF = config.CONF
@@ -83,17 +83,13 @@
     @classmethod
     def _clear_stacks(cls):
         for stack_identifier in cls.stacks:
-            try:
-                cls.client.delete_stack(stack_identifier)
-            except lib_exc.NotFound:
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                cls.client.delete_stack, stack_identifier)
 
         for stack_identifier in cls.stacks:
-            try:
-                cls.client.wait_for_stack_status(
-                    stack_identifier, 'DELETE_COMPLETE')
-            except lib_exc.NotFound:
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                cls.client.wait_for_stack_status, stack_identifier,
+                'DELETE_COMPLETE')
 
     @classmethod
     def _create_keypair(cls, name_start='keypair-heat-'):
@@ -124,10 +120,8 @@
     @classmethod
     def _clear_images(cls):
         for image_id in cls.images:
-            try:
-                cls.images_v2_client.delete_image(image_id)
-            except lib_exc.NotFound:
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                cls.images_v2_client.delete_image, image_id)
 
     @classmethod
     def read_template(cls, name, ext='yaml'):
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 14819e3..6116d72 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -18,7 +18,7 @@
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
-from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import test_utils
 import tempest.test
 
 CONF = config.CONF
@@ -223,15 +223,9 @@
     @classmethod
     def clear_qos_specs(cls):
         for qos_id in cls.qos_specs:
-            try:
-                cls.volume_qos_client.delete_qos(qos_id)
-            except lib_exc.NotFound:
-                # The qos_specs may have already been deleted which is OK.
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                cls.volume_qos_client.delete_qos, qos_id)
 
         for qos_id in cls.qos_specs:
-            try:
-                cls.volume_qos_client.wait_for_resource_deletion(qos_id)
-            except lib_exc.NotFound:
-                # The qos_specs may have already been deleted which is OK.
-                pass
+            test_utils.call_and_ignore_notfound_exc(
+                cls.volume_qos_client.wait_for_resource_deletion, qos_id)
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 5975231..38913ce 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -12,14 +12,14 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+import testtools
 
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest.lib import exceptions
+from tempest.lib.common.utils import test_utils
 from tempest import test
-import testtools
 
 CONF = config.CONF
 
@@ -124,19 +124,13 @@
             self.volume['id'], image_name=image_name,
             disk_format=CONF.volume.disk_format)['os-volume_upload_image']
         image_id = body["image_id"]
-        self.addCleanup(self._cleanup_image, image_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.image_client.delete_image,
+                        image_id)
         waiters.wait_for_image_status(self.image_client, image_id, 'active')
         waiters.wait_for_volume_status(self.client,
                                        self.volume['id'], 'available')
 
-    def _cleanup_image(self, image_id):
-        # Ignores the image deletion
-        # in the case that image wasn't created in the first place
-        try:
-            self.image_client.delete_image(image_id)
-        except exceptions.NotFound:
-            pass
-
     @test.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33')
     def test_reserve_unreserve_volume(self):
         # Mark volume as reserved.
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 3f573b7..0a3e8d3 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -21,7 +21,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import ssh
-from tempest.lib.common.utils import misc as misc_utils
+from tempest.lib.common.utils import test_utils
 import tempest.lib.exceptions
 
 CONF = config.CONF
@@ -37,7 +37,7 @@
         except tempest.lib.exceptions.SSHTimeout:
             try:
                 original_exception = sys.exc_info()
-                caller = misc_utils.find_test_caller() or "not found"
+                caller = test_utils.find_test_caller() or "not found"
                 if self.server:
                     msg = 'Caller: %s. Timeout trying to ssh to server %s'
                     LOG.debug(msg, caller, self.server)
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 627143d..bf107d2 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -26,7 +26,7 @@
 import six
 
 from tempest.lib.common import http
-from tempest.lib.common.utils import misc as misc_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions
 
 # redrive rate limited calls at most twice
@@ -397,7 +397,7 @@
                            req_body=None):
         if req_headers is None:
             req_headers = {}
-        caller_name = misc_utils.find_test_caller()
+        caller_name = test_utils.find_test_caller()
         if self.trace_requests and re.search(self.trace_requests, caller_name):
             self.LOG.debug('Starting Request (%s): %s %s' %
                            (caller_name, method, req_url))
@@ -436,7 +436,7 @@
         # we're going to just provide work around on who is actually
         # providing timings by gracefully adding no content if they don't.
         # Once we're down to 1 caller, clean this up.
-        caller_name = misc_utils.find_test_caller()
+        caller_name = test_utils.find_test_caller()
         if secs:
             secs = " %.3fs" % secs
         self.LOG.info(
@@ -853,7 +853,7 @@
                            'the required time (%(timeout)s s).' %
                            {'resource_type': self.resource_type, 'id': id,
                             'timeout': self.build_timeout})
-                caller = misc_utils.find_test_caller()
+                caller = test_utils.find_test_caller()
                 if caller:
                     message = '(%s) %s' % (caller, message)
                 raise exceptions.TimeoutException(message)
diff --git a/tempest/lib/common/utils/misc.py b/tempest/lib/common/utils/misc.py
index b97dd86..f13b4c8 100644
--- a/tempest/lib/common/utils/misc.py
+++ b/tempest/lib/common/utils/misc.py
@@ -12,12 +12,10 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-
-import inspect
-import re
-
 from oslo_log import log as logging
 
+from tempest.lib.common.utils import test_utils
+
 LOG = logging.getLogger(__name__)
 
 
@@ -32,56 +30,8 @@
     return getinstance
 
 
-def find_test_caller():
-    """Find the caller class and test name.
-
-    Because we know that the interesting things that call us are
-    test_* methods, and various kinds of setUp / tearDown, we
-    can look through the call stack to find appropriate methods,
-    and the class we were in when those were called.
-    """
-    caller_name = None
-    names = []
-    frame = inspect.currentframe()
-    is_cleanup = False
-    # Start climbing the ladder until we hit a good method
-    while True:
-        try:
-            frame = frame.f_back
-            name = frame.f_code.co_name
-            names.append(name)
-            if re.search("^(test_|setUp|tearDown)", name):
-                cname = ""
-                if 'self' in frame.f_locals:
-                    cname = frame.f_locals['self'].__class__.__name__
-                if 'cls' in frame.f_locals:
-                    cname = frame.f_locals['cls'].__name__
-                caller_name = cname + ":" + name
-                break
-            elif re.search("^_run_cleanup", name):
-                is_cleanup = True
-            elif name == 'main':
-                caller_name = 'main'
-                break
-            else:
-                cname = ""
-                if 'self' in frame.f_locals:
-                    cname = frame.f_locals['self'].__class__.__name__
-                if 'cls' in frame.f_locals:
-                    cname = frame.f_locals['cls'].__name__
-
-                # the fact that we are running cleanups is indicated pretty
-                # deep in the stack, so if we see that we want to just
-                # start looking for a real class name, and declare victory
-                # once we do.
-                if is_cleanup and cname:
-                    if not re.search("^RunTest", cname):
-                        caller_name = cname + ":_run_cleanups"
-                        break
-        except Exception:
-            break
-    # prevents frame leaks
-    del frame
-    if caller_name is None:
-        LOG.debug("Sane call name not found in %s" % names)
-    return caller_name
+def find_test_caller(*args, **kwargs):
+    LOG.warning("tempest.lib.common.utils.misc.find_test_caller is deprecated "
+                "in favor of tempest.lib.common.utils.test_utils."
+                "find_test_caller")
+    test_utils.find_test_caller(*args, **kwargs)
diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py
new file mode 100644
index 0000000..50a1a7d
--- /dev/null
+++ b/tempest/lib/common/utils/test_utils.py
@@ -0,0 +1,85 @@
+# Copyright 2016 OpenStack Foundation
+# All Rights Reserved.
+#
+#    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.
+import inspect
+import re
+
+from oslo_log import log as logging
+
+from tempest.lib import exceptions
+
+LOG = logging.getLogger(__name__)
+
+
+def find_test_caller():
+    """Find the caller class and test name.
+
+    Because we know that the interesting things that call us are
+    test_* methods, and various kinds of setUp / tearDown, we
+    can look through the call stack to find appropriate methods,
+    and the class we were in when those were called.
+    """
+    caller_name = None
+    names = []
+    frame = inspect.currentframe()
+    is_cleanup = False
+    # Start climbing the ladder until we hit a good method
+    while True:
+        try:
+            frame = frame.f_back
+            name = frame.f_code.co_name
+            names.append(name)
+            if re.search("^(test_|setUp|tearDown)", name):
+                cname = ""
+                if 'self' in frame.f_locals:
+                    cname = frame.f_locals['self'].__class__.__name__
+                if 'cls' in frame.f_locals:
+                    cname = frame.f_locals['cls'].__name__
+                caller_name = cname + ":" + name
+                break
+            elif re.search("^_run_cleanup", name):
+                is_cleanup = True
+            elif name == 'main':
+                caller_name = 'main'
+                break
+            else:
+                cname = ""
+                if 'self' in frame.f_locals:
+                    cname = frame.f_locals['self'].__class__.__name__
+                if 'cls' in frame.f_locals:
+                    cname = frame.f_locals['cls'].__name__
+
+                # the fact that we are running cleanups is indicated pretty
+                # deep in the stack, so if we see that we want to just
+                # start looking for a real class name, and declare victory
+                # once we do.
+                if is_cleanup and cname:
+                    if not re.search("^RunTest", cname):
+                        caller_name = cname + ":_run_cleanups"
+                        break
+        except Exception:
+            break
+    # prevents frame leaks
+    del frame
+    if caller_name is None:
+        LOG.debug("Sane call name not found in %s" % names)
+    return caller_name
+
+
+def call_and_ignore_notfound_exc(func, *args, **kwargs):
+    """Call the given function and pass if a `NotFound` exception is raised."""
+    try:
+        return func(*args, **kwargs)
+    except exceptions.NotFound:
+        pass
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 7389722..6a28e02 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -27,7 +27,7 @@
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
-from tempest.lib.common.utils import misc as misc_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 from tempest.scenario import network_resources
 import tempest.test
@@ -95,21 +95,6 @@
         # not at the end of the class
         self.addCleanup(self._wait_for_cleanups)
 
-    def delete_wrapper(self, delete_thing, *args, **kwargs):
-        """Ignores NotFound exceptions for delete operations.
-
-        @param delete_thing: delete method of a resource. method will be
-            executed as delete_thing(*args, **kwargs)
-
-        """
-        try:
-            # Tempest clients return dicts, so there is no common delete
-            # method available. Using a callable instead
-            delete_thing(*args, **kwargs)
-        except lib_exc.NotFound:
-            # If the resource is already missing, mission accomplished.
-            pass
-
     def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
                              cleanup_callable, cleanup_args=None,
                              cleanup_kwargs=None, waiter_client=None):
@@ -254,7 +239,7 @@
         self.addCleanup_with_wait(
             waiter_callable=waiters.wait_for_server_termination,
             thing_id=body['id'], thing_id_param='server_id',
-            cleanup_callable=self.delete_wrapper,
+            cleanup_callable=test_utils.call_and_ignore_notfound_exc,
             cleanup_args=[clients.servers_client.delete_server, body['id']],
             waiter_client=clients.servers_client)
         server = clients.servers_client.show_server(body['id'])['server']
@@ -274,7 +259,7 @@
 
         self.addCleanup(self.volumes_client.wait_for_resource_deletion,
                         volume['id'])
-        self.addCleanup(self.delete_wrapper,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.volumes_client.delete_volume, volume['id'])
 
         # NOTE(e0ne): Cinder API v2 uses name instead of display_name
@@ -334,7 +319,7 @@
         self.assertEqual(secgroup['name'], sg_name)
         self.assertEqual(secgroup['description'], sg_desc)
         self.addCleanup(
-            self.delete_wrapper,
+            test_utils.call_and_ignore_notfound_exc,
             self.compute_security_groups_client.delete_security_group,
             secgroup['id'])
 
@@ -373,7 +358,7 @@
             message = ('Initializing SSH connection to %(ip)s failed. '
                        'Error: %(error)s' % {'ip': ip_address,
                                              'error': e})
-            caller = misc_utils.find_test_caller()
+            caller = test_utils.find_test_caller()
             if caller:
                 message = '(%s) %s' % (caller, message)
             LOG.exception(message)
@@ -463,7 +448,7 @@
         self.addCleanup_with_wait(
             waiter_callable=_image_client.wait_for_resource_deletion,
             thing_id=image_id, thing_id_param='id',
-            cleanup_callable=self.delete_wrapper,
+            cleanup_callable=test_utils.call_and_ignore_notfound_exc,
             cleanup_args=[_image_client.delete_image, image_id])
         snapshot_image = _image_client.check_image(image_id)
 
@@ -475,12 +460,11 @@
                 self.addCleanup(
                     self.snapshots_client.wait_for_resource_deletion,
                     snapshot_id)
-                self.addCleanup(
-                    self.delete_wrapper, self.snapshots_client.delete_snapshot,
-                    snapshot_id)
+                self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                                self.snapshots_client.delete_snapshot,
+                                snapshot_id)
                 waiters.wait_for_snapshot_status(self.snapshots_client,
                                                  snapshot_id, 'available')
-
         image_name = snapshot_image['name']
         self.assertEqual(name, image_name)
         LOG.debug("Created snapshot image %s for server %s",
@@ -537,7 +521,7 @@
 
             return (proc.returncode == 0) == should_succeed
 
-        caller = misc_utils.find_test_caller()
+        caller = test_utils.find_test_caller()
         LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
                   ' expected result is %(should_succeed)s' % {
                       'caller': caller, 'ip': ip_address, 'timeout': timeout,
@@ -606,7 +590,7 @@
             pool_name = CONF.network.floating_network_name
         floating_ip = (self.compute_floating_ips_client.
                        create_floating_ip(pool=pool_name)['floating_ip'])
-        self.addCleanup(self.delete_wrapper,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.compute_floating_ips_client.delete_floating_ip,
                         floating_ip['id'])
         self.compute_floating_ips_client.associate_floating_ip_to_server(
@@ -701,7 +685,8 @@
             networks_client=networks_client, routers_client=routers_client,
             **result['network'])
         self.assertEqual(network.name, name)
-        self.addCleanup(self.delete_wrapper, network.delete)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        network.delete)
         return network
 
     def _list_networks(self, *args, **kwargs):
@@ -794,7 +779,7 @@
             subnets_client=subnets_client,
             routers_client=routers_client, **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
-        self.addCleanup(self.delete_wrapper, subnet.delete)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc, subnet.delete)
         return subnet
 
     def _create_port(self, network_id, client=None, namestart='port-quotatest',
@@ -809,7 +794,7 @@
         self.assertIsNotNone(result, 'Unable to allocate port')
         port = network_resources.DeletablePort(ports_client=client,
                                                **result['port'])
-        self.addCleanup(self.delete_wrapper, port.delete)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc, port.delete)
         return port
 
     def _get_server_port_id_and_ip4(self, server, ip_addr=None):
@@ -860,7 +845,8 @@
         floating_ip = network_resources.DeletableFloatingIp(
             client=client,
             **result['floatingip'])
-        self.addCleanup(self.delete_wrapper, floating_ip.delete)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        floating_ip.delete)
         return floating_ip
 
     def _associate_floating_ip(self, floating_ip, server):
@@ -998,7 +984,8 @@
         self.assertEqual(secgroup.name, sg_name)
         self.assertEqual(tenant_id, secgroup.tenant_id)
         self.assertEqual(secgroup.description, sg_desc)
-        self.addCleanup(self.delete_wrapper, secgroup.delete)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        secgroup.delete)
         return secgroup
 
     def _default_security_group(self, client=None, tenant_id=None):
@@ -1158,7 +1145,7 @@
         router = network_resources.DeletableRouter(routers_client=client,
                                                    **result['router'])
         self.assertEqual(router.name, name)
-        self.addCleanup(self.delete_wrapper, router.delete)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc, router.delete)
         return router
 
     def _update_router_admin_state(self, router, admin_state_up):
@@ -1287,11 +1274,8 @@
         """Waits for a node to be associated with instance_id."""
 
         def _get_node():
-            node = None
-            try:
-                node = self.get_node(instance_id=instance_id)
-            except lib_exc.NotFound:
-                pass
+            node = test_utils.call_and_ignore_notfound_exc(
+                self.get_node, instance_id=instance_id)
             return node is not None
 
         if not tempest.test.call_until_true(
@@ -1438,7 +1422,7 @@
         # look for the container to assure it is created
         self.list_and_check_container_objects(name)
         LOG.debug('Container %s created' % (name))
-        self.addCleanup(self.delete_wrapper,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.container_client.delete_container,
                         name)
         return name
@@ -1451,7 +1435,7 @@
         obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
         obj_data = data_utils.arbitrary_string()
         self.object_client.create_object(container_name, obj_name, obj_data)
-        self.addCleanup(self.delete_wrapper,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.object_client.delete_object,
                         container_name,
                         obj_name)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index f0ae223..f5134e5 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -23,6 +23,7 @@
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common.utils import test_utils
 from tempest.scenario import manager
 from tempest.scenario import network_resources
 from tempest import test
@@ -252,7 +253,7 @@
             net_id=self.new_net.id)['interfaceAttachment']
         self.addCleanup(self.ports_client.wait_for_resource_deletion,
                         interface['port_id'])
-        self.addCleanup(self.delete_wrapper,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.interface_client.delete_interface,
                         server['id'], interface['port_id'])
 
diff --git a/tempest/tests/lib/common/utils/test_misc.py b/tempest/tests/lib/common/utils/test_misc.py
index 9597f5b..47e81d1 100644
--- a/tempest/tests/lib/common/utils/test_misc.py
+++ b/tempest/tests/lib/common/utils/test_misc.py
@@ -50,39 +50,3 @@
         self.assertEqual(test, test2)
         test3 = TestBar()
         self.assertNotEqual(test, test3)
-
-    def test_find_test_caller_test_case(self):
-        # Calling it from here should give us the method we're in.
-        self.assertEqual('TestMisc:test_find_test_caller_test_case',
-                         misc.find_test_caller())
-
-    def test_find_test_caller_setup_self(self):
-        def setUp(self):
-            return misc.find_test_caller()
-        self.assertEqual('TestMisc:setUp', setUp(self))
-
-    def test_find_test_caller_setup_no_self(self):
-        def setUp():
-            return misc.find_test_caller()
-        self.assertEqual(':setUp', setUp())
-
-    def test_find_test_caller_setupclass_cls(self):
-        def setUpClass(cls):  # noqa
-            return misc.find_test_caller()
-        self.assertEqual('TestMisc:setUpClass', setUpClass(self.__class__))
-
-    def test_find_test_caller_teardown_self(self):
-        def tearDown(self):
-            return misc.find_test_caller()
-        self.assertEqual('TestMisc:tearDown', tearDown(self))
-
-    def test_find_test_caller_teardown_no_self(self):
-        def tearDown():
-            return misc.find_test_caller()
-        self.assertEqual(':tearDown', tearDown())
-
-    def test_find_test_caller_teardown_class(self):
-        def tearDownClass(cls):  # noqa
-            return misc.find_test_caller()
-        self.assertEqual('TestMisc:tearDownClass',
-                         tearDownClass(self.__class__))
diff --git a/tempest/tests/lib/common/utils/test_test_utils.py b/tempest/tests/lib/common/utils/test_test_utils.py
new file mode 100644
index 0000000..919e219
--- /dev/null
+++ b/tempest/tests/lib/common/utils/test_test_utils.py
@@ -0,0 +1,78 @@
+# Copyright 2016 OpenStack Foundation
+# All Rights Reserved.
+#
+#    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.
+import mock
+
+from tempest.lib.common.utils import test_utils
+from tempest.lib import exceptions
+from tempest.tests import base
+
+
+class TestTestUtils(base.TestCase):
+
+    def test_find_test_caller_test_case(self):
+        # Calling it from here should give us the method we're in.
+        self.assertEqual('TestTestUtils:test_find_test_caller_test_case',
+                         test_utils.find_test_caller())
+
+    def test_find_test_caller_setup_self(self):
+        def setUp(self):
+            return test_utils.find_test_caller()
+        self.assertEqual('TestTestUtils:setUp', setUp(self))
+
+    def test_find_test_caller_setup_no_self(self):
+        def setUp():
+            return test_utils.find_test_caller()
+        self.assertEqual(':setUp', setUp())
+
+    def test_find_test_caller_setupclass_cls(self):
+        def setUpClass(cls):  # noqa
+            return test_utils.find_test_caller()
+        self.assertEqual('TestTestUtils:setUpClass',
+                         setUpClass(self.__class__))
+
+    def test_find_test_caller_teardown_self(self):
+        def tearDown(self):
+            return test_utils.find_test_caller()
+        self.assertEqual('TestTestUtils:tearDown', tearDown(self))
+
+    def test_find_test_caller_teardown_no_self(self):
+        def tearDown():
+            return test_utils.find_test_caller()
+        self.assertEqual(':tearDown', tearDown())
+
+    def test_find_test_caller_teardown_class(self):
+        def tearDownClass(cls):  # noqa
+            return test_utils.find_test_caller()
+        self.assertEqual('TestTestUtils:tearDownClass',
+                         tearDownClass(self.__class__))
+
+    def test_call_and_ignore_notfound_exc_when_notfound_raised(self):
+        def raise_not_found():
+            raise exceptions.NotFound()
+        self.assertIsNone(
+            test_utils.call_and_ignore_notfound_exc(raise_not_found))
+
+    def test_call_and_ignore_notfound_exc_when_value_error_raised(self):
+        def raise_value_error():
+            raise ValueError()
+        self.assertRaises(ValueError, test_utils.call_and_ignore_notfound_exc,
+                          raise_value_error)
+
+    def test_call_and_ignore_notfound_exc(self):
+        m = mock.Mock(return_value=42)
+        args, kwargs = (1,), {'1': None}
+        self.assertEqual(
+            42, test_utils.call_and_ignore_notfound_exc(m, *args, **kwargs))
+        m.assert_called_once_with(*args, **kwargs)