Merge "Reduce chance of name collision for resources."
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index d68b9ed..88c8886 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -320,6 +320,10 @@
             except KeyError:
                 ctype = 'application/json'
 
+        # It is not an error response
+        if resp.status < 400:
+            return
+
         JSON_ENC = ['application/json; charset=UTF-8', 'application/json',
                     'application/json; charset=utf-8']
         # NOTE(mtreinish): This is for compatibility with Glance and swift
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index 77c9cd2..9c7269f 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -18,13 +18,17 @@
 import copy
 import errno
 import json
+import logging
 import os
+import time
 import urllib
 
 from tempest.common import glance_http
 from tempest.common.rest_client import RestClient
 from tempest import exceptions
 
+LOG = logging.getLogger(__name__)
+
 
 class ImageClientJSON(RestClient):
 
@@ -59,8 +63,13 @@
     def _image_meta_to_headers(self, fields):
         headers = {}
         fields_copy = copy.deepcopy(fields)
+        copy_from = fields_copy.pop('copy_from', None)
+        if copy_from is not None:
+            headers['x-glance-api-copy-from'] = copy_from
         for key, value in fields_copy.pop('properties', {}).iteritems():
             headers['x-image-meta-property-%s' % key] = str(value)
+        for key, value in fields_copy.pop('api', {}).iteritems():
+            headers['x-glance-api-property-%s' % key] = str(value)
         for key, value in fields_copy.iteritems():
             headers['x-image-meta-%s' % key] = str(value)
         return headers
@@ -130,7 +139,7 @@
 
         headers = {}
 
-        for option in ['is_public', 'location', 'properties']:
+        for option in ['is_public', 'location', 'properties', 'copy_from']:
             if option in kwargs:
                 params[option] = kwargs.get(option)
 
@@ -187,10 +196,15 @@
         body = json.loads(body)
         return resp, body['images']
 
+    def get_image_meta(self, image_id):
+        url = 'v1/images/%s' % image_id
+        resp, __ = self.head(url)
+        body = self._image_meta_from_headers(resp)
+        return resp, body
+
     def get_image(self, image_id):
         url = 'v1/images/%s' % image_id
-        resp, __ = self.get(url)
-        body = self._image_meta_from_headers(resp)
+        resp, body = self.get(url)
         return resp, body
 
     def is_resource_deleted(self, id):
@@ -231,3 +245,34 @@
         resp, data = self.put(url, body, self.headers)
         data = json.loads(data)
         return resp, data
+
+    #NOTE(afazekas): just for the wait function
+    def _get_image_status(self, image_id):
+        resp, meta = self.get_image_meta(image_id)
+        status = meta['status']
+        return status
+
+    #NOTE(afazkas): Wait reinvented again. It is not in the correct layer
+    def wait_for_image_status(self, image_id, status):
+        """Waits for a Image to reach a given status."""
+        start_time = time.time()
+        old_value = value = self._get_image_status(image_id)
+        while True:
+            dtime = time.time() - start_time
+            time.sleep(self.build_interval)
+            if value != old_value:
+                LOG.info('Value transition from "%s" to "%s"'
+                         'in %d second(s).', old_value,
+                         value, dtime)
+            if (value == status):
+                return value
+
+            if dtime > self.build_timeout:
+                message = ('Time Limit Exceeded! (%ds)'
+                           'while waiting for %s, '
+                           'but we got %s.' %
+                           (self.build_timeout, status, value))
+                raise exceptions.TimeoutException(message)
+            time.sleep(self.build_interval)
+            old_value = value
+            value = self._get_image_status(image_id)
diff --git a/tempest/tests/compute/images/test_images_oneserver.py b/tempest/tests/compute/images/test_images_oneserver.py
index 9412d39..ca3dbb5 100644
--- a/tempest/tests/compute/images/test_images_oneserver.py
+++ b/tempest/tests/compute/images/test_images_oneserver.py
@@ -41,7 +41,12 @@
         super(ImagesOneServerTestJSON, cls).setUpClass()
         cls.client = cls.images_client
         cls.servers_client = cls.servers_client
-        resp, cls.server = cls.create_server(wait_until='ACTIVE')
+
+        try:
+            resp, cls.server = cls.create_server(wait_until='ACTIVE')
+        except Exception:
+            cls.tearDownClass()
+            raise
 
         cls.image_ids = []
 
diff --git a/tempest/tests/identity/admin/test_users.py b/tempest/tests/identity/admin/test_users.py
index 80c6fc9..0573b21 100644
--- a/tempest/tests/identity/admin/test_users.py
+++ b/tempest/tests/identity/admin/test_users.py
@@ -326,17 +326,9 @@
         invalid_id.append(rand_name("dddd@#%%^$"))
         invalid_id.append('!@#()$%^&*?<>{}[]')
         #List the users with invalid tenant id
-        fail = list()
         for invalid in invalid_id:
-            try:
-                resp, body = self.client.list_users_for_tenant(invalid)
-            except exceptions.NotFound:
-                pass
-            else:
-                fail.append(invalid)
-        if len(fail) != 0:
-            self.fail('Should raise Not Found when list users with invalid'
-                      'tenant ids %s' % fail)
+            self.assertRaises(exceptions.NotFound,
+                              self.client.list_users_for_tenant, invalid)
 
 
 class UsersTestXML(UsersTestJSON):
diff --git a/tempest/tests/image/v1/test_images.py b/tempest/tests/image/v1/test_images.py
index 9304a33..1b6fa10 100644
--- a/tempest/tests/image/v1/test_images.py
+++ b/tempest/tests/image/v1/test_images.py
@@ -80,6 +80,43 @@
         self.assertEqual(properties['key1'], 'value1')
         self.assertEqual(properties['key2'], 'value2')
 
+    def test_register_http_image(self):
+        container_client = self.os.container_client
+        object_client = self.os.object_client
+        container_name = "image_container"
+        object_name = "test_image.img"
+        container_client.create_container(container_name)
+        self.addCleanup(container_client.delete_container, container_name)
+        cont_headers = {'X-Container-Read': '.r:*'}
+        resp, _ = container_client.update_container_metadata(
+                    container_name,
+                    metadata=cont_headers,
+                    metadata_prefix='')
+        self.assertEqual(resp['status'], '204')
+
+        data = "TESTIMAGE"
+        resp, _ = object_client.create_object(container_name,
+                                              object_name, data)
+        self.addCleanup(object_client.delete_object, container_name,
+                        object_name)
+        self.assertEqual(resp['status'], '201')
+        object_url = '/'.join((object_client.base_url,
+                               container_name,
+                               object_name))
+        resp, body = self.create_image(name='New Http Image',
+                                       container_format='bare',
+                                       disk_format='raw', is_public=True,
+                                       copy_from=object_url)
+        self.assertTrue('id' in body)
+        image_id = body.get('id')
+        self.created_images.append(image_id)
+        self.assertEqual('New Http Image', body.get('name'))
+        self.assertTrue(body.get('is_public'))
+        self.client.wait_for_image_status(image_id, 'active')
+        resp, body = self.client.get_image(image_id)
+        self.assertEqual(resp['status'], '200')
+        self.assertEqual(body, data)
+
 
 class ListImagesTest(base.BaseV1ImageTest):