decoding, an artifact        # of WSGI/webob dispatch?
        now = timeutils.utcnow()
        hour_ago = now.strftime('%Y-%m-%dT%H:%M:%S%%2B01:00')
        params = "changes-since=%s" % hour_ago
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 3)
        # 17. GET /images with future changes-since filter
        tomorrow = timeutils.isotime(timeutils.utcnow() +
                                     datetime.timedelta(1))
        params = "changes-since=%s" % tomorrow
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 0)
        # one timezone east of Greenwich equates to an hour from now
        now = timeutils.utcnow()
        hour_hence = now.strftime('%Y-%m-%dT%H:%M:%S-01:00')
        params = "changes-since=%s" % hour_hence
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 0)
        # 18. GET /images with size_min filter
        # Verify correct images returned with size >= expected
        params = "size_min=-1"
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 400)
        self.assertTrue("filter size_min got -1" in content)
        # 19. GET /images with size_min filter
        # Verify correct images returned with size >= expected
        params = "size_max=-1"
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 400)
        self.assertTrue("filter size_max got -1" in content)
        # 20. GET /images with size_min filter
        # Verify correct images returned with size >= expected
        params = "min_ram=-1"
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 400)
        self.assertTrue("Bad value passed to filter min_ram got -1" in content)
        # 21. GET /images with size_min filter
        # Verify correct images returned with size >= expected
        params = "protected=imalittleteapot"
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 400)
        self.assertTrue("protected got imalittleteapot" in content)
        # 22. GET /images with size_min filter
        # Verify correct images returned with size >= expected
        params = "is_public=imalittleteapot"
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 400)
        self.assertTrue("is_public got imalittleteapot" in content)
**** CubicPower OpenStack Study ****
    def test_limited_images(self):
        """
        Ensure marker and limit query params work
        """
        # 0. GET /images
        # Verify no public images
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')
        image_ids = []
        # 1. POST /images with three public images with various attributes
        headers = minimal_headers('Image1')
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        image_ids.append(jsonutils.loads(content)['image']['id'])
        headers = minimal_headers('Image2')
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        image_ids.append(jsonutils.loads(content)['image']['id'])
        headers = minimal_headers('Image3')
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        image_ids.append(jsonutils.loads(content)['image']['id'])
        # 2. GET /images with all images
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 3)
        # 3. GET /images with limit of 2
        # Verify only two images were returned
        params = "limit=2"
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images']
        self.assertEqual(len(data), 2)
        self.assertEqual(data[0]['id'], images[0]['id'])
        self.assertEqual(data[1]['id'], images[1]['id'])
        # 4. GET /images with marker
        # Verify only two images were returned
        params = "marker=%s" % images[0]['id']
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images']
        self.assertEqual(len(data), 2)
        self.assertEqual(data[0]['id'], images[1]['id'])
        self.assertEqual(data[1]['id'], images[2]['id'])
        # 5. GET /images with marker and limit
        # Verify only one image was returned with the correct id
        params = "limit=1&marker=%s" % images[1]['id']
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images']
        self.assertEqual(len(data), 1)
        self.assertEqual(data[0]['id'], images[2]['id'])
        # 6. GET /images/detail with marker and limit
        # Verify only one image was returned with the correct id
        params = "limit=1&marker=%s" % images[1]['id']
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images']
        self.assertEqual(len(data), 1)
        self.assertEqual(data[0]['id'], images[2]['id'])
        # DELETE images
        for image_id in image_ids:
            path = "/v1/images/%s" % (image_id)
            response, content = self.http.request(path, 'DELETE')
            self.assertEqual(response.status, 200)
