Merge "Remove Glance v1 APIs tests"

This commit is contained in:
Zuul 2023-08-16 15:03:11 +00:00 committed by Gerrit Code Review
commit 49c64a985c
27 changed files with 64 additions and 1147 deletions

View File

@ -0,0 +1,8 @@
---
prelude: >
Glance v1 APIs were removed in Rocky release and last
supported release for v1 was Queens. Tempest master does
not support the Rocky or Queens release so we removed
the Glance v1 tests, config option, and its service clients.
If you would like to test the v1 APIs then you can use the old
Tempest version.

View File

@ -113,14 +113,11 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
cls.attachments_client = cls.os_primary.attachments_client_latest
cls.snapshots_client = cls.os_primary.snapshots_client_latest
if CONF.service_available.glance:
if CONF.image_feature_enabled.api_v1:
cls.images_client = cls.os_primary.image_client
elif CONF.image_feature_enabled.api_v2:
if CONF.image_feature_enabled.api_v2:
cls.images_client = cls.os_primary.image_client_v2
else:
raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
'api_v2 must be True in [image-feature-enabled].')
@classmethod
def resource_setup(cls):

View File

@ -17,7 +17,6 @@ import io
import random
from tempest.api.compute import base
from tempest.common import image as common_image
from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
@ -48,23 +47,15 @@ class FlavorsV2NegativeTest(base.BaseV2ComputeTest):
'name': data_utils.rand_name('image'),
'container_format': CONF.image.container_formats[0],
'disk_format': CONF.image.disk_formats[0],
'min_ram': min_img_ram
'min_ram': min_img_ram,
'visibility': 'private'
}
if CONF.image_feature_enabled.api_v1:
params.update({'is_public': False})
params = {'headers': common_image.image_meta_to_headers(**params)}
else:
params.update({'visibility': 'private'})
image = self.images_client.create_image(**params)
image = image['image'] if 'image' in image else image
self.addCleanup(self.images_client.delete_image, image['id'])
if CONF.image_feature_enabled.api_v1:
self.images_client.update_image(image['id'], data=image_file)
else:
self.images_client.store_image_file(image['id'], data=image_file)
self.images_client.store_image_file(image['id'], data=image_file)
self.assertEqual(min_img_ram, image['min_ram'])

View File

@ -16,7 +16,6 @@
import io
from tempest.api.compute import base
from tempest.common import image as common_image
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
@ -42,17 +41,11 @@ class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
@classmethod
def setup_clients(cls):
super(ImagesMetadataTestJSON, cls).setup_clients()
# Check if glance v1 is available to determine which client to use. We
# prefer glance v1 for the compute API tests since the compute image
# API proxy was written for glance v1.
if CONF.image_feature_enabled.api_v1:
cls.glance_client = cls.os_primary.image_client
elif CONF.image_feature_enabled.api_v2:
if CONF.image_feature_enabled.api_v2:
cls.glance_client = cls.os_primary.image_client_v2
else:
raise exceptions.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
'api_v2 must be True in [image-feature-enabled].')
cls.client = cls.compute_images_client
@classmethod
@ -63,13 +56,9 @@ class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
params = {
'name': data_utils.rand_name('image'),
'container_format': 'bare',
'disk_format': 'raw'
'disk_format': 'raw',
'visibility': 'private'
}
if CONF.image_feature_enabled.api_v1:
params.update({'is_public': False})
params = {'headers': common_image.image_meta_to_headers(**params)}
else:
params.update({'visibility': 'private'})
body = cls.glance_client.create_image(**params)
body = body['image'] if 'image' in body else body
@ -78,10 +67,7 @@ class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
cls.glance_client.delete_image,
cls.image_id)
image_file = io.BytesIO((b'*' * 1024))
if CONF.image_feature_enabled.api_v1:
cls.glance_client.update_image(cls.image_id, data=image_file)
else:
cls.glance_client.store_image_file(cls.image_id, data=image_file)
cls.glance_client.store_image_file(cls.image_id, data=image_file)
waiters.wait_for_image_status(cls.client, cls.image_id, 'ACTIVE')
def setUp(self):

View File

@ -19,7 +19,6 @@ import io
import testtools
from tempest.api.compute import base
from tempest.common import image as common_image
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
@ -46,17 +45,11 @@ class ListImageFiltersTestJSON(base.BaseV2ComputeTest):
def setup_clients(cls):
super(ListImageFiltersTestJSON, cls).setup_clients()
cls.client = cls.compute_images_client
# Check if glance v1 is available to determine which client to use. We
# prefer glance v1 for the compute API tests since the compute image
# API proxy was written for glance v1.
if CONF.image_feature_enabled.api_v1:
cls.glance_client = cls.os_primary.image_client
elif CONF.image_feature_enabled.api_v2:
if CONF.image_feature_enabled.api_v2:
cls.glance_client = cls.os_primary.image_client_v2
else:
raise exceptions.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
'api_v2 must be True in [image-feature-enabled].')
@classmethod
def resource_setup(cls):
@ -66,14 +59,9 @@ class ListImageFiltersTestJSON(base.BaseV2ComputeTest):
params = {
'name': data_utils.rand_name(cls.__name__ + '-image'),
'container_format': 'bare',
'disk_format': 'raw'
'disk_format': 'raw',
'visibility': 'private'
}
if CONF.image_feature_enabled.api_v1:
params.update({'is_public': False})
params = {'headers':
common_image.image_meta_to_headers(**params)}
else:
params.update({'visibility': 'private'})
body = cls.glance_client.create_image(**params)
body = body['image'] if 'image' in body else body
@ -86,10 +74,7 @@ class ListImageFiltersTestJSON(base.BaseV2ComputeTest):
# between created_at and updated_at.
time.sleep(1)
image_file = io.BytesIO((b'*' * 1024))
if CONF.image_feature_enabled.api_v1:
cls.glance_client.update_image(image_id, data=image_file)
else:
cls.glance_client.store_image_file(image_id, data=image_file)
cls.glance_client.store_image_file(image_id, data=image_file)
waiters.wait_for_image_status(cls.client, image_id, 'ACTIVE')
body = cls.client.show_image(image_id)['image']
return body

