Merge "Increase exception log details"
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 f4ad449..32e7b39 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -51,17 +51,15 @@
         # Positive test:Allocation of a new floating IP to a project
         # should be successful
         resp, body = self.client.create_floating_ip()
-        self.assertEqual(200, resp.status)
         floating_ip_id_allocated = body['id']
-        try:
-            resp, floating_ip_details = \
-                self.client.get_floating_ip_details(floating_ip_id_allocated)
-            # Checking if the details of allocated IP is in list of floating IP
-            resp, body = self.client.list_floating_ips()
-            self.assertIn(floating_ip_details, body)
-        finally:
-            # Deleting the floating IP which is created in this method
-            self.client.delete_floating_ip(floating_ip_id_allocated)
+        self.addCleanup(self.client.delete_floating_ip,
+                        floating_ip_id_allocated)
+        self.assertEqual(200, resp.status)
+        resp, floating_ip_details = \
+            self.client.get_floating_ip_details(floating_ip_id_allocated)
+        # Checking if the details of allocated IP is in list of floating IP
+        resp, body = self.client.list_floating_ips()
+        self.assertIn(floating_ip_details, body)
 
     @attr(type='gate')
     def test_delete_floating_ip(self):
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index e4d03ae..9238994 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -54,25 +54,23 @@
     def test_get_floating_ip_details(self):
         # Positive test:Should be able to GET the details of floatingIP
         # Creating a floating IP for which details are to be checked
-        try:
-            resp, body = self.client.create_floating_ip()
-            floating_ip_instance_id = body['instance_id']
-            floating_ip_ip = body['ip']
-            floating_ip_fixed_ip = body['fixed_ip']
-            floating_ip_id = body['id']
-            resp, body = \
-                self.client.get_floating_ip_details(floating_ip_id)
-            self.assertEqual(200, resp.status)
-            # Comparing the details of floating IP
-            self.assertEqual(floating_ip_instance_id,
-                             body['instance_id'])
-            self.assertEqual(floating_ip_ip, body['ip'])
-            self.assertEqual(floating_ip_fixed_ip,
-                             body['fixed_ip'])
-            self.assertEqual(floating_ip_id, body['id'])
-        # Deleting the floating IP created in this method
-        finally:
-            self.client.delete_floating_ip(floating_ip_id)
+        resp, body = self.client.create_floating_ip()
+        floating_ip_id = body['id']
+        self.addCleanup(self.client.delete_floating_ip,
+                        floating_ip_id)
+        floating_ip_instance_id = body['instance_id']
+        floating_ip_ip = body['ip']
+        floating_ip_fixed_ip = body['fixed_ip']
+        resp, body = \
+            self.client.get_floating_ip_details(floating_ip_id)
+        self.assertEqual(200, resp.status)
+        # Comparing the details of floating IP
+        self.assertEqual(floating_ip_instance_id,
+                         body['instance_id'])
+        self.assertEqual(floating_ip_ip, body['ip'])
+        self.assertEqual(floating_ip_fixed_ip,
+                         body['fixed_ip'])
+        self.assertEqual(floating_ip_id, body['id'])
 
     @attr(type='gate')
     def test_list_floating_ip_pools(self):
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/test_services.py
index 7fe5171..872adb8 100644
--- a/tempest/api/identity/admin/test_services.py
+++ b/tempest/api/identity/admin/test_services.py
@@ -25,47 +25,47 @@
 class ServicesTestJSON(base.BaseIdentityAdminTest):
     _interface = 'json'
 
+    def _del_service(self, service_id):
+        # Deleting the service created in this method
+        resp, _ = self.client.delete_service(service_id)
+        self.assertEqual(resp['status'], '204')
+        # Checking whether service is deleted successfully
+        self.assertRaises(exceptions.NotFound, self.client.get_service,
+                          service_id)
+
     @attr(type='smoke')
     def test_create_get_delete_service(self):
         # GET Service