**** CubicPower OpenStack Study ****
    def test_ordered_images(self):
        """
        Set up three test images and ensure each query param filter works
        """
        # 0. GET /images
        # Verify no public images
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')
        # 1. POST /images with three public images with various attributes
        image_ids = []
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Name': 'Image1',
                   'X-Image-Meta-Status': 'active',
                   'X-Image-Meta-Container-Format': 'ovf',
                   'X-Image-Meta-Disk-Format': 'vdi',
                   'X-Image-Meta-Size': '19',
                   'X-Image-Meta-Is-Public': 'True'}
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        image_ids.append(jsonutils.loads(content)['image']['id'])
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Name': 'ASDF',
                   'X-Image-Meta-Status': 'active',
                   'X-Image-Meta-Container-Format': 'bare',
                   'X-Image-Meta-Disk-Format': 'iso',
                   'X-Image-Meta-Size': '2',
                   'X-Image-Meta-Is-Public': 'True'}
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        image_ids.append(jsonutils.loads(content)['image']['id'])
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Name': 'XYZ',
                   'X-Image-Meta-Status': 'saving',
                   'X-Image-Meta-Container-Format': 'ami',
                   'X-Image-Meta-Disk-Format': 'ami',
                   'X-Image-Meta-Size': '5',
                   'X-Image-Meta-Is-Public': 'True'}
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        image_ids.append(jsonutils.loads(content)['image']['id'])
        # 2. GET /images with no query params
        # Verify three public images sorted by created_at desc
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 3)
        self.assertEqual(data['images'][0]['id'], image_ids[2])
        self.assertEqual(data['images'][1]['id'], image_ids[1])
        self.assertEqual(data['images'][2]['id'], image_ids[0])
        # 3. GET /images sorted by name asc
        params = 'sort_key=name&sort_dir=asc'
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 3)
        self.assertEqual(data['images'][0]['id'], image_ids[1])
        self.assertEqual(data['images'][1]['id'], image_ids[0])
        self.assertEqual(data['images'][2]['id'], image_ids[2])
        # 4. GET /images sorted by size desc
        params = 'sort_key=size&sort_dir=desc'
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 3)
        self.assertEqual(data['images'][0]['id'], image_ids[0])
        self.assertEqual(data['images'][1]['id'], image_ids[2])
        self.assertEqual(data['images'][2]['id'], image_ids[1])
        # 5. GET /images sorted by size desc with a marker
        params = 'sort_key=size&sort_dir=desc&marker=%s' % image_ids[0]
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 2)
        self.assertEqual(data['images'][0]['id'], image_ids[2])
        self.assertEqual(data['images'][1]['id'], image_ids[1])
        # 6. GET /images sorted by name asc with a marker
        params = 'sort_key=name&sort_dir=asc&marker=%s' % image_ids[2]
        path = "/v1/images?%s" % (params)
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['images']), 0)
        # DELETE images
        for image_id in image_ids:
            path = "/v1/images/%s" % (image_id)
            response, content = self.http.request(path, 'DELETE')
            self.assertEqual(response.status, 200)
**** CubicPower OpenStack Study ****
    def test_duplicate_image_upload(self):
        """
        Upload initial image, then attempt to upload duplicate image
        """
        # 0. GET /images
        # Verify no public images
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')
        # 1. POST /images with public image named Image1
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Name': 'Image1',
                   'X-Image-Meta-Status': 'active',
                   'X-Image-Meta-Container-Format': 'ovf',
                   'X-Image-Meta-Disk-Format': 'vdi',
                   'X-Image-Meta-Size': '19',
                   'X-Image-Meta-Is-Public': 'True'}
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        image = jsonutils.loads(content)['image']
        # 2. POST /images with public image named Image1, and ID: 1
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Name': 'Image1 Update',
                   'X-Image-Meta-Status': 'active',
                   'X-Image-Meta-Container-Format': 'ovf',
                   'X-Image-Meta-Disk-Format': 'vdi',
                   'X-Image-Meta-Size': '19',
                   'X-Image-Meta-Id': image['id'],
                   'X-Image-Meta-Is-Public': 'True'}
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 409)
**** CubicPower OpenStack Study ****
    def test_delete_not_existing(self):
        """
        We test the following:
        0. GET /images/1
        - Verify 404
        1. DELETE /images/1
        - Verify 404
        """
        # 0. GET /images
        # Verify no public images
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')
        # 1. DELETE /images/1
        # Verify 404 returned
        path = "/v1/images/1"
        response, content = self.http.request(path, 'DELETE')
        self.assertEqual(response.status, 404)