View File

@ -569,17 +569,11 @@ class ServerActionsTestOtherB(ServerActionsBase):
# create the first and the second backup
# Check if glance v1 is available to determine which client to use. We
# prefer glance v1 for the compute API tests since the compute image
# API proxy was written for glance v1.
if CONF.image_feature_enabled.api_v1:
glance_client = self.os_primary.image_client
elif CONF.image_feature_enabled.api_v2:
if CONF.image_feature_enabled.api_v2:
glance_client = self.os_primary.image_client_v2
else:
raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
'api_v2 must be True in [image-feature-enabled].')
backup1 = data_utils.rand_name('backup-1')
resp = self.client.create_backup(self.server_id,
@ -635,16 +629,9 @@ class ServerActionsTestOtherB(ServerActionsBase):
'sort_key': 'created_at',
'sort_dir': 'asc'
}
if CONF.image_feature_enabled.api_v1:
for key, value in properties.items():
params['property-%s' % key] = value
image_list = glance_client.list_images(
detail=True,
**params)['images']
else:
# Additional properties are flattened in glance v2.
params.update(properties)
image_list = glance_client.list_images(params)['images']
# Additional properties are flattened in glance v2.
params.update(properties)
image_list = glance_client.list_images(params)['images']
self.assertEqual(2, len(image_list))
self.assertEqual((backup1, backup2),
@ -668,11 +655,7 @@ class ServerActionsTestOtherB(ServerActionsBase):
waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
glance_client.wait_for_resource_deletion(image1_id)
oldest_backup_exist = False
if CONF.image_feature_enabled.api_v1:
image_list = glance_client.list_images(
detail=True, **params)['images']
else:
image_list = glance_client.list_images(params)['images']
image_list = glance_client.list_images(params)['images']
self.assertEqual(2, len(image_list),
'Unexpected number of images for '
'v2:test_create_backup; was the oldest backup not '
@ -733,23 +716,16 @@ class ServerActionsTestOtherB(ServerActionsBase):
"""Test shelving and unshelving server"""
if CONF.image_feature_enabled.api_v2:
glance_client = self.os_primary.image_client_v2
elif CONF.image_feature_enabled.api_v1:
glance_client = self.os_primary.image_client
else:
raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
'api_v2 must be True in [image-feature-enabled].')
compute.shelve_server(self.client, self.server_id,
force_shelve_offload=True)
server = self.client.show_server(self.server_id)['server']
image_name = server['name'] + '-shelved'
params = {'name': image_name}
if CONF.image_feature_enabled.api_v2:
images = glance_client.list_images(params)['images']
elif CONF.image_feature_enabled.api_v1:
images = glance_client.list_images(
detail=True, **params)['images']
images = glance_client.list_images(params)['images']
self.assertEqual(1, len(images))
self.assertEqual(image_name, images[0]['name'])

View File

@ -508,10 +508,7 @@ class ServersNegativeTestJSON(base.BaseV2ComputeTest):
server = self.client.show_server(self.server_id)['server']
image_name = server['name'] + '-shelved'
if CONF.image_feature_enabled.api_v1:
kwargs = {'name': image_name}
else:
kwargs = {'params': {'name': image_name}}
kwargs = {'params': {'name': image_name}}
images = self.images_client.list_images(**kwargs)['images']
self.assertEqual(1, len(images))
self.assertEqual(image_name, images[0]['name'])

View File

@ -12,10 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import io
import time
from tempest.common import image as common_image
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@ -56,17 +54,7 @@ class BaseImageTest(tempest.test.BaseTestCase):
name = data_utils.rand_name(cls.__name__ + "-image")
kwargs['name'] = name
params = cls._get_create_params(**kwargs)
if data:
# NOTE: On glance v1 API, the data should be passed on
# a header. Then here handles the data separately.
params['data'] = data
image = cls.client.create_image(**params)
# Image objects returned by the v1 client have the image
# data inside a dict that is keyed against 'image'.
if 'image' in image:
image = image['image']
image = cls.client.create_image(**kwargs)
cls.created_images.append(image['id'])
cls.addClassResourceCleanup(cls.client.wait_for_resource_deletion,
image['id'])
@ -74,54 +62,6 @@ class BaseImageTest(tempest.test.BaseTestCase):
cls.client.delete_image, image['id'])
return image
@classmethod
def _get_create_params(cls, **kwargs):
return kwargs
class BaseV1ImageTest(BaseImageTest):
@classmethod
def skip_checks(cls):
super(BaseV1ImageTest, cls).skip_checks()
if not CONF.image_feature_enabled.api_v1:
msg = "Glance API v1 not supported"
raise cls.skipException(msg)
@classmethod
def setup_clients(cls):
super(BaseV1ImageTest, cls).setup_clients()
cls.client = cls.os_primary.image_client
@classmethod
def _get_create_params(cls, **kwargs):
return {'headers': common_image.image_meta_to_headers(**kwargs)}
class BaseV1ImageMembersTest(BaseV1ImageTest):
credentials = ['primary', 'alt']
@classmethod
def setup_clients(cls):
super(BaseV1ImageMembersTest, cls).setup_clients()
cls.image_member_client = cls.os_primary.image_member_client
cls.alt_image_member_client = cls.os_alt.image_member_client
cls.alt_img_cli = cls.os_alt.image_client
@classmethod
def resource_setup(cls):
super(BaseV1ImageMembersTest, cls).resource_setup()
cls.alt_tenant_id = cls.alt_image_member_client.tenant_id
def _create_image(self):
image_file = io.BytesIO(data_utils.random_bytes())
image = self.create_image(container_format='bare',
disk_format='raw',
is_public=False,
data=image_file)
return image['id']
class BaseV2ImageTest(BaseImageTest):