-        try:
-            # Creating a Service
-            name = data_utils.rand_name('service-')
-            type = data_utils.rand_name('type--')
-            description = data_utils.rand_name('description-')
-            resp, service_data = self.client.create_service(
-                name, type, description=description)
-            self.assertTrue(resp['status'].startswith('2'))
-            # Verifying response body of create service
-            self.assertIn('id', service_data)
-            self.assertFalse(service_data['id'] is None)
-            self.assertIn('name', service_data)
-            self.assertEqual(name, service_data['name'])
-            self.assertIn('type', service_data)
-            self.assertEqual(type, service_data['type'])
-            self.assertIn('description', service_data)
-            self.assertEqual(description, service_data['description'])
-            # Get service
-            resp, fetched_service = self.client.get_service(service_data['id'])
-            self.assertTrue(resp['status'].startswith('2'))
-            # verifying the existence of service created
-            self.assertIn('id', fetched_service)
-            self.assertEqual(fetched_service['id'], service_data['id'])
-            self.assertIn('name', fetched_service)
-            self.assertEqual(fetched_service['name'], service_data['name'])
-            self.assertIn('type', fetched_service)
-            self.assertEqual(fetched_service['type'], service_data['type'])
-            self.assertIn('description', fetched_service)
-            self.assertEqual(fetched_service['description'],
-                             service_data['description'])
-        finally:
-            if 'service_data' in locals():
-                # Deleting the service created in this method
-                resp, _ = self.client.delete_service(service_data['id'])
-                self.assertEqual(resp['status'], '204')
-                # Checking whether service is deleted successfully
-                self.assertRaises(exceptions.NotFound, self.client.get_service,
-                                  service_data['id'])
+        # Creating a Service
+        name = data_utils.rand_name('service-')
+        type = data_utils.rand_name('type--')
+        description = data_utils.rand_name('description-')
+        resp, service_data = self.client.create_service(
+            name, type, description=description)
+        self.assertFalse(service_data['id'] is None)
+        self.addCleanup(self._del_service, service_data['id'])
+        self.assertTrue(resp['status'].startswith('2'))
+        # Verifying response body of create service
+        self.assertIn('id', service_data)
+        self.assertIn('name', service_data)
+        self.assertEqual(name, service_data['name'])
+        self.assertIn('type', service_data)
+        self.assertEqual(type, service_data['type'])
+        self.assertIn('description', service_data)
+        self.assertEqual(description, service_data['description'])
+        # Get service
+        resp, fetched_service = self.client.get_service(service_data['id'])
+        self.assertTrue(resp['status'].startswith('2'))
+        # verifying the existence of service created
+        self.assertIn('id', fetched_service)
+        self.assertEqual(fetched_service['id'], service_data['id'])
+        self.assertIn('name', fetched_service)
+        self.assertEqual(fetched_service['name'], service_data['name'])
+        self.assertIn('type', fetched_service)
+        self.assertEqual(fetched_service['type'], service_data['type'])
+        self.assertIn('description', fetched_service)
+        self.assertEqual(fetched_service['description'],
+                         service_data['description'])
 
     @attr(type='smoke')
     def test_list_services(self):
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 5e13a5a..e1d28d7 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -12,10 +12,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import datetime
+import re
 from tempest.api.identity import base
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
+from tempest.openstack.common import timeutils
 from tempest.test import attr
 
 
@@ -115,7 +118,15 @@
                        summary=False):
         self.assertIsNotNone(trust['id'])
         self.assertEqual(impersonate, trust['impersonation'])
-        self.assertEqual(expires, trust['expires_at'])
+        # FIXME(shardy): ref bug #1246383 we can't check the
+        # microsecond component of the expiry time, because mysql
+        # <5.6.4 doesn't support microseconds.
+        # expected format 2013-12-20T16:08:36.036987Z
+        if expires is not None:
+            expires_nousec = re.sub(r'\.([0-9]){6}Z', '', expires)
+            self.assertTrue(trust['expires_at'].startswith(expires_nousec))
+        else:
+            self.assertIsNone(trust['expires_at'])
         self.assertEqual(self.trustor_user_id, trust['trustor_user_id'])
         self.assertEqual(self.trustee_user_id, trust['trustee_user_id'])
         self.assertIn('v3/OS-TRUST/trusts', trust['links']['self'])
@@ -212,6 +223,24 @@
         self.delete_trust()
 
     @attr(type='smoke')