**** CubicPower OpenStack Study ****
    def _do_test_post_image_content_bad_format(self, format):
        """
        We test that missing container/disk format fails with 400 "Bad Request"
        :see https://bugs.launchpad.net/glance/+bug/933702
        """
        # Verify no public images
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)
        path = "/v1/images"
        # POST /images without given format being specified
        headers = minimal_headers('Image1')
        headers['X-Image-Meta-' + format] = 'bad_value'
        with tempfile.NamedTemporaryFile() as test_data_file:
            test_data_file.write("XXX")
            test_data_file.flush()
        response, content = self.http.request(path, 'POST',
                                              headers=headers,
                                              body=test_data_file.name)
        self.assertEqual(response.status, 400)
        type = format.replace('_format', '')
        expected = "Invalid %s format 'bad_value' for image" % type
        self.assertTrue(expected in content,
                        "Could not find '%s' in '%s'" % (expected, content))
        # make sure the image was not created
        # Verify no public images
        path = "/v1/images"
        response, content = self.http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)
**** CubicPower OpenStack Study ****
    def test_post_image_content_bad_container_format(self):
        self._do_test_post_image_content_bad_format('container_format')
**** CubicPower OpenStack Study ****
    def test_post_image_content_bad_disk_format(self):
        self._do_test_post_image_content_bad_format('disk_format')
**** CubicPower OpenStack Study ****
    def _do_test_put_image_content_missing_format(self, format):
        """
        We test that missing container/disk format only fails with
        400 "Bad Request" when the image content is PUT (i.e. not
        on the original POST of a queued image).
        :see https://bugs.launchpad.net/glance/+bug/937216
        """
        # POST queued image
        path = "/v1/images"
        headers = {
            'X-Image-Meta-Name': 'Image1',
            'X-Image-Meta-Is-Public': 'True',
        }
        response, content = self.http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        self.addDetail('image_data', testtools.content.json_content(data))
        # PUT image content images without given format being specified
        path = "/v1/images/%s" % (image_id)
        headers = minimal_headers('Image1')
        del headers['X-Image-Meta-' + format]
        with tempfile.NamedTemporaryFile() as test_data_file:
            test_data_file.write("XXX")
            test_data_file.flush()
        response, content = self.http.request(path, 'PUT',
                                              headers=headers,
                                              body=test_data_file.name)
        self.assertEqual(response.status, 400)
        type = format.replace('_format', '')
        expected = "Invalid %s format 'None' for image" % type
        self.assertTrue(expected in content,
                        "Could not find '%s' in '%s'" % (expected, content))
**** CubicPower OpenStack Study ****
    def test_put_image_content_bad_container_format(self):
        self._do_test_put_image_content_missing_format('container_format')
**** CubicPower OpenStack Study ****
    def test_put_image_content_bad_disk_format(self):
        self._do_test_put_image_content_missing_format('disk_format')
**** CubicPower OpenStack Study ****
    def _do_test_mismatched_attribute(self, attribute, value):
        """
        Test mismatched attribute.
        """
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1')
        headers[attribute] = value
        path = "/v1/images"
        response, content = self.http.request(path, 'POST', headers=headers,
                                              body=image_data)
        self.assertEqual(response.status, 400)
        images_dir = os.path.join(self.test_dir, 'images')
        image_count = len([name for name in os.listdir(images_dir)
                           if os.path.isfile(os.path.join(images_dir, name))])
        self.assertEqual(image_count, 0)
**** CubicPower OpenStack Study ****
    def test_mismatched_size(self):
        """
        Test mismatched size.
        """
        self._do_test_mismatched_attribute('x-image-meta-size',
                                           str(FIVE_KB + 1))
**** CubicPower OpenStack Study ****
    def test_mismatched_checksum(self):
        """
        Test mismatched checksum.
        """
        self._do_test_mismatched_attribute('x-image-meta-checksum',
                                           'foobar')