View File

@ -1,63 +0,0 @@
# Copyright 2013 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.api.image import base
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
class ImageMembersTest(base.BaseV1ImageMembersTest):
"""Test image members"""
@decorators.idempotent_id('1d6ef640-3a20-4c84-8710-d95828fdb6ad')
def test_add_image_member(self):
"""Test adding member for image"""
image = self._create_image()
self.image_member_client.create_image_member(image, self.alt_tenant_id)
body = self.image_member_client.list_image_members(image)
members = body['members']
members = [member['member_id'] for member in members]
self.assertIn(self.alt_tenant_id, members)
# get image as alt user
self.alt_img_cli.show_image(image)
@decorators.idempotent_id('6a5328a5-80e8-4b82-bd32-6c061f128da9')
def test_get_shared_images(self):
"""Test getting shared images"""
image = self._create_image()
self.image_member_client.create_image_member(image, self.alt_tenant_id)
share_image = self._create_image()
self.image_member_client.create_image_member(share_image,
self.alt_tenant_id)
body = self.image_member_client.list_shared_images(
self.alt_tenant_id)
images = body['shared_images']
images = [img['image_id'] for img in images]
self.assertIn(share_image, images)
self.assertIn(image, images)
@decorators.idempotent_id('a76a3191-8948-4b44-a9d6-4053e5f2b138')
def test_remove_member(self):
"""Test removing member from image"""
image_id = self._create_image()
self.image_member_client.create_image_member(image_id,
self.alt_tenant_id)
self.image_member_client.delete_image_member(image_id,
self.alt_tenant_id)
body = self.image_member_client.list_image_members(image_id)
members = body['members']
self.assertEmpty(members)
self.assertRaises(
lib_exc.NotFound, self.alt_img_cli.show_image, image_id)

View File

@ -1,62 +0,0 @@
# Copyright 2013 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.api.image import base
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
class ImageMembersNegativeTest(base.BaseV1ImageMembersTest):
"""Negative tests of image members"""
@decorators.attr(type=['negative'])
@decorators.idempotent_id('147a9536-18e3-45da-91ea-b037a028f364')
def test_add_member_with_non_existing_image(self):
"""Add member with non existing image"""
non_exist_image = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.image_member_client.create_image_member,
non_exist_image, self.alt_tenant_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('e1559f05-b667-4f1b-a7af-518b52dc0c0f')
def test_delete_member_with_non_existing_image(self):
"""Delete member with non existing image"""
non_exist_image = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.image_member_client.delete_image_member,
non_exist_image, self.alt_tenant_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f5720333-dd69-4194-bb76-d2f048addd56')
def test_delete_member_with_non_existing_tenant(self):
"""Delete member from image with non existing tenant"""
image_id = self._create_image()
non_exist_tenant = data_utils.rand_uuid_hex()
self.assertRaises(lib_exc.NotFound,
self.image_member_client.delete_image_member,
image_id, non_exist_tenant)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f25f89e4-0b6c-453b-a853-1f80b9d7ef26')
def test_get_image_without_membership(self):
"""Get image without membership
Image is hidden from another tenants.
"""
image_id = self._create_image()
self.assertRaises(lib_exc.NotFound,
self.alt_img_cli.show_image,
image_id)

View File