+    def test_trust_expire(self):
+        # Test case to check we can create, get and delete a trust
+        # with an expiry specified
+        expires_at = timeutils.utcnow() + datetime.timedelta(hours=1)
+        expires_str = timeutils.isotime(at=expires_at, subsecond=True)
+
+        trust = self.create_trust(expires=expires_str)
+        self.validate_trust(trust, expires=expires_str)
+
+        trust_get = self.get_trust()
+
+        self.validate_trust(trust_get, expires=expires_str)
+
+        self.check_trust_roles()
+
+        self.delete_trust()
+
+    @attr(type='smoke')
     def test_trust_expire_invalid(self):
         # Test case to check we can check an invlaid expiry time
         # is rejected with the correct error
@@ -220,3 +249,22 @@
         self.assertRaises(exceptions.BadRequest,
                           self.create_trust,
                           expires=expires_str)
+
+    @attr(type='smoke')
+    def test_get_trusts_query(self):
+        self.create_trust()
+        resp, trusts_get = self.trustor_v3_client.get_trusts(
+            trustor_user_id=self.trustor_user_id)
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(1, len(trusts_get))
+        self.validate_trust(trusts_get[0], summary=True)
+
+    @attr(type='smoke')
+    def test_get_trusts_all(self):
+        self.create_trust()
+        resp, trusts_get = self.v3_client.get_trusts()
+        self.assertEqual('200', resp['status'])
+        trusts = [t for t in trusts_get
+                  if t['id'] == self.trust_id]
+        self.assertEqual(1, len(trusts))
+        self.validate_trust(trusts[0], summary=True)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 318d891..dcad101 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -66,6 +66,7 @@
         cls.health_monitors = []
         cls.vpnservices = []
         cls.ikepolicies = []
+        cls.floating_ips = []
 
     @classmethod
     def tearDownClass(cls):
@@ -75,6 +76,9 @@
         # Clean up vpn services
         for vpnservice in cls.vpnservices:
             cls.client.delete_vpnservice(vpnservice['id'])
+        # Clean up floating IPs
+        for floating_ip in cls.floating_ips:
+            cls.client.delete_floating_ip(floating_ip['id'])
         # Clean up routers
         for router in cls.routers:
             resp, body = cls.client.list_router_interfaces(router['id'])
@@ -167,6 +171,16 @@
         return router
 
     @classmethod