**** CubicPower OpenStack Study ****
class TestApiWithFakeAuth(base.ApiTest):
    
**** CubicPower OpenStack Study ****
    def __init__(self, *args, **kwargs):
        super(TestApiWithFakeAuth, self).__init__(*args, **kwargs)
        self.api_flavor = 'fakeauth'
        self.registry_flavor = 'fakeauth'
**** CubicPower OpenStack Study ****
    def test_ownership(self):
        # Add an image with admin privileges and ensure the owner
        # can be set to something other than what was used to authenticate
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        create_headers = {
            'X-Image-Meta-Name': 'MyImage',
            'X-Image-Meta-disk_format': 'raw',
            'X-Image-Meta-container_format': 'ovf',
            'X-Image-Meta-Is-Public': 'True',
            'X-Image-Meta-Owner': 'tenant2',
        }
        create_headers.update(auth_headers)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=create_headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        path = "/v1/images/%s" % (image_id)
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertEqual('tenant2', response['x-image-meta-owner'])
        # Now add an image without admin privileges and ensure the owner
        # cannot be set to something other than what was used to authenticate
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:role1',
        }
        create_headers.update(auth_headers)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=create_headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        # We have to be admin to see the owner
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        create_headers.update(auth_headers)
        path = "/v1/images/%s" % (image_id)
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertEqual('tenant1', response['x-image-meta-owner'])
        # Make sure the non-privileged user can't update their owner either
        update_headers = {
            'X-Image-Meta-Name': 'MyImage2',
            'X-Image-Meta-Owner': 'tenant2',
            'X-Auth-Token': 'user1:tenant1:role1',
        }
        path = "/v1/images/%s" % (image_id)
        response, content = self.http.request(path, 'PUT',
                                              headers=update_headers)
        self.assertEqual(response.status, 200)
        # We have to be admin to see the owner
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        path = "/v1/images/%s" % (image_id)
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertEqual('tenant1', response['x-image-meta-owner'])
        # An admin user should be able to update the owner
        auth_headers = {
            'X-Auth-Token': 'user1:tenant3:admin',
        }
        update_headers = {
            'X-Image-Meta-Name': 'MyImage2',
            'X-Image-Meta-Owner': 'tenant2',
        }
        update_headers.update(auth_headers)
        path = "/v1/images/%s" % (image_id)
        response, content = self.http.request(path, 'PUT',
                                              headers=update_headers)
        self.assertEqual(response.status, 200)
        path = "/v1/images/%s" % (image_id)
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertEqual('tenant2', response['x-image-meta-owner'])
**** CubicPower OpenStack Study ****
    def test_image_visibility_to_different_users(self):
        owners = ['admin', 'tenant1', 'tenant2', 'none']
        visibilities = {'public': 'True', 'private': 'False'}
        image_ids = {}
        for owner in owners:
            for visibility, is_public in visibilities.items():
                name = '%s-%s' % (owner, visibility)
                headers = {
                    'Content-Type': 'application/octet-stream',
                    'X-Image-Meta-Name': name,
                    'X-Image-Meta-Status': 'active',
                    'X-Image-Meta-Is-Public': is_public,
                    'X-Image-Meta-Owner': owner,
                    'X-Auth-Token': 'createuser:createtenant:admin',
                }
                path = "/v1/images"
                response, content = self.http.request(path, 'POST',
                                                      headers=headers)
                self.assertEqual(response.status, 201)
                data = jsonutils.loads(content)
                image_ids[name] = data['image']['id']
        def list_images(tenant, role='', is_public=None):
            auth_token = 'user:%s:%s' % (tenant, role)
            headers = {'X-Auth-Token': auth_token}
            path = "/v1/images/detail"
            if is_public is not None:
                path += '?is_public=%s' % is_public
            response, content = self.http.request(path, 'GET', headers=headers)
            self.assertEqual(response.status, 200)
            return jsonutils.loads(content)['images']
        # 1. Known user sees public and their own images
        images = list_images('tenant1')
        self.assertEqual(len(images), 5)
        for image in images:
            self.assertTrue(image['is_public'] or image['owner'] == 'tenant1')
        # 2. Unknown user sees only public images
        images = list_images('none')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertTrue(image['is_public'])
        # 3. Unknown admin sees only public images
        images = list_images('none', role='admin')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertTrue(image['is_public'])
        # 4. Unknown admin, is_public=none, shows all images
        images = list_images('none', role='admin', is_public='none')
        self.assertEqual(len(images), 8)
        # 5. Unknown admin, is_public=true, shows only public images
        images = list_images('none', role='admin', is_public='true')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertTrue(image['is_public'])
        # 6. Unknown admin, is_public=false, sees only private images
        images = list_images('none', role='admin', is_public='false')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertFalse(image['is_public'])
        # 7. Known admin sees public and their own images
        images = list_images('admin', role='admin')
        self.assertEqual(len(images), 5)
        for image in images:
            self.assertTrue(image['is_public'] or image['owner'] == 'admin')
        # 8. Known admin, is_public=none, shows all images
        images = list_images('admin', role='admin', is_public='none')
        self.assertEqual(len(images), 8)
        # 9. Known admin, is_public=true, sees all public and their images
        images = list_images('admin', role='admin', is_public='true')
        self.assertEqual(len(images), 5)
        for image in images:
            self.assertTrue(image['is_public'] or image['owner'] == 'admin')
        # 10. Known admin, is_public=false, sees all private images
        images = list_images('admin', role='admin', is_public='false')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertFalse(image['is_public'])