@ -1,341 +0,0 @@
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import io
from tempest.api.image import base
from tempest.common import image as common_image
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
CONF = config.CONF
def get_container_and_disk_format():
a_formats = ['ami', 'ari', 'aki']
container_format = CONF.image.container_formats[0]
# In v1, If container_format is one of ['ami', 'ari', 'aki'], then
# disk_format must be same with container_format.
# If they are of different item sequence in tempest.conf, such as:
# container_formats = ami,ari,aki,bare
# disk_formats = ari,ami,aki,vhd
# we can select one in disk_format list that is same with container_format.
if container_format in a_formats:
if container_format in CONF.image.disk_formats:
disk_format = container_format
else:
msg = ("The container format and the disk format don't match. "
"Container format: %(container)s, Disk format: %(disk)s." %
{'container': container_format, 'disk':
CONF.image.disk_formats})
raise exceptions.InvalidConfiguration(msg)
else:
disk_format = CONF.image.disk_formats[0]
return container_format, disk_format
class CreateRegisterImagesTest(base.BaseV1ImageTest):
"""Here we test the registration and creation of images."""
@decorators.idempotent_id('3027f8e6-3492-4a11-8575-c3293017af4d')
def test_register_then_upload(self):
"""Register, then upload an image"""
properties = {'prop1': 'val1'}
container_format, disk_format = get_container_and_disk_format()
image = self.create_image(name='New Name',
container_format=container_format,
disk_format=disk_format,
is_public=False,
properties=properties)
self.assertEqual('New Name', image.get('name'))
self.assertFalse(image.get('is_public'))
self.assertEqual('queued', image.get('status'))
for key, val in properties.items():
self.assertEqual(val, image.get('properties')[key])
# Now try uploading an image file
image_file = io.BytesIO(data_utils.random_bytes())
body = self.client.update_image(image['id'], data=image_file)['image']
self.assertIn('size', body)
self.assertEqual(1024, body.get('size'))
@decorators.idempotent_id('69da74d9-68a9-404b-9664-ff7164ccb0f5')
def test_register_remote_image(self):
"""Register a new remote image"""
container_format, disk_format = get_container_and_disk_format()
body = self.create_image(name='New Remote Image',
container_format=container_format,
disk_format=disk_format, is_public=False,
location=CONF.image.http_image,
properties={'key1': 'value1',
'key2': 'value2'})
self.assertEqual('New Remote Image', body.get('name'))
self.assertFalse(body.get('is_public'))
self.assertEqual('active', body.get('status'))
properties = body.get('properties')
self.assertEqual(properties['key1'], 'value1')
self.assertEqual(properties['key2'], 'value2')
@decorators.idempotent_id('6d0e13a7-515b-460c-b91f-9f4793f09816')
def test_register_http_image(self):
"""Register a new image from an http image path url"""
container_format, disk_format = get_container_and_disk_format()
image = self.create_image(name='New Http Image',
container_format=container_format,
disk_format=disk_format, is_public=False,
copy_from=CONF.image.http_image)
self.assertEqual('New Http Image', image.get('name'))
self.assertFalse(image.get('is_public'))
waiters.wait_for_image_status(self.client, image['id'], 'active')
self.client.show_image(image['id'])
@decorators.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b')
def test_register_image_with_min_ram(self):
"""Register an image with min ram"""
container_format, disk_format = get_container_and_disk_format()
properties = {'prop1': 'val1'}
body = self.create_image(name='New_image_with_min_ram',
container_format=container_format,
disk_format=disk_format,
is_public=False,
min_ram=40,
properties=properties)
self.assertEqual('New_image_with_min_ram', body.get('name'))
self.assertFalse(body.get('is_public'))
self.assertEqual('queued', body.get('status'))
self.assertEqual(40, body.get('min_ram'))
for key, val in properties.items():
self.assertEqual(val, body.get('properties')[key])
self.client.delete_image(body['id'])
class ListImagesTest(base.BaseV1ImageTest):
"""Here we test the listing of image information"""
@classmethod
def skip_checks(cls):
super(ListImagesTest, cls).skip_checks()
if (len(CONF.image.container_formats) < 2 or
len(CONF.image.disk_formats) < 2):
skip_msg = ("%s skipped as multiple container formats "
"or disk formats are not available." % cls.__name__)
raise cls.skipException(skip_msg)
@classmethod
def resource_setup(cls):
super(ListImagesTest, cls).resource_setup()
# We add a few images here to test the listing functionality of
# the images API
a_formats = ['ami', 'ari', 'aki']
(cls.container_format,
container_format_alt) = CONF.image.container_formats[:2]
cls.disk_format, cls.disk_format_alt = CONF.image.disk_formats[:2]
if cls.container_format in a_formats:
cls.disk_format = cls.container_format
if container_format_alt in a_formats:
cls.disk_format_alt = container_format_alt
img1 = cls._create_remote_image('one', cls.container_format,
cls.disk_format)
img2 = cls._create_remote_image('two', container_format_alt,
cls.disk_format_alt)
img3 = cls._create_remote_image('dup', cls.container_format,
cls.disk_format)
img4 = cls._create_remote_image('dup', cls.container_format,
cls.disk_format)
img5 = cls._create_standard_image('1', container_format_alt,
cls.disk_format_alt, 42)
img6 = cls._create_standard_image('2', container_format_alt,
cls.disk_format_alt, 142)
img7 = cls._create_standard_image('33', cls.container_format,
cls.disk_format, 142)
img8 = cls._create_standard_image('33', cls.container_format,
cls.disk_format, 142)
cls.created_set = set(cls.created_images)
# same container format
cls.same_container_format_set = set((img1, img3, img4, img7, img8))
# same disk format
cls.same_disk_format_set = set((img2, img5, img6))
# 1x with size 42
cls.size42_set = set((img5,))
# 3x with size 142
cls.size142_set = set((img6, img7, img8,))
# dup named
cls.dup_set = set((img3, img4))
@classmethod
def _create_remote_image(cls, name, container_format, disk_format):
"""Create a new remote image and return newly-registered image-id"""
name = 'New Remote Image %s' % name
location = CONF.image.http_image
image = cls.create_image(name=name,
container_format=container_format,
disk_format=disk_format,
is_public=False,
location=location)
return image['id']
@classmethod
def _create_standard_image(cls, name, container_format,
disk_format, size):
"""Create a new standard image and return newly-registered image-id
Note that the size of the new image is a random number between
1024 and 4096
"""
image_file = io.BytesIO(data_utils.random_bytes(size))
name = 'New Standard Image %s' % name
image = cls.create_image(name=name,
container_format=container_format,
disk_format=disk_format,
is_public=False, data=image_file)
return image['id']
@decorators.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d')
def test_index_no_params(self):
"""Simple test to see all fixture images returned"""
images_list = self.client.list_images()['images']
image_list = [image['id'] for image in images_list]
for image_id in self.created_images:
self.assertIn(image_id, image_list)
@decorators.idempotent_id('f1755589-63d6-4468-b098-589820eb4031')
def test_index_disk_format(self):
"""Test listing images by disk format"""
images_list = self.client.list_images(
disk_format=self.disk_format_alt)['images']
for image in images_list:
self.assertEqual(image['disk_format'], self.disk_format_alt)
result_set = set(map(lambda x: x['id'], images_list))
self.assertTrue(self.same_disk_format_set <= result_set)
self.assertFalse(self.created_set - self.same_disk_format_set <=
result_set)
@decorators.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b')
def test_index_container_format(self):
"""Test listing images by container format"""
images_list = self.client.list_images(
container_format=self.container_format)['images']
for image in images_list:
self.assertEqual(image['container_format'], self.container_format)
result_set = set(map(lambda x: x['id'], images_list))
self.assertTrue(self.same_container_format_set <= result_set)
self.assertFalse(self.created_set - self.same_container_format_set <=
result_set)
@decorators.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14')
def test_index_max_size(self):
"""Test listing images by max size"""
images_list = self.client.list_images(size_max=42)['images']
for image in images_list:
self.assertLessEqual(image['size'], 42)
result_set = set(map(lambda x: x['id'], images_list))
self.assertTrue(self.size42_set <= result_set)
self.assertFalse(self.created_set - self.size42_set <= result_set)
@decorators.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8')
def test_index_min_size(self):
"""Test listing images by min size"""
images_list = self.client.list_images(size_min=142)['images']
for image in images_list:
self.assertGreaterEqual(image['size'], 142)
result_set = set(map(lambda x: x['id'], images_list))
self.assertTrue(self.size142_set <= result_set)
self.assertFalse(self.size42_set <= result_set)
@decorators.idempotent_id('e5dc26d9-9aa2-48dd-bda5-748e1445da98')
def test_index_status_active_detail(self):
"""Test listing active images sorting by size in descending order"""
images_list = self.client.list_images(detail=True,
status='active',
sort_key='size',
sort_dir='desc')['images']
top_size = images_list[0]['size'] # We have non-zero sized images
for image in images_list:
size = image['size']
self.assertLessEqual(size, top_size)
top_size = size
self.assertEqual(image['status'], 'active')
@decorators.idempotent_id('097af10a-bae8-4342-bff4-edf89969ed2a')
def test_index_name(self):
"""Test listing images by its name"""
images_list = self.client.list_images(
detail=True,
name='New Remote Image dup')['images']
result_set = set(map(lambda x: x['id'], images_list))
for image in images_list:
self.assertEqual(image['name'], 'New Remote Image dup')
self.assertTrue(self.dup_set <= result_set)
self.assertFalse(self.created_set - self.dup_set <= result_set)
class UpdateImageMetaTest(base.BaseV1ImageTest):
"""Test image metadata"""
@classmethod
def resource_setup(cls):
super(UpdateImageMetaTest, cls).resource_setup()
container_format, disk_format = get_container_and_disk_format()
cls.image_id = cls._create_standard_image('1', container_format,
disk_format, 42)
@classmethod
def _create_standard_image(cls, name, container_format,
disk_format, size):
"""Create a new standard image and return newly-registered image-id"""
image_file = io.BytesIO(data_utils.random_bytes(size))
name = 'New Standard Image %s' % name
image = cls.create_image(name=name,
container_format=container_format,
disk_format=disk_format,
is_public=False, data=image_file,
properties={'key1': 'value1'})
return image['id']
@decorators.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928')
def test_list_image_metadata(self):
"""Test listing image metadata"""
# All metadata key/value pairs for an image should be returned
resp = self.client.check_image(self.image_id)
resp_metadata = common_image.get_image_meta_from_headers(resp)
expected = {'key1': 'value1'}
self.assertEqual(expected, resp_metadata['properties'])
@decorators.idempotent_id('d6d7649c-08ce-440d-9ea7-e3dda552f33c')
def test_update_image_metadata(self):
"""Test updating image metadata"""
# The metadata for the image should match the updated values
req_metadata = {'key1': 'alt1', 'key2': 'value2'}
resp = self.client.check_image(self.image_id)
metadata = common_image.get_image_meta_from_headers(resp)
self.assertEqual(metadata['properties'], {'key1': 'value1'})
metadata['properties'].update(req_metadata)
headers = common_image.image_meta_to_headers(
properties=metadata['properties'])
self.client.update_image(self.image_id, headers=headers)
resp = self.client.check_image(self.image_id)
resp_metadata = common_image.get_image_meta_from_headers(resp)
self.assertEqual(req_metadata, resp_metadata['properties'])