+    def create_floating_ip(cls, external_network_id, **kwargs):
+        """Wrapper utility that returns a test floating IP."""
+        resp, body = cls.client.create_floating_ip(
+            external_network_id,
+            **kwargs)
+        fip = body['floatingip']
+        cls.floating_ips.append(fip)
+        return fip
+
+    @classmethod
     def create_pool(cls, name, lb_method, protocol, subnet):
         """Wrapper utility that returns a test pool."""
         resp, body = cls.client.create_pool(
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 7ce8ca6..6f3fa4b 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -32,6 +32,9 @@
         Delete a Floating IP
         List all Floating IPs
         Show Floating IP details
+        Associate a Floating IP with a port and then delete that port
+        Associate a Floating IP with a port and then with a port on another
+        router
 
     v2.0 of the Neutron API is assumed. It is also assumed that the following
     options are defined in the [network] section of etc/tempest.conf:
@@ -55,31 +58,17 @@
         for i in range(2):
             cls.create_port(cls.network)
 
-    def _delete_floating_ip(self, floating_ip_id):
-        # Deletes a floating IP and verifies if it is deleted or not
-        resp, _ = self.client.delete_floatingip(floating_ip_id)
-        self.assertEqual(204, resp.status)
-        # Asserting that the floating_ip is not found in list after deletion
-        resp, floating_ips = self.client.list_floatingips()
-        floatingip_id_list = list()
-        for f in floating_ips['floatingips']:
-            floatingip_id_list.append(f['id'])
-        self.assertNotIn(floating_ip_id, floatingip_id_list)
-
     @attr(type='smoke')
     def test_create_list_show_update_delete_floating_ip(self):
         # Creates a floating IP
-        resp, floating_ip = self.client.create_floating_ip(
+        created_floating_ip = self.create_floating_ip(
             self.ext_net_id, port_id=self.ports[0]['id'])
-        self.assertEqual('201', resp['status'])
-        created_floating_ip = floating_ip['floatingip']
         self.assertIsNotNone(created_floating_ip['id'])
         self.assertIsNotNone(created_floating_ip['tenant_id'])
         self.assertIsNotNone(created_floating_ip['floating_ip_address'])
         self.assertEqual(created_floating_ip['port_id'], self.ports[0]['id'])
         self.assertEqual(created_floating_ip['floating_network_id'],
                          self.ext_net_id)
-        self.addCleanup(self._delete_floating_ip, created_floating_ip['id'])
         # Verifies the details of a floating_ip
         resp, floating_ip = self.client.show_floating_ip(
             created_floating_ip['id'])
@@ -120,6 +109,51 @@
         self.assertIsNone(updated_floating_ip['fixed_ip_address'])
         self.assertIsNone(updated_floating_ip['router_id'])
 
+    @attr(type='smoke')
+    def test_floating_ip_delete_port(self):
+        # Create a floating IP
+        created_floating_ip = self.create_floating_ip(self.ext_net_id)
+        # Create a port
+        resp, port = self.client.create_port(self.network['id'])
+        created_port = port['port']
+        resp, floating_ip = self.client.update_floating_ip(
+            created_floating_ip['id'], port_id=created_port['id'])
+        self.assertEqual('200', resp['status'])
+        # Delete port
+        self.client.delete_port(created_port['id'])
+        # Verifies the details of the floating_ip
+        resp, floating_ip = self.client.show_floating_ip(
+            created_floating_ip['id'])
+        self.assertEqual('200', resp['status'])
+        shown_floating_ip = floating_ip['floatingip']
+        # Confirm the fields are back to None
+        self.assertEqual(shown_floating_ip['id'], created_floating_ip['id'])
+        self.assertIsNone(shown_floating_ip['port_id'])
+        self.assertIsNone(shown_floating_ip['fixed_ip_address'])
+        self.assertIsNone(shown_floating_ip['router_id'])
+
+    @attr(type='smoke')
+    def test_floating_ip_update_different_router(self):
+        # Associate a floating IP to a port on a router
+        created_floating_ip = self.create_floating_ip(
+            self.ext_net_id, port_id=self.ports[1]['id'])
+        self.assertEqual(created_floating_ip['router_id'], self.router['id'])
+        network2 = self.create_network()
+        subnet2 = self.create_subnet(network2)
+        router2 = self.create_router(data_utils.rand_name('router-'),
+                                     external_network_id=self.ext_net_id)
+        self.create_router_interface(router2['id'], subnet2['id'])
+        port_other_router = self.create_port(network2)
+        # Associate floating IP to the other port on another router
+        resp, floating_ip = self.client.update_floating_ip(
+            created_floating_ip['id'], port_id=port_other_router['id'])
+        self.assertEqual('200', resp['status'])
+        updated_floating_ip = floating_ip['floatingip']
+        self.assertEqual(updated_floating_ip['router_id'], router2['id'])
+        self.assertEqual(updated_floating_ip['port_id'],
+                         port_other_router['id'])
+        self.assertIsNotNone(updated_floating_ip['fixed_ip_address'])
+
 
 class FloatingIPTestXML(FloatingIPTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 9d5a1c0..d0e5353 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -39,27 +39,36 @@
     def setUpClass(cls):
         super(ObjectTempUrlTest, cls).setUpClass()
 
-        # skip this test if CORS isn't enabled in the conf file.
+        # skip this test if TempUrl isn't enabled in the conf file.
         if not cls.tempurl_available:
             skip_msg = ("%s skipped as TempUrl middleware not available"
                         % cls.__name__)
             raise cls.skipException(skip_msg)
 
+        # create a container
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
         cls.containers = [cls.container_name]
 
         # update account metadata
         cls.key = 'Meta'
+        cls.metadatas = []
         cls.metadata = {'Temp-URL-Key': cls.key}
+        cls.metadatas.append(cls.metadata)
         cls.account_client.create_account_metadata(metadata=cls.metadata)
-        cls.account_client_metadata, _ = \
-            cls.account_client.list_account_metadata()
+
+        # create an object
+        cls.object_name = data_utils.rand_name(name='ObjectTemp')
+        cls.content = data_utils.arbitrary_string(size=len(cls.object_name),
+                                                  base_text=cls.object_name)
+        cls.object_client.create_object(cls.container_name,
+                                        cls.object_name, cls.content)
 
     @classmethod
     def tearDownClass(cls):
-        resp, _ = cls.account_client.delete_account_metadata(
-            metadata=cls.metadata)
+        for metadata in cls.metadata:
+            cls.account_client.delete_account_metadata(
+                metadata=metadata)
 
         cls.delete_containers(cls.containers)
 
@@ -69,21 +78,16 @@
 
     def setUp(self):
         super(ObjectTempUrlTest, self).setUp()
+
         # make sure the metadata has been set
+        account_client_metadata, _ = \
+            self.account_client.list_account_metadata()
         self.assertIn('x-account-meta-temp-url-key',
-                      self.account_client_metadata)
-
+                      account_client_metadata)
         self.assertEqual(
-            self.account_client_metadata['x-account-meta-temp-url-key'],
+            account_client_metadata['x-account-meta-temp-url-key'],
             self.key)
 
-        # create object
-        self.object_name = data_utils.rand_name(name='ObjectTemp')
-        self.data = data_utils.arbitrary_string(size=len(self.object_name),
-                                                base_text=self.object_name)
-        self.object_client.create_object(self.container_name,
-                                         self.object_name, self.data)
-
     def _get_expiry_date(self, expiration_time=1000):
         return int(time.time() + expiration_time)
 
@@ -114,10 +118,10 @@
                                  expires, self.key)
 
         # trying to get object using temp url within expiry time
-        resp, body = self.object_client.get_object_using_temp_url(url)
+        resp, body = self.object_client.get(url)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
-        self.assertEqual(body, self.data)
+        self.assertEqual(body, self.content)
 
         # Testing a HEAD on this Temp URL
         resp, body = self.object_client.head(url)
@@ -129,23 +133,27 @@
         key2 = 'Meta2-'
         metadata = {'Temp-URL-Key-2': key2}
         self.account_client.create_account_metadata(metadata=metadata)
+        self.metadatas.append(metadata)
 
-        self.account_client_metadata, _ = \
+        # make sure the metadata has been set
+        account_client_metadata, _ = \
             self.account_client.list_account_metadata()
         self.assertIn('x-account-meta-temp-url-key-2',
-                      self.account_client_metadata)
+                      account_client_metadata)
+        self.assertEqual(
+            account_client_metadata['x-account-meta-temp-url-key-2'],
+            key2)
 
         expires = self._get_expiry_date()
         url = self._get_temp_url(self.container_name,
                                  self.object_name, "GET",
                                  expires, key2)
