Wait for resource deletion after 202 response. Fixes bug 1007447.

Added RestClient.wait_for_resource_deletion that waits for a subclass-specific condition.
Added RestClient.is_resource_deleted that implements a subclass-specific deletion predicate.
Removed redundant test by combining floating_ip associate/dissacociate into a single test.

Change-Id: Iac043b12e8d5a5e88786e3b573280bfbc3f6a8d6
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index ea52479..dd5e3cf 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -47,6 +47,8 @@
         self.strategy = self.config.identity.strategy
         self.headers = {'Content-Type': 'application/json',
                         'Accept': 'application/json'}
+        self.build_interval = config.compute.build_interval
+        self.build_timeout = config.compute.build_timeout
 
     def _set_auth(self):
         """
@@ -230,3 +232,19 @@
             raise exceptions.TempestException(str(resp.status))
 
         return resp, resp_body
+
+    def wait_for_resource_deletion(self, id):
+        """Waits for a resource to be deleted"""
+        start_time = int(time.time())
+        while True:
+            if self.is_resource_deleted(id):
+                return
+            if int(time.time()) - start_time >= self.build_timeout:
+                raise exceptions.TimeoutException
+            time.sleep(self.build_interval)
+
+    def is_resource_deleted(self, id):
+        """
+        Subclasses override with specific deletion detection.
+        """
+        return False
diff --git a/tempest/services/nova/json/floating_ips_client.py b/tempest/services/nova/json/floating_ips_client.py
index 5b5b538..9f382ff 100644
--- a/tempest/services/nova/json/floating_ips_client.py
+++ b/tempest/services/nova/json/floating_ips_client.py
@@ -68,3 +68,10 @@
         post_body = json.dumps(post_body)
         resp, body = self.post(url, post_body, self.headers)
         return resp, body
+
+    def is_resource_deleted(self, id):
+        try:
+            self.get_floating_ip_details(id)
+        except exceptions.NotFound:
+            return True
+        return False
diff --git a/tempest/services/nova/json/servers_client.py b/tempest/services/nova/json/servers_client.py
index b732b41..2c345f1 100644
--- a/tempest/services/nova/json/servers_client.py
+++ b/tempest/services/nova/json/servers_client.py
@@ -10,8 +10,6 @@
         super(ServersClient, self).__init__(config, username, password,
                                            auth_url, tenant_name)
         self.service = self.config.compute.catalog_type
-        self.build_interval = self.config.compute.build_interval
-        self.build_timeout = self.config.compute.build_timeout
 
     def create_server(self, name, image_ref, flavor_ref, **kwargs):
         """
diff --git a/tempest/services/nova/json/volumes_client.py b/tempest/services/nova/json/volumes_client.py
index 165640f..fd577b7 100644
--- a/tempest/services/nova/json/volumes_client.py
+++ b/tempest/services/nova/json/volumes_client.py
@@ -90,3 +90,10 @@
                 'the required time (%s s).' % (volume_name, status,
                                               self.build_timeout)
                 raise exceptions.TimeoutException(message)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.get_volume(id)
+        except exceptions.NotFound:
+            return True
+        return False
diff --git a/tempest/tests/test_floating_ips_actions.py b/tempest/tests/test_floating_ips_actions.py
index 595dcba..9a84a21 100644
--- a/tempest/tests/test_floating_ips_actions.py
+++ b/tempest/tests/test_floating_ips_actions.py
@@ -78,17 +78,15 @@
         #Deleting the floating IP from the project
         resp, body = self.client.delete_floating_ip(floating_ip_body['id'])
         self.assertEqual(202, resp.status)
-        #Listing the floating IPs and checking the existence
-        #of deleted floating IP
-        resp, body = self.client.list_floating_ips()
-        self.assertTrue(floating_ip_details not in body)
+        # Check it was really deleted.
+        self.client.wait_for_resource_deletion(floating_ip_body['id'])
 
     @attr(type='positive')
-    def test_associate_floating_ip(self):
+    def test_associate_disassociate_floating_ip(self):
         """
-        Positive test:Associate the provided floating IP to a specific server
-        should be successfull
-       l"""
+        Positive test:Associate and disassociate the provided floating IP to a
+        specific server should be successfull
+        """
         #Association of floating IP to fixed IP address
         resp, body =\
         self.client.associate_floating_ip_to_server(self.floating_ip,
@@ -98,22 +96,6 @@
         resp, body = \
             self.client.disassociate_floating_ip_from_server(self.floating_ip,
                                                              self.server_id)
-
-    @attr(type='positive')
-    def test_dissociate_floating_ip(self):
-        """
-        Positive test:Dissociate the provided floating IP
-        from a specific server should be successfull
-        """
-        #Association of floating IP to a specific server
-        #so as to check dissociation
-        resp, body = \
-            self.client.associate_floating_ip_to_server(self.floating_ip,
-                                                        self.server_id)
-        #Disassociation of floating IP
-        resp, body = \
-        self.client.disassociate_floating_ip_from_server(self.floating_ip,
-                                                         self.server_id)
         self.assertEqual(202, resp.status)
 
     @attr(type='negative')
diff --git a/tempest/tests/test_volumes_get.py b/tempest/tests/test_volumes_get.py
index e6a8944..94de178 100644
--- a/tempest/tests/test_volumes_get.py
+++ b/tempest/tests/test_volumes_get.py
@@ -1,6 +1,5 @@
 from nose.plugins.attrib import attr
 import unittest2 as unittest
-from unittest.case import SkipTest
 from tempest import openstack
 from tempest.common.utils.data_utils import rand_name
 
@@ -52,9 +51,7 @@
             resp, _ = self.client.delete_volume(volume['id'])
             self.assertEqual(202, resp.status)
             #Checking if the deleted Volume still exists
-            resp, fetched_list = self.client.list_volumes()
-            self.assertTrue(fetched_volume not in fetched_list,
-                            'The Volume is not Deleted')
+            self.client.wait_for_resource_deletion(volume['id'])
 
     @attr(type='positive')
     def test_volume_get_metadata_none(self):