View File

@ -1,82 +0,0 @@
# Copyright 2013 IBM Corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.api.image import base
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
class CreateDeleteImagesNegativeTest(base.BaseV1ImageTest):
"""Here are negative tests for the deletion and creation of images."""
@decorators.attr(type=['negative'])
@decorators.idempotent_id('036ede36-6160-4463-8c01-c781eee6369d')
def test_register_with_invalid_container_format(self):
"""Create image with invalid container format
Negative tests for invalid data supplied to POST /images
"""
self.assertRaises(lib_exc.BadRequest, self.client.create_image,
headers={'x-image-meta-name': 'test',
'x-image-meta-container_format': 'wrong',
'x-image-meta-disk_format': 'vhd'})
@decorators.attr(type=['negative'])
@decorators.idempotent_id('993face5-921d-4e84-aabf-c1bba4234a67')
def test_register_with_invalid_disk_format(self):
"""Create image with invalid disk format"""
self.assertRaises(lib_exc.BadRequest, self.client.create_image,
headers={'x-image-meta-name': 'test',
'x-image-meta-container_format': 'bare',
'x-image-meta-disk_format': 'wrong'})
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ec652588-7e3c-4b67-a2f2-0fa96f57c8fc')
def test_delete_non_existent_image(self):
"""Return an error while trying to delete a non-existent image"""
non_existent_image_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
non_existent_image_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('04f72aa3-fcec-45a3-81a3-308ef7cc82bc')
def test_delete_image_blank_id(self):
"""Return an error while trying to delete an image with blank Id"""
self.assertRaises(lib_exc.NotFound, self.client.delete_image, '')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('950e5054-a3c7-4dee-ada5-e576f1087abd')
def test_delete_image_non_hex_string_id(self):
"""Return an error while trying to delete an image with non hex id"""
invalid_image_id = data_utils.rand_uuid()[:-1] + "j"
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
invalid_image_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4ed757cd-450c-44b1-9fd1-c819748c650d')
def test_delete_image_negative_image_id(self):
"""Return an error while trying to delete an image with negative id"""
self.assertRaises(lib_exc.NotFound, self.client.delete_image, -1)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('a4a448ab-3db2-4d2d-b9b2-6a1271241dfe')
def test_delete_image_id_over_character_limit(self):
"""Return an error while trying to delete image with id over limit"""
overlimit_image_id = data_utils.rand_uuid() + "1"
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
overlimit_image_id)