**** CubicPower OpenStack Study ****
        def list_images(tenant, role='', is_public=None):
            auth_token = 'user:%s:%s' % (tenant, role)
            headers = {'X-Auth-Token': auth_token}
            path = "/v1/images/detail"
            if is_public is not None:
                path += '?is_public=%s' % is_public
            response, content = self.http.request(path, 'GET', headers=headers)
            self.assertEqual(response.status, 200)
            return jsonutils.loads(content)['images']
        # 1. Known user sees public and their own images
        images = list_images('tenant1')
        self.assertEqual(len(images), 5)
        for image in images:
            self.assertTrue(image['is_public'] or image['owner'] == 'tenant1')
        # 2. Unknown user sees only public images
        images = list_images('none')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertTrue(image['is_public'])
        # 3. Unknown admin sees only public images
        images = list_images('none', role='admin')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertTrue(image['is_public'])
        # 4. Unknown admin, is_public=none, shows all images
        images = list_images('none', role='admin', is_public='none')
        self.assertEqual(len(images), 8)
        # 5. Unknown admin, is_public=true, shows only public images
        images = list_images('none', role='admin', is_public='true')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertTrue(image['is_public'])
        # 6. Unknown admin, is_public=false, sees only private images
        images = list_images('none', role='admin', is_public='false')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertFalse(image['is_public'])
        # 7. Known admin sees public and their own images
        images = list_images('admin', role='admin')
        self.assertEqual(len(images), 5)
        for image in images:
            self.assertTrue(image['is_public'] or image['owner'] == 'admin')
        # 8. Known admin, is_public=none, shows all images
        images = list_images('admin', role='admin', is_public='none')
        self.assertEqual(len(images), 8)
        # 9. Known admin, is_public=true, sees all public and their images
        images = list_images('admin', role='admin', is_public='true')
        self.assertEqual(len(images), 5)
        for image in images:
            self.assertTrue(image['is_public'] or image['owner'] == 'admin')
        # 10. Known admin, is_public=false, sees all private images
        images = list_images('admin', role='admin', is_public='false')
        self.assertEqual(len(images), 4)
        for image in images:
            self.assertFalse(image['is_public'])