-        resp, body = self.object_client.get_object_using_temp_url(url)
+        resp, body = self.object_client.get(url)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
-        self.assertEqual(body, self.data)
+        self.assertEqual(body, self.content)
 
     @attr(type='gate')
     def test_put_object_using_temp_url(self):
-        # make sure the metadata has been set
         new_data = data_utils.arbitrary_string(
             size=len(self.object_name),
             base_text=data_utils.rand_name(name="random"))
@@ -156,9 +164,7 @@
                                  expires, self.key)
 
         # trying to put random data in the object using temp url
-        resp, body = self.object_client.put_object_using_temp_url(
-            url, new_data)
-
+        resp, body = self.object_client.put(url, new_data, None)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'PUT')
 
@@ -172,9 +178,23 @@
                                  self.object_name, "GET",
                                  expires, self.key)
 
-        _, body = self.object_client.get_object_using_temp_url(url)
+        _, body = self.object_client.get(url)
         self.assertEqual(body, new_data)
 
+    @attr(type='gate')
+    def test_head_object_using_temp_url(self):
+        expires = self._get_expiry_date()
+
+        # get a temp URL for the created object
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "HEAD",
+                                 expires, self.key)
+
+        # Testing a HEAD on this Temp URL
+        resp, body = self.object_client.head(url)
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'HEAD')
+
     @attr(type=['gate', 'negative'])
     def test_get_object_after_expiration_time(self):
 
@@ -188,5 +208,4 @@
         time.sleep(2)
 
         self.assertRaises(exceptions.Unauthorized,
-                          self.object_client.get_object_using_temp_url,
-                          url)
+                          self.object_client.get, url)
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 9e0adff..5c86d1f 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -134,14 +134,6 @@
         resp, body = self.put(url, data, self.headers)
         return resp, body
 
-    def get_object_using_temp_url(self, url):
-        """Retrieve object's data using temp URL."""
-        return self.get(url)
-
-    def put_object_using_temp_url(self, url, data):
-        """Put data in an object using temp URL."""
-        return self.put(url, data, None)
-
 
 class ObjectClientCustomizedHeader(RestClient):