View File

@ -83,8 +83,6 @@ class Manager(clients.ServiceClients):
def _set_image_clients(self):
if CONF.service_available.glance:
self.image_client = self.image_v1.ImagesClient()
self.image_member_client = self.image_v1.ImageMembersClient()
self.image_client_v2 = self.image_v2.ImagesClient()
self.image_member_client_v2 = self.image_v2.ImageMembersClient()
self.image_cache_client = self.image_v2.ImageCacheClient()

View File

@ -118,25 +118,16 @@ def verify_glance_api_versions(os, update):
# Since we want to verify that the configuration is correct, we cannot
# rely on a specific version of the API being available.
try:
_, versions = os.image_v1.ImagesClient().get_versions()
versions = os.image_v2.VersionsClient().list_versions()['versions']
versions = [x['id'] for x in versions]
except lib_exc.NotFound:
# If not found, we use v2. The assumption is that either v1 or v2
# are available, since glance is marked as available in the catalog.
# If not, glance should be disabled in Tempest conf.
try:
versions = os.image_v2.VersionsClient().list_versions()['versions']
versions = [x['id'] for x in versions]
except lib_exc.NotFound:
msg = ('Glance is available in the catalog, but no known version, '
'(v1.x or v2.x) of Glance could be found, so Glance should '
'be configured as not available')
LOG.warning(msg)
print_and_or_update('glance', 'service-available', False, update)
return
msg = ('Glance is available in the catalog, but no known version, '
'of Glance could be found, so Glance should '
'be configured as not available')
LOG.warning(msg)
print_and_or_update('glance', 'service-available', False, update)
return
if CONF.image_feature_enabled.api_v1 != contains_version('v1.', versions):
print_and_or_update('api_v1', 'image-feature-enabled',
not CONF.image_feature_enabled.api_v1, update)
if CONF.image_feature_enabled.api_v2 != contains_version('v2.', versions):
print_and_or_update('api_v2', 'image-feature-enabled',
not CONF.image_feature_enabled.api_v2, update)

View File