**** CubicPower OpenStack Study ****
    def test_property_protections(self):
        # Enable property protection
        self.config(property_protection_file=self.property_file)
        self.setUp()
        CREATE_HEADERS = {
            'X-Image-Meta-Name': 'MyImage',
            'X-Image-Meta-disk_format': 'raw',
            'X-Image-Meta-container_format': 'ovf',
            'X-Image-Meta-Is-Public': 'True',
            'X-Image-Meta-Owner': 'tenant2',
        }
        # Create an image for role member with extra properties
        # Raises 403 since user is not allowed to create 'foo'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:member',
        }
        custom_props = {
            'x-image-meta-property-foo': 'bar'
        }
        auth_headers.update(custom_props)
        auth_headers.update(CREATE_HEADERS)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        # Create an image for role member without 'foo'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:member',
        }
        custom_props = {
            'x-image-meta-property-x_owner_foo': 'o_s_bar',
        }
        auth_headers.update(custom_props)
        auth_headers.update(CREATE_HEADERS)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=auth_headers)
        self.assertEqual(response.status, 201)
        # Returned image entity should have 'x_owner_foo'
        data = jsonutils.loads(content)
        self.assertEqual(data['image']['properties']['x_owner_foo'],
                         'o_s_bar')
        # Create an image for role spl_role with extra properties
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:spl_role',
        }
        custom_props = {
            'X-Image-Meta-Property-spl_create_prop': 'create_bar',
            'X-Image-Meta-Property-spl_read_prop': 'read_bar',
            'X-Image-Meta-Property-spl_update_prop': 'update_bar',
            'X-Image-Meta-Property-spl_delete_prop': 'delete_bar'
        }
        auth_headers.update(custom_props)
        auth_headers.update(CREATE_HEADERS)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=auth_headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        # Attempt to update two properties, one protected(spl_read_prop), the
        # other not(spl_update_prop).  Request should be forbidden.
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:spl_role',
        }
        custom_props = {
            'X-Image-Meta-Property-spl_read_prop': 'r',
            'X-Image-Meta-Property-spl_update_prop': 'u',
            'X-Glance-Registry-Purge-Props': 'False'
        }
        auth_headers.update(auth_headers)
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        # Attempt to create properties which are forbidden
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:spl_role',
        }
        custom_props = {
            'X-Image-Meta-Property-spl_new_prop': 'new',
            'X-Glance-Registry-Purge-Props': 'True'
        }
        auth_headers.update(auth_headers)
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        # Attempt to update, create and delete properties
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:spl_role',
        }
        custom_props = {
            'X-Image-Meta-Property-spl_create_prop': 'create_bar',
            'X-Image-Meta-Property-spl_read_prop': 'read_bar',
            'X-Image-Meta-Property-spl_update_prop': 'u',
            'X-Glance-Registry-Purge-Props': 'True'
        }
        auth_headers.update(auth_headers)
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        # Returned image entity should reflect the changes
        image = jsonutils.loads(content)
        # 'spl_update_prop' has update permission for spl_role
        # hence the value has changed
        self.assertEqual('u', image['image']['properties']['spl_update_prop'])
        # 'spl_delete_prop' has delete permission for spl_role
        # hence the property has been deleted
        self.assertTrue('spl_delete_prop' not in image['image']['properties'])
        # 'spl_create_prop' has create permission for spl_role
        # hence the property has been created
        self.assertEqual('create_bar',
                         image['image']['properties']['spl_create_prop'])
        # Image Deletion should work
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:spl_role',
        }
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'DELETE',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        # This image should be no longer be directly accessible
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:spl_role',
        }
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 404)
**** CubicPower OpenStack Study ****
    def test_property_protections_special_chars(self):
        # Enable property protection
        self.config(property_protection_file=self.property_file)
        self.setUp()
        CREATE_HEADERS = {
            'X-Image-Meta-Name': 'MyImage',
            'X-Image-Meta-disk_format': 'raw',
            'X-Image-Meta-container_format': 'ovf',
            'X-Image-Meta-Is-Public': 'True',
            'X-Image-Meta-Owner': 'tenant2',
            'X-Image-Meta-Size': '0',
        }
        # Create an image
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:member',
        }
        auth_headers.update(CREATE_HEADERS)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=auth_headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        # Verify both admin and unknown role can create properties marked with
        # '@'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_all_permitted_admin': '1'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        image = jsonutils.loads(content)
        self.assertEqual('1',
                         image['image']['properties']['x_all_permitted_admin'])
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        custom_props = {
            'X-Image-Meta-Property-x_all_permitted_joe_soap': '1',
            'X-Glance-Registry-Purge-Props': 'False'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        image = jsonutils.loads(content)
        self.assertEqual(
            '1', image['image']['properties']['x_all_permitted_joe_soap'])
        # Verify both admin and unknown role can read properties marked with
        # '@'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertEqual('1', response.get(
            'x-image-meta-property-x_all_permitted_admin'))
        self.assertEqual('1', response.get(
            'x-image-meta-property-x_all_permitted_joe_soap'))
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertEqual('1', response.get(
            'x-image-meta-property-x_all_permitted_admin'))
        self.assertEqual('1', response.get(
            'x-image-meta-property-x_all_permitted_joe_soap'))
        # Verify both admin and unknown role can update properties marked with
        # '@'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_all_permitted_admin': '2',
            'X-Glance-Registry-Purge-Props': 'False'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        image = jsonutils.loads(content)
        self.assertEqual('2',
                         image['image']['properties']['x_all_permitted_admin'])
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        custom_props = {
            'X-Image-Meta-Property-x_all_permitted_joe_soap': '2',
            'X-Glance-Registry-Purge-Props': 'False'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        image = jsonutils.loads(content)
        self.assertEqual(
            '2', image['image']['properties']['x_all_permitted_joe_soap'])
        # Verify both admin and unknown role can delete properties marked with
        # '@'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_all_permitted_joe_soap': '2',
            'X-Glance-Registry-Purge-Props': 'True'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        image = jsonutils.loads(content)
        self.assertNotIn('x_all_permitted_admin', image['image']['properties'])
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        custom_props = {
            'X-Glance-Registry-Purge-Props': 'True'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        image = jsonutils.loads(content)
        self.assertNotIn('x_all_permitted_joe_soap',
                         image['image']['properties'])
        # Verify neither admin nor unknown role can create a property protected
        # with '!'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_none_permitted_admin': '1'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        custom_props = {
            'X-Image-Meta-Property-x_none_permitted_joe_soap': '1'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        # Verify neither admin nor unknown role can read properties marked with
        # '!'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_none_read': '1'
        }
        auth_headers.update(custom_props)
        auth_headers.update(CREATE_HEADERS)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=auth_headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertRaises(KeyError,
                          response.get, 'X-Image-Meta-Property-x_none_read')
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'HEAD',
                                              headers=auth_headers)
        self.assertEqual(response.status, 200)
        self.assertRaises(KeyError,
                          response.get, 'X-Image-Meta-Property-x_none_read')
        # Verify neither admin nor unknown role can update properties marked
        # with '!'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_none_update': '1'
        }
        auth_headers.update(custom_props)
        auth_headers.update(CREATE_HEADERS)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=auth_headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_none_update': '2'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        custom_props = {
            'X-Image-Meta-Property-x_none_update': '2'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        # Verify neither admin nor unknown role can delete properties marked
        # with '!'
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Image-Meta-Property-x_none_delete': '1'
        }
        auth_headers.update(custom_props)
        auth_headers.update(CREATE_HEADERS)
        path = "/v1/images"
        response, content = self.http.request(path, 'POST',
                                              headers=auth_headers)
        self.assertEqual(response.status, 201)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:admin',
        }
        custom_props = {
            'X-Glance-Registry-Purge-Props': 'True'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)
        auth_headers = {
            'X-Auth-Token': 'user1:tenant1:joe_soap',
        }
        custom_props = {
            'X-Glance-Registry-Purge-Props': 'True'
        }
        auth_headers.update(custom_props)
        path = "/v1/images/%s" % image_id
        response, content = self.http.request(path, 'PUT',
                                              headers=auth_headers)
        self.assertEqual(response.status, 403)