Merge "Fixes LP#903978 - Write testcases for test_server_actions (boundary)"
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 7fc368e..119494d 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -1,13 +1,15 @@
 import json
-
 import httplib2
-
+import logging
+import sys
 from tempest import exceptions
 
 
 class RestClient(object):
 
     def __init__(self, config, user, key, auth_url, service, tenant_name=None):
+        self.log = logging.getLogger(__name__)
+        self.log.setLevel(logging.ERROR)
         self.config = config
         if self.config.env.authentication == 'keystone_v2':
             self.token, self.base_url = self.keystone_v2_auth(user,
@@ -99,6 +101,12 @@
     def put(self, url, body, headers):
         return self.request('PUT', url, headers, body)
 
+    def _log(self, req_url, body, resp, resp_body):
+        self.log.error('Request URL: ' + req_url)
+        self.log.error('Request Body: ' + str(body))
+        self.log.error('Response Headers: ' + str(resp))
+        self.log.error('Response Body: ' + str(resp_body))
+
     def request(self, method, url, headers=None, body=None):
         """A simple HTTP request interface."""
 
@@ -108,34 +116,38 @@
         headers['X-Auth-Token'] = self.token
 
         req_url = "%s/%s" % (self.base_url, url)
-        resp, body = self.http_obj.request(req_url, method,
+        resp, resp_body = self.http_obj.request(req_url, method,
                                            headers=headers, body=body)
 
         if resp.status == 404:
-            raise exceptions.NotFound(body)
+            self._log(req_url, body, resp, resp_body)
+            raise exceptions.NotFound(resp_body)
 
         if resp.status == 400:
-            body = json.loads(body)
-            raise exceptions.BadRequest(body['badRequest']['message'])
+            resp_body = json.loads(resp_body)
+            self._log(req_url, body, resp, resp_body)
+            raise exceptions.BadRequest(resp_body['badRequest']['message'])
 
         if resp.status == 413:
-            body = json.loads(body)
-            if 'overLimit' in body:
-                raise exceptions.OverLimit(body['overLimit']['message'])
+            resp_body = json.loads(resp_body)
+            self._log(req_url, body, resp, resp_body)
+            if 'overLimit' in resp_body:
+                raise exceptions.OverLimit(resp_body['overLimit']['message'])
             else:
                 raise exceptions.RateLimitExceeded(
-                    message=body['overLimitFault']['message'],
-                    details=body['overLimitFault']['details'])
+                    message=resp_body['overLimitFault']['message'],
+                    details=resp_body['overLimitFault']['details'])
 
         if resp.status in (500, 501):
-            body = json.loads(body)
+            resp_body = json.loads(resp_body)
+            self._log(req_url, body, resp, resp_body)
             #I'm seeing both computeFault and cloudServersFault come back.
             #Will file a bug to fix, but leave as is for now.
 
-            if 'cloudServersFault' in body:
-                message = body['cloudServersFault']['message']
+            if 'cloudServersFault' in resp_body:
+                message = resp_body['cloudServersFault']['message']
             else:
-                message = body['computeFault']['message']
+                message = resp_body['computeFault']['message']
             raise exceptions.ComputeFault(message)
 
-        return resp, body
+        return resp, resp_body
diff --git a/tempest/tests/test_list_images.py b/tempest/tests/test_list_images.py
index 1e30651..65cbe00 100644
--- a/tempest/tests/test_list_images.py
+++ b/tempest/tests/test_list_images.py
@@ -25,14 +25,13 @@
 
         name = rand_name('server')
         resp, cls.server1 = cls.servers_client.create_server(name,
-                                                              cls.image_ref,
-                                                              cls.flavor_ref)
-        cls.servers_client.wait_for_server_status(cls.server1['id'], 'ACTIVE')
-
+                                                             cls.image_ref,
+                                                             cls.flavor_ref)
         name = rand_name('server')
         resp, cls.server2 = cls.servers_client.create_server(name,
-                                                              cls.image_ref,
-                                                              cls.flavor_ref)
+                                                             cls.image_ref,
+                                                             cls.flavor_ref)
+        cls.servers_client.wait_for_server_status(cls.server1['id'], 'ACTIVE')
         cls.servers_client.wait_for_server_status(cls.server2['id'], 'ACTIVE')
 
         # Create images to be used in the filter tests
@@ -43,13 +42,9 @@
         cls.client.wait_for_image_status(cls.image1_id, 'ACTIVE')
         resp, cls.image1 = cls.client.get_image(cls.image1_id)
 
-        image2_name = rand_name('image')
-        resp, body = cls.client.create_image(cls.server1['id'], image2_name)
-        cls.image2_id = _parse_image_id(resp['location'])
-        cls.client.wait_for_image_resp_code(cls.image2_id, 200)
-        cls.client.wait_for_image_status(cls.image2_id, 'ACTIVE')
-        resp, cls.image2 = cls.client.get_image(cls.image2_id)
-
+        # Servers have a hidden property for when they are being imaged
+        # Performing back-to-back create image calls on a single
+        # server will sometimes cause failures
         image3_name = rand_name('image')
         resp, body = cls.client.create_image(cls.server2['id'], image3_name)
         cls.image3_id = _parse_image_id(resp['location'])
@@ -57,6 +52,13 @@
         cls.client.wait_for_image_status(cls.image3_id, 'ACTIVE')
         resp, cls.image3 = cls.client.get_image(cls.image3_id)
 
+        image2_name = rand_name('image')
+        resp, body = cls.client.create_image(cls.server1['id'], image2_name)
+        cls.image2_id = _parse_image_id(resp['location'])
+        cls.client.wait_for_image_resp_code(cls.image2_id, 200)
+        cls.client.wait_for_image_status(cls.image2_id, 'ACTIVE')
+        resp, cls.image2 = cls.client.get_image(cls.image2_id)
+
     @classmethod
     def tearDownClass(cls):
         cls.client.delete_image(cls.image1_id)
@@ -162,13 +164,6 @@
 
     @attr(type='smoke')
     def test_list_images_with_detail(self):
-        """Detailed list of all images should contain the expected image"""
-        resp, images = self.client.list_images_with_detail()
-        found = any([i for i in images if i['id'] == self.image_ref])
-        self.assertTrue(found)
-
-    @attr(type='smoke')
-    def test_list_images_with_detail(self):
         """Detailed list of all images should contain the expected images"""
         resp, images = self.client.list_images_with_detail()
 
diff --git a/tempest/tests/test_list_servers.py b/tempest/tests/test_list_servers.py
index a39069e..af739df 100644
--- a/tempest/tests/test_list_servers.py
+++ b/tempest/tests/test_list_servers.py
@@ -2,6 +2,7 @@
 
 import nose.plugins.skip
 
+from nose.plugins.attrib import attr
 from tempest import openstack
 from tempest import exceptions
 from tempest.common.utils.data_utils import rand_name
@@ -127,3 +128,13 @@
         self.assertEqual(self.s1_name, server['name'])
         self.assertEqual(self.image_ref, server['image']['id'])
         self.assertEqual(str(self.flavor_ref), server['flavor']['id'])
+
+    @attr(type='negative')
+    def test_get_nonexistant_server_details(self):
+        """Negative test: GET on non existant server should not succeed"""
+        try:
+            resp, server = self.client.get_server(999)
+        except exceptions.NotFound:
+            pass
+        else:
+            self.fail('GET on non existant server should not succeed')