@ -16,12 +16,10 @@ import time
from oslo_log import log as logging
from tempest.common import image as common_image
from tempest import config
from tempest import exceptions
from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.image.v1 import images_client as images_v1_client
CONF = config.CONF
LOG = logging.getLogger(__name__)
@ -156,17 +154,7 @@ def wait_for_image_status(client, image_id, status):
The client should have a show_image(image_id) method to get the image.
The client should also have build_interval and build_timeout attributes.
"""
if isinstance(client, images_v1_client.ImagesClient):
# The 'check_image' method is used here because the show_image method
# returns image details plus the image itself which is very expensive.
# The 'check_image' method returns just image details.
def _show_image_v1(image_id):
resp = client.check_image(image_id)
return common_image.get_image_meta_from_headers(resp)
show_image = _show_image_v1
else:
show_image = client.show_image
show_image = client.show_image
current_status = 'An unknown status'
start = int(time.time())

View File

@ -719,14 +719,6 @@ ImageFeaturesGroup = [
'are current one. In future, Tempest will '
'test v2 APIs only so this config option '
'will be removed.'),
cfg.BoolOpt('api_v1',
default=False,
help="Is the v1 image API enabled",
deprecated_for_removal=True,
deprecated_reason='Glance v1 APIs are deprecated and v2 APIs '
'are current one. In future, Tempest will '
'test v2 APIs only so this config option '
'will be removed.'),
# Image import feature is setup in devstack victoria onwards.
# Once all stable branches setup the same via glance standalone
# mode or with uwsgi, we can remove this config option.

View File

@ -48,7 +48,6 @@ def tempest_modules():
'placement': placement,
'identity.v2': identity.v2,
'identity.v3': identity.v3,
'image.v1': image.v1,
'image.v2': image.v2,
'network': network,
'object-storage': object_storage,

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations under
# the License.
from tempest.lib.services.image import v1
from tempest.lib.services.image import v2
__all__ = ['v1', 'v2']
__all__ = ['v2']

View File

@ -1,28 +0,0 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import warnings
from tempest.lib.services.image.v1.image_members_client import \
ImageMembersClient
from tempest.lib.services.image.v1.images_client import ImagesClient
__all__ = ['ImageMembersClient', 'ImagesClient']
warnings.warn(
"The tempest.lib.services.image.v1 module (Image v1 APIs service "
"clients) is deprecated in favor of tempest.lib.services.image.v2 "
"(Image v2 APIs service clients) and will be removed once Tempest stop "
"supporting stable Ussuri.", DeprecationWarning)

View File

@ -1,66 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_serialization import jsonutils as json
from tempest.lib.common import rest_client
class ImageMembersClient(rest_client.RestClient):
api_version = "v1"
def list_image_members(self, image_id):
"""List all members of an image."""
url = 'images/%s/members' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_shared_images(self, tenant_id):
"""List image memberships for the given tenant.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/image/v1/#list-shared-images
"""
url = 'shared-images/%s' % tenant_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def create_image_member(self, image_id, member_id, **kwargs):
"""Add a member to an image.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/image/v1/#add-member-to-image
"""
url = 'images/%s/members/%s' % (image_id, member_id)
body = json.dumps({'member': kwargs})
resp, __ = self.put(url, body)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp)
def delete_image_member(self, image_id, member_id):
"""Removes a membership from the image.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/image/v1/#remove-member
"""
url = 'images/%s/members/%s' % (image_id, member_id)
resp, __ = self.delete(url)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp)

View File

@ -1,155 +0,0 @@
# Copyright 2013 IBM Corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import functools
from urllib import parse as urllib
from oslo_serialization import jsonutils as json
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
CHUNKSIZE = 1024 * 64 # 64kB
class ImagesClient(rest_client.RestClient):
api_version = "v1"
def _create_with_data(self, headers, data):
# We are going to do chunked transfert, so split the input data
# info fixed-sized chunks.
headers['Content-Type'] = 'application/octet-stream'
data = iter(functools.partial(data.read, CHUNKSIZE), b'')
resp, body = self.request('POST', 'images',
headers=headers, body=data, chunked=True)
self._error_checker(resp, body)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def _update_with_data(self, image_id, headers, data):
# We are going to do chunked transfert, so split the input data
# info fixed-sized chunks.
headers['Content-Type'] = 'application/octet-stream'
data = iter(functools.partial(data.read, CHUNKSIZE), b'')
url = 'images/%s' % image_id
resp, body = self.request('PUT', url, headers=headers,
body=data, chunked=True)
self._error_checker(resp, body)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@property
def http(self):
if self._http is None:
self._http = self._get_http()
return self._http
def create_image(self, data=None, headers=None):
"""Create an image.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/image/v1/index.html#create-image
"""
if headers is None:
headers = {}
if data is not None:
return self._create_with_data(headers, data)
resp, body = self.post('images', None, headers)
self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def update_image(self, image_id, data=None, headers=None):
"""Update an image.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/image/v1/index.html#update-image
"""
if headers is None:
headers = {}
if data is not None:
return self._update_with_data(image_id, headers, data)
url = 'images/%s' % image_id
resp, body = self.put(url, None, headers)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def delete_image(self, image_id):
url = 'images/%s' % image_id
resp, body = self.delete(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
def list_images(self, detail=False, **kwargs):
"""Return a list of all images filtered by input parameters.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/image/v1/#list-images
Most parameters except the following are passed to the API without
any changes.
:param changes_since: The name is changed to changes-since
"""
url = 'images'
if detail:
url += '/detail'
if 'changes_since' in kwargs:
kwargs['changes-since'] = kwargs.pop('changes_since')
if kwargs:
url += '?%s' % urllib.urlencode(kwargs)
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def check_image(self, image_id):
"""Check image metadata."""
url = 'images/%s' % image_id
resp, body = self.head(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
def show_image(self, image_id):
"""Get image details plus the image itself."""
url = 'images/%s' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBodyData(resp, body)
def is_resource_deleted(self, id):
try:
resp = self.check_image(id)
if resp.response["x-image-meta-status"] == 'deleted':
return True
except lib_exc.NotFound:
return True
return False
@property
def resource_type(self):
"""Returns the primary type of resource this client works with."""
return 'image_meta'

View File

@ -25,7 +25,6 @@ from oslo_serialization import jsonutils as json
from oslo_utils import netutils
from tempest.common import compute
from tempest.common import image as common_image
from tempest.common.utils.linux import remote_client
from tempest.common.utils import net_utils
from tempest.common import waiters
@ -124,15 +123,11 @@ class ScenarioTest(tempest.test.BaseTestCase):
"""This setup the service clients for the tests"""
super(ScenarioTest, cls).setup_clients()
if CONF.service_available.glance:
# Check if glance v1 is available to determine which client to use.
if CONF.image_feature_enabled.api_v1:
cls.image_client = cls.os_primary.image_client
elif CONF.image_feature_enabled.api_v2:
if CONF.image_feature_enabled.api_v2:
cls.image_client = cls.os_primary.image_client_v2
else:
raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
'api_v2 must be True in [image-feature-enabled].')
cls.setup_compute_client(cls)
cls.setup_network_client(cls)
@ -371,11 +366,7 @@ class ScenarioTest(tempest.test.BaseTestCase):
if size is None:
size = CONF.volume.volume_size
if imageRef:
if CONF.image_feature_enabled.api_v1:
resp = self.image_client.check_image(imageRef)
image = common_image.get_image_meta_from_headers(resp)
else:
image = self.image_client.show_image(imageRef)
image = self.image_client.show_image(imageRef)
min_disk = image.get('min_disk')
size = max(size, min_disk)
if name is None:
@ -796,27 +787,18 @@ class ScenarioTest(tempest.test.BaseTestCase):
'name': name,
'container_format': img_container_format,
'disk_format': img_disk_format or img_container_format,
'visibility': 'private'
}
if CONF.image_feature_enabled.api_v1:
params['is_public'] = 'False'
if img_properties:
params['properties'] = img_properties
params = {'headers': common_image.image_meta_to_headers(**params)}
else:
params['visibility'] = 'private'
# Additional properties are flattened out in the v2 API.
if img_properties:
params.update(img_properties)
# Additional properties are flattened out in the v2 API.
if img_properties:
params.update(img_properties)
params.update(kwargs)
body = self.image_client.create_image(**params)
image = body['image'] if 'image' in body else body
self.addCleanup(self.image_client.delete_image, image['id'])
self.assertEqual("queued", image['status'])
with open(img_path, 'rb') as image_file:
if CONF.image_feature_enabled.api_v1:
self.image_client.update_image(image['id'], data=image_file)
else:
self.image_client.store_image_file(image['id'], image_file)
self.image_client.store_image_file(image['id'], image_file)
LOG.debug("image:%s", image['id'])
return image['id']
@ -864,15 +846,9 @@ class ScenarioTest(tempest.test.BaseTestCase):
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
_image_client.delete_image, image_id)
if CONF.image_feature_enabled.api_v1:
# In glance v1 the additional properties are stored in the headers
resp = _image_client.check_image(image_id)
snapshot_image = common_image.get_image_meta_from_headers(resp)
image_props = snapshot_image.get('properties', {})
else:
# In glance v2 the additional properties are flattened.
snapshot_image = _image_client.show_image(image_id)
image_props = snapshot_image
# In glance v2 the additional properties are flattened.
snapshot_image = _image_client.show_image(image_id)
image_props = snapshot_image
bdm = image_props.get('block_device_mapping')
if bdm:

View File

@ -178,13 +178,13 @@ class TestDiscovery(base.TestCase):
def test_verify_glance_version_no_v2_with_v1_1(self):
# This test verifies that wrong config api_v2 = True is detected
class FakeClient(object):
def get_versions(self):
return (None, ['v1.1'])
def list_versions(self):
return {'versions': [{'id': 'v1.1'}]}
fake_os = mock.MagicMock()
fake_module = mock.MagicMock()
fake_module.ImagesClient = FakeClient
fake_os.image_v1 = fake_module
fake_module.VersionsClient = FakeClient
fake_os.image_v2 = fake_module
with mock.patch.object(verify_tempest_config,
'print_and_or_update') as print_mock:
verify_tempest_config.verify_glance_api_versions(fake_os, True)
@ -194,53 +194,28 @@ class TestDiscovery(base.TestCase):
def test_verify_glance_version_no_v2_with_v1_0(self):
# This test verifies that wrong config api_v2 = True is detected
class FakeClient(object):
def get_versions(self):
return (None, ['v1.0'])
def list_versions(self):
return {'versions': [{'id': 'v1.0'}]}
fake_os = mock.MagicMock()
fake_module = mock.MagicMock()
fake_module.ImagesClient = FakeClient
fake_os.image_v1 = fake_module
fake_module.VersionsClient = FakeClient
fake_os.image_v2 = fake_module
with mock.patch.object(verify_tempest_config,
'print_and_or_update') as print_mock:
verify_tempest_config.verify_glance_api_versions(fake_os, True)
print_mock.assert_called_with('api_v2', 'image-feature-enabled',
False, True)
def test_verify_glance_version_no_v1(self):
# This test verifies that wrong config api_v1 = True is detected
class FakeClient(object):
def get_versions(self):
raise lib_exc.NotFound()
def list_versions(self):
return {'versions': [{'id': 'v2.0'}]}
fake_os = mock.MagicMock()
fake_module = mock.MagicMock()
fake_module.ImagesClient = FakeClient
fake_module.VersionsClient = FakeClient
fake_os.image_v1 = fake_module
fake_os.image_v2 = fake_module
with mock.patch.object(verify_tempest_config,
'print_and_or_update') as print_mock:
verify_tempest_config.verify_glance_api_versions(fake_os, True)
print_mock.assert_not_called()
def test_verify_glance_version_no_version(self):
# This test verifies that wrong config api_v1 = True is detected
# This test verifies that wrong config api_v2 = True is detected
class FakeClient(object):
def get_versions(self):
raise lib_exc.NotFound()
def list_versions(self):
raise lib_exc.NotFound()
fake_os = mock.MagicMock()
fake_module = mock.MagicMock()
fake_module.ImagesClient = FakeClient
fake_module.VersionsClient = FakeClient
fake_os.image_v1 = fake_module
fake_os.image_v2 = fake_module
with mock.patch.object(verify_tempest_config,
'print_and_or_update') as print_mock:

View File

@ -1,84 +0,0 @@
# Copyright 2016 NEC Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib.services.image.v1 import image_members_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib.services import base
class TestImageMembersClient(base.BaseServiceTest):
FAKE_LIST_IMAGE_MEMBERS = {
"members": [
{
"created_at": "2013-10-07T17:58:03Z",
"image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe",
"member_id": "123456789",
"status": "pending",
"updated_at": "2013-10-07T17:58:03Z"
},
{
"created_at": "2013-10-07T17:58:55Z",
"image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe",
"member_id": "987654321",
"status": "accepted",
"updated_at": "2013-10-08T12:08:55Z"
}
]
}
def setUp(self):
super(TestImageMembersClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = image_members_client.ImageMembersClient(fake_auth,
'image',
'regionOne')
def _test_list_image_members(self, bytes_body=False):
self.check_service_client_function(
self.client.list_image_members,
'tempest.lib.common.rest_client.RestClient.get',
self.FAKE_LIST_IMAGE_MEMBERS,
bytes_body,
image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e")
def _test_create_image_member(self, bytes_body=False):
self.check_service_client_function(
self.client.create_image_member,
'tempest.lib.common.rest_client.RestClient.put',
{},
bytes_body,
image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e",
member_id="8989447062e04a818baf9e073fd04fa7",
status=204)
def test_list_image_members_with_str_body(self):
self._test_list_image_members()
def test_list_image_members_with_bytes_body(self):
self._test_list_image_members(bytes_body=True)
def test_create_image_member_with_str_body(self):
self._test_create_image_member()
def test_create_image_member_with_bytes_body(self):
self._test_create_image_member(bytes_body=True)
def test_delete_image_member(self):
self.check_service_client_function(
self.client.delete_image_member,
'tempest.lib.common.rest_client.RestClient.delete',
{},
image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e",
member_id="8989447062e04a818baf9e073fd04fa7",
status=204)

View File

@ -37,7 +37,7 @@ class RegistryFixture(fixtures.Fixture):
def __init__(self):
"""Initialise the registry fixture"""
self.services = set(['compute', 'identity.v2', 'identity.v3',
'image.v1', 'image.v2', 'network', 'placement',
'image.v2', 'network', 'placement',
'volume.v2', 'volume.v3', 'object-storage'])
def _setUp(self):